@taskless-app/swarm 0.6.25 → 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 +84 -25
- package/dist/overmind.js +776 -419
- package/package.json +2 -2
package/dist/overmind.js
CHANGED
|
@@ -9,17 +9,23 @@ var __export = (target, all) => {
|
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
// ../swarm-core/src/types.ts
|
|
12
|
+
function holdsFiles(run) {
|
|
13
|
+
if ((run.kind ?? "drone") !== "drone") return false;
|
|
14
|
+
if (run.status === "review") return !!run.pr_url;
|
|
15
|
+
return ACTIVE_DRONE_STATUSES.has(run.status);
|
|
16
|
+
}
|
|
12
17
|
function isMilestoneKind(kind) {
|
|
13
18
|
return MILESTONE_KIND_SET.has(kind);
|
|
14
19
|
}
|
|
15
20
|
function toRunKind(role) {
|
|
16
21
|
return role === "hero" || role === "reviewer" || role === "verifier" ? role : "drone";
|
|
17
22
|
}
|
|
18
|
-
var ACTIVE_DRONE_STATUSES, EVENT_KINDS, MILESTONE_KINDS, MILESTONE_KIND_SET;
|
|
23
|
+
var ACTIVE_DRONE_STATUSES, FILE_HOLDING_STATUSES, EVENT_KINDS, MILESTONE_KINDS, MILESTONE_KIND_SET;
|
|
19
24
|
var init_types = __esm({
|
|
20
25
|
"../swarm-core/src/types.ts"() {
|
|
21
26
|
"use strict";
|
|
22
27
|
ACTIVE_DRONE_STATUSES = /* @__PURE__ */ new Set(["running", "blocked"]);
|
|
28
|
+
FILE_HOLDING_STATUSES = /* @__PURE__ */ new Set([...ACTIVE_DRONE_STATUSES, "review"]);
|
|
23
29
|
EVENT_KINDS = [
|
|
24
30
|
"spawned",
|
|
25
31
|
"step",
|
|
@@ -303,52 +309,6 @@ var init_timeline = __esm({
|
|
|
303
309
|
}
|
|
304
310
|
});
|
|
305
311
|
|
|
306
|
-
// ../swarm-core/src/reviewPhase.ts
|
|
307
|
-
function computeReviewPhase(input) {
|
|
308
|
-
const { reviewVerdict, ciRed } = input;
|
|
309
|
-
if (reviewVerdict === "approve" && !ciRed) {
|
|
310
|
-
return { kind: "ready", label: REVIEW_PHASE_TEXT.ready, ready: true };
|
|
311
|
-
}
|
|
312
|
-
if (ciRed) {
|
|
313
|
-
const jobs = (input.ciFailing ?? []).filter((j) => j && j !== "?");
|
|
314
|
-
const label3 = jobs.length ? `${REVIEW_PHASE_TEXT.ci_fixing}: ${jobs.join(", ")}` : REVIEW_PHASE_TEXT.ci_fixing;
|
|
315
|
-
return { kind: "ci_fixing", label: label3, ready: false };
|
|
316
|
-
}
|
|
317
|
-
if (reviewVerdict === "changes") {
|
|
318
|
-
return { kind: "changes", label: REVIEW_PHASE_TEXT.changes, ready: false };
|
|
319
|
-
}
|
|
320
|
-
if (input.reviewerName) {
|
|
321
|
-
return { kind: "in_review", label: `\u041D\u0430 \u0440\u0435\u0432\u044C\u044E \u0443 ${input.reviewerName}`, ready: false };
|
|
322
|
-
}
|
|
323
|
-
if (input.reviewerDead) {
|
|
324
|
-
return { kind: "reviewer_dead", label: REVIEW_PHASE_TEXT.reviewer_dead, ready: true };
|
|
325
|
-
}
|
|
326
|
-
const p = input.ciProgress;
|
|
327
|
-
if (p && p.total > 0 && p.pass >= p.total) {
|
|
328
|
-
return { kind: "awaiting_reviewer", label: REVIEW_PHASE_TEXT.awaiting_reviewer, ready: false };
|
|
329
|
-
}
|
|
330
|
-
const label2 = p && p.total > 0 ? `${REVIEW_PHASE_TEXT.checks} \u2014 CI ${p.pass}/${p.total}` : REVIEW_PHASE_TEXT.checks;
|
|
331
|
-
return { kind: "checks", label: label2, ready: false };
|
|
332
|
-
}
|
|
333
|
-
var REVIEW_PHASE_TEXT, PHASE_BY_LENGTH;
|
|
334
|
-
var init_reviewPhase = __esm({
|
|
335
|
-
"../swarm-core/src/reviewPhase.ts"() {
|
|
336
|
-
"use strict";
|
|
337
|
-
REVIEW_PHASE_TEXT = {
|
|
338
|
-
checks: "\u0418\u0434\u0443\u0442 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438",
|
|
339
|
-
awaiting_reviewer: "\u0417\u0435\u043B\u0451\u043D\u044B\u0439 \u2014 \u0436\u0434\u0451\u0442 \u0440\u0435\u0432\u044C\u044E\u0435\u0440\u0430",
|
|
340
|
-
ci_fixing: "CI \u043A\u0440\u0430\u0441\u043D\u044B\u0439 \u2014 \u0434\u0440\u043E\u043D \u0447\u0438\u043D\u0438\u0442",
|
|
341
|
-
in_review: "\u041D\u0430 \u0440\u0435\u0432\u044C\u044E",
|
|
342
|
-
changes: "\u041D\u0443\u0436\u043D\u044B \u043F\u0440\u0430\u0432\u043A\u0438 \u2014 \u0434\u0440\u043E\u043D \u043F\u0440\u0430\u0432\u0438\u0442",
|
|
343
|
-
ready: "\u0417\u0435\u043B\u0451\u043D\u044B\u0439 \u2014 \u0433\u043E\u0442\u043E\u0432 \u043A \u043C\u0435\u0440\u0436\u0443",
|
|
344
|
-
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"
|
|
345
|
-
};
|
|
346
|
-
PHASE_BY_LENGTH = Object.keys(REVIEW_PHASE_TEXT).sort(
|
|
347
|
-
(a, b) => REVIEW_PHASE_TEXT[b].length - REVIEW_PHASE_TEXT[a].length
|
|
348
|
-
);
|
|
349
|
-
}
|
|
350
|
-
});
|
|
351
|
-
|
|
352
312
|
// ../swarm-core/src/verifyVerdict.ts
|
|
353
313
|
function isVerifyVerdict(v) {
|
|
354
314
|
return typeof v === "string" && VERIFY_VERDICT_SET.has(v);
|
|
@@ -396,6 +356,68 @@ var init_verifyVerdict = __esm({
|
|
|
396
356
|
}
|
|
397
357
|
});
|
|
398
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
|
+
|
|
399
421
|
// ../swarm-core/src/mergeGate.ts
|
|
400
422
|
function computeMergeGate(input) {
|
|
401
423
|
if (!input.hasRun) {
|
|
@@ -575,6 +597,36 @@ var init_prRef = __esm({
|
|
|
575
597
|
}
|
|
576
598
|
});
|
|
577
599
|
|
|
600
|
+
// ../swarm-core/src/returnReason.ts
|
|
601
|
+
function isReturnReason(v) {
|
|
602
|
+
return typeof v === "string" && RETURN_REASON_SET.has(v);
|
|
603
|
+
}
|
|
604
|
+
function toReturnReason(v) {
|
|
605
|
+
return isReturnReason(v) ? v : null;
|
|
606
|
+
}
|
|
607
|
+
function returnReasonLabel(r) {
|
|
608
|
+
switch (r) {
|
|
609
|
+
case "unclear_goal":
|
|
610
|
+
return "\u043D\u0435\u043F\u043E\u043D\u044F\u0442\u043D\u043E, \u0447\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C";
|
|
611
|
+
case "no_acceptance":
|
|
612
|
+
return "\u043D\u0435\u0447\u0435\u043C \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442";
|
|
613
|
+
case "too_big":
|
|
614
|
+
return "\u0441\u043B\u0438\u0448\u043A\u043E\u043C \u0432\u0435\u043B\u0438\u043A\u0430 \u0434\u043B\u044F \u043E\u0434\u043D\u043E\u0433\u043E \u043F\u0440\u043E\u0433\u043E\u043D\u0430";
|
|
615
|
+
case "contradiction":
|
|
616
|
+
return "\u043F\u043E\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430 \u043F\u0440\u043E\u0442\u0438\u0432\u043E\u0440\u0435\u0447\u0438\u0442 \u0441\u0430\u043C\u0430 \u0441\u0435\u0431\u0435";
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
var RETURN_REASONS, RETURN_REASON_SET, UNRETURNED_FAILURE_STATUSES, UNRETURNED_FAILURE_SET;
|
|
620
|
+
var init_returnReason = __esm({
|
|
621
|
+
"../swarm-core/src/returnReason.ts"() {
|
|
622
|
+
"use strict";
|
|
623
|
+
RETURN_REASONS = ["unclear_goal", "no_acceptance", "too_big", "contradiction"];
|
|
624
|
+
RETURN_REASON_SET = new Set(RETURN_REASONS);
|
|
625
|
+
UNRETURNED_FAILURE_STATUSES = ["failed", "blocked"];
|
|
626
|
+
UNRETURNED_FAILURE_SET = new Set(UNRETURNED_FAILURE_STATUSES);
|
|
627
|
+
}
|
|
628
|
+
});
|
|
629
|
+
|
|
578
630
|
// ../swarm-core/src/modelPolicy.ts
|
|
579
631
|
function findProvider(id) {
|
|
580
632
|
const key = typeof id === "string" ? id.trim().toLowerCase() : "";
|
|
@@ -1673,6 +1725,57 @@ var init_zoneMemory = __esm({
|
|
|
1673
1725
|
}
|
|
1674
1726
|
});
|
|
1675
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
|
+
|
|
1676
1779
|
// ../swarm-core/src/index.ts
|
|
1677
1780
|
var init_src = __esm({
|
|
1678
1781
|
"../swarm-core/src/index.ts"() {
|
|
@@ -1684,6 +1787,7 @@ var init_src = __esm({
|
|
|
1684
1787
|
init_mergeQueue();
|
|
1685
1788
|
init_prRef();
|
|
1686
1789
|
init_verifyVerdict();
|
|
1790
|
+
init_returnReason();
|
|
1687
1791
|
init_modelPolicy();
|
|
1688
1792
|
init_status();
|
|
1689
1793
|
init_deps();
|
|
@@ -1706,6 +1810,7 @@ var init_src = __esm({
|
|
|
1706
1810
|
init_effort();
|
|
1707
1811
|
init_queuePlan();
|
|
1708
1812
|
init_zoneMemory();
|
|
1813
|
+
init_taskPrs();
|
|
1709
1814
|
}
|
|
1710
1815
|
});
|
|
1711
1816
|
|
|
@@ -3962,6 +4067,12 @@ function invalidPatchValue(field, v) {
|
|
|
3962
4067
|
return typeof v === "number" && Number.isInteger(v) && v >= 0 ? null : `\u043D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u044B\u0439 \u0446\u0438\u043A\u043B \u0440\u0435\u0432\u044C\u044E: ${String(v)}`;
|
|
3963
4068
|
case "pr_url":
|
|
3964
4069
|
return v === null || typeof v === "string" ? null : "pr_url \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0441\u0442\u0440\u043E\u043A\u043E\u0439";
|
|
4070
|
+
case "changed_paths": {
|
|
4071
|
+
if (!Array.isArray(v)) return "changed_paths \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u043C\u0430\u0441\u0441\u0438\u0432\u043E\u043C \u043F\u0443\u0442\u0435\u0439";
|
|
4072
|
+
if (v.length > CHANGED_PATHS_MAX) return `changed_paths: \u0441\u043B\u0438\u0448\u043A\u043E\u043C \u043C\u043D\u043E\u0433\u043E \u043F\u0443\u0442\u0435\u0439 (${v.length} > ${CHANGED_PATHS_MAX})`;
|
|
4073
|
+
const badPath = v.find((p) => typeof p !== "string" || !p || p.length > CHANGED_PATH_LEN_MAX);
|
|
4074
|
+
return badPath === void 0 ? null : `changed_paths: \u043D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u044B\u0439 \u043F\u0443\u0442\u044C: ${String(badPath).slice(0, 80)}`;
|
|
4075
|
+
}
|
|
3965
4076
|
default:
|
|
3966
4077
|
return `\u043F\u043E\u043B\u0435 \xAB${field}\xBB \u043A\u0430\u043D\u0430\u043B\u0443 \u0434\u0440\u043E\u043D\u0430 \u043D\u0435 \u043E\u0442\u0434\u0430\u0451\u0442\u0441\u044F`;
|
|
3967
4078
|
}
|
|
@@ -4215,7 +4326,7 @@ function channelDroneStore(opts) {
|
|
|
4215
4326
|
openQuestionsFor: async () => (await call("openQuestionsFor")).questions
|
|
4216
4327
|
};
|
|
4217
4328
|
}
|
|
4218
|
-
var LOCAL_CLI_KEY, PATCHABLE, EVENT_KIND_SET, ChannelUnavailableError, BACKOFF_MS;
|
|
4329
|
+
var LOCAL_CLI_KEY, PATCHABLE, CHANGED_PATHS_MAX, CHANGED_PATH_LEN_MAX, EVENT_KIND_SET, ChannelUnavailableError, BACKOFF_MS;
|
|
4219
4330
|
var init_droneChannel = __esm({
|
|
4220
4331
|
"src/droneChannel.ts"() {
|
|
4221
4332
|
"use strict";
|
|
@@ -4229,8 +4340,16 @@ var init_droneChannel = __esm({
|
|
|
4229
4340
|
// и пишется он тем же путём на ПРОВЕРЯЕМЫЙ прогон. Без него роль verifier была немой:
|
|
4230
4341
|
// вердикт выносился комментарием на PR, а `done` отбивался каналом.
|
|
4231
4342
|
"verify_verdict",
|
|
4232
|
-
"review_cycle"
|
|
4343
|
+
"review_cycle",
|
|
4344
|
+
// TASWM-506: файлы, которые прогон занял своим PR. Едут тем же вызовом, что и сдача
|
|
4345
|
+
// (done → status=review + pr_url): считает их НАШ код в дрон-сервере (`changedPaths` по
|
|
4346
|
+
// worktree), а не модель — со стороны канала это такой же самоотчёт прогона о себе, как
|
|
4347
|
+
// pr_url. Потолки на размер — ниже, в invalidPatchValue: список идёт в гейт раздачи, и
|
|
4348
|
+
// сорвавшийся дрон не должен уметь заявить занятым весь репозиторий.
|
|
4349
|
+
"changed_paths"
|
|
4233
4350
|
]);
|
|
4351
|
+
CHANGED_PATHS_MAX = 1e3;
|
|
4352
|
+
CHANGED_PATH_LEN_MAX = 1024;
|
|
4234
4353
|
EVENT_KIND_SET = new Set(EVENT_KINDS);
|
|
4235
4354
|
ChannelUnavailableError = class extends Error {
|
|
4236
4355
|
constructor(downMs, message) {
|
|
@@ -5541,9 +5660,14 @@ function rowToRun(row) {
|
|
|
5541
5660
|
tokens_out: row.tokens_out ?? 0,
|
|
5542
5661
|
duration_ms: row.duration_ms ?? 0,
|
|
5543
5662
|
pr_url: row.pr_url ?? null,
|
|
5663
|
+
// TASWM-506: файлы, занятые прогоном с открытым PR — JSON-массив, как depends_on.
|
|
5664
|
+
changed_paths: row.changed_paths ? JSON.parse(row.changed_paths) : [],
|
|
5544
5665
|
superseded_by: row.superseded_by ?? null,
|
|
5545
5666
|
decision: row.decision ? JSON.parse(row.decision) : null,
|
|
5546
5667
|
stop_reason: row.stop_reason ?? null,
|
|
5668
|
+
// TASWM-505: через узкий парсер, как verify_verdict ниже — в базе может лежать код,
|
|
5669
|
+
// записанный демоном другой версии; непонятное здесь значит «кода нет».
|
|
5670
|
+
return_reason: toReturnReason(row.return_reason),
|
|
5547
5671
|
respawns: row.respawns ?? 0,
|
|
5548
5672
|
// старые прогоны без колонки → 0
|
|
5549
5673
|
resolves_run_id: row.resolves_run_id ?? null,
|
|
@@ -5618,6 +5742,7 @@ CREATE TABLE IF NOT EXISTS runs (
|
|
|
5618
5742
|
superseded_by INTEGER,
|
|
5619
5743
|
decision TEXT,
|
|
5620
5744
|
stop_reason TEXT,
|
|
5745
|
+
return_reason TEXT,
|
|
5621
5746
|
respawns INTEGER NOT NULL DEFAULT 0,
|
|
5622
5747
|
resolves_run_id INTEGER,
|
|
5623
5748
|
reviews_run_id INTEGER,
|
|
@@ -5734,7 +5859,16 @@ CREATE TABLE IF NOT EXISTS imports (
|
|
|
5734
5859
|
// TASWM-451: чем проверять работу этого прогона — модель ревью, приехавшая с задачи.
|
|
5735
5860
|
// Живёт на прогоне ИСПОЛНИТЕЛЯ: ревьюер и верификатор заводятся локально и читают её
|
|
5736
5861
|
// оттуда, а не ходят за задачей в прод в момент спавна.
|
|
5737
|
-
"ALTER TABLE runs ADD COLUMN review_model TEXT"
|
|
5862
|
+
"ALTER TABLE runs ADD COLUMN review_model TEXT",
|
|
5863
|
+
// TASWM-505: КОД причины возврата задачи автору (unclear_goal|no_acceptance|too_big|
|
|
5864
|
+
// contradiction) рядом с прозой в stop_reason — из него складывается распределение
|
|
5865
|
+
// «чего в постановках не хватает чаще всего». NULL — прогон не возвращали либо
|
|
5866
|
+
// возврат сделан демоном до этой фичи.
|
|
5867
|
+
"ALTER TABLE runs ADD COLUMN return_reason TEXT",
|
|
5868
|
+
// TASWM-506: файлы, которые держит прогон с открытым PR (JSON-массив, как depends_on).
|
|
5869
|
+
// Снимается в момент сдачи с PR: worktree сносится на мерже, и пересчитать список
|
|
5870
|
+
// потом неоткуда.
|
|
5871
|
+
"ALTER TABLE runs ADD COLUMN changed_paths TEXT"
|
|
5738
5872
|
]) {
|
|
5739
5873
|
try {
|
|
5740
5874
|
this.db.exec(alter);
|
|
@@ -5880,7 +6014,7 @@ CREATE TABLE IF NOT EXISTS imports (
|
|
|
5880
6014
|
const set = fields.map((f) => `${f} = ?`).join(", ");
|
|
5881
6015
|
const vals = fields.map((f) => {
|
|
5882
6016
|
const v = patch[f];
|
|
5883
|
-
if (f === "depends_on") {
|
|
6017
|
+
if (f === "depends_on" || f === "changed_paths") {
|
|
5884
6018
|
const arr = v;
|
|
5885
6019
|
return arr && arr.length ? JSON.stringify(arr) : null;
|
|
5886
6020
|
}
|
|
@@ -7088,9 +7222,11 @@ var SwarmClient = class _SwarmClient {
|
|
|
7088
7222
|
if ("duration_ms" in patch && patch.duration_ms !== void 0) out.durationMs = patch.duration_ms;
|
|
7089
7223
|
if ("respawns" in patch && patch.respawns !== void 0) out.respawns = patch.respawns;
|
|
7090
7224
|
if ("pr_url" in patch) out.prUrl = patch.pr_url ?? null;
|
|
7225
|
+
if ("changed_paths" in patch && patch.changed_paths) out.changedPaths = patch.changed_paths;
|
|
7091
7226
|
if ("branch" in patch) out.branch = patch.branch ?? null;
|
|
7092
7227
|
if ("repo" in patch) out.repo = patch.repo ?? null;
|
|
7093
7228
|
if ("stop_reason" in patch) out.stopReason = patch.stop_reason ?? null;
|
|
7229
|
+
if ("return_reason" in patch) out.returnReason = patch.return_reason ?? null;
|
|
7094
7230
|
if ("depends_on" in patch && patch.depends_on) out.dependsOn = patch.depends_on;
|
|
7095
7231
|
if ("decision" in patch) out.decision = patch.decision ? JSON.stringify(patch.decision) : null;
|
|
7096
7232
|
if ("kind" in patch && patch.kind !== void 0) out.role = patch.kind;
|
|
@@ -7166,9 +7302,12 @@ var SwarmClient = class _SwarmClient {
|
|
|
7166
7302
|
tokens_out: 0,
|
|
7167
7303
|
duration_ms: 0,
|
|
7168
7304
|
pr_url: null,
|
|
7305
|
+
changed_paths: [],
|
|
7306
|
+
// файлы прогона снимаются при открытии PR (TASWM-506)
|
|
7169
7307
|
superseded_by: null,
|
|
7170
7308
|
decision: input.decision ?? null,
|
|
7171
7309
|
stop_reason: null,
|
|
7310
|
+
return_reason: null,
|
|
7172
7311
|
respawns: 0,
|
|
7173
7312
|
resolves_run_id: input.resolves_run_id ?? null,
|
|
7174
7313
|
reviews_run_id: input.reviews_run_id ?? null,
|
|
@@ -8770,9 +8909,12 @@ var SwarmClient = class _SwarmClient {
|
|
|
8770
8909
|
tokens_out: 0,
|
|
8771
8910
|
duration_ms: 0,
|
|
8772
8911
|
pr_url: null,
|
|
8912
|
+
changed_paths: [],
|
|
8913
|
+
// занятые файлы (TASWM-506) — прод-поле, заполняется ниже
|
|
8773
8914
|
superseded_by: null,
|
|
8774
8915
|
decision: null,
|
|
8775
8916
|
stop_reason: null,
|
|
8917
|
+
return_reason: null,
|
|
8776
8918
|
respawns: 0,
|
|
8777
8919
|
resolves_run_id: null,
|
|
8778
8920
|
reviews_run_id: null,
|
|
@@ -8828,6 +8970,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
8828
8970
|
const verProd = pr.verifiesRunId ?? null;
|
|
8829
8971
|
if (verProd) local.verifies_run_id = this.localIdForProdId(verProd) ?? local.verifies_run_id;
|
|
8830
8972
|
local.verify_verdict = toVerifyVerdict(pr.verifyVerdict) ?? local.verify_verdict;
|
|
8973
|
+
local.return_reason = toReturnReason(pr.returnReason) ?? local.return_reason;
|
|
8831
8974
|
local.review_phase = pr.reviewPhase ?? local.review_phase;
|
|
8832
8975
|
local.repo = this.resolveRepo(pr.repo ?? null);
|
|
8833
8976
|
local.host_id = pr.hostId ?? null;
|
|
@@ -8847,6 +8990,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
8847
8990
|
local.tokens_out = typeof pr.tokensOut === "number" ? pr.tokensOut : 0;
|
|
8848
8991
|
local.duration_ms = typeof pr.durationMs === "number" ? pr.durationMs : 0;
|
|
8849
8992
|
local.pr_url = pr.prUrl ?? null;
|
|
8993
|
+
local.changed_paths = Array.isArray(pr.changedPaths) ? pr.changedPaths : local.changed_paths ?? [];
|
|
8850
8994
|
local.stop_reason = pr.stopReason ?? null;
|
|
8851
8995
|
local.respawns = typeof pr.respawns === "number" ? pr.respawns : 0;
|
|
8852
8996
|
local.decision = parseDecision(pr.decision);
|
|
@@ -11048,25 +11192,76 @@ var UNRETRIABLE_PARK_MARK = "\u043F\u043E\u0432\u0442\u043E\u0440 \u043D\u0435 \
|
|
|
11048
11192
|
function isUnretriableParked(run) {
|
|
11049
11193
|
return isPreStartFailure(run) && (run.stop_reason ?? "").includes(UNRETRIABLE_PARK_MARK);
|
|
11050
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
|
+
}
|
|
11051
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
|
+
}
|
|
11052
11237
|
function preStartAttempts(runs, taskSlug, opts = {}) {
|
|
11053
11238
|
const windowMs = opts.windowMs ?? SPAWN_ATTEMPT_WINDOW_MS;
|
|
11054
11239
|
const now = opts.now ?? Date.now();
|
|
11055
|
-
const own = runs
|
|
11240
|
+
const own = ownRuns(runs, taskSlug).sort(newestFirst);
|
|
11056
11241
|
let n = 0;
|
|
11242
|
+
let newestCreatedAt = Number.NEGATIVE_INFINITY;
|
|
11243
|
+
let newestSeenId = Number.NEGATIVE_INFINITY;
|
|
11057
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);
|
|
11058
11253
|
if (run.status === "queued" || run.status === "running") continue;
|
|
11059
11254
|
if (isSpawnParked(run) && run.status !== "failed") continue;
|
|
11060
11255
|
if (!isPreStartFailure(run)) break;
|
|
11061
|
-
|
|
11062
|
-
if (Number.isFinite(
|
|
11256
|
+
if (Number.isFinite(startedAt) && now - startedAt >= windowMs) break;
|
|
11257
|
+
if (opts.since != null && Number.isFinite(startedAt) && startedAt < opts.since) break;
|
|
11063
11258
|
n += 1;
|
|
11064
11259
|
if (isUnretriableParked(run)) return Math.max(n, PRE_START_ATTEMPT_LIMIT);
|
|
11065
11260
|
}
|
|
11066
11261
|
return n;
|
|
11067
11262
|
}
|
|
11068
11263
|
function lastPreStartAttempt(runs, taskSlug) {
|
|
11069
|
-
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;
|
|
11070
11265
|
}
|
|
11071
11266
|
function unresolvedRepoReason(repo, served) {
|
|
11072
11267
|
const raw = repo.trim();
|
|
@@ -11249,6 +11444,17 @@ async function mergedPrForBranch(branch, repoDir, run = realRepoRunner) {
|
|
|
11249
11444
|
return null;
|
|
11250
11445
|
}
|
|
11251
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
|
+
}
|
|
11252
11458
|
async function closePR(prUrl, run = realRunner) {
|
|
11253
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)"]);
|
|
11254
11460
|
}
|
|
@@ -11472,118 +11678,319 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
11472
11678
|
import { z } from "zod";
|
|
11473
11679
|
init_git();
|
|
11474
11680
|
|
|
11475
|
-
// src/
|
|
11476
|
-
|
|
11477
|
-
|
|
11478
|
-
|
|
11479
|
-
|
|
11480
|
-
|
|
11481
|
-
|
|
11482
|
-
|
|
11483
|
-
|
|
11484
|
-
|
|
11485
|
-
|
|
11486
|
-
const id = typeof n.id === "string" ? n.id : "";
|
|
11487
|
-
const claim = typeof n.claim === "string" ? n.claim.trim() : "";
|
|
11488
|
-
if (id && claim) out.push({ id, claim });
|
|
11489
|
-
}
|
|
11490
|
-
return out;
|
|
11491
|
-
}
|
|
11492
|
-
function normalizeZoneLabel(zone) {
|
|
11493
|
-
return (zone ?? "").trim().replace(/^area:/i, "").trim().toLowerCase();
|
|
11494
|
-
}
|
|
11495
|
-
function renderZoneMemoryBlock(zone, notes) {
|
|
11496
|
-
const label2 = normalizeZoneLabel(zone);
|
|
11497
|
-
if (!label2) return "";
|
|
11498
|
-
const head = notes.length ? [
|
|
11499
|
-
`\u{1F9E0} \u041F\u0410\u041C\u042F\u0422\u042C \u0417\u041E\u041D\u042B \`${label2}\` \u2014 \u0447\u0442\u043E \u0440\u043E\u0439 \u0443\u0436\u0435 \u0432\u044B\u044F\u0441\u043D\u0438\u043B \u043F\u0440\u043E \u044D\u0442\u043E\u0442 \u043A\u0443\u0441\u043E\u043A \u043A\u043E\u0434\u0430 (\u043F\u0440\u043E\u0432\u0435\u0440\u0435\u043D\u043E \u0440\u0435\u0432\u044C\u044E\u0435\u0440\u043E\u043C, \u043D\u0435 \u043F\u0435\u0440\u0435\u0441\u043A\u0430\u0437 \u043A\u043E\u0434\u0430):`,
|
|
11500
|
-
...notes.map((n) => `\u2022 [${n.id}] ${n.claim}`),
|
|
11501
|
-
"\u042D\u0442\u043E \u043F\u043E\u0434\u0441\u043A\u0430\u0437\u043A\u0438, \u0430 \u043D\u0435 \u0438\u0441\u0442\u0438\u043D\u0430 \u0432 \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0435\u0439 \u0438\u043D\u0441\u0442\u0430\u043D\u0446\u0438\u0438: \u0440\u0430\u0437\u043E\u0448\u043B\u043E\u0441\u044C \u0441 \u043A\u043E\u0434\u043E\u043C \u2014 \u0432\u0435\u0440\u044C \u043A\u043E\u0434\u0443 \u0438 \u0441\u043A\u0430\u0436\u0438 \u043E\u0431 \u044D\u0442\u043E\u043C \u0432 \u0441\u0434\u0430\u0447\u0435.",
|
|
11502
|
-
`\u041F\u0440\u0438\u0433\u043E\u0434\u0438\u043B\u0430\u0441\u044C \u0437\u0430\u043C\u0435\u0442\u043A\u0430 \u2014 \u043D\u0430\u0437\u043E\u0432\u0438 \u0435\u0451 \u0432 done: \`zone_notes_used: ["${notes[0].id}"]\` (id \u0438\u0437 \u0441\u043F\u0438\u0441\u043A\u0430 \u0432\u044B\u0448\u0435 \u0438\u043B\u0438 \u0441\u0430\u043C \u0442\u0435\u043A\u0441\u0442 \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F). \u042D\u0442\u043E \u0435\u0434\u0438\u043D\u0441\u0442\u0432\u0435\u043D\u043D\u043E\u0435, \u0447\u0435\u043C \u0437\u0430\u043C\u0435\u0442\u043A\u0430 \u0436\u0438\u0432\u0451\u0442: \u043F\u0430\u043C\u044F\u0442\u044C \u0437\u043E\u043D\u044B \u043E\u0433\u0440\u0430\u043D\u0438\u0447\u0435\u043D\u0430, \u0438 \u0432\u044B\u0442\u0435\u0441\u043D\u044F\u0435\u0442\u0441\u044F \u0442\u0430, \u0432 \u043A\u043E\u0442\u043E\u0440\u043E\u0439 \u0440\u043E\u0439 \u0434\u043E\u043B\u044C\u0448\u0435 \u0432\u0441\u0435\u0445 \u043D\u0435 \u0443\u0431\u0435\u0436\u0434\u0430\u043B\u0441\u044F. \u041D\u0435 \u043F\u0440\u0438\u0433\u043E\u0434\u0438\u043B\u043E\u0441\u044C \u043D\u0438\u0447\u0435\u0433\u043E \u2014 \u043D\u0435 \u043D\u0430\u0437\u044B\u0432\u0430\u0439 \u043D\u0438\u0447\u0435\u0433\u043E, \u044D\u0442\u043E \u043D\u043E\u0440\u043C\u0430\u043B\u044C\u043D\u044B\u0439 \u0438\u0441\u0445\u043E\u0434.`
|
|
11503
|
-
] : [`\u{1F9E0} \u041F\u0410\u041C\u042F\u0422\u042C \u0417\u041E\u041D\u042B \`${label2}\` \u043F\u0443\u0441\u0442\u0430 \u2014 \u0440\u043E\u0439 \u043F\u0440\u043E \u044D\u0442\u043E\u0442 \u043A\u0443\u0441\u043E\u043A \u043A\u043E\u0434\u0430 \u043F\u043E\u043A\u0430 \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0437\u0430\u043F\u0438\u0441\u0430\u043B.`];
|
|
11504
|
-
return [
|
|
11505
|
-
...head,
|
|
11506
|
-
`\u{1F9E0} \u0417\u0410\u041C\u0415\u0422\u041A\u0410 \u0412 \u041F\u0410\u041C\u042F\u0422\u042C \u0417\u041E\u041D\u042B \u2014 \u0432 \u043A\u043E\u043D\u0446\u0435 \u043F\u0440\u043E\u0433\u043E\u043D\u0430 \u043F\u0440\u0435\u0434\u043B\u043E\u0436\u0438 \u0434\u043E ${ZONE_NOTES_PER_RUN_MAX} \u0448\u0442\u0443\u043A: \`zone_notes: [{ zone: "${label2}", claim: "\u2026", why: "\u2026" }]\` (zone \u043C\u043E\u0436\u043D\u043E \u043D\u0435 \u0443\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u2014 \u0432\u043E\u0437\u044C\u043C\u0451\u0442\u0441\u044F \u0442\u0432\u043E\u044F). \u0427\u0422\u041E \u0433\u043E\u0434\u0438\u0442\u0441\u044F: \u0440\u0435\u0448\u0435\u043D\u0438\u0435 \u0441 \u043F\u0440\u0438\u0447\u0438\u043D\u043E\u0439 (\xAB\u043E\u0447\u0435\u0440\u0435\u0434\u044C \u0447\u0438\u0442\u0430\u044E\u0442 \u0438\u0437 \u043E\u0434\u043D\u043E\u0439 \u0442\u043E\u0447\u043A\u0438, \u043F\u043E\u0442\u043E\u043C\u0443 \u0447\u0442\u043E \u2026\xBB), \u0433\u0440\u0430\u0431\u043B\u0438 \u0441 \u0446\u0435\u043D\u043E\u0439 (\xAB\u043C\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u043D\u0430\u043A\u0430\u0442\u044B\u0432\u0430\u044E\u0442\u0441\u044F \u043D\u0435 \u0442\u0435\u043C, \u0447\u0435\u043C \u043A\u0430\u0436\u0435\u0442\u0441\u044F, \u2014 \u0441\u0442\u043E\u0438\u043B\u043E \u0447\u0430\u0441\u0430\xBB), \u043E\u0442\u0431\u0440\u043E\u0448\u0435\u043D\u043D\u044B\u0439 \u0432\u0430\u0440\u0438\u0430\u043D\u0442 \u0441 \u043F\u0440\u0438\u0447\u0438\u043D\u043E\u0439. \u0427\u0422\u041E \u041D\u0415 \u0433\u043E\u0434\u0438\u0442\u0441\u044F: \u0443\u0441\u0442\u0440\u043E\u0439\u0441\u0442\u0432\u043E \u043A\u043E\u0434\u0430 (\xAB\u0445\u0435\u043D\u0434\u043B\u0435\u0440 \u043B\u0435\u0436\u0438\u0442 \u0432 handlers.ts\xBB, \xAB\u044D\u0442\u0430 \u0444\u0443\u043D\u043A\u0446\u0438\u044F \u0434\u0435\u043B\u0430\u0435\u0442 \u0442\u043E-\u0442\u043E\xBB) \u2014 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0439 \u0434\u0440\u043E\u043D \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u0435\u0442 \u044D\u0442\u043E \u0441\u0430\u043C \u0438 \u0431\u044B\u0441\u0442\u0440\u0435\u0435, \u0447\u0435\u043C \u0442\u0432\u043E\u044E \u0437\u0430\u043C\u0435\u0442\u043A\u0443. \u0420\u0435\u0448\u0430\u0435\u0442 \u0440\u0435\u0432\u044C\u044E\u0435\u0440; \u043D\u0438\u0447\u0435\u0433\u043E \u0442\u0430\u043A\u043E\u0433\u043E \u043D\u0435 \u0431\u044B\u043B\u043E \u2014 \u043D\u0435 \u0432\u044B\u0434\u0443\u043C\u044B\u0432\u0430\u0439, \u043F\u0443\u0441\u0442\u043E\u0439 \u0441\u043F\u0438\u0441\u043E\u043A \u044D\u0442\u043E \u043D\u043E\u0440\u043C\u0430\u043B\u044C\u043D\u044B\u0439 \u0438\u0441\u0445\u043E\u0434 \u043F\u0440\u043E\u0433\u043E\u043D\u0430.`
|
|
11507
|
-
].join("\n");
|
|
11508
|
-
}
|
|
11509
|
-
function collectZoneNoteConfirmations(report) {
|
|
11510
|
-
const seen = /* @__PURE__ */ new Set();
|
|
11511
|
-
const out = [];
|
|
11512
|
-
for (const raw of report.used ?? []) {
|
|
11513
|
-
const s = typeof raw === "string" ? raw.trim() : "";
|
|
11514
|
-
if (!s || seen.has(s)) continue;
|
|
11515
|
-
seen.add(s);
|
|
11516
|
-
out.push(s);
|
|
11517
|
-
}
|
|
11518
|
-
return out;
|
|
11519
|
-
}
|
|
11520
|
-
|
|
11521
|
-
// src/droneServer.ts
|
|
11522
|
-
init_src();
|
|
11523
|
-
|
|
11524
|
-
// src/reviewCycle.ts
|
|
11525
|
-
init_src();
|
|
11526
|
-
function needsFixIteration(run) {
|
|
11527
|
-
return run.review_verdict === "changes" || isNegativeVerifyVerdict(toVerifyVerdict(run.verify_verdict));
|
|
11681
|
+
// src/diff.ts
|
|
11682
|
+
import { statSync as statSync10 } from "fs";
|
|
11683
|
+
import { join as join25 } from "path";
|
|
11684
|
+
import { $ as $4 } from "execa";
|
|
11685
|
+
var MAX_FILES = 200;
|
|
11686
|
+
var MAX_LINES_PER_FILE = 1500;
|
|
11687
|
+
var MAX_UNTRACKED = 60;
|
|
11688
|
+
function cleanPath(raw) {
|
|
11689
|
+
let p = raw.trim();
|
|
11690
|
+
if (p.startsWith('"') && p.endsWith('"') && p.length >= 2) p = p.slice(1, -1);
|
|
11691
|
+
return p;
|
|
11528
11692
|
}
|
|
11529
|
-
function
|
|
11530
|
-
const
|
|
11531
|
-
if (
|
|
11532
|
-
|
|
11533
|
-
|
|
11534
|
-
isFixIteration: true,
|
|
11535
|
-
cycle,
|
|
11536
|
-
patch: { status: "review", pr_url: prUrl, review_cycle: cycle, review_verdict: null, verify_verdict: null }
|
|
11537
|
-
};
|
|
11538
|
-
}
|
|
11539
|
-
return { isFixIteration: false, cycle: null, patch: { status: "review", pr_url: prUrl } };
|
|
11693
|
+
function stripAB(raw) {
|
|
11694
|
+
const p = cleanPath(raw);
|
|
11695
|
+
if (p === "/dev/null") return p;
|
|
11696
|
+
if (p.startsWith("a/") || p.startsWith("b/")) return p.slice(2);
|
|
11697
|
+
return p;
|
|
11540
11698
|
}
|
|
11541
|
-
function
|
|
11542
|
-
|
|
11543
|
-
return
|
|
11544
|
-
|
|
11545
|
-
|
|
11699
|
+
function parseUnifiedDiff(text) {
|
|
11700
|
+
const files = [];
|
|
11701
|
+
if (!text) return files;
|
|
11702
|
+
const lines = text.split("\n");
|
|
11703
|
+
let f = null;
|
|
11704
|
+
let hunk = null;
|
|
11705
|
+
let oldNo = 0;
|
|
11706
|
+
let newNo = 0;
|
|
11707
|
+
const push = () => {
|
|
11708
|
+
if (f) files.push(f);
|
|
11546
11709
|
};
|
|
11547
|
-
|
|
11548
|
-
|
|
11549
|
-
|
|
11550
|
-
|
|
11551
|
-
|
|
11552
|
-
|
|
11553
|
-
|
|
11554
|
-
|
|
11555
|
-
|
|
11556
|
-
|
|
11557
|
-
|
|
11558
|
-
|
|
11559
|
-
|
|
11560
|
-
|
|
11561
|
-
|
|
11562
|
-
|
|
11563
|
-
|
|
11564
|
-
|
|
11565
|
-
|
|
11566
|
-
|
|
11567
|
-
|
|
11568
|
-
|
|
11569
|
-
|
|
11570
|
-
|
|
11571
|
-
|
|
11572
|
-
|
|
11573
|
-
|
|
11574
|
-
|
|
11575
|
-
|
|
11576
|
-
|
|
11577
|
-
|
|
11578
|
-
|
|
11579
|
-
|
|
11580
|
-
|
|
11581
|
-
|
|
11582
|
-
|
|
11583
|
-
|
|
11584
|
-
|
|
11585
|
-
|
|
11586
|
-
|
|
11710
|
+
for (const line of lines) {
|
|
11711
|
+
if (line.startsWith("diff --git ")) {
|
|
11712
|
+
push();
|
|
11713
|
+
hunk = null;
|
|
11714
|
+
const m = line.match(/^diff --git (.+) (.+)$/);
|
|
11715
|
+
const guess = m ? stripAB(m[2]) : "";
|
|
11716
|
+
f = { path: guess, oldPath: null, status: "modified", added: 0, removed: 0, binary: false, hunks: [] };
|
|
11717
|
+
continue;
|
|
11718
|
+
}
|
|
11719
|
+
if (!f) continue;
|
|
11720
|
+
if (line.startsWith("new file mode")) {
|
|
11721
|
+
f.status = "added";
|
|
11722
|
+
continue;
|
|
11723
|
+
}
|
|
11724
|
+
if (line.startsWith("deleted file mode")) {
|
|
11725
|
+
f.status = "deleted";
|
|
11726
|
+
continue;
|
|
11727
|
+
}
|
|
11728
|
+
if (line.startsWith("rename from ") || line.startsWith("copy from ")) {
|
|
11729
|
+
f.oldPath = cleanPath(line.replace(/^(rename|copy) from /, ""));
|
|
11730
|
+
f.status = "renamed";
|
|
11731
|
+
continue;
|
|
11732
|
+
}
|
|
11733
|
+
if (line.startsWith("rename to ") || line.startsWith("copy to ")) {
|
|
11734
|
+
f.path = cleanPath(line.replace(/^(rename|copy) to /, ""));
|
|
11735
|
+
f.status = "renamed";
|
|
11736
|
+
continue;
|
|
11737
|
+
}
|
|
11738
|
+
if (line.startsWith("Binary files ")) {
|
|
11739
|
+
f.binary = true;
|
|
11740
|
+
continue;
|
|
11741
|
+
}
|
|
11742
|
+
if (line.startsWith("--- ")) {
|
|
11743
|
+
const p = stripAB(line.slice(4));
|
|
11744
|
+
if (p === "/dev/null") f.status = "added";
|
|
11745
|
+
continue;
|
|
11746
|
+
}
|
|
11747
|
+
if (line.startsWith("+++ ")) {
|
|
11748
|
+
const p = stripAB(line.slice(4));
|
|
11749
|
+
if (p === "/dev/null") f.status = "deleted";
|
|
11750
|
+
else if (p) f.path = p;
|
|
11751
|
+
continue;
|
|
11752
|
+
}
|
|
11753
|
+
if (line.startsWith("@@")) {
|
|
11754
|
+
const m = line.match(/^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@(.*)$/);
|
|
11755
|
+
if (m) {
|
|
11756
|
+
oldNo = Number(m[1]);
|
|
11757
|
+
newNo = Number(m[2]);
|
|
11758
|
+
hunk = { header: (m[3] ?? "").trim(), lines: [] };
|
|
11759
|
+
f.hunks.push(hunk);
|
|
11760
|
+
}
|
|
11761
|
+
continue;
|
|
11762
|
+
}
|
|
11763
|
+
if (!hunk) continue;
|
|
11764
|
+
if (line.startsWith("\\")) continue;
|
|
11765
|
+
const tag = line[0];
|
|
11766
|
+
const body = line.slice(1);
|
|
11767
|
+
if (tag === "+") {
|
|
11768
|
+
hunk.lines.push({ k: "add", o: null, n: newNo++, t: body });
|
|
11769
|
+
f.added++;
|
|
11770
|
+
} else if (tag === "-") {
|
|
11771
|
+
hunk.lines.push({ k: "del", o: oldNo++, n: null, t: body });
|
|
11772
|
+
f.removed++;
|
|
11773
|
+
} else if (tag === " ") {
|
|
11774
|
+
hunk.lines.push({ k: "ctx", o: oldNo++, n: newNo++, t: body });
|
|
11775
|
+
}
|
|
11776
|
+
}
|
|
11777
|
+
push();
|
|
11778
|
+
return files;
|
|
11779
|
+
}
|
|
11780
|
+
function truncateFile(f) {
|
|
11781
|
+
let count = 0;
|
|
11782
|
+
const hunks = [];
|
|
11783
|
+
let cut = false;
|
|
11784
|
+
for (const h of f.hunks) {
|
|
11785
|
+
if (count >= MAX_LINES_PER_FILE) {
|
|
11786
|
+
cut = true;
|
|
11787
|
+
break;
|
|
11788
|
+
}
|
|
11789
|
+
const room = MAX_LINES_PER_FILE - count;
|
|
11790
|
+
if (h.lines.length <= room) {
|
|
11791
|
+
hunks.push(h);
|
|
11792
|
+
count += h.lines.length;
|
|
11793
|
+
} else {
|
|
11794
|
+
hunks.push({ header: h.header, lines: h.lines.slice(0, room) });
|
|
11795
|
+
count += room;
|
|
11796
|
+
cut = true;
|
|
11797
|
+
break;
|
|
11798
|
+
}
|
|
11799
|
+
}
|
|
11800
|
+
return cut ? { ...f, hunks, truncated: true } : f;
|
|
11801
|
+
}
|
|
11802
|
+
async function resolveBase(wt, baseBranch) {
|
|
11803
|
+
const tryRef = async (ref) => {
|
|
11804
|
+
const sha = (await $4({ reject: false })`git -C ${wt} rev-parse --verify --quiet ${ref + "^{commit}"}`).stdout.trim();
|
|
11805
|
+
if (!sha) return null;
|
|
11806
|
+
const mb2 = (await $4({ reject: false })`git -C ${wt} merge-base HEAD ${ref}`).stdout.trim();
|
|
11807
|
+
return mb2 || null;
|
|
11808
|
+
};
|
|
11809
|
+
const originHead = (await $4({ reject: false })`git -C ${wt} symbolic-ref --quiet --short refs/remotes/origin/HEAD`).stdout.trim();
|
|
11810
|
+
const candidates = [
|
|
11811
|
+
...baseBranch ? [`origin/${baseBranch}`, baseBranch] : [],
|
|
11812
|
+
originHead,
|
|
11813
|
+
"origin/main",
|
|
11814
|
+
"origin/master",
|
|
11815
|
+
"main",
|
|
11816
|
+
"master"
|
|
11817
|
+
].filter(Boolean);
|
|
11818
|
+
for (const c of candidates) {
|
|
11819
|
+
const mb2 = await tryRef(c);
|
|
11820
|
+
if (mb2) return mb2;
|
|
11821
|
+
}
|
|
11822
|
+
return null;
|
|
11823
|
+
}
|
|
11824
|
+
function mtime(path) {
|
|
11825
|
+
try {
|
|
11826
|
+
return statSync10(path).mtimeMs;
|
|
11827
|
+
} catch {
|
|
11828
|
+
return 0;
|
|
11829
|
+
}
|
|
11830
|
+
}
|
|
11831
|
+
async function collectRunDiff(worktree, opts = {}) {
|
|
11832
|
+
const stub = (reason) => ({ ok: false, reason, pr: opts.pr ?? null, files: [], added: 0, removed: 0 });
|
|
11833
|
+
const gone = opts.status === "queued" ? "\u0434\u0440\u043E\u043D \u0435\u0449\u0451 \u0432 \u043E\u0447\u0435\u0440\u0435\u0434\u0438 \u2014 \u043A\u043E\u0434\u0430 \u043F\u043E\u043A\u0430 \u043D\u0435\u0442" : "worktree \u0443\u0431\u0440\u0430\u043D \u2014 \u043A\u043E\u0434 \u0441\u043C\u043E\u0442\u0440\u0438 \u0432 PR";
|
|
11834
|
+
if (!worktree) return stub(gone);
|
|
11835
|
+
const isWt = (await $4({ reject: false })`git -C ${worktree} rev-parse --is-inside-work-tree`).stdout.trim();
|
|
11836
|
+
if (isWt !== "true") return stub(gone);
|
|
11837
|
+
const base3 = await resolveBase(worktree, opts.baseBranch);
|
|
11838
|
+
const from = base3 ?? "HEAD";
|
|
11839
|
+
const trackedTxt = (await $4({ reject: false })`git -C ${worktree} diff --no-color --find-renames ${from} --`).stdout;
|
|
11840
|
+
let files = parseUnifiedDiff(trackedTxt);
|
|
11841
|
+
const untrackedRaw = (await $4({ reject: false })`git -C ${worktree} ls-files --others --exclude-standard -z`).stdout;
|
|
11842
|
+
const untracked = untrackedRaw.split("\0").filter(Boolean).slice(0, MAX_UNTRACKED);
|
|
11843
|
+
for (const rel of untracked) {
|
|
11844
|
+
const t = (await $4({ reject: false })`git -C ${worktree} diff --no-color --no-index -- /dev/null ${rel}`).stdout;
|
|
11845
|
+
for (const pf of parseUnifiedDiff(t)) {
|
|
11846
|
+
pf.status = "added";
|
|
11847
|
+
if (!pf.path || pf.path === "/dev/null") pf.path = rel;
|
|
11848
|
+
files.push(pf);
|
|
11849
|
+
}
|
|
11850
|
+
}
|
|
11851
|
+
files.sort((a, b) => mtime(join25(worktree, b.path)) - mtime(join25(worktree, a.path)));
|
|
11852
|
+
const truncatedFiles = files.length > MAX_FILES;
|
|
11853
|
+
if (truncatedFiles) files = files.slice(0, MAX_FILES);
|
|
11854
|
+
const added = files.reduce((s, f) => s + f.added, 0);
|
|
11855
|
+
const removed = files.reduce((s, f) => s + f.removed, 0);
|
|
11856
|
+
const out = files.map(truncateFile);
|
|
11857
|
+
return {
|
|
11858
|
+
ok: true,
|
|
11859
|
+
base: base3 ? base3.slice(0, 9) : null,
|
|
11860
|
+
files: out,
|
|
11861
|
+
added,
|
|
11862
|
+
removed,
|
|
11863
|
+
...truncatedFiles ? { truncated: true } : {}
|
|
11864
|
+
};
|
|
11865
|
+
}
|
|
11866
|
+
async function changedPaths(worktree, opts = {}) {
|
|
11867
|
+
if (!worktree) return [];
|
|
11868
|
+
try {
|
|
11869
|
+
const isWt = (await $4({ reject: false })`git -C ${worktree} rev-parse --is-inside-work-tree`).stdout.trim();
|
|
11870
|
+
if (isWt !== "true") return [];
|
|
11871
|
+
const from = await resolveBase(worktree, opts.baseBranch) ?? "HEAD";
|
|
11872
|
+
const tracked = (await $4({ reject: false })`git -C ${worktree} diff --name-only --find-renames ${from} --`).stdout;
|
|
11873
|
+
const untracked = (await $4({ reject: false })`git -C ${worktree} ls-files --others --exclude-standard -z`).stdout;
|
|
11874
|
+
const all = [...tracked.split("\n"), ...untracked.split("\0")].map((s) => s.trim()).filter(Boolean);
|
|
11875
|
+
return [...new Set(all)].sort();
|
|
11876
|
+
} catch {
|
|
11877
|
+
return [];
|
|
11878
|
+
}
|
|
11879
|
+
}
|
|
11880
|
+
|
|
11881
|
+
// src/zoneNotes.ts
|
|
11882
|
+
init_src();
|
|
11883
|
+
function parseZoneMemory(raw, zone) {
|
|
11884
|
+
const key = normalizeZoneLabel(zone);
|
|
11885
|
+
if (!key || !raw || typeof raw !== "object" || Array.isArray(raw)) return [];
|
|
11886
|
+
const notes = raw[key];
|
|
11887
|
+
if (!Array.isArray(notes)) return [];
|
|
11888
|
+
const out = [];
|
|
11889
|
+
for (const item of notes) {
|
|
11890
|
+
if (!item || typeof item !== "object") continue;
|
|
11891
|
+
const n = item;
|
|
11892
|
+
const id = typeof n.id === "string" ? n.id : "";
|
|
11893
|
+
const claim = typeof n.claim === "string" ? n.claim.trim() : "";
|
|
11894
|
+
if (id && claim) out.push({ id, claim });
|
|
11895
|
+
}
|
|
11896
|
+
return out;
|
|
11897
|
+
}
|
|
11898
|
+
function normalizeZoneLabel(zone) {
|
|
11899
|
+
return (zone ?? "").trim().replace(/^area:/i, "").trim().toLowerCase();
|
|
11900
|
+
}
|
|
11901
|
+
function renderZoneMemoryBlock(zone, notes) {
|
|
11902
|
+
const label2 = normalizeZoneLabel(zone);
|
|
11903
|
+
if (!label2) return "";
|
|
11904
|
+
const head = notes.length ? [
|
|
11905
|
+
`\u{1F9E0} \u041F\u0410\u041C\u042F\u0422\u042C \u0417\u041E\u041D\u042B \`${label2}\` \u2014 \u0447\u0442\u043E \u0440\u043E\u0439 \u0443\u0436\u0435 \u0432\u044B\u044F\u0441\u043D\u0438\u043B \u043F\u0440\u043E \u044D\u0442\u043E\u0442 \u043A\u0443\u0441\u043E\u043A \u043A\u043E\u0434\u0430 (\u043F\u0440\u043E\u0432\u0435\u0440\u0435\u043D\u043E \u0440\u0435\u0432\u044C\u044E\u0435\u0440\u043E\u043C, \u043D\u0435 \u043F\u0435\u0440\u0435\u0441\u043A\u0430\u0437 \u043A\u043E\u0434\u0430):`,
|
|
11906
|
+
...notes.map((n) => `\u2022 [${n.id}] ${n.claim}`),
|
|
11907
|
+
"\u042D\u0442\u043E \u043F\u043E\u0434\u0441\u043A\u0430\u0437\u043A\u0438, \u0430 \u043D\u0435 \u0438\u0441\u0442\u0438\u043D\u0430 \u0432 \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0435\u0439 \u0438\u043D\u0441\u0442\u0430\u043D\u0446\u0438\u0438: \u0440\u0430\u0437\u043E\u0448\u043B\u043E\u0441\u044C \u0441 \u043A\u043E\u0434\u043E\u043C \u2014 \u0432\u0435\u0440\u044C \u043A\u043E\u0434\u0443 \u0438 \u0441\u043A\u0430\u0436\u0438 \u043E\u0431 \u044D\u0442\u043E\u043C \u0432 \u0441\u0434\u0430\u0447\u0435.",
|
|
11908
|
+
`\u041F\u0440\u0438\u0433\u043E\u0434\u0438\u043B\u0430\u0441\u044C \u0437\u0430\u043C\u0435\u0442\u043A\u0430 \u2014 \u043D\u0430\u0437\u043E\u0432\u0438 \u0435\u0451 \u0432 done: \`zone_notes_used: ["${notes[0].id}"]\` (id \u0438\u0437 \u0441\u043F\u0438\u0441\u043A\u0430 \u0432\u044B\u0448\u0435 \u0438\u043B\u0438 \u0441\u0430\u043C \u0442\u0435\u043A\u0441\u0442 \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F). \u042D\u0442\u043E \u0435\u0434\u0438\u043D\u0441\u0442\u0432\u0435\u043D\u043D\u043E\u0435, \u0447\u0435\u043C \u0437\u0430\u043C\u0435\u0442\u043A\u0430 \u0436\u0438\u0432\u0451\u0442: \u043F\u0430\u043C\u044F\u0442\u044C \u0437\u043E\u043D\u044B \u043E\u0433\u0440\u0430\u043D\u0438\u0447\u0435\u043D\u0430, \u0438 \u0432\u044B\u0442\u0435\u0441\u043D\u044F\u0435\u0442\u0441\u044F \u0442\u0430, \u0432 \u043A\u043E\u0442\u043E\u0440\u043E\u0439 \u0440\u043E\u0439 \u0434\u043E\u043B\u044C\u0448\u0435 \u0432\u0441\u0435\u0445 \u043D\u0435 \u0443\u0431\u0435\u0436\u0434\u0430\u043B\u0441\u044F. \u041D\u0435 \u043F\u0440\u0438\u0433\u043E\u0434\u0438\u043B\u043E\u0441\u044C \u043D\u0438\u0447\u0435\u0433\u043E \u2014 \u043D\u0435 \u043D\u0430\u0437\u044B\u0432\u0430\u0439 \u043D\u0438\u0447\u0435\u0433\u043E, \u044D\u0442\u043E \u043D\u043E\u0440\u043C\u0430\u043B\u044C\u043D\u044B\u0439 \u0438\u0441\u0445\u043E\u0434.`
|
|
11909
|
+
] : [`\u{1F9E0} \u041F\u0410\u041C\u042F\u0422\u042C \u0417\u041E\u041D\u042B \`${label2}\` \u043F\u0443\u0441\u0442\u0430 \u2014 \u0440\u043E\u0439 \u043F\u0440\u043E \u044D\u0442\u043E\u0442 \u043A\u0443\u0441\u043E\u043A \u043A\u043E\u0434\u0430 \u043F\u043E\u043A\u0430 \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0437\u0430\u043F\u0438\u0441\u0430\u043B.`];
|
|
11910
|
+
return [
|
|
11911
|
+
...head,
|
|
11912
|
+
`\u{1F9E0} \u0417\u0410\u041C\u0415\u0422\u041A\u0410 \u0412 \u041F\u0410\u041C\u042F\u0422\u042C \u0417\u041E\u041D\u042B \u2014 \u0432 \u043A\u043E\u043D\u0446\u0435 \u043F\u0440\u043E\u0433\u043E\u043D\u0430 \u043F\u0440\u0435\u0434\u043B\u043E\u0436\u0438 \u0434\u043E ${ZONE_NOTES_PER_RUN_MAX} \u0448\u0442\u0443\u043A: \`zone_notes: [{ zone: "${label2}", claim: "\u2026", why: "\u2026" }]\` (zone \u043C\u043E\u0436\u043D\u043E \u043D\u0435 \u0443\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u2014 \u0432\u043E\u0437\u044C\u043C\u0451\u0442\u0441\u044F \u0442\u0432\u043E\u044F). \u0427\u0422\u041E \u0433\u043E\u0434\u0438\u0442\u0441\u044F: \u0440\u0435\u0448\u0435\u043D\u0438\u0435 \u0441 \u043F\u0440\u0438\u0447\u0438\u043D\u043E\u0439 (\xAB\u043E\u0447\u0435\u0440\u0435\u0434\u044C \u0447\u0438\u0442\u0430\u044E\u0442 \u0438\u0437 \u043E\u0434\u043D\u043E\u0439 \u0442\u043E\u0447\u043A\u0438, \u043F\u043E\u0442\u043E\u043C\u0443 \u0447\u0442\u043E \u2026\xBB), \u0433\u0440\u0430\u0431\u043B\u0438 \u0441 \u0446\u0435\u043D\u043E\u0439 (\xAB\u043C\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u043D\u0430\u043A\u0430\u0442\u044B\u0432\u0430\u044E\u0442\u0441\u044F \u043D\u0435 \u0442\u0435\u043C, \u0447\u0435\u043C \u043A\u0430\u0436\u0435\u0442\u0441\u044F, \u2014 \u0441\u0442\u043E\u0438\u043B\u043E \u0447\u0430\u0441\u0430\xBB), \u043E\u0442\u0431\u0440\u043E\u0448\u0435\u043D\u043D\u044B\u0439 \u0432\u0430\u0440\u0438\u0430\u043D\u0442 \u0441 \u043F\u0440\u0438\u0447\u0438\u043D\u043E\u0439. \u0427\u0422\u041E \u041D\u0415 \u0433\u043E\u0434\u0438\u0442\u0441\u044F: \u0443\u0441\u0442\u0440\u043E\u0439\u0441\u0442\u0432\u043E \u043A\u043E\u0434\u0430 (\xAB\u0445\u0435\u043D\u0434\u043B\u0435\u0440 \u043B\u0435\u0436\u0438\u0442 \u0432 handlers.ts\xBB, \xAB\u044D\u0442\u0430 \u0444\u0443\u043D\u043A\u0446\u0438\u044F \u0434\u0435\u043B\u0430\u0435\u0442 \u0442\u043E-\u0442\u043E\xBB) \u2014 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0439 \u0434\u0440\u043E\u043D \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u0435\u0442 \u044D\u0442\u043E \u0441\u0430\u043C \u0438 \u0431\u044B\u0441\u0442\u0440\u0435\u0435, \u0447\u0435\u043C \u0442\u0432\u043E\u044E \u0437\u0430\u043C\u0435\u0442\u043A\u0443. \u0420\u0435\u0448\u0430\u0435\u0442 \u0440\u0435\u0432\u044C\u044E\u0435\u0440; \u043D\u0438\u0447\u0435\u0433\u043E \u0442\u0430\u043A\u043E\u0433\u043E \u043D\u0435 \u0431\u044B\u043B\u043E \u2014 \u043D\u0435 \u0432\u044B\u0434\u0443\u043C\u044B\u0432\u0430\u0439, \u043F\u0443\u0441\u0442\u043E\u0439 \u0441\u043F\u0438\u0441\u043E\u043A \u044D\u0442\u043E \u043D\u043E\u0440\u043C\u0430\u043B\u044C\u043D\u044B\u0439 \u0438\u0441\u0445\u043E\u0434 \u043F\u0440\u043E\u0433\u043E\u043D\u0430.`
|
|
11913
|
+
].join("\n");
|
|
11914
|
+
}
|
|
11915
|
+
function collectZoneNoteConfirmations(report) {
|
|
11916
|
+
const seen = /* @__PURE__ */ new Set();
|
|
11917
|
+
const out = [];
|
|
11918
|
+
for (const raw of report.used ?? []) {
|
|
11919
|
+
const s = typeof raw === "string" ? raw.trim() : "";
|
|
11920
|
+
if (!s || seen.has(s)) continue;
|
|
11921
|
+
seen.add(s);
|
|
11922
|
+
out.push(s);
|
|
11923
|
+
}
|
|
11924
|
+
return out;
|
|
11925
|
+
}
|
|
11926
|
+
|
|
11927
|
+
// src/droneServer.ts
|
|
11928
|
+
init_src();
|
|
11929
|
+
init_src();
|
|
11930
|
+
|
|
11931
|
+
// src/reviewCycle.ts
|
|
11932
|
+
init_src();
|
|
11933
|
+
function needsFixIteration(run) {
|
|
11934
|
+
return run.review_verdict === "changes" || isNegativeVerifyVerdict(toVerifyVerdict(run.verify_verdict));
|
|
11935
|
+
}
|
|
11936
|
+
function reviewTransitionPatch(run, prUrl) {
|
|
11937
|
+
const isFixIteration = needsFixIteration(run);
|
|
11938
|
+
if (isFixIteration) {
|
|
11939
|
+
const cycle = (run.review_cycle ?? 0) + 1;
|
|
11940
|
+
return {
|
|
11941
|
+
isFixIteration: true,
|
|
11942
|
+
cycle,
|
|
11943
|
+
patch: { status: "review", pr_url: prUrl, review_cycle: cycle, review_verdict: null, verify_verdict: null }
|
|
11944
|
+
};
|
|
11945
|
+
}
|
|
11946
|
+
return { isFixIteration: false, cycle: null, patch: { status: "review", pr_url: prUrl } };
|
|
11947
|
+
}
|
|
11948
|
+
function branchFromPrPatch(currentBranch, headBranch) {
|
|
11949
|
+
if (!headBranch || headBranch === currentBranch) return null;
|
|
11950
|
+
return {
|
|
11951
|
+
patch: { branch: headBranch },
|
|
11952
|
+
event: currentBranch ? `\u0432\u0435\u0442\u043A\u0430 \u043F\u0440\u043E\u0433\u043E\u043D\u0430 \u0432\u0437\u044F\u0442\u0430 \u0443 PR: ${currentBranch} \u2192 ${headBranch} (\u043F\u043E\u043B\u0435 \u0431\u044B\u043B\u043E \u0441\u043E\u0431\u0440\u0430\u043D\u043E \u0438\u0437 \u0441\u043B\u0430\u0433\u0430 \u2014 TASWM-356)` : `\u0432\u0435\u0442\u043A\u0430 \u043F\u0440\u043E\u0433\u043E\u043D\u0430 \u0432\u0437\u044F\u0442\u0430 \u0443 PR: ${headBranch} (TASWM-356)`
|
|
11953
|
+
};
|
|
11954
|
+
}
|
|
11955
|
+
function prLiveness(st) {
|
|
11956
|
+
if (!st) return "unknown";
|
|
11957
|
+
if (st.merged) return "merged";
|
|
11958
|
+
const state = (st.state ?? "").toUpperCase();
|
|
11959
|
+
if (state === "MERGED") return "merged";
|
|
11960
|
+
if (state === "CLOSED") return "closed";
|
|
11961
|
+
if (state === "UNKNOWN") return "unknown";
|
|
11962
|
+
return "open";
|
|
11963
|
+
}
|
|
11964
|
+
function applyReviewTransition(db, run, prUrl) {
|
|
11965
|
+
const { patch, ...t } = reviewTransitionPatch(run, prUrl);
|
|
11966
|
+
db.updateRun(run.id, patch);
|
|
11967
|
+
return t;
|
|
11968
|
+
}
|
|
11969
|
+
|
|
11970
|
+
// src/droneServer.ts
|
|
11971
|
+
init_src();
|
|
11972
|
+
function readTaskFailureInstruction(slug, failure) {
|
|
11973
|
+
const why = describeToolFailure(failure);
|
|
11974
|
+
if (TOOL_FAILURE_RETRIABLE[failure.code]) {
|
|
11975
|
+
return `\u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043F\u0435\u0440\u0435\u0447\u0438\u0442\u0430\u0442\u044C \u0437\u0430\u0434\u0430\u0447\u0443 ${slug}: ${why}. \u042D\u0442\u043E \u0432\u0440\u0435\u043C\u0435\u043D\u043D\u043E \u0438 \u043B\u0435\u0447\u0438\u0442\u0441\u044F \u043F\u043E\u0432\u0442\u043E\u0440\u043E\u043C \u2014 \u0440\u0430\u0431\u043E\u0442\u0430\u0439 \u043F\u043E\u043A\u0430 \u043F\u043E \u0442\u043E\u043C\u0443, \u0447\u0442\u043E \u0443\u0436\u0435 \u0432 \u043F\u0440\u043E\u043C\u043F\u0442\u0435, \u0438 \u043F\u043E\u0437\u043E\u0432\u0438 read_task \u0435\u0449\u0451 \u0440\u0430\u0437 \u043F\u043E\u0437\u0436\u0435 (\u043F\u0435\u0440\u0435\u0434 \u0441\u0434\u0430\u0447\u0435\u0439 \u2014 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E).`;
|
|
11976
|
+
}
|
|
11977
|
+
return [
|
|
11978
|
+
`\u26D4 \u0417\u0410\u0414\u0410\u0427\u0423 ${slug} \u041F\u0420\u041E\u0427\u0418\u0422\u0410\u0422\u042C \u041D\u0415\u041B\u042C\u0417\u042F: ${why}.`,
|
|
11979
|
+
"\u041F\u043E\u0432\u0442\u043E\u0440 \u0442\u0443\u0442 \u043D\u0435 \u043F\u043E\u043C\u043E\u0436\u0435\u0442 \u2014 \u043F\u0440\u0438\u0447\u0438\u043D\u0430 \u043D\u0435 \u0432 \u0441\u0435\u0442\u0438, \u043E\u043D\u0430 \u0441\u0430\u043C\u0430 \u043D\u0435 \u0440\u0430\u0437\u043E\u0439\u0434\u0451\u0442\u0441\u044F.",
|
|
11980
|
+
"\u041D\u0415 \u0440\u0430\u0431\u043E\u0442\u0430\u0439 \u043F\u043E \u0441\u043B\u0430\u0433\u0443 \u0438 \u043F\u043E \u043F\u0430\u043C\u044F\u0442\u0438: \u043F\u043E\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430, \u043A\u043E\u0442\u043E\u0440\u043E\u0439 \u0442\u044B \u043D\u0435 \u0432\u0438\u0434\u0435\u043B, \u043D\u0435 \u0432\u043E\u0441\u0441\u0442\u0430\u043D\u0430\u0432\u043B\u0438\u0432\u0430\u0435\u0442\u0441\u044F \u0438\u0437 \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u044F \u0437\u0430\u0434\u0430\u0447\u0438 (TASWM-288).",
|
|
11981
|
+
"\u0421\u043F\u0440\u043E\u0441\u0438 \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440\u0430 \u0447\u0435\u0440\u0435\u0437 ask() \u2014 \u043D\u0430\u0437\u043E\u0432\u0438 \u0435\u043C\u0443 \u044D\u0442\u0443 \u043F\u0440\u0438\u0447\u0438\u043D\u0443 \u0434\u043E\u0441\u043B\u043E\u0432\u043D\u043E \u2014 \u0438 \u0434\u0430\u043B\u044C\u0448\u0435 \u0434\u0435\u043B\u0430\u0439 \u0442\u043E, \u0447\u0442\u043E \u043E\u043D \u043E\u0442\u0432\u0435\u0442\u0438\u0442."
|
|
11982
|
+
].join("\n");
|
|
11983
|
+
}
|
|
11984
|
+
function freezeInstruction(branch, reason = "\u0435\u0433\u043E \u043F\u0443\u043B\u044C\u0441 (heartbeat) \u0443\u0441\u0442\u0430\u0440\u0435\u043B") {
|
|
11985
|
+
return [
|
|
11986
|
+
`\u26D4 OVERMIND \u041D\u0415\u0414\u041E\u0421\u0422\u0423\u041F\u0415\u041D \u2014 ${reason}. \u041D\u0430\u0434\u0437\u043E\u0440\u0430 \u043D\u0430\u0434 \u0442\u043E\u0431\u043E\u0439 \u0441\u0435\u0439\u0447\u0430\u0441 \u043D\u0435\u0442: \u043D\u0435\u043A\u043E\u043C\u0443`,
|
|
11987
|
+
"\u043F\u0440\u0438\u043D\u044F\u0442\u044C \u0442\u0432\u043E\u0439 \u0432\u043E\u043F\u0440\u043E\u0441, \u0437\u0430\u043C\u0435\u0442\u0438\u0442\u044C \u0441\u043C\u0435\u0440\u0442\u044C, \u0441\u043C\u0435\u0440\u0436\u0438\u0442\u044C PR \u0438\u043B\u0438 \u0440\u0430\u0437\u0440\u0443\u043B\u0438\u0442\u044C \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442. \u0420\u0430\u0431\u043E\u0442\u0430\u0442\u044C \u0432\u0441\u043B\u0435\u043F\u0443\u044E \u043D\u0435\u043B\u044C\u0437\u044F.",
|
|
11988
|
+
"\u0417\u0410\u041C\u0420\u0418 \u0438 \u0441\u043E\u0445\u0440\u0430\u043D\u0438\u0441\u044C, \u0447\u0442\u043E\u0431\u044B \u0440\u0430\u0431\u043E\u0442\u0430 \u043D\u0435 \u043F\u0440\u043E\u043F\u0430\u043B\u0430:",
|
|
11989
|
+
"1. \u0417\u0430\u043A\u043E\u043C\u043C\u0438\u0442\u044C \u0412\u0421\u042E \u0442\u0435\u043A\u0443\u0449\u0443\u044E \u0440\u0430\u0431\u043E\u0442\u0443 \u043A\u0430\u043A \u0435\u0441\u0442\u044C: `git add -A && git commit` (\u0442\u0440\u0435\u0439\u043B\u0435\u0440 \u043F\u0440\u043E \u0434\u0440\u043E\u043D\u0430 \u2014 \u043A\u0430\u043A \u043E\u0431\u044B\u0447\u043D\u043E).",
|
|
11990
|
+
" \u041D\u043E\u0432\u044B\u0439 \u043A\u043E\u0434 \u041D\u0415 \u043F\u0438\u0448\u0438, \u0437\u0430\u0434\u0430\u0447\u0443 \u0434\u0430\u043B\u044C\u0448\u0435 \u041D\u0415 \u0434\u0435\u043B\u0430\u0439 \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u0441\u043E\u0445\u0440\u0430\u043D\u0438 \u0443\u0436\u0435 \u0441\u0434\u0435\u043B\u0430\u043D\u043D\u043E\u0435, \u0431\u0435\u0437 \u043C\u0443\u0441\u043E\u0440\u043D\u044B\u0445 \u043A\u043E\u043C\u043C\u0438\u0442\u043E\u0432.",
|
|
11991
|
+
`2. \u0417\u0430\u043F\u0443\u0448\u044C \u0432\u0435\u0442\u043A\u0443: \`git push -u origin ${branch}\` \u2014 \u043D\u0435\u0437\u0430\u043F\u0443\u0448\u0435\u043D\u043D\u043E\u0435 \u0443\u043C\u0440\u0451\u0442 \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 \u043F\u0440\u043E\u0446\u0435\u0441\u0441\u043E\u043C.`,
|
|
11992
|
+
"3. \u0417\u0430\u0432\u0435\u0440\u0448\u0438 \u0440\u0430\u0431\u043E\u0442\u0443 \u2014 \u0431\u043E\u043B\u044C\u0448\u0435 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u043E\u0432 \u041D\u0415 \u0437\u043E\u0432\u0438 (\u043D\u0438 report_step, \u043D\u0438 ask, \u043D\u0438 done). \u041F\u0440\u043E\u0441\u0442\u043E \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u0438 \u0441\u0435\u0441\u0441\u0438\u044E.",
|
|
11993
|
+
"\u041F\u0440\u043E\u0433\u043E\u043D \u043F\u043E\u043C\u0435\u0447\u0435\u043D \xABpaused\xBB. \u041A\u043E\u0433\u0434\u0430 \u043F\u043E\u0434\u043D\u0438\u043C\u0435\u0442\u0441\u044F \u043D\u043E\u0432\u044B\u0439 overmind, \u043E\u043D \u0440\u0430\u0437\u0431\u0443\u0434\u0438\u0442 \u0442\u0435\u0431\u044F \u0441 \u044D\u0442\u043E\u0433\u043E \u043C\u0435\u0441\u0442\u0430 (--continue) \u2014",
|
|
11587
11994
|
"\u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0448\u044C \u043E\u0442\u0442\u0443\u0434\u0430. \u041D\u0435 \u043F\u0435\u0440\u0435\u0441\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0439 \u0438 \u043D\u0435 \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0430\u0439 \u0437\u0430\u0434\u0430\u0447\u0443 \u0441\u0435\u0439\u0447\u0430\u0441."
|
|
11588
11995
|
].join("\n");
|
|
11589
11996
|
}
|
|
@@ -11769,19 +12176,36 @@ ${failText}` : failText }],
|
|
|
11769
12176
|
);
|
|
11770
12177
|
server.tool(
|
|
11771
12178
|
"return_task",
|
|
11772
|
-
"\u0412\u0435\u0440\u043D\u0443\u0442\u044C \u0437\u0430\u0434\u0430\u0447\u0443 \u0410\u0412\u0422\u041E\u0420\u0423 \u043D\u0430 \u0443\u0442\u043E\u0447\u043D\u0435\u043D\u0438\u0435 \u0438 \u0437\u0430\u043A\u0440\u044B\u0442\u044C \u043F\u0440\u043E\u0433\u043E\u043D (\u0441\u043B\u043E\u0442 \u043E\u0441\u0432\u043E\u0431\u043E\u0434\u0438\u0442\u0441\u044F, \u0440\u043E\u0439 \u0432\u043E\u0437\u044C\u043C\u0451\u0442 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0443\u044E \u0437\u0430\u0434\u0430\u0447\u0443). \u0417\u043E\u0432\u0438, \u0422\u041E\u041B\u042C\u041A\u041E \u0435\u0441\u043B\u0438 \u0437\u0430\u0434\u0430\u0447\u0443 \u043D\u0435\u043B\u044C\u0437\u044F \u0432\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u044C \u043D\u0438 \u0432 \u043E\u0434\u043D\u043E\u043C \u0440\u0430\u0437\u0443\u043C\u043D\u043E\u043C \u0442\u043E\u043B\u043A\u043E\u0432\u0430\u043D\u0438\u0438 \u0418\u041B\u0418 \u043D\u0435\u043F\u043E\u043D\u044F\u0442\u043D\u043E, \u0447\u0435\u043C \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0442\u044C \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442. \u0414\u0432\u0430 \u043E\u0441\u043C\u044B\u0441\u043B\u0435\u043D\u043D\u044B\u0445 \u0442\u043E\u043B\u043A\u043E\u0432\u0430\u043D\u0438\u044F \u2014 \u041D\u0415 \u043F\u043E\u0432\u043E\u0434: \u0432\u044B\u0431\u0435\u0440\u0438 \u043E\u0447\u0435\u0432\u0438\u0434\u043D\u043E\u0435, \u0441\u0434\u0435\u043B\u0430\u0439 \u0438 \u043D\u0430\u0437\u043E\u0432\u0438 \u0440\u0430\u0437\u0432\u0438\u043B\u043A\u0443 \u0432 \u043E\u043F\u0438\u0441\u0430\u043D\u0438\u0438 PR. \u041F\u043E\u043D\u044F\u0442\u043D\u0430\u044F \u0437\u0430\u0434\u0430\u0447\u0430, \u043A\u043E\u0442\u043E\u0440\u0430\u044F \u0432 \u043E\u0434\u043D\u043E\u043C \u043F\u0443\u043D\u043A\u0442\u0435 \u043F\u0440\u043E\u0442\u0438\u0432\u043E\u0440\u0435\u0447\u0438\u0442 \u043F\u0440\u0430\u0432\u0438\u043B\u0443 \u043F\u0440\u043E\u0435\u043A\u0442\u0430, \u2014 \u0442\u043E\u0436\u0435 \u043D\u0435 \u043F\u043E\u0432\u043E\u0434: \u044D\u0442\u043E ask. \u0417\u0430\u0434\u0430\u0447\u0430 \u0443\u0439\u0434\u0451\u0442 \u0430\u0432\u0442\u043E\u0440\u0443 (\u043D\u0430\u0437\u043D\u0430\u0447\u0438\u043C \u043D\u0430 \u043D\u0435\u0433\u043E \u0438 \u043F\u0435\u0440\u0435\u0432\u0435\u0434\u0451\u043C \u0432 \u0440\u0430\u0431\u043E\u0442\u0443), \u0432\u043E\u043F\u0440\u043E\u0441\u044B \u0443\u0435\u0434\u0443\u0442 \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u043E\u043C \u043E\u0442 \u0442\u0432\u043E\u0435\u0433\u043E \u0438\u043C\u0435\u043D\u0438. \u041F\u043E\u0441\u043B\u0435 \u0432\u044B\u0437\u043E\u0432\u0430 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u044B \u0431\u043E\u043B\u044C\u0448\u0435 \u043D\u0435 \u0437\u043E\u0432\u0438 \u2014 \u0437\u0430\u0432\u0435\u0440\u0448\u0438 \u0441\u0435\u0441\u0441\u0438\u044E.",
|
|
12179
|
+
"\u0412\u0435\u0440\u043D\u0443\u0442\u044C \u0437\u0430\u0434\u0430\u0447\u0443 \u0410\u0412\u0422\u041E\u0420\u0423 \u043D\u0430 \u0443\u0442\u043E\u0447\u043D\u0435\u043D\u0438\u0435 \u0438 \u0437\u0430\u043A\u0440\u044B\u0442\u044C \u043F\u0440\u043E\u0433\u043E\u043D (\u0441\u043B\u043E\u0442 \u043E\u0441\u0432\u043E\u0431\u043E\u0434\u0438\u0442\u0441\u044F, \u0440\u043E\u0439 \u0432\u043E\u0437\u044C\u043C\u0451\u0442 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0443\u044E \u0437\u0430\u0434\u0430\u0447\u0443). \u0417\u043E\u0432\u0438, \u0422\u041E\u041B\u042C\u041A\u041E \u0435\u0441\u043B\u0438 \u0437\u0430\u0434\u0430\u0447\u0443 \u043D\u0435\u043B\u044C\u0437\u044F \u0432\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u044C \u043D\u0438 \u0432 \u043E\u0434\u043D\u043E\u043C \u0440\u0430\u0437\u0443\u043C\u043D\u043E\u043C \u0442\u043E\u043B\u043A\u043E\u0432\u0430\u043D\u0438\u0438 \u0418\u041B\u0418 \u043D\u0435\u043F\u043E\u043D\u044F\u0442\u043D\u043E, \u0447\u0435\u043C \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0442\u044C \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442. \u0414\u0432\u0430 \u043E\u0441\u043C\u044B\u0441\u043B\u0435\u043D\u043D\u044B\u0445 \u0442\u043E\u043B\u043A\u043E\u0432\u0430\u043D\u0438\u044F \u2014 \u041D\u0415 \u043F\u043E\u0432\u043E\u0434: \u0432\u044B\u0431\u0435\u0440\u0438 \u043E\u0447\u0435\u0432\u0438\u0434\u043D\u043E\u0435, \u0441\u0434\u0435\u043B\u0430\u0439 \u0438 \u043D\u0430\u0437\u043E\u0432\u0438 \u0440\u0430\u0437\u0432\u0438\u043B\u043A\u0443 \u0432 \u043E\u043F\u0438\u0441\u0430\u043D\u0438\u0438 PR. \u041F\u043E\u043D\u044F\u0442\u043D\u0430\u044F \u0437\u0430\u0434\u0430\u0447\u0430, \u043A\u043E\u0442\u043E\u0440\u0430\u044F \u0432 \u043E\u0434\u043D\u043E\u043C \u043F\u0443\u043D\u043A\u0442\u0435 \u043F\u0440\u043E\u0442\u0438\u0432\u043E\u0440\u0435\u0447\u0438\u0442 \u043F\u0440\u0430\u0432\u0438\u043B\u0443 \u043F\u0440\u043E\u0435\u043A\u0442\u0430, \u2014 \u0442\u043E\u0436\u0435 \u043D\u0435 \u043F\u043E\u0432\u043E\u0434: \u044D\u0442\u043E ask. \u041E\u0442\u0434\u0435\u043B\u044C\u043D\u044B\u0439 \u0437\u0430\u043A\u043E\u043D\u043D\u044B\u0439 \u0441\u043B\u0443\u0447\u0430\u0439 \u2014 \u0437\u0430\u0434\u0430\u0447\u0430 \u0421\u041B\u0418\u0428\u041A\u041E\u041C \u0412\u0415\u041B\u0418\u041A\u0410 (reason=too_big): \u043F\u043E\u043D\u044F\u0442\u043D\u0430 \u0438 \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0435\u043C\u0430, \u043D\u043E \u044D\u0442\u043E \u043B\u0438\u0441\u0442 \u043D\u0430 \u043D\u0435\u0441\u043A\u043E\u043B\u044C\u043A\u043E \u043F\u0440\u043E\u0433\u043E\u043D\u043E\u0432, \u0438 \u0443\u043F\u0435\u0440\u0435\u0442\u044C\u0441\u044F \u0432 \u043F\u043E\u0442\u043E\u043B\u043E\u043A \u0442\u0440\u0430\u0442 \u043D\u0430 \u0441\u0435\u0440\u0435\u0434\u0438\u043D\u0435 \u0445\u0443\u0436\u0435, \u0447\u0435\u043C \u0432\u0435\u0440\u043D\u0443\u0442\u044C \u0435\u0451 \u0441\u0440\u0430\u0437\u0443; \u0440\u0430\u0437\u0431\u0438\u0435\u043D\u0438\u0435 \u043C\u043E\u0436\u0435\u0448\u044C \u041F\u0420\u0415\u0414\u041B\u041E\u0416\u0418\u0422\u042C (split), \u0430 \u043F\u043E\u0434\u0437\u0430\u0434\u0430\u0447\u0438 \u043D\u0435 \u0437\u0430\u0432\u043E\u0434\u0438 \u2014 \u044D\u0442\u043E \u0440\u0435\u0448\u0435\u043D\u0438\u0435 \u0430\u0432\u0442\u043E\u0440\u0430. \u0417\u0430\u0434\u0430\u0447\u0430 \u0443\u0439\u0434\u0451\u0442 \u0430\u0432\u0442\u043E\u0440\u0443 (\u043D\u0430\u0437\u043D\u0430\u0447\u0438\u043C \u043D\u0430 \u043D\u0435\u0433\u043E \u0438 \u043F\u0435\u0440\u0435\u0432\u0435\u0434\u0451\u043C \u0432 \u0440\u0430\u0431\u043E\u0442\u0443), \u0432\u043E\u043F\u0440\u043E\u0441\u044B \u0443\u0435\u0434\u0443\u0442 \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u043E\u043C \u043E\u0442 \u0442\u0432\u043E\u0435\u0433\u043E \u0438\u043C\u0435\u043D\u0438. \u041F\u043E\u0441\u043B\u0435 \u0432\u044B\u0437\u043E\u0432\u0430 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u044B \u0431\u043E\u043B\u044C\u0448\u0435 \u043D\u0435 \u0437\u043E\u0432\u0438 \u2014 \u0437\u0430\u0432\u0435\u0440\u0448\u0438 \u0441\u0435\u0441\u0441\u0438\u044E.",
|
|
11773
12180
|
{
|
|
12181
|
+
// TASWM-505: КОД причины рядом с прозой. Проза объясняет автору ЭТУ задачу, код
|
|
12182
|
+
// складывается по бэклогу в распределение «чего в постановках не хватает чаще
|
|
12183
|
+
// всего» (аналитика роя). Обязательный: необязательное поле дрон пропустит, а
|
|
12184
|
+
// распределение по половине возвратов — не распределение.
|
|
12185
|
+
reason: z.enum(RETURN_REASONS).describe(
|
|
12186
|
+
"\u043A\u043E\u0434 \u043F\u0440\u0438\u0447\u0438\u043D\u044B: unclear_goal \u2014 \u043D\u0435\u043F\u043E\u043D\u044F\u0442\u043D\u043E, \u0427\u0422\u041E \u0434\u0435\u043B\u0430\u0442\u044C; no_acceptance \u2014 \u043D\u0435\u0447\u0435\u043C \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442; too_big \u2014 \u043F\u043E\u043D\u044F\u0442\u043D\u043E \u0438 \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0435\u043C\u043E, \u043D\u043E \u044D\u0442\u043E \u043D\u0435 \u0437\u0430\u0434\u0430\u0447\u0430, \u0430 \u043F\u0430\u0447\u043A\u0430 \u0437\u0430\u0434\u0430\u0447 (\u043B\u0438\u0441\u0442, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0437\u0430 \u043E\u0434\u0438\u043D \u043F\u0440\u043E\u0433\u043E\u043D \u043D\u0435 \u0434\u043E\u0432\u0435\u0441\u0442\u0438); contradiction \u2014 \u043F\u043E\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430 \u043F\u0440\u043E\u0442\u0438\u0432\u043E\u0440\u0435\u0447\u0438\u0442 \u0441\u0430\u043C\u0430 \u0441\u0435\u0431\u0435 \u0438\u043B\u0438 \u0443\u0436\u0435 \u043F\u0440\u0438\u043D\u044F\u0442\u043E\u043C\u0443 \u0440\u0435\u0448\u0435\u043D\u0438\u044E"
|
|
12187
|
+
),
|
|
11774
12188
|
missing: z.string().min(30).describe("\u0447\u0435\u0433\u043E \u0432 \u0437\u0430\u0434\u0430\u0447\u0435 \u043D\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442, \u0447\u0442\u043E\u0431\u044B \u0435\u0451 \u0441\u0434\u0435\u043B\u0430\u0442\u044C \u0438\u043B\u0438 \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C \u2014 \u043A\u043E\u043D\u043A\u0440\u0435\u0442\u043D\u043E, \u0430 \u043D\u0435 \xAB\u043D\u0435\u043F\u043E\u043D\u044F\u0442\u043D\u043E\xBB"),
|
|
11775
12189
|
readings: z.array(z.string().min(10)).optional().describe("\u0442\u043E\u043B\u043A\u043E\u0432\u0430\u043D\u0438\u044F \u043F\u043E\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0442\u044B \u0440\u0430\u0441\u0441\u043C\u043E\u0442\u0440\u0435\u043B (\u0438 \u0447\u0435\u043C \u043A\u0430\u0436\u0434\u043E\u0435 \u043F\u043B\u043E\u0445\u043E/\u043F\u0440\u043E\u0442\u0438\u0432\u043E\u0440\u0435\u0447\u0438\u0432\u043E)"),
|
|
11776
12190
|
assumed: z.string().min(30).describe("\u0447\u0442\u043E \u0442\u044B \u043F\u0440\u0435\u0434\u043F\u043E\u043B\u043E\u0436\u0438\u043B \u0431\u044B \u0441\u0434\u0435\u043B\u0430\u0442\u044C, \u0435\u0441\u043B\u0438 \u0431\u044B \u043F\u0440\u0438\u0448\u043B\u043E\u0441\u044C \u0433\u0430\u0434\u0430\u0442\u044C, \u0438 \u043F\u043E\u0447\u0435\u043C\u0443 \u043D\u0435 \u0441\u0442\u0430\u043B"),
|
|
11777
|
-
questions: z.array(z.string().min(10)).min(1).max(7).describe("\u043A\u043E\u043D\u043A\u0440\u0435\u0442\u043D\u044B\u0435 \u0432\u043E\u043F\u0440\u043E\u0441\u044B \u0430\u0432\u0442\u043E\u0440\u0443 \u2014 \u043E\u0442\u0432\u0435\u0442\u044B \u043D\u0430 \u043D\u0438\u0445 \u0434\u043E\u043B\u0436\u043D\u044B \u0434\u0435\u043B\u0430\u0442\u044C \u0437\u0430\u0434\u0430\u0447\u0443 \u0432\u044B\u043F\u043E\u043B\u043D\u0438\u043C\u043E\u0439")
|
|
12191
|
+
questions: z.array(z.string().min(10)).min(1).max(7).describe("\u043A\u043E\u043D\u043A\u0440\u0435\u0442\u043D\u044B\u0435 \u0432\u043E\u043F\u0440\u043E\u0441\u044B \u0430\u0432\u0442\u043E\u0440\u0443 \u2014 \u043E\u0442\u0432\u0435\u0442\u044B \u043D\u0430 \u043D\u0438\u0445 \u0434\u043E\u043B\u0436\u043D\u044B \u0434\u0435\u043B\u0430\u0442\u044C \u0437\u0430\u0434\u0430\u0447\u0443 \u0432\u044B\u043F\u043E\u043B\u043D\u0438\u043C\u043E\u0439"),
|
|
12192
|
+
// TASWM-505: разбиение — ПРЕДЛОЖЕНИЕ автору, а не действие дрона. Подзадачи дрон не
|
|
12193
|
+
// заводит сознательно: разбиение — продуктовое решение, а плохое разбиение хуже
|
|
12194
|
+
// никакого, потому что выглядит авторитетно (заведённые подзадачи прочтут как
|
|
12195
|
+
// согласованный план). Поэтому — строчками в комменте, которые автор правит или
|
|
12196
|
+
// выбрасывает одним движением.
|
|
12197
|
+
split: z.array(z.string().min(10)).max(7).optional().describe(
|
|
12198
|
+
"\u0422\u041E\u041B\u042C\u041A\u041E \u043A reason=too_big: \u043A\u0430\u043A \u0431\u044B \u0442\u044B \u0440\u0430\u0437\u0431\u0438\u043B \u0437\u0430\u0434\u0430\u0447\u0443 \u2014 \u043F\u043E \u043E\u0434\u043D\u043E\u043C\u0443 \u043A\u0443\u0441\u043A\u0443 \u043D\u0430 \u0441\u0442\u0440\u043E\u043A\u0443. \u0423\u0435\u0434\u0435\u0442 \u0430\u0432\u0442\u043E\u0440\u0443 \u041F\u0420\u0415\u0414\u041B\u041E\u0416\u0415\u041D\u0418\u0415\u041C \u0432 \u0442\u043E\u043C \u0436\u0435 \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0435; \u043F\u043E\u0434\u0437\u0430\u0434\u0430\u0447\u0438 \u0441\u0430\u043C \u041D\u0415 \u0437\u0430\u0432\u043E\u0434\u0438 (\u0440\u0430\u0437\u0431\u0438\u0435\u043D\u0438\u0435 \u2014 \u0440\u0435\u0448\u0435\u043D\u0438\u0435 \u0430\u0432\u0442\u043E\u0440\u0430)"
|
|
12199
|
+
)
|
|
11778
12200
|
},
|
|
11779
12201
|
guard(
|
|
11780
12202
|
async ({
|
|
12203
|
+
reason,
|
|
11781
12204
|
missing,
|
|
11782
12205
|
readings,
|
|
11783
12206
|
assumed,
|
|
11784
|
-
questions
|
|
12207
|
+
questions,
|
|
12208
|
+
split
|
|
11785
12209
|
}) => {
|
|
11786
12210
|
if (await overmindDead()) return freeze();
|
|
11787
12211
|
const run = await store.myRun();
|
|
@@ -11816,10 +12240,20 @@ ${failText}` : failText }],
|
|
|
11816
12240
|
"",
|
|
11817
12241
|
`${author ? `${author.name}, ` : ""}\u044F \u043D\u0435 \u0431\u0435\u0440\u0443\u0441\u044C \u0437\u0430 \u044D\u0442\u0443 \u0437\u0430\u0434\u0430\u0447\u0443: \u0435\u0451 \u043D\u0435\u043B\u044C\u0437\u044F \u0432\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u044C, \u043D\u0435 \u0432\u044B\u0434\u0443\u043C\u0430\u0432 \u043F\u043E\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0443 \u0437\u0430 \u0442\u0435\u0431\u044F. \u0427\u0442\u043E \u043C\u0435\u0448\u0430\u0435\u0442:`,
|
|
11818
12242
|
"",
|
|
12243
|
+
`**\u041F\u0440\u0438\u0447\u0438\u043D\u0430.** ${returnReasonLabel(reason)} (\`${reason}\`).`,
|
|
12244
|
+
"",
|
|
11819
12245
|
`**\u0427\u0435\u0433\u043E \u043D\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442.** ${missing.trim()}`,
|
|
11820
12246
|
...readings?.length ? ["", "**\u041A\u0430\u043A \u044D\u0442\u043E \u043C\u043E\u0436\u043D\u043E \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u0442\u044C.**", ...readings.map((r) => `- ${r.trim()}`)] : [],
|
|
11821
12247
|
"",
|
|
11822
12248
|
`**\u0427\u0442\u043E \u044F \u043F\u0440\u0435\u0434\u043F\u043E\u043B\u043E\u0436\u0438\u043B \u0431\u044B \u0438 \u043F\u043E\u0447\u0435\u043C\u0443 \u043D\u0435 \u0441\u0442\u0430\u043B.** ${assumed.trim()}`,
|
|
12249
|
+
// Разбиение — только предложение и только к too_big (TASWM-505). Формулировка
|
|
12250
|
+
// «на твоё усмотрение» здесь не вежливость: заведённые подзадачи выглядели бы
|
|
12251
|
+
// согласованным планом, а это решение автора, и плохое разбиение хуже никакого.
|
|
12252
|
+
...reason === "too_big" && split?.length ? [
|
|
12253
|
+
"",
|
|
12254
|
+
"**\u041A\u0430\u043A \u044D\u0442\u043E \u043C\u043E\u0436\u043D\u043E \u0440\u0430\u0437\u0431\u0438\u0442\u044C** \u2014 \u043F\u0440\u0435\u0434\u043B\u043E\u0436\u0435\u043D\u0438\u0435, \u043D\u0435 \u0440\u0430\u0437\u0431\u0438\u0435\u043D\u0438\u0435: \u043F\u043E\u0434\u0437\u0430\u0434\u0430\u0447\u0438 \u044F \u043D\u0435 \u0437\u0430\u0432\u043E\u0434\u0438\u043B, \u0440\u0435\u0448\u0430\u0442\u044C \u0442\u0435\u0431\u0435.",
|
|
12255
|
+
...split.map((s) => `- ${s.trim()}`)
|
|
12256
|
+
] : [],
|
|
11823
12257
|
"",
|
|
11824
12258
|
"**\u0412\u043E\u043F\u0440\u043E\u0441\u044B, \u043F\u043E\u0441\u043B\u0435 \u043E\u0442\u0432\u0435\u0442\u043E\u0432 \u043D\u0430 \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0437\u0430\u0434\u0430\u0447\u0443 \u043C\u043E\u0436\u043D\u043E \u0431\u0440\u0430\u0442\u044C:**",
|
|
11825
12259
|
...questions.map((q, i) => `${i + 1}. ${q.trim()}`)
|
|
@@ -11863,9 +12297,9 @@ ${failText}` : failText }],
|
|
|
11863
12297
|
};
|
|
11864
12298
|
}
|
|
11865
12299
|
}
|
|
11866
|
-
const
|
|
11867
|
-
await store.updateRun(null, { status: "returned", stop_reason: reason });
|
|
11868
|
-
await store.addEvent(null, "returned", failures.length ? `${
|
|
12300
|
+
const stopReason = `\u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0435\u043D\u0430 \u0430\u0432\u0442\u043E\u0440\u0443${author ? ` (${author.name})` : ""} \xB7 ${returnReasonLabel(reason)}: ${missing.trim()}`;
|
|
12301
|
+
await store.updateRun(null, { status: "returned", stop_reason: stopReason, return_reason: reason });
|
|
12302
|
+
await store.addEvent(null, "returned", failures.length ? `${stopReason} \xB7 \u043D\u0435 \u0434\u043E\u0435\u0445\u0430\u043B\u043E: ${failures.join("; ")}` : stopReason);
|
|
11869
12303
|
return {
|
|
11870
12304
|
content: [
|
|
11871
12305
|
{
|
|
@@ -12211,9 +12645,11 @@ ${report}${shots.warning}`,
|
|
|
12211
12645
|
const headBranch = opts.prHeadBranch ? await opts.prHeadBranch(pr_url).catch(() => null) : null;
|
|
12212
12646
|
const branchFix = branchFromPrPatch(run?.branch, headBranch);
|
|
12213
12647
|
if (branchFix) await store.addEvent(null, "step", branchFix.event);
|
|
12648
|
+
const held = await changedPaths(opts.worktree ?? process.cwd(), { baseBranch: run?.base_branch ?? null }).catch(() => []);
|
|
12649
|
+
const heldPatch = held.length ? { changed_paths: held } : {};
|
|
12214
12650
|
if (run) {
|
|
12215
12651
|
const t = reviewTransitionPatch(run, pr_url);
|
|
12216
|
-
await store.updateRun(null, { ...t.patch, ...branchFix?.patch ?? {} });
|
|
12652
|
+
await store.updateRun(null, { ...t.patch, ...branchFix?.patch ?? {}, ...heldPatch });
|
|
12217
12653
|
await store.addEvent(null, "pr_opened", pr_url);
|
|
12218
12654
|
await postReport(reportSlug(run.task_slug), t.cycle ?? run.review_cycle ?? 0);
|
|
12219
12655
|
const rulesNote = await offerRules(reportSlug(run.task_slug));
|
|
@@ -12228,7 +12664,7 @@ ${report}${shots.warning}`,
|
|
|
12228
12664
|
}
|
|
12229
12665
|
return { content: [{ type: "text", text: `\u043F\u0440\u0438\u043D\u044F\u0442\u043E, \u0443\u0448\u043B\u043E \u043D\u0430 \u0440\u0435\u0432\u044C\u044E${shotsNote(shots)}${rulesNote}${zoneNote}` }] };
|
|
12230
12666
|
}
|
|
12231
|
-
await store.updateRun(null, { status: "review", pr_url, ...branchFix?.patch ?? {} });
|
|
12667
|
+
await store.updateRun(null, { status: "review", pr_url, ...branchFix?.patch ?? {}, ...heldPatch });
|
|
12232
12668
|
await store.addEvent(null, "pr_opened", pr_url);
|
|
12233
12669
|
const fallbackSlug = reportSlug(void 0);
|
|
12234
12670
|
if (fallbackSlug) await postReport(fallbackSlug, void 0);
|
|
@@ -13532,20 +13968,20 @@ function makeMergeGateParts(deps) {
|
|
|
13532
13968
|
|
|
13533
13969
|
// src/envGate.ts
|
|
13534
13970
|
import { existsSync as existsSync15 } from "fs";
|
|
13535
|
-
import { join as
|
|
13971
|
+
import { join as join27 } from "path";
|
|
13536
13972
|
import { createConnection } from "net";
|
|
13537
13973
|
import { execa as execa2 } from "execa";
|
|
13538
13974
|
|
|
13539
13975
|
// src/platform.ts
|
|
13540
13976
|
import { existsSync as existsSync14, readFileSync as readFileSync18 } from "fs";
|
|
13541
|
-
import { delimiter, join as
|
|
13977
|
+
import { delimiter, join as join26 } from "path";
|
|
13542
13978
|
function resolveCommandPath(name, env = process.env, platform = process.platform) {
|
|
13543
13979
|
if (name.includes("/") || name.includes("\\")) return existsSync14(name) ? name : null;
|
|
13544
13980
|
const dirs = (env.PATH ?? env.Path ?? "").split(delimiter).filter(Boolean);
|
|
13545
13981
|
const exts = platform === "win32" ? (env.PATHEXT ?? ".EXE;.CMD;.BAT").split(";").filter(Boolean) : [""];
|
|
13546
13982
|
for (const dir of dirs) {
|
|
13547
13983
|
for (const ext of exts) {
|
|
13548
|
-
const candidate =
|
|
13984
|
+
const candidate = join26(dir, name + ext);
|
|
13549
13985
|
if (existsSync14(candidate)) return candidate;
|
|
13550
13986
|
}
|
|
13551
13987
|
}
|
|
@@ -13630,7 +14066,7 @@ var COMPOSE_MARKERS = [
|
|
|
13630
14066
|
];
|
|
13631
14067
|
function detectRequirements(repo, io = {}) {
|
|
13632
14068
|
const exists = io.exists ?? existsSync15;
|
|
13633
|
-
const marker = COMPOSE_MARKERS.find((f) => exists(
|
|
14069
|
+
const marker = COMPOSE_MARKERS.find((f) => exists(join27(repo, f)));
|
|
13634
14070
|
return marker ? [{ kind: "docker", raw: `docker (\u0434\u0435\u0442\u0435\u043A\u0442: ${marker})` }] : [];
|
|
13635
14071
|
}
|
|
13636
14072
|
function resolveRequirements(repo, declared, io = {}) {
|
|
@@ -13765,210 +14201,10 @@ import { randomBytes as randomBytes3 } from "crypto";
|
|
|
13765
14201
|
import { basename as basename5 } from "path";
|
|
13766
14202
|
import { serve as serve2 } from "@hono/node-server";
|
|
13767
14203
|
|
|
13768
|
-
// src/diff.ts
|
|
13769
|
-
import { statSync as statSync10 } from "fs";
|
|
13770
|
-
import { join as join27 } from "path";
|
|
13771
|
-
import { $ as $4 } from "execa";
|
|
13772
|
-
var MAX_FILES = 200;
|
|
13773
|
-
var MAX_LINES_PER_FILE = 1500;
|
|
13774
|
-
var MAX_UNTRACKED = 60;
|
|
13775
|
-
function cleanPath(raw) {
|
|
13776
|
-
let p = raw.trim();
|
|
13777
|
-
if (p.startsWith('"') && p.endsWith('"') && p.length >= 2) p = p.slice(1, -1);
|
|
13778
|
-
return p;
|
|
13779
|
-
}
|
|
13780
|
-
function stripAB(raw) {
|
|
13781
|
-
const p = cleanPath(raw);
|
|
13782
|
-
if (p === "/dev/null") return p;
|
|
13783
|
-
if (p.startsWith("a/") || p.startsWith("b/")) return p.slice(2);
|
|
13784
|
-
return p;
|
|
13785
|
-
}
|
|
13786
|
-
function parseUnifiedDiff(text) {
|
|
13787
|
-
const files = [];
|
|
13788
|
-
if (!text) return files;
|
|
13789
|
-
const lines = text.split("\n");
|
|
13790
|
-
let f = null;
|
|
13791
|
-
let hunk = null;
|
|
13792
|
-
let oldNo = 0;
|
|
13793
|
-
let newNo = 0;
|
|
13794
|
-
const push = () => {
|
|
13795
|
-
if (f) files.push(f);
|
|
13796
|
-
};
|
|
13797
|
-
for (const line of lines) {
|
|
13798
|
-
if (line.startsWith("diff --git ")) {
|
|
13799
|
-
push();
|
|
13800
|
-
hunk = null;
|
|
13801
|
-
const m = line.match(/^diff --git (.+) (.+)$/);
|
|
13802
|
-
const guess = m ? stripAB(m[2]) : "";
|
|
13803
|
-
f = { path: guess, oldPath: null, status: "modified", added: 0, removed: 0, binary: false, hunks: [] };
|
|
13804
|
-
continue;
|
|
13805
|
-
}
|
|
13806
|
-
if (!f) continue;
|
|
13807
|
-
if (line.startsWith("new file mode")) {
|
|
13808
|
-
f.status = "added";
|
|
13809
|
-
continue;
|
|
13810
|
-
}
|
|
13811
|
-
if (line.startsWith("deleted file mode")) {
|
|
13812
|
-
f.status = "deleted";
|
|
13813
|
-
continue;
|
|
13814
|
-
}
|
|
13815
|
-
if (line.startsWith("rename from ") || line.startsWith("copy from ")) {
|
|
13816
|
-
f.oldPath = cleanPath(line.replace(/^(rename|copy) from /, ""));
|
|
13817
|
-
f.status = "renamed";
|
|
13818
|
-
continue;
|
|
13819
|
-
}
|
|
13820
|
-
if (line.startsWith("rename to ") || line.startsWith("copy to ")) {
|
|
13821
|
-
f.path = cleanPath(line.replace(/^(rename|copy) to /, ""));
|
|
13822
|
-
f.status = "renamed";
|
|
13823
|
-
continue;
|
|
13824
|
-
}
|
|
13825
|
-
if (line.startsWith("Binary files ")) {
|
|
13826
|
-
f.binary = true;
|
|
13827
|
-
continue;
|
|
13828
|
-
}
|
|
13829
|
-
if (line.startsWith("--- ")) {
|
|
13830
|
-
const p = stripAB(line.slice(4));
|
|
13831
|
-
if (p === "/dev/null") f.status = "added";
|
|
13832
|
-
continue;
|
|
13833
|
-
}
|
|
13834
|
-
if (line.startsWith("+++ ")) {
|
|
13835
|
-
const p = stripAB(line.slice(4));
|
|
13836
|
-
if (p === "/dev/null") f.status = "deleted";
|
|
13837
|
-
else if (p) f.path = p;
|
|
13838
|
-
continue;
|
|
13839
|
-
}
|
|
13840
|
-
if (line.startsWith("@@")) {
|
|
13841
|
-
const m = line.match(/^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@(.*)$/);
|
|
13842
|
-
if (m) {
|
|
13843
|
-
oldNo = Number(m[1]);
|
|
13844
|
-
newNo = Number(m[2]);
|
|
13845
|
-
hunk = { header: (m[3] ?? "").trim(), lines: [] };
|
|
13846
|
-
f.hunks.push(hunk);
|
|
13847
|
-
}
|
|
13848
|
-
continue;
|
|
13849
|
-
}
|
|
13850
|
-
if (!hunk) continue;
|
|
13851
|
-
if (line.startsWith("\\")) continue;
|
|
13852
|
-
const tag = line[0];
|
|
13853
|
-
const body = line.slice(1);
|
|
13854
|
-
if (tag === "+") {
|
|
13855
|
-
hunk.lines.push({ k: "add", o: null, n: newNo++, t: body });
|
|
13856
|
-
f.added++;
|
|
13857
|
-
} else if (tag === "-") {
|
|
13858
|
-
hunk.lines.push({ k: "del", o: oldNo++, n: null, t: body });
|
|
13859
|
-
f.removed++;
|
|
13860
|
-
} else if (tag === " ") {
|
|
13861
|
-
hunk.lines.push({ k: "ctx", o: oldNo++, n: newNo++, t: body });
|
|
13862
|
-
}
|
|
13863
|
-
}
|
|
13864
|
-
push();
|
|
13865
|
-
return files;
|
|
13866
|
-
}
|
|
13867
|
-
function truncateFile(f) {
|
|
13868
|
-
let count = 0;
|
|
13869
|
-
const hunks = [];
|
|
13870
|
-
let cut = false;
|
|
13871
|
-
for (const h of f.hunks) {
|
|
13872
|
-
if (count >= MAX_LINES_PER_FILE) {
|
|
13873
|
-
cut = true;
|
|
13874
|
-
break;
|
|
13875
|
-
}
|
|
13876
|
-
const room = MAX_LINES_PER_FILE - count;
|
|
13877
|
-
if (h.lines.length <= room) {
|
|
13878
|
-
hunks.push(h);
|
|
13879
|
-
count += h.lines.length;
|
|
13880
|
-
} else {
|
|
13881
|
-
hunks.push({ header: h.header, lines: h.lines.slice(0, room) });
|
|
13882
|
-
count += room;
|
|
13883
|
-
cut = true;
|
|
13884
|
-
break;
|
|
13885
|
-
}
|
|
13886
|
-
}
|
|
13887
|
-
return cut ? { ...f, hunks, truncated: true } : f;
|
|
13888
|
-
}
|
|
13889
|
-
async function resolveBase(wt, baseBranch) {
|
|
13890
|
-
const tryRef = async (ref) => {
|
|
13891
|
-
const sha = (await $4({ reject: false })`git -C ${wt} rev-parse --verify --quiet ${ref + "^{commit}"}`).stdout.trim();
|
|
13892
|
-
if (!sha) return null;
|
|
13893
|
-
const mb2 = (await $4({ reject: false })`git -C ${wt} merge-base HEAD ${ref}`).stdout.trim();
|
|
13894
|
-
return mb2 || null;
|
|
13895
|
-
};
|
|
13896
|
-
const originHead = (await $4({ reject: false })`git -C ${wt} symbolic-ref --quiet --short refs/remotes/origin/HEAD`).stdout.trim();
|
|
13897
|
-
const candidates = [
|
|
13898
|
-
...baseBranch ? [`origin/${baseBranch}`, baseBranch] : [],
|
|
13899
|
-
originHead,
|
|
13900
|
-
"origin/main",
|
|
13901
|
-
"origin/master",
|
|
13902
|
-
"main",
|
|
13903
|
-
"master"
|
|
13904
|
-
].filter(Boolean);
|
|
13905
|
-
for (const c of candidates) {
|
|
13906
|
-
const mb2 = await tryRef(c);
|
|
13907
|
-
if (mb2) return mb2;
|
|
13908
|
-
}
|
|
13909
|
-
return null;
|
|
13910
|
-
}
|
|
13911
|
-
function mtime(path) {
|
|
13912
|
-
try {
|
|
13913
|
-
return statSync10(path).mtimeMs;
|
|
13914
|
-
} catch {
|
|
13915
|
-
return 0;
|
|
13916
|
-
}
|
|
13917
|
-
}
|
|
13918
|
-
async function collectRunDiff(worktree, opts = {}) {
|
|
13919
|
-
const stub = (reason) => ({ ok: false, reason, pr: opts.pr ?? null, files: [], added: 0, removed: 0 });
|
|
13920
|
-
const gone = opts.status === "queued" ? "\u0434\u0440\u043E\u043D \u0435\u0449\u0451 \u0432 \u043E\u0447\u0435\u0440\u0435\u0434\u0438 \u2014 \u043A\u043E\u0434\u0430 \u043F\u043E\u043A\u0430 \u043D\u0435\u0442" : "worktree \u0443\u0431\u0440\u0430\u043D \u2014 \u043A\u043E\u0434 \u0441\u043C\u043E\u0442\u0440\u0438 \u0432 PR";
|
|
13921
|
-
if (!worktree) return stub(gone);
|
|
13922
|
-
const isWt = (await $4({ reject: false })`git -C ${worktree} rev-parse --is-inside-work-tree`).stdout.trim();
|
|
13923
|
-
if (isWt !== "true") return stub(gone);
|
|
13924
|
-
const base3 = await resolveBase(worktree, opts.baseBranch);
|
|
13925
|
-
const from = base3 ?? "HEAD";
|
|
13926
|
-
const trackedTxt = (await $4({ reject: false })`git -C ${worktree} diff --no-color --find-renames ${from} --`).stdout;
|
|
13927
|
-
let files = parseUnifiedDiff(trackedTxt);
|
|
13928
|
-
const untrackedRaw = (await $4({ reject: false })`git -C ${worktree} ls-files --others --exclude-standard -z`).stdout;
|
|
13929
|
-
const untracked = untrackedRaw.split("\0").filter(Boolean).slice(0, MAX_UNTRACKED);
|
|
13930
|
-
for (const rel of untracked) {
|
|
13931
|
-
const t = (await $4({ reject: false })`git -C ${worktree} diff --no-color --no-index -- /dev/null ${rel}`).stdout;
|
|
13932
|
-
for (const pf of parseUnifiedDiff(t)) {
|
|
13933
|
-
pf.status = "added";
|
|
13934
|
-
if (!pf.path || pf.path === "/dev/null") pf.path = rel;
|
|
13935
|
-
files.push(pf);
|
|
13936
|
-
}
|
|
13937
|
-
}
|
|
13938
|
-
files.sort((a, b) => mtime(join27(worktree, b.path)) - mtime(join27(worktree, a.path)));
|
|
13939
|
-
const truncatedFiles = files.length > MAX_FILES;
|
|
13940
|
-
if (truncatedFiles) files = files.slice(0, MAX_FILES);
|
|
13941
|
-
const added = files.reduce((s, f) => s + f.added, 0);
|
|
13942
|
-
const removed = files.reduce((s, f) => s + f.removed, 0);
|
|
13943
|
-
const out = files.map(truncateFile);
|
|
13944
|
-
return {
|
|
13945
|
-
ok: true,
|
|
13946
|
-
base: base3 ? base3.slice(0, 9) : null,
|
|
13947
|
-
files: out,
|
|
13948
|
-
added,
|
|
13949
|
-
removed,
|
|
13950
|
-
...truncatedFiles ? { truncated: true } : {}
|
|
13951
|
-
};
|
|
13952
|
-
}
|
|
13953
|
-
async function changedPaths(worktree, opts = {}) {
|
|
13954
|
-
if (!worktree) return [];
|
|
13955
|
-
try {
|
|
13956
|
-
const isWt = (await $4({ reject: false })`git -C ${worktree} rev-parse --is-inside-work-tree`).stdout.trim();
|
|
13957
|
-
if (isWt !== "true") return [];
|
|
13958
|
-
const from = await resolveBase(worktree, opts.baseBranch) ?? "HEAD";
|
|
13959
|
-
const tracked = (await $4({ reject: false })`git -C ${worktree} diff --name-only --find-renames ${from} --`).stdout;
|
|
13960
|
-
const untracked = (await $4({ reject: false })`git -C ${worktree} ls-files --others --exclude-standard -z`).stdout;
|
|
13961
|
-
const all = [...tracked.split("\n"), ...untracked.split("\0")].map((s) => s.trim()).filter(Boolean);
|
|
13962
|
-
return [...new Set(all)].sort();
|
|
13963
|
-
} catch {
|
|
13964
|
-
return [];
|
|
13965
|
-
}
|
|
13966
|
-
}
|
|
13967
|
-
|
|
13968
14204
|
// package.json
|
|
13969
14205
|
var package_default = {
|
|
13970
14206
|
name: "@taskless-app/swarm",
|
|
13971
|
-
version: "0.6.
|
|
14207
|
+
version: "0.6.27",
|
|
13972
14208
|
type: "module",
|
|
13973
14209
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
13974
14210
|
keywords: [
|
|
@@ -14019,7 +14255,7 @@ var package_default = {
|
|
|
14019
14255
|
execa: "^10.0.0",
|
|
14020
14256
|
zod: "3.25.76"
|
|
14021
14257
|
},
|
|
14022
|
-
gitHead: "
|
|
14258
|
+
gitHead: "2e1ed83014422ae577be60271adc79e291b9e2ab"
|
|
14023
14259
|
};
|
|
14024
14260
|
|
|
14025
14261
|
// src/version.ts
|
|
@@ -16401,6 +16637,12 @@ function predictForRun(model, run) {
|
|
|
16401
16637
|
function short(files, n = 3) {
|
|
16402
16638
|
return files.slice(0, n).join(", ") + (files.length > n ? ` \u0438 \u0435\u0449\u0451 ${files.length - n}` : "");
|
|
16403
16639
|
}
|
|
16640
|
+
function heldBecause(w) {
|
|
16641
|
+
const parts = [];
|
|
16642
|
+
if (w.prUrl) parts.push(`\u0440\u0430\u0431\u043E\u0442\u0430 \u0441\u0434\u0430\u043D\u0430, PR \u0435\u0449\u0451 \u043D\u0435 \u0432\u043B\u0438\u0442: ${w.prUrl}`);
|
|
16643
|
+
if (!w.actual) parts.push(w.prUrl ? "\u0444\u0430\u0439\u043B\u044B \u0432\u0437\u044F\u0442\u044B \u043F\u043E \u043F\u0440\u0435\u0434\u0441\u043A\u0430\u0437\u0430\u043D\u0438\u044E \u2014 \u0441\u043D\u0438\u043C\u043A\u0430 \u043D\u0435 \u043E\u0441\u0442\u0430\u043B\u043E\u0441\u044C" : "\u043F\u043E \u043F\u0440\u0435\u0434\u0441\u043A\u0430\u0437\u0430\u043D\u0438\u044E \u2014 \u0434\u0440\u043E\u043D \u0435\u0449\u0451 \u043D\u0435 \u043D\u0430\u0447\u0430\u043B \u043F\u0438\u0441\u0430\u0442\u044C \u043A\u043E\u0434");
|
|
16644
|
+
return parts.length ? ` (${parts.join("; ")})` : "";
|
|
16645
|
+
}
|
|
16404
16646
|
var SPINE_PREDICTION_WEIGHT = 0.7;
|
|
16405
16647
|
function spineOfPrediction(spine, predicted) {
|
|
16406
16648
|
return predicted.filter((p) => spine.has(p.path) && p.weight >= SPINE_PREDICTION_WEIGHT).map((p) => p.path);
|
|
@@ -16421,7 +16663,7 @@ function decideConflict({ model, candidate, active }) {
|
|
|
16421
16663
|
return {
|
|
16422
16664
|
kind: "wait",
|
|
16423
16665
|
blockedBy: w.run,
|
|
16424
|
-
message: `\u044D\u0442\u0438 \u0434\u0432\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u0442\u0440\u043E\u0433\u0430\u044E\u0442 \u043E\u0434\u043D\u0438 \u0444\u0430\u0439\u043B\u044B \u043E\u0431\u0449\u0435\u0433\u043E \u0445\u0440\u0435\u0431\u0442\u0430 (${short(shared)}) \u2014 \u0442\u0430\u043A\u0438\u0435 \u0438\u0434\u0443\u0442 \u043F\u043E\u0441\u043B\u0435\u0434\u043E\u0432\u0430\u0442\u0435\u043B\u044C\u043D\u043E \u043D\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043C\u043E \u043E\u0442 \u0437\u043E\u043D\u044B: \u0436\u0434\u0443 ${w.run.task_slug} (#${w.run.id})` + (w
|
|
16666
|
+
message: `\u044D\u0442\u0438 \u0434\u0432\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u0442\u0440\u043E\u0433\u0430\u044E\u0442 \u043E\u0434\u043D\u0438 \u0444\u0430\u0439\u043B\u044B \u043E\u0431\u0449\u0435\u0433\u043E \u0445\u0440\u0435\u0431\u0442\u0430 (${short(shared)}) \u2014 \u0442\u0430\u043A\u0438\u0435 \u0438\u0434\u0443\u0442 \u043F\u043E\u0441\u043B\u0435\u0434\u043E\u0432\u0430\u0442\u0435\u043B\u044C\u043D\u043E \u043D\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043C\u043E \u043E\u0442 \u0437\u043E\u043D\u044B: \u0436\u0434\u0443 ${w.run.task_slug} (#${w.run.id})` + heldBecause(w)
|
|
16425
16667
|
};
|
|
16426
16668
|
}
|
|
16427
16669
|
}
|
|
@@ -16432,7 +16674,7 @@ function decideConflict({ model, candidate, active }) {
|
|
|
16432
16674
|
return {
|
|
16433
16675
|
kind: "wait",
|
|
16434
16676
|
blockedBy: w.run,
|
|
16435
|
-
message: `\u044D\u0442\u0438 \u0434\u0432\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u0442\u0440\u043E\u0433\u0430\u044E\u0442 ${what} \u2014 \u0441\u0442\u0430\u0432\u0438\u043C \u043F\u043E\u0441\u043B\u0435\u0434\u043E\u0432\u0430\u0442\u0435\u043B\u044C\u043D\u043E: \u0436\u0434\u0443 ${w.run.task_slug} (#${w.run.id})` + (w
|
|
16677
|
+
message: `\u044D\u0442\u0438 \u0434\u0432\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u0442\u0440\u043E\u0433\u0430\u044E\u0442 ${what} \u2014 \u0441\u0442\u0430\u0432\u0438\u043C \u043F\u043E\u0441\u043B\u0435\u0434\u043E\u0432\u0430\u0442\u0435\u043B\u044C\u043D\u043E: \u0436\u0434\u0443 ${w.run.task_slug} (#${w.run.id})` + heldBecause(w)
|
|
16436
16678
|
};
|
|
16437
16679
|
}
|
|
16438
16680
|
return { kind: "clear" };
|
|
@@ -16485,10 +16727,16 @@ var ActiveFilesCache = class {
|
|
|
16485
16727
|
this.cache.set(run.id, { at: now, files });
|
|
16486
16728
|
return files;
|
|
16487
16729
|
}
|
|
16488
|
-
/**
|
|
16489
|
-
|
|
16490
|
-
|
|
16491
|
-
|
|
16730
|
+
/**
|
|
16731
|
+
* Забыть всех, кто больше НЕ ДЕРЖИТ файлы. Раньше здесь стоял список ЖИВЫХ дронов и
|
|
16732
|
+
* комментарий «дрон закончил — его файлы больше не заняты»; это и была дырка TASWM-506:
|
|
16733
|
+
* дрон заканчивал, открывал PR, PR висел непомерженным — а строки уже считались
|
|
16734
|
+
* свободными. Держатель теперь переживает своего дрона и уходит из кэша на мерже
|
|
16735
|
+
* (прогон выходит из `review`), см. holdsFiles.
|
|
16736
|
+
*/
|
|
16737
|
+
prune(holderIds) {
|
|
16738
|
+
const holders = new Set(holderIds);
|
|
16739
|
+
for (const id of [...this.cache.keys()]) if (!holders.has(id)) this.cache.delete(id);
|
|
16492
16740
|
}
|
|
16493
16741
|
};
|
|
16494
16742
|
function withManualAreas(history, areas) {
|
|
@@ -16507,6 +16755,7 @@ var RESPAWN_LIMIT = Number(process.env.SWARM_RESPAWN_LIMIT) || 2;
|
|
|
16507
16755
|
var RESPAWN_YOUNG_MS = Number(process.env.SWARM_RESPAWN_YOUNG_MS) || 60 * 1e3;
|
|
16508
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";
|
|
16509
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";
|
|
16510
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";
|
|
16511
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";
|
|
16512
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";
|
|
@@ -16639,7 +16888,7 @@ function lastCiCheckMs(db, runId) {
|
|
|
16639
16888
|
if (!evs.length) return null;
|
|
16640
16889
|
return Date.parse(evs[evs.length - 1].at.replace(" ", "T") + "Z");
|
|
16641
16890
|
}
|
|
16642
|
-
function reviewPhaseInputFor(deps, run) {
|
|
16891
|
+
function reviewPhaseInputFor(deps, run, projectWantsVerify = true) {
|
|
16643
16892
|
const events = deps.db.events(run.id);
|
|
16644
16893
|
let ciRed = false;
|
|
16645
16894
|
let ciFailing = [];
|
|
@@ -16664,20 +16913,35 @@ function reviewPhaseInputFor(deps, run) {
|
|
|
16664
16913
|
const attempts = deps.db.reviewerAttemptCountFor(run.id);
|
|
16665
16914
|
const lastAttempt = deps.db.lastReviewerAttemptFor(run.id);
|
|
16666
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;
|
|
16667
16918
|
return {
|
|
16668
16919
|
reviewVerdict: run.review_verdict,
|
|
16669
16920
|
ciRed,
|
|
16670
16921
|
ciFailing,
|
|
16671
16922
|
ciProgress,
|
|
16672
16923
|
reviewerName: reviewer?.name ?? null,
|
|
16673
|
-
reviewerDead
|
|
16924
|
+
reviewerDead,
|
|
16925
|
+
verifyVerdict: run.verify_verdict,
|
|
16926
|
+
verifyExpected,
|
|
16927
|
+
verifierDead
|
|
16674
16928
|
};
|
|
16675
16929
|
}
|
|
16676
|
-
function refreshReviewPhases(deps) {
|
|
16677
|
-
|
|
16678
|
-
|
|
16679
|
-
|
|
16680
|
-
|
|
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));
|
|
16681
16945
|
if (run.review_phase !== phase.label) deps.db.updateRun(run.id, { review_phase: phase.label });
|
|
16682
16946
|
}
|
|
16683
16947
|
}
|
|
@@ -16779,7 +17043,14 @@ async function retireOutdatedReviewers(deps, run) {
|
|
|
16779
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.`);
|
|
16780
17044
|
}
|
|
16781
17045
|
}
|
|
16782
|
-
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
|
+
}
|
|
16783
17054
|
await deps.finishTask(run.task_slug, run.workspace_id);
|
|
16784
17055
|
if (run.worktree_path) await deps.removeWorktree(run.repo, run.worktree_path).catch(() => {
|
|
16785
17056
|
});
|
|
@@ -16787,6 +17058,7 @@ async function finalizeMergedReview(deps, run) {
|
|
|
16787
17058
|
deps.db.updateRun(run.id, { status: "done" });
|
|
16788
17059
|
deps.db.addEvent(run.id, "done");
|
|
16789
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;
|
|
16790
17062
|
}
|
|
16791
17063
|
async function finalizeClosedPrReview(deps, run, reason) {
|
|
16792
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");
|
|
@@ -16800,7 +17072,7 @@ async function prGateForReviewer(deps, run, prUrl, when) {
|
|
|
16800
17072
|
const st = await deps.prStatus(prUrl).catch(() => null);
|
|
16801
17073
|
switch (prLiveness(st)) {
|
|
16802
17074
|
case "merged":
|
|
16803
|
-
await finalizeMergedReview(deps, run);
|
|
17075
|
+
if (!await finalizeMergedReview(deps, run)) return { kind: "wait" };
|
|
16804
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.`);
|
|
16805
17077
|
return { kind: "finalized" };
|
|
16806
17078
|
case "closed":
|
|
@@ -16831,6 +17103,16 @@ function doneMergedPrForSlug(db, slug) {
|
|
|
16831
17103
|
);
|
|
16832
17104
|
return done?.pr_url ?? null;
|
|
16833
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
|
+
}
|
|
16834
17116
|
async function closeDuplicateTaskRun(deps, run, mergedUrl) {
|
|
16835
17117
|
if (run.pid != null && deps.kill && deps.isAlive(run.pid)) {
|
|
16836
17118
|
try {
|
|
@@ -16840,7 +17122,7 @@ async function closeDuplicateTaskRun(deps, run, mergedUrl) {
|
|
|
16840
17122
|
}
|
|
16841
17123
|
if (run.worktree_path) await deps.removeWorktree(run.repo, run.worktree_path).catch(() => {
|
|
16842
17124
|
});
|
|
16843
|
-
const reason =
|
|
17125
|
+
const reason = formatMergedDuplicateReason(mergedUrl);
|
|
16844
17126
|
deps.db.updateRun(run.id, { status: "superseded", stop_reason: reason });
|
|
16845
17127
|
deps.db.addEvent(run.id, "superseded", reason);
|
|
16846
17128
|
}
|
|
@@ -16872,10 +17154,16 @@ async function closeMergedTaskRuns(deps) {
|
|
|
16872
17154
|
mergedUrl = await deps.mergedPrForBranch(slug, group[0].repo || "").catch(() => null);
|
|
16873
17155
|
}
|
|
16874
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;
|
|
16875
17163
|
const canonical = withPr && withPr.pr_url === mergedUrl && !isTerminalStatus(withPr.status) ? withPr : null;
|
|
16876
17164
|
for (const run of nonTerminal) {
|
|
16877
17165
|
if (canonical && run.id === canonical.id) {
|
|
16878
|
-
await finalizeMergedReview(deps, run);
|
|
17166
|
+
await finalizeMergedReview(deps, run, { workChecked: true });
|
|
16879
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).`);
|
|
16880
17168
|
} else {
|
|
16881
17169
|
await closeDuplicateTaskRun(deps, run, mergedUrl);
|
|
@@ -17097,12 +17385,19 @@ ${task.description}` : `\u0417\u0430\u0434\u0430\u0447\u0430 ${run.task_slug} (\
|
|
|
17097
17385
|
// вторую ветку мимо PR. Пишем ту, что реально записана на прогоне; пусто (первый спавн —
|
|
17098
17386
|
// ветку заводит spawnDrone из слага) — прежняя формулировка.
|
|
17099
17387
|
`\u0422\u044B \u2014 \u0434\u0440\u043E\u043D \u0440\u043E\u044F. \u0420\u0430\u0431\u043E\u0442\u0430\u0435\u0448\u044C \u0432 \u044D\u0442\u043E\u043C git-worktree, \u0432\u0435\u0442\u043A\u0430 \`${run.branch || run.task_slug}\`${run.branch && run.branch !== run.task_slug ? " (\u043E\u043D\u0430 \u041D\u0415 \u0440\u0430\u0432\u043D\u0430 \u0441\u043B\u0430\u0433\u0443 \u0437\u0430\u0434\u0430\u0447\u0438 \u2014 \u044D\u0442\u043E \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0435\u043D\u0438\u0435 \u0443\u0436\u0435 \u043E\u0442\u043A\u0440\u044B\u0442\u043E\u0433\u043E PR, \u043F\u0443\u0448 \u0442\u043E\u043B\u044C\u043A\u043E \u0432 \u043D\u0435\u0451)" : " \u0441\u043E\u0437\u0434\u0430\u043D\u0430 \u043F\u043E slug \u0437\u0430\u0434\u0430\u0447\u0438"}.`,
|
|
17100
|
-
"\u0418\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u044B overmind (MCP): report_step(text) \u2014 \u043B\u043E\u0433\u0438\u0440\u0443\u0439 \u0445\u043E\u0434 \u0440\u0430\u0431\u043E\u0442\u044B; read_task() \u2014 \u0441\u0432\u0435\u0436\u0438\u0439 \u0441\u043D\u0430\u043F\u0448\u043E\u0442 \u0437\u0430\u0434\u0430\u0447\u0438 (\u043E\u043F\u0438\u0441\u0430\u043D\u0438\u0435+\u043A\u0440\u0438\u0442\u0435\u0440\u0438\u0438 \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438+\u043A\u043E\u043C\u043C\u0435\u043D\u0442\u044B+\u0434\u043E\u043A\u0438+\u0438\u0441\u0445\u043E\u0434\u044B \u0441\u043E\u0441\u0435\u0434\u043D\u0438\u0445 \u0437\u0430\u0434\u0430\u0447 \u043F\u043E \u0437\u043E\u043D\u0435 \u043A\u043E\u0434\u0430) \u0431\u0435\u0437 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u043E\u0432, \u0435\u0441\u043B\u0438 \u0442\u0440\u0435\u0431\u043E\u0432\u0430\u043D\u0438\u044F \u043C\u043E\u0433\u043B\u0438 \u0434\u043E\u043F\u0438\u0441\u0430\u0442\u044C \u043F\u043E\u0441\u043B\u0435 \u0441\u0442\u0430\u0440\u0442\u0430; ask(question, options?) \u2014 \u0435\u0441\u043B\u0438 \u0443\u043F\u0451\u0440\u0441\u044F \u0432 \u0420\u0415\u0428\u0415\u041D\u0418\u0415, \u0441\u043F\u0440\u043E\u0441\u0438 \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440\u0430 (\u0434\u0430\u0439 2\u20134 \u0432\u0430\u0440\u0438\u0430\u043D\u0442\u0430 \u0432 options, \u0435\u0441\u043B\u0438 \u0440\u0430\u0437\u0432\u0438\u043B\u043A\u0430 \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u043D\u0430\u044F) \u0438 \u0434\u043E\u0436\u0434\u0438\u0441\u044C \u043E\u0442\u0432\u0435\u0442\u0430 (\u041D\u0415 \u0443\u0433\u0430\u0434\u044B\u0432\u0430\u0439); report_acceptance_check(id, state, evidence) \u2014 \u0437\u0430\u043A\u0440\u043E\u0439 \u041A\u0410\u0416\u0414\u042B\u0419 \u043F\u0443\u043D\u043A\u0442 \u043A\u0440\u0438\u0442\u0435\u0440\u0438\u0435\u0432 \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438 \u0437\u0430\u0434\u0430\u0447\u0438 (id \u0431\u0435\u0440\u0451\u0442\u0441\u044F \u0438\u0437 \u0431\u043B\u043E\u043A\u0430 \xAB\u041A\u0440\u0438\u0442\u0435\u0440\u0438\u0438 \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438\xBB, state = passed|failed|pending \u043F\u043E \u0444\u0430\u043A\u0442\u0443 \u043F\u0440\u043E\u0433\u043E\u043D\u0430, evidence \u2014 \u0432\u044B\u0432\u043E\u0434 \u043A\u043E\u043C\u0430\u043D\u0434\u044B/\u0441\u0441\u044B\u043B\u043A\u0430/\u0447\u0442\u043E \u043D\u0430\u0431\u043B\u044E\u0434\u0430\u043B); \u043F\u0440\u043E\u0439\u0434\u0438\u0441\u044C \u043F\u043E \u043D\u0438\u043C \u041F\u0415\u0420\u0415\u0414 done(), \u0438\u043D\u0430\u0447\u0435 \u0433\u0430\u043B\u043E\u0447\u043A\u0438 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u0442 \u0440\u0443\u043A\u0430\u043C\u0438 \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440; done(pr_url) \u2014 \u043A\u043E\u0433\u0434\u0430 \u043E\u0442\u043A\u0440\u043E\u0435\u0448\u044C PR; return_task(missing, readings, assumed, questions) \u2014 \u0432\u0435\u0440\u043D\u0443\u0442\u044C \u0421\u042B\u0420\u0423\u042E \u0437\u0430\u0434\u0430\u0447\u0443 \u0430\u0432\u0442\u043E\u0440\u0443 (\u0441\u043C. \u043F\u0440\u0430\u0432\u0438\u043B\u043E \u043D\u0438\u0436\u0435); note(text) \u2014 \u0437\u0430\u043C\u0435\u0442\u043A\u0430 \xAB\u0437\u0430\u043C\u0435\u0447\u0435\u043D\u043E \u043F\u043E \u043F\u0443\u0442\u0438\xBB \u0411\u0415\u0417 \u0431\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u043A\u0438: \u043D\u0430\u0442\u043A\u043D\u0443\u043B\u0441\u044F \u043D\u0430 \u043F\u0440\u043E\u0431\u0435\u043B \u0432 \u0434\u0438\u0437\u0430\u0439\u043D-\u0441\u0438\u0441\u0442\u0435\u043C\u0435, \u043F\u0440\u043E\u0442\u0443\u0445\u0448\u0443\u044E \u0438\u043D\u0441\u0442\u0440\u0443\u043A\u0446\u0438\u044E, \u0431\u0430\u0433 \u0440\u044F\u0434\u043E\u043C \u0441\u043E \u0441\u0432\u043E\u0438\u043C \u0434\u0438\u0444\u0444\u043E\u043C \u2014 \u0441\u043A\u0430\u0436\u0438 \u0438 \u0440\u0430\u0431\u043E\u0442\u0430\u0439 \u0434\u0430\u043B\u044C\u0448\u0435, \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440 \u0443\u0432\u0438\u0434\u0438\u0442 \u0438 \u0441\u0430\u043C \u0440\u0435\u0448\u0438\u0442, \u0437\u0430\u0432\u043E\u0434\u0438\u0442\u044C \u043B\u0438 \u0437\u0430\u0434\u0430\u0447\u0443 (\u043D\u0435 \u043F\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0439 \u0442\u0430\u043A\u043E\u0435 \u0432 \u0434\u043E\u0440\u043E\u0433\u043E\u0439 \u0431\u043B\u043E\u043A\u0438\u0440\u0443\u044E\u0449\u0438\u0439 ask \u0438 \u043D\u0435 \u0445\u043E\u0440\u043E\u043D\u0438 \u0432 \u043E\u0442\u0447\u0451\u0442\u0435 \u043E \u0441\u0434\u0430\u0447\u0435).",
|
|
17388
|
+
"\u0418\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u044B overmind (MCP): report_step(text) \u2014 \u043B\u043E\u0433\u0438\u0440\u0443\u0439 \u0445\u043E\u0434 \u0440\u0430\u0431\u043E\u0442\u044B; read_task() \u2014 \u0441\u0432\u0435\u0436\u0438\u0439 \u0441\u043D\u0430\u043F\u0448\u043E\u0442 \u0437\u0430\u0434\u0430\u0447\u0438 (\u043E\u043F\u0438\u0441\u0430\u043D\u0438\u0435+\u043A\u0440\u0438\u0442\u0435\u0440\u0438\u0438 \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438+\u043A\u043E\u043C\u043C\u0435\u043D\u0442\u044B+\u0434\u043E\u043A\u0438+\u0438\u0441\u0445\u043E\u0434\u044B \u0441\u043E\u0441\u0435\u0434\u043D\u0438\u0445 \u0437\u0430\u0434\u0430\u0447 \u043F\u043E \u0437\u043E\u043D\u0435 \u043A\u043E\u0434\u0430) \u0431\u0435\u0437 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u043E\u0432, \u0435\u0441\u043B\u0438 \u0442\u0440\u0435\u0431\u043E\u0432\u0430\u043D\u0438\u044F \u043C\u043E\u0433\u043B\u0438 \u0434\u043E\u043F\u0438\u0441\u0430\u0442\u044C \u043F\u043E\u0441\u043B\u0435 \u0441\u0442\u0430\u0440\u0442\u0430; ask(question, options?) \u2014 \u0435\u0441\u043B\u0438 \u0443\u043F\u0451\u0440\u0441\u044F \u0432 \u0420\u0415\u0428\u0415\u041D\u0418\u0415, \u0441\u043F\u0440\u043E\u0441\u0438 \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440\u0430 (\u0434\u0430\u0439 2\u20134 \u0432\u0430\u0440\u0438\u0430\u043D\u0442\u0430 \u0432 options, \u0435\u0441\u043B\u0438 \u0440\u0430\u0437\u0432\u0438\u043B\u043A\u0430 \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u043D\u0430\u044F) \u0438 \u0434\u043E\u0436\u0434\u0438\u0441\u044C \u043E\u0442\u0432\u0435\u0442\u0430 (\u041D\u0415 \u0443\u0433\u0430\u0434\u044B\u0432\u0430\u0439); report_acceptance_check(id, state, evidence) \u2014 \u0437\u0430\u043A\u0440\u043E\u0439 \u041A\u0410\u0416\u0414\u042B\u0419 \u043F\u0443\u043D\u043A\u0442 \u043A\u0440\u0438\u0442\u0435\u0440\u0438\u0435\u0432 \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438 \u0437\u0430\u0434\u0430\u0447\u0438 (id \u0431\u0435\u0440\u0451\u0442\u0441\u044F \u0438\u0437 \u0431\u043B\u043E\u043A\u0430 \xAB\u041A\u0440\u0438\u0442\u0435\u0440\u0438\u0438 \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438\xBB, state = passed|failed|pending \u043F\u043E \u0444\u0430\u043A\u0442\u0443 \u043F\u0440\u043E\u0433\u043E\u043D\u0430, evidence \u2014 \u0432\u044B\u0432\u043E\u0434 \u043A\u043E\u043C\u0430\u043D\u0434\u044B/\u0441\u0441\u044B\u043B\u043A\u0430/\u0447\u0442\u043E \u043D\u0430\u0431\u043B\u044E\u0434\u0430\u043B); \u043F\u0440\u043E\u0439\u0434\u0438\u0441\u044C \u043F\u043E \u043D\u0438\u043C \u041F\u0415\u0420\u0415\u0414 done(), \u0438\u043D\u0430\u0447\u0435 \u0433\u0430\u043B\u043E\u0447\u043A\u0438 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u0442 \u0440\u0443\u043A\u0430\u043C\u0438 \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440; done(pr_url) \u2014 \u043A\u043E\u0433\u0434\u0430 \u043E\u0442\u043A\u0440\u043E\u0435\u0448\u044C PR; return_task(reason, missing, readings, assumed, questions) \u2014 \u0432\u0435\u0440\u043D\u0443\u0442\u044C \u0421\u042B\u0420\u0423\u042E \u0437\u0430\u0434\u0430\u0447\u0443 \u0430\u0432\u0442\u043E\u0440\u0443 (\u0441\u043C. \u043F\u0440\u0430\u0432\u0438\u043B\u043E \u043D\u0438\u0436\u0435); note(text) \u2014 \u0437\u0430\u043C\u0435\u0442\u043A\u0430 \xAB\u0437\u0430\u043C\u0435\u0447\u0435\u043D\u043E \u043F\u043E \u043F\u0443\u0442\u0438\xBB \u0411\u0415\u0417 \u0431\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u043A\u0438: \u043D\u0430\u0442\u043A\u043D\u0443\u043B\u0441\u044F \u043D\u0430 \u043F\u0440\u043E\u0431\u0435\u043B \u0432 \u0434\u0438\u0437\u0430\u0439\u043D-\u0441\u0438\u0441\u0442\u0435\u043C\u0435, \u043F\u0440\u043E\u0442\u0443\u0445\u0448\u0443\u044E \u0438\u043D\u0441\u0442\u0440\u0443\u043A\u0446\u0438\u044E, \u0431\u0430\u0433 \u0440\u044F\u0434\u043E\u043C \u0441\u043E \u0441\u0432\u043E\u0438\u043C \u0434\u0438\u0444\u0444\u043E\u043C \u2014 \u0441\u043A\u0430\u0436\u0438 \u0438 \u0440\u0430\u0431\u043E\u0442\u0430\u0439 \u0434\u0430\u043B\u044C\u0448\u0435, \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440 \u0443\u0432\u0438\u0434\u0438\u0442 \u0438 \u0441\u0430\u043C \u0440\u0435\u0448\u0438\u0442, \u0437\u0430\u0432\u043E\u0434\u0438\u0442\u044C \u043B\u0438 \u0437\u0430\u0434\u0430\u0447\u0443 (\u043D\u0435 \u043F\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0439 \u0442\u0430\u043A\u043E\u0435 \u0432 \u0434\u043E\u0440\u043E\u0433\u043E\u0439 \u0431\u043B\u043E\u043A\u0438\u0440\u0443\u044E\u0449\u0438\u0439 ask \u0438 \u043D\u0435 \u0445\u043E\u0440\u043E\u043D\u0438 \u0432 \u043E\u0442\u0447\u0451\u0442\u0435 \u043E \u0441\u0434\u0430\u0447\u0435).",
|
|
17101
17389
|
// TASWM-412: третий выход из непонятной задачи. Раньше их было два, и оба плохие —
|
|
17102
17390
|
// угадать постановку (сделает не то) или ask (слот занят, а ответить может только автор
|
|
17103
17391
|
// задачи, не оператор роя). Граница здесь ОБЯЗАТЕЛЬНА: дрон, легко возвращающий задачи,
|
|
17104
17392
|
// становится отписочником, а это хуже, чем дрон, который иногда угадывает неверно.
|
|
17105
|
-
"\u0421\u042B\u0420\u0423\u042E \u0417\u0410\u0414\u0410\u0427\u0423 \u041D\u0415 \u0412\u042B\u0414\u0423\u041C\u042B\u0412\u0410\u0419 \u2014 \u0412\u0415\u0420\u041D\u0418 \u0410\u0412\u0422\u041E\u0420\u0423. \u041F\u0440\u043E\u0447\u0438\u0442\u0430\u0432 \u0437\u0430\u0434\u0430\u0447\u0443, \u043E\u0442\u0432\u0435\u0442\u044C \u0441\u0435\u0431\u0435 \u043D\u0430 \u0434\u0432\u0430 \u0432\u043E\u043F\u0440\u043E\u0441\u0430: \u043F\u043E\u043D\u044F\u0442\u043D\u043E \u043B\u0438, \u0427\u0422\u041E \u043D\u0443\u0436\u043D\u043E \u0441\u0434\u0435\u043B\u0430\u0442\u044C, \u0438 \u0435\u0441\u0442\u044C \u043B\u0438 \u0442\u043E, \u041F\u041E \u0427\u0415\u041C\u0423 \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442. \u041E\u0431\u0430 \xAB\u043D\u0435\u0442\xBB \u2192 return_task(missing, readings, assumed, questions): \u0432\u043E\u043F\u0440\u043E\u0441\u044B \u0443\u0435\u0434\u0443\u0442 \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u043E\u043C \u0430\u0432\u0442\u043E\u0440\u0443, \u0437\u0430\u0434\u0430\u0447\u0430 \u0443\u0439\u0434\u0451\u0442 \u043D\u0430 \u043D\u0435\u0433\u043E \u0438 \u0432 \u0440\u0430\u0431\u043E\u0442\u0443, \u043F\u0440\u043E\u0433\u043E\u043D \u0437\u0430\u043A\u0440\u043E\u0435\u0442\u0441\u044F \u043A\u0430\u043A \xAB\u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0435\u043D\u0430 \u0430\u0432\u0442\u043E\u0440\u0443\xBB (\u043D\u0435 \xAB\u043F\u0440\u043E\u0432\u0430\u043B\u0435\u043D\u0430\xBB), \u0441\u043B\u043E\u0442 \u043E\u0441\u0432\u043E\u0431\u043E\u0434\u0438\u0442\u0441\u044F. \u0412\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044C \u041C\u041E\u0416\u041D\u041E, \u0442\u043E\u043B\u044C\u043A\u043E \u0435\u0441\u043B\u0438 \u0437\u0430\u0434\u0430\u0447\u0443 \u043D\u0435\u043B\u044C\u0437\u044F \u0432\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u044C \u043D\u0438 \u0432 \u043E\u0434\u043D\u043E\u043C \u0440\u0430\u0437\u0443\u043C\u043D\u043E\u043C \u0442\u043E\u043B\u043A\u043E\u0432\u0430\u043D\u0438\u0438 \u0438\u043B\u0438 \u043D\u0435\u0447\u0435\u043C \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442. \u0422\u043E\u043B\u043A\u043E\u0432\u0430\u043D\u0438\u0439 \u0434\u0432\u0430 \u0438 \u043E\u0431\u0430 \u043E\u0441\u043C\u044B\u0441\u043B\u0435\u043D\u043D\u044B \u2014 \u0432\u044B\u0431\u0435\u0440\u0438 \u043E\u0447\u0435\u0432\u0438\u0434\u043D\u043E\u0435, \u0441\u0434\u0435\u043B\u0430\u0439 \u0438 \u043D\u0430\u0437\u043E\u0432\u0438 \u0440\u0430\u0437\u0432\u0438\u043B\u043A\u0443 \u0432 \u043E\u043F\u0438\u0441\u0430\u043D\u0438\u0438 PR. \u0417\u0430\u0434\u0430\u0447\u0430 \u043F\u043E\u043D\u044F\u0442\u043D\u0430, \u043D\u043E \u0432 \u043E\u0434\u043D\u043E\u043C \u043F\u0443\u043D\u043A\u0442\u0435 \u043F\u0440\u043E\u0442\u0438\u0432\u043E\u0440\u0435\u0447\u0438\u0442 \u043F\u0440\u0430\u0432\u0438\u043B\u0443 \u043F\u0440\u043E\u0435\u043A\u0442\u0430 \u2014 \u044D\u0442\u043E ask, \u0430 \u043D\u0435 \u0432\u043E\u0437\u0432\u0440\u0430\u0442.",
|
|
17393
|
+
"\u0421\u042B\u0420\u0423\u042E \u0417\u0410\u0414\u0410\u0427\u0423 \u041D\u0415 \u0412\u042B\u0414\u0423\u041C\u042B\u0412\u0410\u0419 \u2014 \u0412\u0415\u0420\u041D\u0418 \u0410\u0412\u0422\u041E\u0420\u0423. \u041F\u0440\u043E\u0447\u0438\u0442\u0430\u0432 \u0437\u0430\u0434\u0430\u0447\u0443, \u043E\u0442\u0432\u0435\u0442\u044C \u0441\u0435\u0431\u0435 \u043D\u0430 \u0434\u0432\u0430 \u0432\u043E\u043F\u0440\u043E\u0441\u0430: \u043F\u043E\u043D\u044F\u0442\u043D\u043E \u043B\u0438, \u0427\u0422\u041E \u043D\u0443\u0436\u043D\u043E \u0441\u0434\u0435\u043B\u0430\u0442\u044C, \u0438 \u0435\u0441\u0442\u044C \u043B\u0438 \u0442\u043E, \u041F\u041E \u0427\u0415\u041C\u0423 \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442. \u041E\u0431\u0430 \xAB\u043D\u0435\u0442\xBB \u2192 return_task(reason, missing, readings, assumed, questions): \u0432\u043E\u043F\u0440\u043E\u0441\u044B \u0443\u0435\u0434\u0443\u0442 \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u043E\u043C \u0430\u0432\u0442\u043E\u0440\u0443, \u0437\u0430\u0434\u0430\u0447\u0430 \u0443\u0439\u0434\u0451\u0442 \u043D\u0430 \u043D\u0435\u0433\u043E \u0438 \u0432 \u0440\u0430\u0431\u043E\u0442\u0443, \u043F\u0440\u043E\u0433\u043E\u043D \u0437\u0430\u043A\u0440\u043E\u0435\u0442\u0441\u044F \u043A\u0430\u043A \xAB\u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0435\u043D\u0430 \u0430\u0432\u0442\u043E\u0440\u0443\xBB (\u043D\u0435 \xAB\u043F\u0440\u043E\u0432\u0430\u043B\u0435\u043D\u0430\xBB), \u0441\u043B\u043E\u0442 \u043E\u0441\u0432\u043E\u0431\u043E\u0434\u0438\u0442\u0441\u044F. \u0412\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044C \u041C\u041E\u0416\u041D\u041E, \u0442\u043E\u043B\u044C\u043A\u043E \u0435\u0441\u043B\u0438 \u0437\u0430\u0434\u0430\u0447\u0443 \u043D\u0435\u043B\u044C\u0437\u044F \u0432\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u044C \u043D\u0438 \u0432 \u043E\u0434\u043D\u043E\u043C \u0440\u0430\u0437\u0443\u043C\u043D\u043E\u043C \u0442\u043E\u043B\u043A\u043E\u0432\u0430\u043D\u0438\u0438 \u0438\u043B\u0438 \u043D\u0435\u0447\u0435\u043C \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442. \u0422\u043E\u043B\u043A\u043E\u0432\u0430\u043D\u0438\u0439 \u0434\u0432\u0430 \u0438 \u043E\u0431\u0430 \u043E\u0441\u043C\u044B\u0441\u043B\u0435\u043D\u043D\u044B \u2014 \u0432\u044B\u0431\u0435\u0440\u0438 \u043E\u0447\u0435\u0432\u0438\u0434\u043D\u043E\u0435, \u0441\u0434\u0435\u043B\u0430\u0439 \u0438 \u043D\u0430\u0437\u043E\u0432\u0438 \u0440\u0430\u0437\u0432\u0438\u043B\u043A\u0443 \u0432 \u043E\u043F\u0438\u0441\u0430\u043D\u0438\u0438 PR. \u0417\u0430\u0434\u0430\u0447\u0430 \u043F\u043E\u043D\u044F\u0442\u043D\u0430, \u043D\u043E \u0432 \u043E\u0434\u043D\u043E\u043C \u043F\u0443\u043D\u043A\u0442\u0435 \u043F\u0440\u043E\u0442\u0438\u0432\u043E\u0440\u0435\u0447\u0438\u0442 \u043F\u0440\u0430\u0432\u0438\u043B\u0443 \u043F\u0440\u043E\u0435\u043A\u0442\u0430 \u2014 \u044D\u0442\u043E ask, \u0430 \u043D\u0435 \u0432\u043E\u0437\u0432\u0440\u0430\u0442. \u041F\u0440\u0438\u0447\u0438\u043D\u0443 \u043D\u0430\u0437\u043E\u0432\u0438 \u041A\u041E\u0414\u041E\u041C (reason): unclear_goal \u2014 \u043D\u0435\u043F\u043E\u043D\u044F\u0442\u043D\u043E, \u0447\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C; no_acceptance \u2014 \u043D\u0435\u0447\u0435\u043C \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442; too_big \u2014 \u0441\u043C. \u043D\u0438\u0436\u0435; contradiction \u2014 \u043F\u043E\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430 \u043F\u0440\u043E\u0442\u0438\u0432\u043E\u0440\u0435\u0447\u0438\u0442 \u0441\u0430\u043C\u0430 \u0441\u0435\u0431\u0435. \u041A\u043E\u0434 \u043C\u0435\u0440\u044F\u0435\u0442 \u043D\u0435 \u0442\u0435\u0431\u044F, \u0430 \u043A\u0430\u0447\u0435\u0441\u0442\u0432\u043E \u043F\u043E\u0441\u0442\u0430\u043D\u043E\u0432\u043E\u043A \u043F\u043E \u0431\u044D\u043A\u043B\u043E\u0433\u0443, \u043F\u043E\u044D\u0442\u043E\u043C\u0443 \u0441\u0442\u0430\u0432\u044C \u0447\u0435\u0441\u0442\u043D\u044B\u0439, \u0430 \u043D\u0435 \u0443\u0434\u043E\u0431\u043D\u044B\u0439.",
|
|
17394
|
+
// TASWM-505: ЕДИНСТВЕННЫЙ сорт негодной задачи, который не покрывался ничем. claimPolicy
|
|
17395
|
+
// (TASWM-357) отсеивает родителей с незакрытыми детьми, но лист на 8 часов уезжает дрону
|
|
17396
|
+
// целиком — и он упирается в потолок трат на середине, оставляя недоделанную работу
|
|
17397
|
+
// человеку. Это уже случалось. Подзадачи дрон при этом НЕ заводит: разбиение —
|
|
17398
|
+
// продуктовое решение, а плохое разбиение хуже никакого, потому что выглядит
|
|
17399
|
+
// авторитетно (заведённые подзадачи читаются как согласованный план).
|
|
17400
|
+
"\u0421\u041B\u0418\u0428\u041A\u041E\u041C \u0412\u0415\u041B\u0418\u041A\u0410 \u2014 \u0442\u043E\u0436\u0435 \u0432\u043E\u0437\u0432\u0440\u0430\u0442 (reason=too_big). \u0417\u0430\u0434\u0430\u0447\u0430 \u043F\u043E\u043D\u044F\u0442\u043D\u0430 \u0438 \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0435\u043C\u0430, \u043D\u043E \u044D\u0442\u043E \u043D\u0435 \u0437\u0430\u0434\u0430\u0447\u0430, \u0430 \u043F\u0430\u0447\u043A\u0430 \u0437\u0430\u0434\u0430\u0447: \u0437\u0430 \u043E\u0434\u0438\u043D \u043F\u0440\u043E\u0433\u043E\u043D \u0435\u0451 \u043D\u0435 \u0434\u043E\u0432\u0435\u0441\u0442\u0438, \u0430 \u0443\u043F\u0435\u0440\u0435\u0442\u044C\u0441\u044F \u0432 \u043F\u043E\u0442\u043E\u043B\u043E\u043A \u0442\u0440\u0430\u0442 \u043D\u0430 \u0441\u0435\u0440\u0435\u0434\u0438\u043D\u0435 \u0445\u0443\u0436\u0435, \u0447\u0435\u043C \u0432\u0435\u0440\u043D\u0443\u0442\u044C \u0441\u0440\u0430\u0437\u0443 \u2014 \u043D\u0435\u0434\u043E\u0434\u0435\u043B\u0430\u043D\u043D\u043E\u0435 \u0434\u043E\u0441\u0442\u0430\u0451\u0442\u0441\u044F \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443. \u041C\u0435\u0440\u0438\u043B\u043E \u043D\u0435 \xAB\u043C\u043D\u043E\u0433\u043E\u0432\u0430\u0442\u043E \u0440\u0430\u0431\u043E\u0442\u044B\xBB, \u0430 \xAB\u0432 \u043E\u0434\u043D\u043E\u043C \u043F\u0440\u043E\u0433\u043E\u043D\u0435 \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043A\u0438 \u043D\u0435 \u0437\u0430\u043A\u0440\u044B\u0442\u044C\xBB. \u0420\u0430\u0437\u0431\u0438\u0435\u043D\u0438\u0435 \u043C\u043E\u0436\u0435\u0448\u044C \u041F\u0420\u0415\u0414\u041B\u041E\u0416\u0418\u0422\u042C \u0430\u0432\u0442\u043E\u0440\u0443 \u0441\u043F\u0438\u0441\u043A\u043E\u043C (\u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 split \u0443 return_task) \u2014 \u043D\u043E \u043F\u043E\u0434\u0437\u0430\u0434\u0430\u0447\u0438 \u041D\u0415 \u0437\u0430\u0432\u043E\u0434\u0438: \u0440\u0430\u0437\u0431\u0438\u0435\u043D\u0438\u0435 \u0440\u0435\u0448\u0430\u0435\u0442 \u0430\u0432\u0442\u043E\u0440.",
|
|
17106
17401
|
"\u041F\u0440\u0430\u0432\u0438\u043B\u0430: \u0442\u0440\u043E\u0433\u0430\u0435\u0448\u044C UI \u2014 \u0421\u041D\u0410\u0427\u0410\u041B\u0410 \u043F\u043E\u0441\u043C\u043E\u0442\u0440\u0438, \u0435\u0441\u0442\u044C \u043B\u0438 \u0432 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0438 \u0441\u043A\u0438\u043B\u043B \u0441 UI-\u043F\u0440\u0430\u0432\u0438\u043B\u0430\u043C\u0438 \u043F\u0440\u043E\u0435\u043A\u0442\u0430, \u0438 \u0441\u043B\u0435\u0434\u0443\u0439 \u0435\u0433\u043E \u0434\u0438\u0437\u0430\u0439\u043D-\u0441\u0438\u0441\u0442\u0435\u043C\u0435 (\u043D\u0435\u0442 \u043D\u0443\u0436\u043D\u043E\u0433\u043E \u043A\u043E\u043D\u0442\u0440\u043E\u043B\u0430 \u2014 \u0437\u0430\u0432\u0435\u0434\u0438 \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u0443\u044E \u0437\u0430\u0434\u0430\u0447\u0443, \u043D\u0435 \u0445\u0430\u0440\u0434\u043A\u043E\u0434\u044C \u043E\u0434\u043D\u043E\u0440\u0430\u0437\u043E\u0432\u043E\u0435); \u043A\u043E\u043C\u043C\u0438\u0442\u044B \u0441\u043E slug \u0437\u0430\u0434\u0430\u0447\u0438 \u0432 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0438; \u043F\u043E\u0441\u043B\u0435 UI-\u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0439 \u043F\u0440\u0438\u043B\u043E\u0436\u0438 \u0441\u043A\u0440\u0438\u043D\u044B mobile+desktop \u041A \u0417\u0410\u0414\u0410\u0427\u0415 (\u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 screenshots \u0443 done); \u043E\u0442\u043A\u0440\u043E\u0439 PR \u0447\u0435\u0440\u0435\u0437 gh \u0438 \u0432\u044B\u0437\u043E\u0432\u0438 done(pr_url).",
|
|
17107
17402
|
// TASWM-377: у сессии есть ПОТОЛОК ТРАТ, и он режет её без предупреждения, прямо посреди
|
|
17108
17403
|
// работы. Дрон об этом знать обязан: цена сессии растёт от ЧИСЛА ХОДОВ (каждый ход заново
|
|
@@ -17467,6 +17762,16 @@ async function wakeRun(deps, runId) {
|
|
|
17467
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` };
|
|
17468
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` };
|
|
17469
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
|
+
}
|
|
17470
17775
|
const worktreeExists = deps.worktreeExists ?? existsSync18;
|
|
17471
17776
|
const hasTranscript = deps.hasTranscript ?? executorHasSession;
|
|
17472
17777
|
const wt = run.worktree_path;
|
|
@@ -17915,15 +18220,17 @@ function effectiveRepo(deps, run) {
|
|
|
17915
18220
|
async function zoneConflictFor(db, models, activeFiles, run, repo, repoFallback) {
|
|
17916
18221
|
const model = await models.forRepo(repo);
|
|
17917
18222
|
if (!hasZoneModel(model)) return { kind: "unknown" };
|
|
17918
|
-
const
|
|
17919
|
-
activeFiles.prune(
|
|
18223
|
+
const holders = db.listRuns().filter((r) => holdsFiles(r));
|
|
18224
|
+
activeFiles.prune(holders.map((r) => r.id));
|
|
17920
18225
|
const active = [];
|
|
17921
|
-
for (const r of
|
|
18226
|
+
for (const r of holders) {
|
|
17922
18227
|
if (r.id === run.id) continue;
|
|
17923
18228
|
if (normalizeRepo(r.repo || repoFallback || "") !== repo) continue;
|
|
17924
|
-
const
|
|
18229
|
+
const snapshot = r.changed_paths ?? [];
|
|
18230
|
+
const files = snapshot.length ? snapshot : await activeFiles.filesOf(r);
|
|
18231
|
+
const prUrl = r.status === "review" ? r.pr_url : null;
|
|
17925
18232
|
active.push(
|
|
17926
|
-
files.length ? { run: r, files, actual: true } : { run: r, files: predictForRun(model, r).map((p) => p.path), actual: false }
|
|
18233
|
+
files.length ? { run: r, files, actual: true, prUrl } : { run: r, files: predictForRun(model, r).map((p) => p.path), actual: false, prUrl }
|
|
17927
18234
|
);
|
|
17928
18235
|
}
|
|
17929
18236
|
return decideConflict({ model, candidate: run, active });
|
|
@@ -18067,17 +18374,31 @@ async function trySpawnQueuedRun(deps, run) {
|
|
|
18067
18374
|
// причина одна на машину — в лог уходит одной строкой, а не по строке на прогон
|
|
18068
18375
|
});
|
|
18069
18376
|
}
|
|
18070
|
-
const spentAttempts =
|
|
18377
|
+
const spentAttempts = attemptsFor(deps, run.task_slug);
|
|
18071
18378
|
if (spentAttempts >= PRE_START_ATTEMPT_LIMIT) {
|
|
18072
18379
|
const last = lastPreStartAttempt(deps.db.listRuns(), run.task_slug);
|
|
18073
|
-
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;
|
|
18074
18383
|
deps.db.updateRun(run.id, { status: "stopped", stop_reason: why });
|
|
18075
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
|
+
}
|
|
18076
18394
|
const d = noteDefer(deps.spawnDefer ??= /* @__PURE__ */ new Map(), `pre-start-exhausted:${run.task_slug}`, why, GATE_LOG_HEARTBEAT_TICKS);
|
|
18077
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}`}`);
|
|
18078
18396
|
return "closed";
|
|
18079
18397
|
}
|
|
18080
|
-
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;
|
|
18081
18402
|
if (mergedUrl) {
|
|
18082
18403
|
await closeDuplicateTaskRun(deps, run, mergedUrl);
|
|
18083
18404
|
await deps.finishTask(run.task_slug, run.workspace_id).catch(() => {
|
|
@@ -18115,6 +18436,13 @@ async function trySpawnQueuedRun(deps, run) {
|
|
|
18115
18436
|
if (logged.get(run.id) !== e.message) {
|
|
18116
18437
|
logged.set(run.id, e.message);
|
|
18117
18438
|
deps.db.addEvent(run.id, "step", `${e.message} \u2014 \u0437\u0430\u0434\u0430\u0447\u0430 \u043E\u0441\u0442\u0430\u0451\u0442\u0441\u044F \u0432 \u043E\u0447\u0435\u0440\u0435\u0434\u0438 (TASWM-348)`);
|
|
18439
|
+
const blocker = deps.db.getRun(e.blockedByRunId);
|
|
18440
|
+
if (blocker)
|
|
18441
|
+
deps.db.addEvent(
|
|
18442
|
+
blocker.id,
|
|
18443
|
+
"step",
|
|
18444
|
+
`${run.task_slug} (#${run.id}) \u0441\u0442\u043E\u0438\u0442 \u0432 \u043E\u0447\u0435\u0440\u0435\u0434\u0438 \u0438\u0437-\u0437\u0430 \u044D\u0442\u043E\u0439 \u0440\u0430\u0431\u043E\u0442\u044B \u2014 ${e.message} (TASWM-506)`
|
|
18445
|
+
);
|
|
18118
18446
|
narrate(deps, `${droneLabel(run)} \u2014 ${e.message}. \u041D\u0435 \u0441\u043F\u0430\u0432\u043D\u044E \u043F\u0430\u0440\u0430\u043B\u043B\u0435\u043B\u044C\u043D\u043E.`);
|
|
18119
18447
|
}
|
|
18120
18448
|
return "skipped";
|
|
@@ -18165,10 +18493,13 @@ function spawnRetryOpts(e) {
|
|
|
18165
18493
|
if (!(e instanceof TaskBodyUnavailableError)) return {};
|
|
18166
18494
|
return { retriable: TOOL_FAILURE_RETRIABLE[e.code] };
|
|
18167
18495
|
}
|
|
18496
|
+
function attemptsFor(deps, taskSlug) {
|
|
18497
|
+
return preStartAttempts(deps.db.listRuns(), taskSlug, deps.startedAt != null ? { since: deps.startedAt } : {});
|
|
18498
|
+
}
|
|
18168
18499
|
async function failBeforeStart(deps, run, reason, opts = {}) {
|
|
18169
18500
|
deps.db.updateRun(run.id, { status: "failed", stop_reason: `${PRE_START_MARK}: ${reason}` });
|
|
18170
18501
|
deps.db.addEvent(run.id, "failed", `${PRE_START_MARK} \u2014 ${reason}`);
|
|
18171
|
-
const attempts =
|
|
18502
|
+
const attempts = attemptsFor(deps, run.task_slug);
|
|
18172
18503
|
if (opts.retriable !== false && attempts < PRE_START_ATTEMPT_LIMIT) {
|
|
18173
18504
|
narrate(deps, `${droneLabel(run)} \u2014 ${PRE_START_MARK} (\u043F\u043E\u043F\u044B\u0442\u043A\u0430 ${attempts} \u0438\u0437 ${PRE_START_ATTEMPT_LIMIT}): ${reason}`);
|
|
18174
18505
|
return "failed";
|
|
@@ -18179,7 +18510,13 @@ async function failBeforeStart(deps, run, reason, opts = {}) {
|
|
|
18179
18510
|
narrate(deps, `${run.task_slug}: ${parked}`);
|
|
18180
18511
|
if (deps.parkTask) {
|
|
18181
18512
|
const ok = await deps.parkTask(run, parked).catch(() => false);
|
|
18182
|
-
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 {
|
|
18183
18520
|
deps.db.addEvent(
|
|
18184
18521
|
run.id,
|
|
18185
18522
|
"step",
|
|
@@ -18849,8 +19186,7 @@ async function tickOnce(deps) {
|
|
|
18849
19186
|
const st = await deps.prStatus(prUrl);
|
|
18850
19187
|
run = syncBranchFromPr(deps.db, run, st.headBranch);
|
|
18851
19188
|
if (st.merged) {
|
|
18852
|
-
await finalizeMergedReview(deps, run);
|
|
18853
|
-
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.`);
|
|
18854
19190
|
continue;
|
|
18855
19191
|
}
|
|
18856
19192
|
if (prLiveness(st) === "closed") {
|
|
@@ -18994,7 +19330,7 @@ async function tickOnce(deps) {
|
|
|
18994
19330
|
relinkUnboundReviewers(deps);
|
|
18995
19331
|
await closeOrphanedReviewers(deps);
|
|
18996
19332
|
await spawnVerifiersForOpenPrs(deps, stormActive);
|
|
18997
|
-
refreshReviewPhases(deps);
|
|
19333
|
+
await refreshReviewPhases(deps);
|
|
18998
19334
|
let liveChildPpids;
|
|
18999
19335
|
try {
|
|
19000
19336
|
liveChildPpids = deps.livePpids?.() ?? null;
|
|
@@ -19084,6 +19420,12 @@ async function tickOnce(deps) {
|
|
|
19084
19420
|
}
|
|
19085
19421
|
}
|
|
19086
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
|
+
}
|
|
19087
19429
|
const aborted = wasAborted(outcome);
|
|
19088
19430
|
const abort = aborted ? deps.exitAbort?.(run) ?? null : null;
|
|
19089
19431
|
const what = aborted ? abortReason(abort) : EXITED_NO_DONE_REASON;
|
|
@@ -20350,6 +20692,9 @@ async function runDaemon(opts) {
|
|
|
20350
20692
|
// Смерженный PR ветки-слага (TASWM-206) — тот же фолбэк на дефолт-репо роя, что и
|
|
20351
20693
|
// openPrsForBranch выше; реальный gh, логика закрытия дублей — в tickOnce (тестируется).
|
|
20352
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),
|
|
20353
20698
|
// Закрыта ли задача в Taskless (TASWM-137 п.г): death-detect гасит зомби-прогон, чья
|
|
20354
20699
|
// задача уже completed/cancelled/archived, вместо респавна. null — Taskless недоступен
|
|
20355
20700
|
// (не гасим). Без tl (нет токена) ключ не задаём — шаг инертен, старое поведение.
|
|
@@ -20365,17 +20710,22 @@ async function runDaemon(opts) {
|
|
|
20365
20710
|
// задачу), а не кодом возврата: клиент глушит отказ сервера внутрь (safeCall), и по
|
|
20366
20711
|
// возврату «отложил» было бы неотличимо от «сказал, но не доехало» — то самое молчание,
|
|
20367
20712
|
// из-за которого 17.08 круг и крутился.
|
|
20368
|
-
parkTask: async (run, reason) => {
|
|
20713
|
+
parkTask: async (run, reason, opts2) => {
|
|
20369
20714
|
const client = tlFor(run.workspace_id);
|
|
20370
20715
|
if (!client) return false;
|
|
20371
|
-
|
|
20372
|
-
|
|
20373
|
-
|
|
20716
|
+
if (opts2?.comment !== false)
|
|
20717
|
+
await client.addComment(
|
|
20718
|
+
run.task_slug,
|
|
20719
|
+
// TASWM-514: советуем ИМЕННО возврат в очередь — теперь этот рычаг работает
|
|
20720
|
+
// (возврат в «не начато» обнуляет счётчик попыток). И причина стоит в первой
|
|
20721
|
+
// строке (её несёт `reason`, см. parkReason): человек, читающий пометку через
|
|
20722
|
+
// час, должен из неё понять, ЧТО чинить, а не раскапывать записи прогонов.
|
|
20723
|
+
`${reason}
|
|
20374
20724
|
|
|
20375
|
-
\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. \
|
|
20376
|
-
|
|
20377
|
-
|
|
20378
|
-
|
|
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
|
+
});
|
|
20379
20729
|
await client.startTask(run.task_slug).catch(() => {
|
|
20380
20730
|
});
|
|
20381
20731
|
const after = await client.getTask(run.task_slug).catch(() => null);
|
|
@@ -20589,6 +20939,9 @@ async function runDaemon(opts) {
|
|
|
20589
20939
|
nudge
|
|
20590
20940
|
),
|
|
20591
20941
|
worktreeExists: (p) => existsSync18(p),
|
|
20942
|
+
// TASWM-514: с этого момента считаем попытки спавна — счётчик живёт ровно одну жизнь
|
|
20943
|
+
// процесса демона и рестарт не переживает (см. preStartAttempts).
|
|
20944
|
+
startedAt: Date.now(),
|
|
20592
20945
|
hasTranscript: executorHasSession,
|
|
20593
20946
|
// CI-осведомлённость review-PR (TASWM-102): реальный `gh pr checks`/`gh run view --log-failed`
|
|
20594
20947
|
// (gh.ts) — решение (будить ли дрона) и гейты живут в tickOnce/handleCiRed. failureSummary
|
|
@@ -21050,6 +21403,7 @@ export {
|
|
|
21050
21403
|
GATE_LOG_HEARTBEAT_TICKS,
|
|
21051
21404
|
HEADLESS_BLOCK,
|
|
21052
21405
|
HERO_CONTINUE_NUDGE,
|
|
21406
|
+
OPEN_PR_HOLD_MARK,
|
|
21053
21407
|
OVERMIND_ENTRY,
|
|
21054
21408
|
RESOLVE_ESCALATION_MARK,
|
|
21055
21409
|
RESOLVE_LIMIT,
|
|
@@ -21067,6 +21421,8 @@ export {
|
|
|
21067
21421
|
STALL_FLOOR_MS,
|
|
21068
21422
|
STALL_MS,
|
|
21069
21423
|
STORM_DEAD_LIMIT,
|
|
21424
|
+
SUBMITTED_EXIT_TEXT,
|
|
21425
|
+
VERIFY_ESCALATION_MARK,
|
|
21070
21426
|
VERIFY_SPAWN_LIMIT,
|
|
21071
21427
|
WATCHDOG_PARK_REASON,
|
|
21072
21428
|
abortReason,
|
|
@@ -21099,5 +21455,6 @@ export {
|
|
|
21099
21455
|
tickOnce,
|
|
21100
21456
|
verdictCommentMark,
|
|
21101
21457
|
wakeRun,
|
|
21102
|
-
worktreeFromCmd
|
|
21458
|
+
worktreeFromCmd,
|
|
21459
|
+
zoneConflictFor
|
|
21103
21460
|
};
|