@taskless-app/swarm 0.6.25 → 0.6.26
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 +51 -5
- package/dist/overmind.js +368 -233
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -51,10 +51,12 @@ function isMilestoneKind(kind) {
|
|
|
51
51
|
function toRunKind(role) {
|
|
52
52
|
return role === "hero" || role === "reviewer" || role === "verifier" ? role : "drone";
|
|
53
53
|
}
|
|
54
|
-
var EVENT_KINDS, MILESTONE_KINDS, MILESTONE_KIND_SET;
|
|
54
|
+
var ACTIVE_DRONE_STATUSES, FILE_HOLDING_STATUSES, EVENT_KINDS, MILESTONE_KINDS, MILESTONE_KIND_SET;
|
|
55
55
|
var init_types = __esm({
|
|
56
56
|
"../swarm-core/src/types.ts"() {
|
|
57
57
|
"use strict";
|
|
58
|
+
ACTIVE_DRONE_STATUSES = /* @__PURE__ */ new Set(["running", "blocked"]);
|
|
59
|
+
FILE_HOLDING_STATUSES = /* @__PURE__ */ new Set([...ACTIVE_DRONE_STATUSES, "review"]);
|
|
58
60
|
EVENT_KINDS = [
|
|
59
61
|
"spawned",
|
|
60
62
|
"step",
|
|
@@ -608,6 +610,24 @@ var init_prRef = __esm({
|
|
|
608
610
|
}
|
|
609
611
|
});
|
|
610
612
|
|
|
613
|
+
// ../swarm-core/src/returnReason.ts
|
|
614
|
+
function isReturnReason(v) {
|
|
615
|
+
return typeof v === "string" && RETURN_REASON_SET.has(v);
|
|
616
|
+
}
|
|
617
|
+
function toReturnReason(v) {
|
|
618
|
+
return isReturnReason(v) ? v : null;
|
|
619
|
+
}
|
|
620
|
+
var RETURN_REASONS, RETURN_REASON_SET, UNRETURNED_FAILURE_STATUSES, UNRETURNED_FAILURE_SET;
|
|
621
|
+
var init_returnReason = __esm({
|
|
622
|
+
"../swarm-core/src/returnReason.ts"() {
|
|
623
|
+
"use strict";
|
|
624
|
+
RETURN_REASONS = ["unclear_goal", "no_acceptance", "too_big", "contradiction"];
|
|
625
|
+
RETURN_REASON_SET = new Set(RETURN_REASONS);
|
|
626
|
+
UNRETURNED_FAILURE_STATUSES = ["failed", "blocked"];
|
|
627
|
+
UNRETURNED_FAILURE_SET = new Set(UNRETURNED_FAILURE_STATUSES);
|
|
628
|
+
}
|
|
629
|
+
});
|
|
630
|
+
|
|
611
631
|
// ../swarm-core/src/modelPolicy.ts
|
|
612
632
|
function findProvider(id) {
|
|
613
633
|
const key = typeof id === "string" ? id.trim().toLowerCase() : "";
|
|
@@ -1610,6 +1630,7 @@ var init_src = __esm({
|
|
|
1610
1630
|
init_mergeQueue();
|
|
1611
1631
|
init_prRef();
|
|
1612
1632
|
init_verifyVerdict();
|
|
1633
|
+
init_returnReason();
|
|
1613
1634
|
init_modelPolicy();
|
|
1614
1635
|
init_status();
|
|
1615
1636
|
init_deps();
|
|
@@ -3019,7 +3040,7 @@ var init_package = __esm({
|
|
|
3019
3040
|
"package.json"() {
|
|
3020
3041
|
package_default = {
|
|
3021
3042
|
name: "@taskless-app/swarm",
|
|
3022
|
-
version: "0.6.
|
|
3043
|
+
version: "0.6.26",
|
|
3023
3044
|
type: "module",
|
|
3024
3045
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
3025
3046
|
keywords: [
|
|
@@ -3070,7 +3091,7 @@ var init_package = __esm({
|
|
|
3070
3091
|
execa: "^10.0.0",
|
|
3071
3092
|
zod: "3.25.76"
|
|
3072
3093
|
},
|
|
3073
|
-
gitHead: "
|
|
3094
|
+
gitHead: "52416995d46b0a843374d14bfb00dd310f71c4bf"
|
|
3074
3095
|
};
|
|
3075
3096
|
}
|
|
3076
3097
|
});
|
|
@@ -4435,9 +4456,14 @@ function rowToRun(row) {
|
|
|
4435
4456
|
tokens_out: row.tokens_out ?? 0,
|
|
4436
4457
|
duration_ms: row.duration_ms ?? 0,
|
|
4437
4458
|
pr_url: row.pr_url ?? null,
|
|
4459
|
+
// TASWM-506: файлы, занятые прогоном с открытым PR — JSON-массив, как depends_on.
|
|
4460
|
+
changed_paths: row.changed_paths ? JSON.parse(row.changed_paths) : [],
|
|
4438
4461
|
superseded_by: row.superseded_by ?? null,
|
|
4439
4462
|
decision: row.decision ? JSON.parse(row.decision) : null,
|
|
4440
4463
|
stop_reason: row.stop_reason ?? null,
|
|
4464
|
+
// TASWM-505: через узкий парсер, как verify_verdict ниже — в базе может лежать код,
|
|
4465
|
+
// записанный демоном другой версии; непонятное здесь значит «кода нет».
|
|
4466
|
+
return_reason: toReturnReason(row.return_reason),
|
|
4441
4467
|
respawns: row.respawns ?? 0,
|
|
4442
4468
|
// старые прогоны без колонки → 0
|
|
4443
4469
|
resolves_run_id: row.resolves_run_id ?? null,
|
|
@@ -4512,6 +4538,7 @@ CREATE TABLE IF NOT EXISTS runs (
|
|
|
4512
4538
|
superseded_by INTEGER,
|
|
4513
4539
|
decision TEXT,
|
|
4514
4540
|
stop_reason TEXT,
|
|
4541
|
+
return_reason TEXT,
|
|
4515
4542
|
respawns INTEGER NOT NULL DEFAULT 0,
|
|
4516
4543
|
resolves_run_id INTEGER,
|
|
4517
4544
|
reviews_run_id INTEGER,
|
|
@@ -4628,7 +4655,16 @@ CREATE TABLE IF NOT EXISTS imports (
|
|
|
4628
4655
|
// TASWM-451: чем проверять работу этого прогона — модель ревью, приехавшая с задачи.
|
|
4629
4656
|
// Живёт на прогоне ИСПОЛНИТЕЛЯ: ревьюер и верификатор заводятся локально и читают её
|
|
4630
4657
|
// оттуда, а не ходят за задачей в прод в момент спавна.
|
|
4631
|
-
"ALTER TABLE runs ADD COLUMN review_model TEXT"
|
|
4658
|
+
"ALTER TABLE runs ADD COLUMN review_model TEXT",
|
|
4659
|
+
// TASWM-505: КОД причины возврата задачи автору (unclear_goal|no_acceptance|too_big|
|
|
4660
|
+
// contradiction) рядом с прозой в stop_reason — из него складывается распределение
|
|
4661
|
+
// «чего в постановках не хватает чаще всего». NULL — прогон не возвращали либо
|
|
4662
|
+
// возврат сделан демоном до этой фичи.
|
|
4663
|
+
"ALTER TABLE runs ADD COLUMN return_reason TEXT",
|
|
4664
|
+
// TASWM-506: файлы, которые держит прогон с открытым PR (JSON-массив, как depends_on).
|
|
4665
|
+
// Снимается в момент сдачи с PR: worktree сносится на мерже, и пересчитать список
|
|
4666
|
+
// потом неоткуда.
|
|
4667
|
+
"ALTER TABLE runs ADD COLUMN changed_paths TEXT"
|
|
4632
4668
|
]) {
|
|
4633
4669
|
try {
|
|
4634
4670
|
this.db.exec(alter);
|
|
@@ -4774,7 +4810,7 @@ CREATE TABLE IF NOT EXISTS imports (
|
|
|
4774
4810
|
const set = fields.map((f) => `${f} = ?`).join(", ");
|
|
4775
4811
|
const vals = fields.map((f) => {
|
|
4776
4812
|
const v = patch[f];
|
|
4777
|
-
if (f === "depends_on") {
|
|
4813
|
+
if (f === "depends_on" || f === "changed_paths") {
|
|
4778
4814
|
const arr = v;
|
|
4779
4815
|
return arr && arr.length ? JSON.stringify(arr) : null;
|
|
4780
4816
|
}
|
|
@@ -7180,9 +7216,11 @@ var SwarmClient = class _SwarmClient {
|
|
|
7180
7216
|
if ("duration_ms" in patch && patch.duration_ms !== void 0) out.durationMs = patch.duration_ms;
|
|
7181
7217
|
if ("respawns" in patch && patch.respawns !== void 0) out.respawns = patch.respawns;
|
|
7182
7218
|
if ("pr_url" in patch) out.prUrl = patch.pr_url ?? null;
|
|
7219
|
+
if ("changed_paths" in patch && patch.changed_paths) out.changedPaths = patch.changed_paths;
|
|
7183
7220
|
if ("branch" in patch) out.branch = patch.branch ?? null;
|
|
7184
7221
|
if ("repo" in patch) out.repo = patch.repo ?? null;
|
|
7185
7222
|
if ("stop_reason" in patch) out.stopReason = patch.stop_reason ?? null;
|
|
7223
|
+
if ("return_reason" in patch) out.returnReason = patch.return_reason ?? null;
|
|
7186
7224
|
if ("depends_on" in patch && patch.depends_on) out.dependsOn = patch.depends_on;
|
|
7187
7225
|
if ("decision" in patch) out.decision = patch.decision ? JSON.stringify(patch.decision) : null;
|
|
7188
7226
|
if ("kind" in patch && patch.kind !== void 0) out.role = patch.kind;
|
|
@@ -7258,9 +7296,12 @@ var SwarmClient = class _SwarmClient {
|
|
|
7258
7296
|
tokens_out: 0,
|
|
7259
7297
|
duration_ms: 0,
|
|
7260
7298
|
pr_url: null,
|
|
7299
|
+
changed_paths: [],
|
|
7300
|
+
// файлы прогона снимаются при открытии PR (TASWM-506)
|
|
7261
7301
|
superseded_by: null,
|
|
7262
7302
|
decision: input.decision ?? null,
|
|
7263
7303
|
stop_reason: null,
|
|
7304
|
+
return_reason: null,
|
|
7264
7305
|
respawns: 0,
|
|
7265
7306
|
resolves_run_id: input.resolves_run_id ?? null,
|
|
7266
7307
|
reviews_run_id: input.reviews_run_id ?? null,
|
|
@@ -8862,9 +8903,12 @@ var SwarmClient = class _SwarmClient {
|
|
|
8862
8903
|
tokens_out: 0,
|
|
8863
8904
|
duration_ms: 0,
|
|
8864
8905
|
pr_url: null,
|
|
8906
|
+
changed_paths: [],
|
|
8907
|
+
// занятые файлы (TASWM-506) — прод-поле, заполняется ниже
|
|
8865
8908
|
superseded_by: null,
|
|
8866
8909
|
decision: null,
|
|
8867
8910
|
stop_reason: null,
|
|
8911
|
+
return_reason: null,
|
|
8868
8912
|
respawns: 0,
|
|
8869
8913
|
resolves_run_id: null,
|
|
8870
8914
|
reviews_run_id: null,
|
|
@@ -8920,6 +8964,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
8920
8964
|
const verProd = pr.verifiesRunId ?? null;
|
|
8921
8965
|
if (verProd) local.verifies_run_id = this.localIdForProdId(verProd) ?? local.verifies_run_id;
|
|
8922
8966
|
local.verify_verdict = toVerifyVerdict(pr.verifyVerdict) ?? local.verify_verdict;
|
|
8967
|
+
local.return_reason = toReturnReason(pr.returnReason) ?? local.return_reason;
|
|
8923
8968
|
local.review_phase = pr.reviewPhase ?? local.review_phase;
|
|
8924
8969
|
local.repo = this.resolveRepo(pr.repo ?? null);
|
|
8925
8970
|
local.host_id = pr.hostId ?? null;
|
|
@@ -8939,6 +8984,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
8939
8984
|
local.tokens_out = typeof pr.tokensOut === "number" ? pr.tokensOut : 0;
|
|
8940
8985
|
local.duration_ms = typeof pr.durationMs === "number" ? pr.durationMs : 0;
|
|
8941
8986
|
local.pr_url = pr.prUrl ?? null;
|
|
8987
|
+
local.changed_paths = Array.isArray(pr.changedPaths) ? pr.changedPaths : local.changed_paths ?? [];
|
|
8942
8988
|
local.stop_reason = pr.stopReason ?? null;
|
|
8943
8989
|
local.respawns = typeof pr.respawns === "number" ? pr.respawns : 0;
|
|
8944
8990
|
local.decision = parseDecision(pr.decision);
|
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",
|
|
@@ -575,6 +581,36 @@ var init_prRef = __esm({
|
|
|
575
581
|
}
|
|
576
582
|
});
|
|
577
583
|
|
|
584
|
+
// ../swarm-core/src/returnReason.ts
|
|
585
|
+
function isReturnReason(v) {
|
|
586
|
+
return typeof v === "string" && RETURN_REASON_SET.has(v);
|
|
587
|
+
}
|
|
588
|
+
function toReturnReason(v) {
|
|
589
|
+
return isReturnReason(v) ? v : null;
|
|
590
|
+
}
|
|
591
|
+
function returnReasonLabel(r) {
|
|
592
|
+
switch (r) {
|
|
593
|
+
case "unclear_goal":
|
|
594
|
+
return "\u043D\u0435\u043F\u043E\u043D\u044F\u0442\u043D\u043E, \u0447\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C";
|
|
595
|
+
case "no_acceptance":
|
|
596
|
+
return "\u043D\u0435\u0447\u0435\u043C \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442";
|
|
597
|
+
case "too_big":
|
|
598
|
+
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";
|
|
599
|
+
case "contradiction":
|
|
600
|
+
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";
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
var RETURN_REASONS, RETURN_REASON_SET, UNRETURNED_FAILURE_STATUSES, UNRETURNED_FAILURE_SET;
|
|
604
|
+
var init_returnReason = __esm({
|
|
605
|
+
"../swarm-core/src/returnReason.ts"() {
|
|
606
|
+
"use strict";
|
|
607
|
+
RETURN_REASONS = ["unclear_goal", "no_acceptance", "too_big", "contradiction"];
|
|
608
|
+
RETURN_REASON_SET = new Set(RETURN_REASONS);
|
|
609
|
+
UNRETURNED_FAILURE_STATUSES = ["failed", "blocked"];
|
|
610
|
+
UNRETURNED_FAILURE_SET = new Set(UNRETURNED_FAILURE_STATUSES);
|
|
611
|
+
}
|
|
612
|
+
});
|
|
613
|
+
|
|
578
614
|
// ../swarm-core/src/modelPolicy.ts
|
|
579
615
|
function findProvider(id) {
|
|
580
616
|
const key = typeof id === "string" ? id.trim().toLowerCase() : "";
|
|
@@ -1684,6 +1720,7 @@ var init_src = __esm({
|
|
|
1684
1720
|
init_mergeQueue();
|
|
1685
1721
|
init_prRef();
|
|
1686
1722
|
init_verifyVerdict();
|
|
1723
|
+
init_returnReason();
|
|
1687
1724
|
init_modelPolicy();
|
|
1688
1725
|
init_status();
|
|
1689
1726
|
init_deps();
|
|
@@ -3962,6 +3999,12 @@ function invalidPatchValue(field, v) {
|
|
|
3962
3999
|
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
4000
|
case "pr_url":
|
|
3964
4001
|
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";
|
|
4002
|
+
case "changed_paths": {
|
|
4003
|
+
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";
|
|
4004
|
+
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})`;
|
|
4005
|
+
const badPath = v.find((p) => typeof p !== "string" || !p || p.length > CHANGED_PATH_LEN_MAX);
|
|
4006
|
+
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)}`;
|
|
4007
|
+
}
|
|
3965
4008
|
default:
|
|
3966
4009
|
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
4010
|
}
|
|
@@ -4215,7 +4258,7 @@ function channelDroneStore(opts) {
|
|
|
4215
4258
|
openQuestionsFor: async () => (await call("openQuestionsFor")).questions
|
|
4216
4259
|
};
|
|
4217
4260
|
}
|
|
4218
|
-
var LOCAL_CLI_KEY, PATCHABLE, EVENT_KIND_SET, ChannelUnavailableError, BACKOFF_MS;
|
|
4261
|
+
var LOCAL_CLI_KEY, PATCHABLE, CHANGED_PATHS_MAX, CHANGED_PATH_LEN_MAX, EVENT_KIND_SET, ChannelUnavailableError, BACKOFF_MS;
|
|
4219
4262
|
var init_droneChannel = __esm({
|
|
4220
4263
|
"src/droneChannel.ts"() {
|
|
4221
4264
|
"use strict";
|
|
@@ -4229,8 +4272,16 @@ var init_droneChannel = __esm({
|
|
|
4229
4272
|
// и пишется он тем же путём на ПРОВЕРЯЕМЫЙ прогон. Без него роль verifier была немой:
|
|
4230
4273
|
// вердикт выносился комментарием на PR, а `done` отбивался каналом.
|
|
4231
4274
|
"verify_verdict",
|
|
4232
|
-
"review_cycle"
|
|
4275
|
+
"review_cycle",
|
|
4276
|
+
// TASWM-506: файлы, которые прогон занял своим PR. Едут тем же вызовом, что и сдача
|
|
4277
|
+
// (done → status=review + pr_url): считает их НАШ код в дрон-сервере (`changedPaths` по
|
|
4278
|
+
// worktree), а не модель — со стороны канала это такой же самоотчёт прогона о себе, как
|
|
4279
|
+
// pr_url. Потолки на размер — ниже, в invalidPatchValue: список идёт в гейт раздачи, и
|
|
4280
|
+
// сорвавшийся дрон не должен уметь заявить занятым весь репозиторий.
|
|
4281
|
+
"changed_paths"
|
|
4233
4282
|
]);
|
|
4283
|
+
CHANGED_PATHS_MAX = 1e3;
|
|
4284
|
+
CHANGED_PATH_LEN_MAX = 1024;
|
|
4234
4285
|
EVENT_KIND_SET = new Set(EVENT_KINDS);
|
|
4235
4286
|
ChannelUnavailableError = class extends Error {
|
|
4236
4287
|
constructor(downMs, message) {
|
|
@@ -5541,9 +5592,14 @@ function rowToRun(row) {
|
|
|
5541
5592
|
tokens_out: row.tokens_out ?? 0,
|
|
5542
5593
|
duration_ms: row.duration_ms ?? 0,
|
|
5543
5594
|
pr_url: row.pr_url ?? null,
|
|
5595
|
+
// TASWM-506: файлы, занятые прогоном с открытым PR — JSON-массив, как depends_on.
|
|
5596
|
+
changed_paths: row.changed_paths ? JSON.parse(row.changed_paths) : [],
|
|
5544
5597
|
superseded_by: row.superseded_by ?? null,
|
|
5545
5598
|
decision: row.decision ? JSON.parse(row.decision) : null,
|
|
5546
5599
|
stop_reason: row.stop_reason ?? null,
|
|
5600
|
+
// TASWM-505: через узкий парсер, как verify_verdict ниже — в базе может лежать код,
|
|
5601
|
+
// записанный демоном другой версии; непонятное здесь значит «кода нет».
|
|
5602
|
+
return_reason: toReturnReason(row.return_reason),
|
|
5547
5603
|
respawns: row.respawns ?? 0,
|
|
5548
5604
|
// старые прогоны без колонки → 0
|
|
5549
5605
|
resolves_run_id: row.resolves_run_id ?? null,
|
|
@@ -5618,6 +5674,7 @@ CREATE TABLE IF NOT EXISTS runs (
|
|
|
5618
5674
|
superseded_by INTEGER,
|
|
5619
5675
|
decision TEXT,
|
|
5620
5676
|
stop_reason TEXT,
|
|
5677
|
+
return_reason TEXT,
|
|
5621
5678
|
respawns INTEGER NOT NULL DEFAULT 0,
|
|
5622
5679
|
resolves_run_id INTEGER,
|
|
5623
5680
|
reviews_run_id INTEGER,
|
|
@@ -5734,7 +5791,16 @@ CREATE TABLE IF NOT EXISTS imports (
|
|
|
5734
5791
|
// TASWM-451: чем проверять работу этого прогона — модель ревью, приехавшая с задачи.
|
|
5735
5792
|
// Живёт на прогоне ИСПОЛНИТЕЛЯ: ревьюер и верификатор заводятся локально и читают её
|
|
5736
5793
|
// оттуда, а не ходят за задачей в прод в момент спавна.
|
|
5737
|
-
"ALTER TABLE runs ADD COLUMN review_model TEXT"
|
|
5794
|
+
"ALTER TABLE runs ADD COLUMN review_model TEXT",
|
|
5795
|
+
// TASWM-505: КОД причины возврата задачи автору (unclear_goal|no_acceptance|too_big|
|
|
5796
|
+
// contradiction) рядом с прозой в stop_reason — из него складывается распределение
|
|
5797
|
+
// «чего в постановках не хватает чаще всего». NULL — прогон не возвращали либо
|
|
5798
|
+
// возврат сделан демоном до этой фичи.
|
|
5799
|
+
"ALTER TABLE runs ADD COLUMN return_reason TEXT",
|
|
5800
|
+
// TASWM-506: файлы, которые держит прогон с открытым PR (JSON-массив, как depends_on).
|
|
5801
|
+
// Снимается в момент сдачи с PR: worktree сносится на мерже, и пересчитать список
|
|
5802
|
+
// потом неоткуда.
|
|
5803
|
+
"ALTER TABLE runs ADD COLUMN changed_paths TEXT"
|
|
5738
5804
|
]) {
|
|
5739
5805
|
try {
|
|
5740
5806
|
this.db.exec(alter);
|
|
@@ -5880,7 +5946,7 @@ CREATE TABLE IF NOT EXISTS imports (
|
|
|
5880
5946
|
const set = fields.map((f) => `${f} = ?`).join(", ");
|
|
5881
5947
|
const vals = fields.map((f) => {
|
|
5882
5948
|
const v = patch[f];
|
|
5883
|
-
if (f === "depends_on") {
|
|
5949
|
+
if (f === "depends_on" || f === "changed_paths") {
|
|
5884
5950
|
const arr = v;
|
|
5885
5951
|
return arr && arr.length ? JSON.stringify(arr) : null;
|
|
5886
5952
|
}
|
|
@@ -7088,9 +7154,11 @@ var SwarmClient = class _SwarmClient {
|
|
|
7088
7154
|
if ("duration_ms" in patch && patch.duration_ms !== void 0) out.durationMs = patch.duration_ms;
|
|
7089
7155
|
if ("respawns" in patch && patch.respawns !== void 0) out.respawns = patch.respawns;
|
|
7090
7156
|
if ("pr_url" in patch) out.prUrl = patch.pr_url ?? null;
|
|
7157
|
+
if ("changed_paths" in patch && patch.changed_paths) out.changedPaths = patch.changed_paths;
|
|
7091
7158
|
if ("branch" in patch) out.branch = patch.branch ?? null;
|
|
7092
7159
|
if ("repo" in patch) out.repo = patch.repo ?? null;
|
|
7093
7160
|
if ("stop_reason" in patch) out.stopReason = patch.stop_reason ?? null;
|
|
7161
|
+
if ("return_reason" in patch) out.returnReason = patch.return_reason ?? null;
|
|
7094
7162
|
if ("depends_on" in patch && patch.depends_on) out.dependsOn = patch.depends_on;
|
|
7095
7163
|
if ("decision" in patch) out.decision = patch.decision ? JSON.stringify(patch.decision) : null;
|
|
7096
7164
|
if ("kind" in patch && patch.kind !== void 0) out.role = patch.kind;
|
|
@@ -7166,9 +7234,12 @@ var SwarmClient = class _SwarmClient {
|
|
|
7166
7234
|
tokens_out: 0,
|
|
7167
7235
|
duration_ms: 0,
|
|
7168
7236
|
pr_url: null,
|
|
7237
|
+
changed_paths: [],
|
|
7238
|
+
// файлы прогона снимаются при открытии PR (TASWM-506)
|
|
7169
7239
|
superseded_by: null,
|
|
7170
7240
|
decision: input.decision ?? null,
|
|
7171
7241
|
stop_reason: null,
|
|
7242
|
+
return_reason: null,
|
|
7172
7243
|
respawns: 0,
|
|
7173
7244
|
resolves_run_id: input.resolves_run_id ?? null,
|
|
7174
7245
|
reviews_run_id: input.reviews_run_id ?? null,
|
|
@@ -8770,9 +8841,12 @@ var SwarmClient = class _SwarmClient {
|
|
|
8770
8841
|
tokens_out: 0,
|
|
8771
8842
|
duration_ms: 0,
|
|
8772
8843
|
pr_url: null,
|
|
8844
|
+
changed_paths: [],
|
|
8845
|
+
// занятые файлы (TASWM-506) — прод-поле, заполняется ниже
|
|
8773
8846
|
superseded_by: null,
|
|
8774
8847
|
decision: null,
|
|
8775
8848
|
stop_reason: null,
|
|
8849
|
+
return_reason: null,
|
|
8776
8850
|
respawns: 0,
|
|
8777
8851
|
resolves_run_id: null,
|
|
8778
8852
|
reviews_run_id: null,
|
|
@@ -8828,6 +8902,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
8828
8902
|
const verProd = pr.verifiesRunId ?? null;
|
|
8829
8903
|
if (verProd) local.verifies_run_id = this.localIdForProdId(verProd) ?? local.verifies_run_id;
|
|
8830
8904
|
local.verify_verdict = toVerifyVerdict(pr.verifyVerdict) ?? local.verify_verdict;
|
|
8905
|
+
local.return_reason = toReturnReason(pr.returnReason) ?? local.return_reason;
|
|
8831
8906
|
local.review_phase = pr.reviewPhase ?? local.review_phase;
|
|
8832
8907
|
local.repo = this.resolveRepo(pr.repo ?? null);
|
|
8833
8908
|
local.host_id = pr.hostId ?? null;
|
|
@@ -8847,6 +8922,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
8847
8922
|
local.tokens_out = typeof pr.tokensOut === "number" ? pr.tokensOut : 0;
|
|
8848
8923
|
local.duration_ms = typeof pr.durationMs === "number" ? pr.durationMs : 0;
|
|
8849
8924
|
local.pr_url = pr.prUrl ?? null;
|
|
8925
|
+
local.changed_paths = Array.isArray(pr.changedPaths) ? pr.changedPaths : local.changed_paths ?? [];
|
|
8850
8926
|
local.stop_reason = pr.stopReason ?? null;
|
|
8851
8927
|
local.respawns = typeof pr.respawns === "number" ? pr.respawns : 0;
|
|
8852
8928
|
local.decision = parseDecision(pr.decision);
|
|
@@ -11472,6 +11548,206 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
11472
11548
|
import { z } from "zod";
|
|
11473
11549
|
init_git();
|
|
11474
11550
|
|
|
11551
|
+
// src/diff.ts
|
|
11552
|
+
import { statSync as statSync10 } from "fs";
|
|
11553
|
+
import { join as join25 } from "path";
|
|
11554
|
+
import { $ as $4 } from "execa";
|
|
11555
|
+
var MAX_FILES = 200;
|
|
11556
|
+
var MAX_LINES_PER_FILE = 1500;
|
|
11557
|
+
var MAX_UNTRACKED = 60;
|
|
11558
|
+
function cleanPath(raw) {
|
|
11559
|
+
let p = raw.trim();
|
|
11560
|
+
if (p.startsWith('"') && p.endsWith('"') && p.length >= 2) p = p.slice(1, -1);
|
|
11561
|
+
return p;
|
|
11562
|
+
}
|
|
11563
|
+
function stripAB(raw) {
|
|
11564
|
+
const p = cleanPath(raw);
|
|
11565
|
+
if (p === "/dev/null") return p;
|
|
11566
|
+
if (p.startsWith("a/") || p.startsWith("b/")) return p.slice(2);
|
|
11567
|
+
return p;
|
|
11568
|
+
}
|
|
11569
|
+
function parseUnifiedDiff(text) {
|
|
11570
|
+
const files = [];
|
|
11571
|
+
if (!text) return files;
|
|
11572
|
+
const lines = text.split("\n");
|
|
11573
|
+
let f = null;
|
|
11574
|
+
let hunk = null;
|
|
11575
|
+
let oldNo = 0;
|
|
11576
|
+
let newNo = 0;
|
|
11577
|
+
const push = () => {
|
|
11578
|
+
if (f) files.push(f);
|
|
11579
|
+
};
|
|
11580
|
+
for (const line of lines) {
|
|
11581
|
+
if (line.startsWith("diff --git ")) {
|
|
11582
|
+
push();
|
|
11583
|
+
hunk = null;
|
|
11584
|
+
const m = line.match(/^diff --git (.+) (.+)$/);
|
|
11585
|
+
const guess = m ? stripAB(m[2]) : "";
|
|
11586
|
+
f = { path: guess, oldPath: null, status: "modified", added: 0, removed: 0, binary: false, hunks: [] };
|
|
11587
|
+
continue;
|
|
11588
|
+
}
|
|
11589
|
+
if (!f) continue;
|
|
11590
|
+
if (line.startsWith("new file mode")) {
|
|
11591
|
+
f.status = "added";
|
|
11592
|
+
continue;
|
|
11593
|
+
}
|
|
11594
|
+
if (line.startsWith("deleted file mode")) {
|
|
11595
|
+
f.status = "deleted";
|
|
11596
|
+
continue;
|
|
11597
|
+
}
|
|
11598
|
+
if (line.startsWith("rename from ") || line.startsWith("copy from ")) {
|
|
11599
|
+
f.oldPath = cleanPath(line.replace(/^(rename|copy) from /, ""));
|
|
11600
|
+
f.status = "renamed";
|
|
11601
|
+
continue;
|
|
11602
|
+
}
|
|
11603
|
+
if (line.startsWith("rename to ") || line.startsWith("copy to ")) {
|
|
11604
|
+
f.path = cleanPath(line.replace(/^(rename|copy) to /, ""));
|
|
11605
|
+
f.status = "renamed";
|
|
11606
|
+
continue;
|
|
11607
|
+
}
|
|
11608
|
+
if (line.startsWith("Binary files ")) {
|
|
11609
|
+
f.binary = true;
|
|
11610
|
+
continue;
|
|
11611
|
+
}
|
|
11612
|
+
if (line.startsWith("--- ")) {
|
|
11613
|
+
const p = stripAB(line.slice(4));
|
|
11614
|
+
if (p === "/dev/null") f.status = "added";
|
|
11615
|
+
continue;
|
|
11616
|
+
}
|
|
11617
|
+
if (line.startsWith("+++ ")) {
|
|
11618
|
+
const p = stripAB(line.slice(4));
|
|
11619
|
+
if (p === "/dev/null") f.status = "deleted";
|
|
11620
|
+
else if (p) f.path = p;
|
|
11621
|
+
continue;
|
|
11622
|
+
}
|
|
11623
|
+
if (line.startsWith("@@")) {
|
|
11624
|
+
const m = line.match(/^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@(.*)$/);
|
|
11625
|
+
if (m) {
|
|
11626
|
+
oldNo = Number(m[1]);
|
|
11627
|
+
newNo = Number(m[2]);
|
|
11628
|
+
hunk = { header: (m[3] ?? "").trim(), lines: [] };
|
|
11629
|
+
f.hunks.push(hunk);
|
|
11630
|
+
}
|
|
11631
|
+
continue;
|
|
11632
|
+
}
|
|
11633
|
+
if (!hunk) continue;
|
|
11634
|
+
if (line.startsWith("\\")) continue;
|
|
11635
|
+
const tag = line[0];
|
|
11636
|
+
const body = line.slice(1);
|
|
11637
|
+
if (tag === "+") {
|
|
11638
|
+
hunk.lines.push({ k: "add", o: null, n: newNo++, t: body });
|
|
11639
|
+
f.added++;
|
|
11640
|
+
} else if (tag === "-") {
|
|
11641
|
+
hunk.lines.push({ k: "del", o: oldNo++, n: null, t: body });
|
|
11642
|
+
f.removed++;
|
|
11643
|
+
} else if (tag === " ") {
|
|
11644
|
+
hunk.lines.push({ k: "ctx", o: oldNo++, n: newNo++, t: body });
|
|
11645
|
+
}
|
|
11646
|
+
}
|
|
11647
|
+
push();
|
|
11648
|
+
return files;
|
|
11649
|
+
}
|
|
11650
|
+
function truncateFile(f) {
|
|
11651
|
+
let count = 0;
|
|
11652
|
+
const hunks = [];
|
|
11653
|
+
let cut = false;
|
|
11654
|
+
for (const h of f.hunks) {
|
|
11655
|
+
if (count >= MAX_LINES_PER_FILE) {
|
|
11656
|
+
cut = true;
|
|
11657
|
+
break;
|
|
11658
|
+
}
|
|
11659
|
+
const room = MAX_LINES_PER_FILE - count;
|
|
11660
|
+
if (h.lines.length <= room) {
|
|
11661
|
+
hunks.push(h);
|
|
11662
|
+
count += h.lines.length;
|
|
11663
|
+
} else {
|
|
11664
|
+
hunks.push({ header: h.header, lines: h.lines.slice(0, room) });
|
|
11665
|
+
count += room;
|
|
11666
|
+
cut = true;
|
|
11667
|
+
break;
|
|
11668
|
+
}
|
|
11669
|
+
}
|
|
11670
|
+
return cut ? { ...f, hunks, truncated: true } : f;
|
|
11671
|
+
}
|
|
11672
|
+
async function resolveBase(wt, baseBranch) {
|
|
11673
|
+
const tryRef = async (ref) => {
|
|
11674
|
+
const sha = (await $4({ reject: false })`git -C ${wt} rev-parse --verify --quiet ${ref + "^{commit}"}`).stdout.trim();
|
|
11675
|
+
if (!sha) return null;
|
|
11676
|
+
const mb2 = (await $4({ reject: false })`git -C ${wt} merge-base HEAD ${ref}`).stdout.trim();
|
|
11677
|
+
return mb2 || null;
|
|
11678
|
+
};
|
|
11679
|
+
const originHead = (await $4({ reject: false })`git -C ${wt} symbolic-ref --quiet --short refs/remotes/origin/HEAD`).stdout.trim();
|
|
11680
|
+
const candidates = [
|
|
11681
|
+
...baseBranch ? [`origin/${baseBranch}`, baseBranch] : [],
|
|
11682
|
+
originHead,
|
|
11683
|
+
"origin/main",
|
|
11684
|
+
"origin/master",
|
|
11685
|
+
"main",
|
|
11686
|
+
"master"
|
|
11687
|
+
].filter(Boolean);
|
|
11688
|
+
for (const c of candidates) {
|
|
11689
|
+
const mb2 = await tryRef(c);
|
|
11690
|
+
if (mb2) return mb2;
|
|
11691
|
+
}
|
|
11692
|
+
return null;
|
|
11693
|
+
}
|
|
11694
|
+
function mtime(path) {
|
|
11695
|
+
try {
|
|
11696
|
+
return statSync10(path).mtimeMs;
|
|
11697
|
+
} catch {
|
|
11698
|
+
return 0;
|
|
11699
|
+
}
|
|
11700
|
+
}
|
|
11701
|
+
async function collectRunDiff(worktree, opts = {}) {
|
|
11702
|
+
const stub = (reason) => ({ ok: false, reason, pr: opts.pr ?? null, files: [], added: 0, removed: 0 });
|
|
11703
|
+
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";
|
|
11704
|
+
if (!worktree) return stub(gone);
|
|
11705
|
+
const isWt = (await $4({ reject: false })`git -C ${worktree} rev-parse --is-inside-work-tree`).stdout.trim();
|
|
11706
|
+
if (isWt !== "true") return stub(gone);
|
|
11707
|
+
const base3 = await resolveBase(worktree, opts.baseBranch);
|
|
11708
|
+
const from = base3 ?? "HEAD";
|
|
11709
|
+
const trackedTxt = (await $4({ reject: false })`git -C ${worktree} diff --no-color --find-renames ${from} --`).stdout;
|
|
11710
|
+
let files = parseUnifiedDiff(trackedTxt);
|
|
11711
|
+
const untrackedRaw = (await $4({ reject: false })`git -C ${worktree} ls-files --others --exclude-standard -z`).stdout;
|
|
11712
|
+
const untracked = untrackedRaw.split("\0").filter(Boolean).slice(0, MAX_UNTRACKED);
|
|
11713
|
+
for (const rel of untracked) {
|
|
11714
|
+
const t = (await $4({ reject: false })`git -C ${worktree} diff --no-color --no-index -- /dev/null ${rel}`).stdout;
|
|
11715
|
+
for (const pf of parseUnifiedDiff(t)) {
|
|
11716
|
+
pf.status = "added";
|
|
11717
|
+
if (!pf.path || pf.path === "/dev/null") pf.path = rel;
|
|
11718
|
+
files.push(pf);
|
|
11719
|
+
}
|
|
11720
|
+
}
|
|
11721
|
+
files.sort((a, b) => mtime(join25(worktree, b.path)) - mtime(join25(worktree, a.path)));
|
|
11722
|
+
const truncatedFiles = files.length > MAX_FILES;
|
|
11723
|
+
if (truncatedFiles) files = files.slice(0, MAX_FILES);
|
|
11724
|
+
const added = files.reduce((s, f) => s + f.added, 0);
|
|
11725
|
+
const removed = files.reduce((s, f) => s + f.removed, 0);
|
|
11726
|
+
const out = files.map(truncateFile);
|
|
11727
|
+
return {
|
|
11728
|
+
ok: true,
|
|
11729
|
+
base: base3 ? base3.slice(0, 9) : null,
|
|
11730
|
+
files: out,
|
|
11731
|
+
added,
|
|
11732
|
+
removed,
|
|
11733
|
+
...truncatedFiles ? { truncated: true } : {}
|
|
11734
|
+
};
|
|
11735
|
+
}
|
|
11736
|
+
async function changedPaths(worktree, opts = {}) {
|
|
11737
|
+
if (!worktree) return [];
|
|
11738
|
+
try {
|
|
11739
|
+
const isWt = (await $4({ reject: false })`git -C ${worktree} rev-parse --is-inside-work-tree`).stdout.trim();
|
|
11740
|
+
if (isWt !== "true") return [];
|
|
11741
|
+
const from = await resolveBase(worktree, opts.baseBranch) ?? "HEAD";
|
|
11742
|
+
const tracked = (await $4({ reject: false })`git -C ${worktree} diff --name-only --find-renames ${from} --`).stdout;
|
|
11743
|
+
const untracked = (await $4({ reject: false })`git -C ${worktree} ls-files --others --exclude-standard -z`).stdout;
|
|
11744
|
+
const all = [...tracked.split("\n"), ...untracked.split("\0")].map((s) => s.trim()).filter(Boolean);
|
|
11745
|
+
return [...new Set(all)].sort();
|
|
11746
|
+
} catch {
|
|
11747
|
+
return [];
|
|
11748
|
+
}
|
|
11749
|
+
}
|
|
11750
|
+
|
|
11475
11751
|
// src/zoneNotes.ts
|
|
11476
11752
|
init_src();
|
|
11477
11753
|
function parseZoneMemory(raw, zone) {
|
|
@@ -11520,6 +11796,7 @@ function collectZoneNoteConfirmations(report) {
|
|
|
11520
11796
|
|
|
11521
11797
|
// src/droneServer.ts
|
|
11522
11798
|
init_src();
|
|
11799
|
+
init_src();
|
|
11523
11800
|
|
|
11524
11801
|
// src/reviewCycle.ts
|
|
11525
11802
|
init_src();
|
|
@@ -11769,19 +12046,36 @@ ${failText}` : failText }],
|
|
|
11769
12046
|
);
|
|
11770
12047
|
server.tool(
|
|
11771
12048
|
"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.",
|
|
12049
|
+
"\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
12050
|
{
|
|
12051
|
+
// TASWM-505: КОД причины рядом с прозой. Проза объясняет автору ЭТУ задачу, код
|
|
12052
|
+
// складывается по бэклогу в распределение «чего в постановках не хватает чаще
|
|
12053
|
+
// всего» (аналитика роя). Обязательный: необязательное поле дрон пропустит, а
|
|
12054
|
+
// распределение по половине возвратов — не распределение.
|
|
12055
|
+
reason: z.enum(RETURN_REASONS).describe(
|
|
12056
|
+
"\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"
|
|
12057
|
+
),
|
|
11774
12058
|
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
12059
|
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
12060
|
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")
|
|
12061
|
+
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"),
|
|
12062
|
+
// TASWM-505: разбиение — ПРЕДЛОЖЕНИЕ автору, а не действие дрона. Подзадачи дрон не
|
|
12063
|
+
// заводит сознательно: разбиение — продуктовое решение, а плохое разбиение хуже
|
|
12064
|
+
// никакого, потому что выглядит авторитетно (заведённые подзадачи прочтут как
|
|
12065
|
+
// согласованный план). Поэтому — строчками в комменте, которые автор правит или
|
|
12066
|
+
// выбрасывает одним движением.
|
|
12067
|
+
split: z.array(z.string().min(10)).max(7).optional().describe(
|
|
12068
|
+
"\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)"
|
|
12069
|
+
)
|
|
11778
12070
|
},
|
|
11779
12071
|
guard(
|
|
11780
12072
|
async ({
|
|
12073
|
+
reason,
|
|
11781
12074
|
missing,
|
|
11782
12075
|
readings,
|
|
11783
12076
|
assumed,
|
|
11784
|
-
questions
|
|
12077
|
+
questions,
|
|
12078
|
+
split
|
|
11785
12079
|
}) => {
|
|
11786
12080
|
if (await overmindDead()) return freeze();
|
|
11787
12081
|
const run = await store.myRun();
|
|
@@ -11816,10 +12110,20 @@ ${failText}` : failText }],
|
|
|
11816
12110
|
"",
|
|
11817
12111
|
`${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
12112
|
"",
|
|
12113
|
+
`**\u041F\u0440\u0438\u0447\u0438\u043D\u0430.** ${returnReasonLabel(reason)} (\`${reason}\`).`,
|
|
12114
|
+
"",
|
|
11819
12115
|
`**\u0427\u0435\u0433\u043E \u043D\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442.** ${missing.trim()}`,
|
|
11820
12116
|
...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
12117
|
"",
|
|
11822
12118
|
`**\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()}`,
|
|
12119
|
+
// Разбиение — только предложение и только к too_big (TASWM-505). Формулировка
|
|
12120
|
+
// «на твоё усмотрение» здесь не вежливость: заведённые подзадачи выглядели бы
|
|
12121
|
+
// согласованным планом, а это решение автора, и плохое разбиение хуже никакого.
|
|
12122
|
+
...reason === "too_big" && split?.length ? [
|
|
12123
|
+
"",
|
|
12124
|
+
"**\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.",
|
|
12125
|
+
...split.map((s) => `- ${s.trim()}`)
|
|
12126
|
+
] : [],
|
|
11823
12127
|
"",
|
|
11824
12128
|
"**\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
12129
|
...questions.map((q, i) => `${i + 1}. ${q.trim()}`)
|
|
@@ -11863,9 +12167,9 @@ ${failText}` : failText }],
|
|
|
11863
12167
|
};
|
|
11864
12168
|
}
|
|
11865
12169
|
}
|
|
11866
|
-
const
|
|
11867
|
-
await store.updateRun(null, { status: "returned", stop_reason: reason });
|
|
11868
|
-
await store.addEvent(null, "returned", failures.length ? `${
|
|
12170
|
+
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()}`;
|
|
12171
|
+
await store.updateRun(null, { status: "returned", stop_reason: stopReason, return_reason: reason });
|
|
12172
|
+
await store.addEvent(null, "returned", failures.length ? `${stopReason} \xB7 \u043D\u0435 \u0434\u043E\u0435\u0445\u0430\u043B\u043E: ${failures.join("; ")}` : stopReason);
|
|
11869
12173
|
return {
|
|
11870
12174
|
content: [
|
|
11871
12175
|
{
|
|
@@ -12211,9 +12515,11 @@ ${report}${shots.warning}`,
|
|
|
12211
12515
|
const headBranch = opts.prHeadBranch ? await opts.prHeadBranch(pr_url).catch(() => null) : null;
|
|
12212
12516
|
const branchFix = branchFromPrPatch(run?.branch, headBranch);
|
|
12213
12517
|
if (branchFix) await store.addEvent(null, "step", branchFix.event);
|
|
12518
|
+
const held = await changedPaths(opts.worktree ?? process.cwd(), { baseBranch: run?.base_branch ?? null }).catch(() => []);
|
|
12519
|
+
const heldPatch = held.length ? { changed_paths: held } : {};
|
|
12214
12520
|
if (run) {
|
|
12215
12521
|
const t = reviewTransitionPatch(run, pr_url);
|
|
12216
|
-
await store.updateRun(null, { ...t.patch, ...branchFix?.patch ?? {} });
|
|
12522
|
+
await store.updateRun(null, { ...t.patch, ...branchFix?.patch ?? {}, ...heldPatch });
|
|
12217
12523
|
await store.addEvent(null, "pr_opened", pr_url);
|
|
12218
12524
|
await postReport(reportSlug(run.task_slug), t.cycle ?? run.review_cycle ?? 0);
|
|
12219
12525
|
const rulesNote = await offerRules(reportSlug(run.task_slug));
|
|
@@ -12228,7 +12534,7 @@ ${report}${shots.warning}`,
|
|
|
12228
12534
|
}
|
|
12229
12535
|
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
12536
|
}
|
|
12231
|
-
await store.updateRun(null, { status: "review", pr_url, ...branchFix?.patch ?? {} });
|
|
12537
|
+
await store.updateRun(null, { status: "review", pr_url, ...branchFix?.patch ?? {}, ...heldPatch });
|
|
12232
12538
|
await store.addEvent(null, "pr_opened", pr_url);
|
|
12233
12539
|
const fallbackSlug = reportSlug(void 0);
|
|
12234
12540
|
if (fallbackSlug) await postReport(fallbackSlug, void 0);
|
|
@@ -13532,20 +13838,20 @@ function makeMergeGateParts(deps) {
|
|
|
13532
13838
|
|
|
13533
13839
|
// src/envGate.ts
|
|
13534
13840
|
import { existsSync as existsSync15 } from "fs";
|
|
13535
|
-
import { join as
|
|
13841
|
+
import { join as join27 } from "path";
|
|
13536
13842
|
import { createConnection } from "net";
|
|
13537
13843
|
import { execa as execa2 } from "execa";
|
|
13538
13844
|
|
|
13539
13845
|
// src/platform.ts
|
|
13540
13846
|
import { existsSync as existsSync14, readFileSync as readFileSync18 } from "fs";
|
|
13541
|
-
import { delimiter, join as
|
|
13847
|
+
import { delimiter, join as join26 } from "path";
|
|
13542
13848
|
function resolveCommandPath(name, env = process.env, platform = process.platform) {
|
|
13543
13849
|
if (name.includes("/") || name.includes("\\")) return existsSync14(name) ? name : null;
|
|
13544
13850
|
const dirs = (env.PATH ?? env.Path ?? "").split(delimiter).filter(Boolean);
|
|
13545
13851
|
const exts = platform === "win32" ? (env.PATHEXT ?? ".EXE;.CMD;.BAT").split(";").filter(Boolean) : [""];
|
|
13546
13852
|
for (const dir of dirs) {
|
|
13547
13853
|
for (const ext of exts) {
|
|
13548
|
-
const candidate =
|
|
13854
|
+
const candidate = join26(dir, name + ext);
|
|
13549
13855
|
if (existsSync14(candidate)) return candidate;
|
|
13550
13856
|
}
|
|
13551
13857
|
}
|
|
@@ -13630,7 +13936,7 @@ var COMPOSE_MARKERS = [
|
|
|
13630
13936
|
];
|
|
13631
13937
|
function detectRequirements(repo, io = {}) {
|
|
13632
13938
|
const exists = io.exists ?? existsSync15;
|
|
13633
|
-
const marker = COMPOSE_MARKERS.find((f) => exists(
|
|
13939
|
+
const marker = COMPOSE_MARKERS.find((f) => exists(join27(repo, f)));
|
|
13634
13940
|
return marker ? [{ kind: "docker", raw: `docker (\u0434\u0435\u0442\u0435\u043A\u0442: ${marker})` }] : [];
|
|
13635
13941
|
}
|
|
13636
13942
|
function resolveRequirements(repo, declared, io = {}) {
|
|
@@ -13765,210 +14071,10 @@ import { randomBytes as randomBytes3 } from "crypto";
|
|
|
13765
14071
|
import { basename as basename5 } from "path";
|
|
13766
14072
|
import { serve as serve2 } from "@hono/node-server";
|
|
13767
14073
|
|
|
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
14074
|
// package.json
|
|
13969
14075
|
var package_default = {
|
|
13970
14076
|
name: "@taskless-app/swarm",
|
|
13971
|
-
version: "0.6.
|
|
14077
|
+
version: "0.6.26",
|
|
13972
14078
|
type: "module",
|
|
13973
14079
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
13974
14080
|
keywords: [
|
|
@@ -14019,7 +14125,7 @@ var package_default = {
|
|
|
14019
14125
|
execa: "^10.0.0",
|
|
14020
14126
|
zod: "3.25.76"
|
|
14021
14127
|
},
|
|
14022
|
-
gitHead: "
|
|
14128
|
+
gitHead: "52416995d46b0a843374d14bfb00dd310f71c4bf"
|
|
14023
14129
|
};
|
|
14024
14130
|
|
|
14025
14131
|
// src/version.ts
|
|
@@ -16401,6 +16507,12 @@ function predictForRun(model, run) {
|
|
|
16401
16507
|
function short(files, n = 3) {
|
|
16402
16508
|
return files.slice(0, n).join(", ") + (files.length > n ? ` \u0438 \u0435\u0449\u0451 ${files.length - n}` : "");
|
|
16403
16509
|
}
|
|
16510
|
+
function heldBecause(w) {
|
|
16511
|
+
const parts = [];
|
|
16512
|
+
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}`);
|
|
16513
|
+
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");
|
|
16514
|
+
return parts.length ? ` (${parts.join("; ")})` : "";
|
|
16515
|
+
}
|
|
16404
16516
|
var SPINE_PREDICTION_WEIGHT = 0.7;
|
|
16405
16517
|
function spineOfPrediction(spine, predicted) {
|
|
16406
16518
|
return predicted.filter((p) => spine.has(p.path) && p.weight >= SPINE_PREDICTION_WEIGHT).map((p) => p.path);
|
|
@@ -16421,7 +16533,7 @@ function decideConflict({ model, candidate, active }) {
|
|
|
16421
16533
|
return {
|
|
16422
16534
|
kind: "wait",
|
|
16423
16535
|
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
|
|
16536
|
+
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
16537
|
};
|
|
16426
16538
|
}
|
|
16427
16539
|
}
|
|
@@ -16432,7 +16544,7 @@ function decideConflict({ model, candidate, active }) {
|
|
|
16432
16544
|
return {
|
|
16433
16545
|
kind: "wait",
|
|
16434
16546
|
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
|
|
16547
|
+
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
16548
|
};
|
|
16437
16549
|
}
|
|
16438
16550
|
return { kind: "clear" };
|
|
@@ -16485,10 +16597,16 @@ var ActiveFilesCache = class {
|
|
|
16485
16597
|
this.cache.set(run.id, { at: now, files });
|
|
16486
16598
|
return files;
|
|
16487
16599
|
}
|
|
16488
|
-
/**
|
|
16489
|
-
|
|
16490
|
-
|
|
16491
|
-
|
|
16600
|
+
/**
|
|
16601
|
+
* Забыть всех, кто больше НЕ ДЕРЖИТ файлы. Раньше здесь стоял список ЖИВЫХ дронов и
|
|
16602
|
+
* комментарий «дрон закончил — его файлы больше не заняты»; это и была дырка TASWM-506:
|
|
16603
|
+
* дрон заканчивал, открывал PR, PR висел непомерженным — а строки уже считались
|
|
16604
|
+
* свободными. Держатель теперь переживает своего дрона и уходит из кэша на мерже
|
|
16605
|
+
* (прогон выходит из `review`), см. holdsFiles.
|
|
16606
|
+
*/
|
|
16607
|
+
prune(holderIds) {
|
|
16608
|
+
const holders = new Set(holderIds);
|
|
16609
|
+
for (const id of [...this.cache.keys()]) if (!holders.has(id)) this.cache.delete(id);
|
|
16492
16610
|
}
|
|
16493
16611
|
};
|
|
16494
16612
|
function withManualAreas(history, areas) {
|
|
@@ -17097,12 +17215,19 @@ ${task.description}` : `\u0417\u0430\u0434\u0430\u0447\u0430 ${run.task_slug} (\
|
|
|
17097
17215
|
// вторую ветку мимо PR. Пишем ту, что реально записана на прогоне; пусто (первый спавн —
|
|
17098
17216
|
// ветку заводит spawnDrone из слага) — прежняя формулировка.
|
|
17099
17217
|
`\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).",
|
|
17218
|
+
"\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
17219
|
// TASWM-412: третий выход из непонятной задачи. Раньше их было два, и оба плохие —
|
|
17102
17220
|
// угадать постановку (сделает не то) или ask (слот занят, а ответить может только автор
|
|
17103
17221
|
// задачи, не оператор роя). Граница здесь ОБЯЗАТЕЛЬНА: дрон, легко возвращающий задачи,
|
|
17104
17222
|
// становится отписочником, а это хуже, чем дрон, который иногда угадывает неверно.
|
|
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.",
|
|
17223
|
+
"\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.",
|
|
17224
|
+
// TASWM-505: ЕДИНСТВЕННЫЙ сорт негодной задачи, который не покрывался ничем. claimPolicy
|
|
17225
|
+
// (TASWM-357) отсеивает родителей с незакрытыми детьми, но лист на 8 часов уезжает дрону
|
|
17226
|
+
// целиком — и он упирается в потолок трат на середине, оставляя недоделанную работу
|
|
17227
|
+
// человеку. Это уже случалось. Подзадачи дрон при этом НЕ заводит: разбиение —
|
|
17228
|
+
// продуктовое решение, а плохое разбиение хуже никакого, потому что выглядит
|
|
17229
|
+
// авторитетно (заведённые подзадачи читаются как согласованный план).
|
|
17230
|
+
"\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
17231
|
"\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
17232
|
// TASWM-377: у сессии есть ПОТОЛОК ТРАТ, и он режет её без предупреждения, прямо посреди
|
|
17108
17233
|
// работы. Дрон об этом знать обязан: цена сессии растёт от ЧИСЛА ХОДОВ (каждый ход заново
|
|
@@ -17915,15 +18040,17 @@ function effectiveRepo(deps, run) {
|
|
|
17915
18040
|
async function zoneConflictFor(db, models, activeFiles, run, repo, repoFallback) {
|
|
17916
18041
|
const model = await models.forRepo(repo);
|
|
17917
18042
|
if (!hasZoneModel(model)) return { kind: "unknown" };
|
|
17918
|
-
const
|
|
17919
|
-
activeFiles.prune(
|
|
18043
|
+
const holders = db.listRuns().filter((r) => holdsFiles(r));
|
|
18044
|
+
activeFiles.prune(holders.map((r) => r.id));
|
|
17920
18045
|
const active = [];
|
|
17921
|
-
for (const r of
|
|
18046
|
+
for (const r of holders) {
|
|
17922
18047
|
if (r.id === run.id) continue;
|
|
17923
18048
|
if (normalizeRepo(r.repo || repoFallback || "") !== repo) continue;
|
|
17924
|
-
const
|
|
18049
|
+
const snapshot = r.changed_paths ?? [];
|
|
18050
|
+
const files = snapshot.length ? snapshot : await activeFiles.filesOf(r);
|
|
18051
|
+
const prUrl = r.status === "review" ? r.pr_url : null;
|
|
17925
18052
|
active.push(
|
|
17926
|
-
files.length ? { run: r, files, actual: true } : { run: r, files: predictForRun(model, r).map((p) => p.path), actual: false }
|
|
18053
|
+
files.length ? { run: r, files, actual: true, prUrl } : { run: r, files: predictForRun(model, r).map((p) => p.path), actual: false, prUrl }
|
|
17927
18054
|
);
|
|
17928
18055
|
}
|
|
17929
18056
|
return decideConflict({ model, candidate: run, active });
|
|
@@ -18115,6 +18242,13 @@ async function trySpawnQueuedRun(deps, run) {
|
|
|
18115
18242
|
if (logged.get(run.id) !== e.message) {
|
|
18116
18243
|
logged.set(run.id, e.message);
|
|
18117
18244
|
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)`);
|
|
18245
|
+
const blocker = deps.db.getRun(e.blockedByRunId);
|
|
18246
|
+
if (blocker)
|
|
18247
|
+
deps.db.addEvent(
|
|
18248
|
+
blocker.id,
|
|
18249
|
+
"step",
|
|
18250
|
+
`${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)`
|
|
18251
|
+
);
|
|
18118
18252
|
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
18253
|
}
|
|
18120
18254
|
return "skipped";
|
|
@@ -21099,5 +21233,6 @@ export {
|
|
|
21099
21233
|
tickOnce,
|
|
21100
21234
|
verdictCommentMark,
|
|
21101
21235
|
wakeRun,
|
|
21102
|
-
worktreeFromCmd
|
|
21236
|
+
worktreeFromCmd,
|
|
21237
|
+
zoneConflictFor
|
|
21103
21238
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taskless-app/swarm",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.26",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
6
6
|
"keywords": [
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"execa": "^10.0.0",
|
|
40
40
|
"zod": "3.25.76"
|
|
41
41
|
},
|
|
42
|
-
"gitHead": "
|
|
42
|
+
"gitHead": "52416995d46b0a843374d14bfb00dd310f71c4bf",
|
|
43
43
|
"scripts": {
|
|
44
44
|
"overmind": "NODE_OPTIONS=\"${NODE_OPTIONS:-} --conditions=development\" tsx src/overmind.ts",
|
|
45
45
|
"swarm": "NODE_OPTIONS=\"${NODE_OPTIONS:-} --conditions=development\" tsx src/cli.ts",
|