@taskless-app/swarm 0.6.17 → 0.6.19
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 +225 -14
- package/dist/overmind.js +452 -52
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -472,6 +472,92 @@ var init_mergeGate = __esm({
|
|
|
472
472
|
}
|
|
473
473
|
});
|
|
474
474
|
|
|
475
|
+
// ../swarm-core/src/mergeQueue.ts
|
|
476
|
+
function orderMergeQueue(ready) {
|
|
477
|
+
return [...ready].sort((a, b) => a.prNumber - b.prNumber || a.runId - b.runId);
|
|
478
|
+
}
|
|
479
|
+
function label(e) {
|
|
480
|
+
return e.slug ? `#${e.prNumber} (${e.slug})` : `#${e.prNumber}`;
|
|
481
|
+
}
|
|
482
|
+
function computeMergeQueue(input) {
|
|
483
|
+
const queue = orderMergeQueue(input.ready);
|
|
484
|
+
const size = queue.length;
|
|
485
|
+
const idx = queue.findIndex((e) => e.runId === input.entry.runId && e.prNumber === input.entry.prNumber);
|
|
486
|
+
const position = idx + 1;
|
|
487
|
+
const head = queue[0];
|
|
488
|
+
if (head && idx > 0) {
|
|
489
|
+
return {
|
|
490
|
+
allowed: false,
|
|
491
|
+
code: "queue_wait",
|
|
492
|
+
reason: `\u0440\u043E\u0439 \u0432\u043B\u0438\u0432\u0430\u0435\u0442 PR \u043F\u043E \u043E\u0434\u043D\u043E\u043C\u0443: \u0441\u0435\u0439\u0447\u0430\u0441 \u043E\u0447\u0435\u0440\u0435\u0434\u044C PR ${label(head)}, \u044D\u0442\u043E\u0442 \u2014 ${position}-\u0439 \u0438\u0437 ${size}. \u041C\u0435\u0440\u0436\u0438\u0442\u044C \u0435\u0433\u043E \u0441\u0435\u0439\u0447\u0430\u0441 \u043D\u0435\u043B\u044C\u0437\u044F \u2014 \u0434\u043E\u0436\u0434\u0438\u0441\u044C, \u043F\u043E\u043A\u0430 \u043F\u0435\u0440\u0435\u0434 \u043D\u0438\u043C \u043E\u0441\u0432\u043E\u0431\u043E\u0434\u0438\u0442\u0441\u044F (TASWM-472)`,
|
|
493
|
+
position,
|
|
494
|
+
size
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
if (input.behindBy == null) {
|
|
498
|
+
return {
|
|
499
|
+
allowed: false,
|
|
500
|
+
code: "base_unknown",
|
|
501
|
+
reason: "\u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0443\u0437\u043D\u0430\u0442\u044C, \u0441\u043E\u0434\u0435\u0440\u0436\u0438\u0442 \u043B\u0438 \u0432\u0435\u0442\u043A\u0430 PR \u0442\u0435\u043A\u0443\u0449\u0438\u0439 main \u2014 \u0430 \u0431\u0435\u0437 \u044D\u0442\u043E\u0433\u043E \u0437\u0435\u043B\u0451\u043D\u044B\u0439 CI \u043D\u0435 \u0433\u043E\u0432\u043E\u0440\u0438\u0442 \u043D\u0438\u0447\u0435\u0433\u043E \u043F\u0440\u043E main \u043F\u043E\u0441\u043B\u0435 \u0432\u043B\u0438\u0432\u0430\u043D\u0438\u044F. \u042D\u0442\u043E \u0442\u0440\u0430\u043D\u0437\u0438\u0435\u043D\u0442\u043D\u043E (gh \u043D\u0435 \u043E\u0442\u0432\u0435\u0442\u0438\u043B): \u043F\u043E\u0432\u0442\u043E\u0440\u0438 \u0447\u0435\u0440\u0435\u0437 \u043C\u0438\u043D\u0443\u0442\u0443 (TASWM-472)",
|
|
502
|
+
position,
|
|
503
|
+
size
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
if (input.behindBy > 0) {
|
|
507
|
+
return {
|
|
508
|
+
allowed: false,
|
|
509
|
+
code: "base_stale",
|
|
510
|
+
reason: `\u0431\u0430\u0437\u0430 \u0443\u0435\u0445\u0430\u043B\u0430 \u0432\u043F\u0435\u0440\u0451\u0434 \u043D\u0430 ${input.behindBy} \u043A\u043E\u043C\u043C\u0438\u0442(\u043E\u0432) \u0441 \u043C\u043E\u043C\u0435\u043D\u0442\u0430 \u043F\u0440\u043E\u0433\u043E\u043D\u0430 \u043F\u0440\u043E\u0432\u0435\u0440\u043E\u043A \u2014 \u0437\u0435\u043B\u0451\u043D\u044B\u0439 CI \u043D\u0430 \u0441\u0442\u0430\u0440\u043E\u0439 \u0431\u0430\u0437\u0435 \u043D\u0435 \u0434\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442, \u0447\u0442\u043E main \u043E\u0441\u0442\u0430\u043D\u0435\u0442\u0441\u044F \u0437\u0435\u043B\u0451\u043D\u044B\u043C. \u0412\u043B\u0435\u0439 main \u0432 \u0432\u0435\u0442\u043A\u0443 PR \u0438 \u0434\u043E\u0436\u0434\u0438\u0441\u044C \u0437\u0435\u043B\u0451\u043D\u044B\u0445 \u043F\u0440\u043E\u0432\u0435\u0440\u043E\u043A \u043D\u0430 \u043E\u0431\u043D\u043E\u0432\u043B\u0451\u043D\u043D\u043E\u0439 \u0431\u0430\u0437\u0435 (TASWM-472)`,
|
|
511
|
+
position,
|
|
512
|
+
size
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
if (input.checks === null) {
|
|
516
|
+
return {
|
|
517
|
+
allowed: false,
|
|
518
|
+
code: "checks_unknown",
|
|
519
|
+
reason: "\u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u043F\u0440\u043E\u0441\u0438\u0442\u044C \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 PR \u2014 \u0430 \u043D\u0430 \u0441\u0432\u0435\u0436\u0435\u0439 \u0431\u0430\u0437\u0435 \u0438\u043C\u0435\u043D\u043D\u043E \u043E\u043D\u0438 \u0438 \u043E\u0442\u0432\u0435\u0447\u0430\u044E\u0442, \u043E\u0441\u0442\u0430\u043D\u0435\u0442\u0441\u044F \u043B\u0438 main \u0437\u0435\u043B\u0451\u043D\u044B\u043C. \u042D\u0442\u043E \u0442\u0440\u0430\u043D\u0437\u0438\u0435\u043D\u0442\u043D\u043E (gh \u043D\u0435 \u043E\u0442\u0432\u0435\u0442\u0438\u043B): \u043F\u043E\u0432\u0442\u043E\u0440\u0438 \u0447\u0435\u0440\u0435\u0437 \u043C\u0438\u043D\u0443\u0442\u0443 (TASWM-472)",
|
|
520
|
+
position,
|
|
521
|
+
size
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
if (input.checks === "fail") {
|
|
525
|
+
return {
|
|
526
|
+
allowed: false,
|
|
527
|
+
code: "checks_red",
|
|
528
|
+
reason: "\u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u043D\u0430 \u041E\u0411\u041D\u041E\u0412\u041B\u0401\u041D\u041D\u041E\u0419 \u0431\u0430\u0437\u0435 \u043A\u0440\u0430\u0441\u043D\u044B\u0435 \u2014 \u044D\u0442\u043E\u0442 PR \u043B\u043E\u043C\u0430\u0435\u0442 main \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 \u0442\u0435\u043A\u0443\u0449\u0438\u043C \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435\u043C \u0431\u0430\u0437\u044B. \u041C\u0435\u0440\u0436\u0438\u0442\u044C \u043D\u0435\u043B\u044C\u0437\u044F: \u0441\u043D\u0430\u0447\u0430\u043B\u0430 \u0434\u043E\u0440\u0430\u0431\u043E\u0442\u043A\u0430 (TASWM-472)",
|
|
529
|
+
position,
|
|
530
|
+
size
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
if (input.checks === "pending") {
|
|
534
|
+
return {
|
|
535
|
+
allowed: false,
|
|
536
|
+
code: "checks_pending",
|
|
537
|
+
reason: "\u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u043D\u0430 \u043E\u0431\u043D\u043E\u0432\u043B\u0451\u043D\u043D\u043E\u0439 \u0431\u0430\u0437\u0435 \u0435\u0449\u0451 \u0438\u0434\u0443\u0442 \u2014 \u0438\u0445 \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442 \u0438 \u0435\u0441\u0442\u044C \u043E\u0442\u0432\u0435\u0442 \xAB\u043E\u0441\u0442\u0430\u043D\u0435\u0442\u0441\u044F \u043B\u0438 main \u0437\u0435\u043B\u0451\u043D\u044B\u043C\xBB. \u0414\u043E\u0436\u0434\u0438\u0441\u044C (TASWM-472)",
|
|
538
|
+
position,
|
|
539
|
+
size
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
return {
|
|
543
|
+
allowed: true,
|
|
544
|
+
code: "queue_head",
|
|
545
|
+
reason: "\u0433\u043E\u043B\u043E\u0432\u0430 \u043E\u0447\u0435\u0440\u0435\u0434\u0438 \u043C\u0435\u0440\u0436\u0430, \u0431\u0430\u0437\u0430 \u043F\u043E\u0434 PR \u0441\u0432\u0435\u0436\u0430\u044F, \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u043D\u0430 \u043D\u0435\u0439 \u043D\u0435 \u043A\u0440\u0430\u0441\u043D\u044B\u0435 \u2014 \u043C\u0435\u0440\u0436\u0438\u0442\u044C \u043C\u043E\u0436\u043D\u043E",
|
|
546
|
+
position,
|
|
547
|
+
size
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
function computeMergeDecision(gate, queue) {
|
|
551
|
+
if (!gate.allowed || gate.code === "unknown_pr" || !queue) return { ...gate, queue: queue ?? null };
|
|
552
|
+
if (!queue.allowed) return { allowed: false, code: queue.code, reason: queue.reason, queue };
|
|
553
|
+
return { ...gate, reason: `${gate.reason}; ${queue.reason}`, queue };
|
|
554
|
+
}
|
|
555
|
+
var init_mergeQueue = __esm({
|
|
556
|
+
"../swarm-core/src/mergeQueue.ts"() {
|
|
557
|
+
"use strict";
|
|
558
|
+
}
|
|
559
|
+
});
|
|
560
|
+
|
|
475
561
|
// ../swarm-core/src/modelPolicy.ts
|
|
476
562
|
function findProvider(id) {
|
|
477
563
|
const key = typeof id === "string" ? id.trim().toLowerCase() : "";
|
|
@@ -1455,6 +1541,14 @@ var init_queuePlan = __esm({
|
|
|
1455
1541
|
}
|
|
1456
1542
|
});
|
|
1457
1543
|
|
|
1544
|
+
// ../swarm-core/src/zoneMemory.ts
|
|
1545
|
+
var init_zoneMemory = __esm({
|
|
1546
|
+
"../swarm-core/src/zoneMemory.ts"() {
|
|
1547
|
+
"use strict";
|
|
1548
|
+
init_time();
|
|
1549
|
+
}
|
|
1550
|
+
});
|
|
1551
|
+
|
|
1458
1552
|
// ../swarm-core/src/index.ts
|
|
1459
1553
|
var init_src = __esm({
|
|
1460
1554
|
"../swarm-core/src/index.ts"() {
|
|
@@ -1463,6 +1557,7 @@ var init_src = __esm({
|
|
|
1463
1557
|
init_timeline();
|
|
1464
1558
|
init_reviewPhase();
|
|
1465
1559
|
init_mergeGate();
|
|
1560
|
+
init_mergeQueue();
|
|
1466
1561
|
init_verifyVerdict();
|
|
1467
1562
|
init_modelPolicy();
|
|
1468
1563
|
init_status();
|
|
@@ -1485,6 +1580,7 @@ var init_src = __esm({
|
|
|
1485
1580
|
init_codeZones();
|
|
1486
1581
|
init_effort();
|
|
1487
1582
|
init_queuePlan();
|
|
1583
|
+
init_zoneMemory();
|
|
1488
1584
|
}
|
|
1489
1585
|
});
|
|
1490
1586
|
|
|
@@ -2071,7 +2167,7 @@ function tokenFromFile() {
|
|
|
2071
2167
|
return "";
|
|
2072
2168
|
}
|
|
2073
2169
|
}
|
|
2074
|
-
var DB_PATH, EXECUTOR, DRONE_HOME, DRONE_HOME_ISOLATION, DRONE_ISOLATION, WORKTREES_NOINDEX_DIR, WORKTREES_LEGACY_DIR, WORKTREES_DIR, RUN_LOGS_DIR, DAEMON_LOG_PATH, DAEMON_LOG_MAX_BYTES, DAEMON_LOG_KEEP, DAEMON_LOG_CHECK_MS, DIST_BUILD, SWARM_BACKEND, SWARM_OUTBOX, SWARM_MAX_IN_FLIGHT, SWARM_CLAIM_INTERVAL_MS, SWARM_MAX_LOAD_FACTOR, SWARM_MIN_FREE_GB, SWARM_MAX_FD_LOAD_FACTOR, SWARM_MAX_CPU_BUSY, SWARM_CPU_WINDOW_MS, SWARM_CPU_SANITY_BUSY, SWARM_CPU_SANITY_LOAD_FACTOR, SWARM_CPU_SANITY_LAG_MS, SWARM_RELIEF_LOAD_FACTOR, SWARM_RELIEF_MIN_FREE_GB, SWARM_RELIEF_MAX_FD_LOAD_FACTOR, SWARM_RELIEF_CPU_BUSY, SWARM_RELIEF_COST_WINDOW_MS, SWARM_RELIEF_ALERT_PAUSES, SWARM_RELIEF_ALERT_LOST_MS, SWARM_RELIEF_ALERT_MIN_STEPS, SWARM_RELIEF_ALERT_SUSTAIN_MS, SWARM_LOW_DISK_GB, SWARM_REHYDRATE_MS, SWARM_DRONE_BRIDGE_MS, SWARM_PROD_HEARTBEAT_MS, SWARM_VERSION_CHECK_MS, SWARM_SWEEP_INTERVAL_MS, DRONE_CHANNEL_ENABLED, DRONE_CHANNEL_PORT, DRONE_CHANNEL_URL, DRONE_CHANNEL_SECRET_PATH, DRONE_CHANNEL_GRACE_MS, HEARTBEAT_PATH, HEARTBEAT_STALE_MS, SWARM_REPO, SWARM_SCAN_DEPTH, SWARM_REPO_PATHS, SWARM_SCAN_ROOTS_RAW, REPO_MAP_PATH, SWARM_REPO_MAP_MS, SWARM_REPO_SCAN_TTL_MS, TASKLESS_API, SWARM_SHOT_TIMEOUT_MS, TASKLESS_MCP_PATH, TASKLESS_TOKEN, TASKLESS_WORKSPACE, TASKLESS_WORKSPACE_SLUG, TASKLESS_TASK_URL_BASE, SWARM_VERIFY, SWARM_AUTO_REVIEW, SWARM_AUTO_VERIFY, REVIEW_CUTOFF_PATH, SWARM_REVIEW_CAP, SWARM_STORM_URL, WEB_PORT, WEB_REDIRECT_URI, SWARM_ANOMALY_RENOTIFY_MS, SWARM_ANOMALY_MAX_REPEATS, SWARM_ANOMALY_RUN_DOWN_WINDOW_MS, SWARM_ANOMALY_FAILED_SPIKE_COUNT, SWARM_ANOMALY_FAILED_SPIKE_WINDOW_MS, SWARM_ANOMALY_QUEUE_STALLED_MS, SWARM_ANOMALY_PR_STUCK_MERGE_MS, SWARM_ANOMALY_PR_NO_REVIEWER_MS, SWARM_ANOMALY_QUESTION_UNANSWERED_MS, SWARM_ANOMALY_OUTBOX_STUCK_MS, SWARM_ANOMALY_RESOURCE_GATE_STALL_MS, SWARM_ANOMALY_DEP_MISSING_MS, SWARM_WATCHDOG_STALL_MS;
|
|
2170
|
+
var DB_PATH, EXECUTOR, DRONE_HOME, DRONE_HOME_ISOLATION, DRONE_ISOLATION, WORKTREES_NOINDEX_DIR, WORKTREES_LEGACY_DIR, WORKTREES_DIR, RUN_LOGS_DIR, DAEMON_LOG_PATH, DAEMON_LOG_MAX_BYTES, DAEMON_LOG_KEEP, DAEMON_LOG_CHECK_MS, DIST_BUILD, SWARM_BACKEND, SWARM_OUTBOX, SWARM_MAX_IN_FLIGHT, SWARM_CLAIM_INTERVAL_MS, SWARM_MAX_LOAD_FACTOR, SWARM_MIN_FREE_GB, SWARM_MAX_FD_LOAD_FACTOR, SWARM_MAX_CPU_BUSY, SWARM_CPU_WINDOW_MS, SWARM_CPU_SANITY_BUSY, SWARM_CPU_SANITY_LOAD_FACTOR, SWARM_CPU_SANITY_LAG_MS, SWARM_RELIEF_LOAD_FACTOR, SWARM_RELIEF_MIN_FREE_GB, SWARM_RELIEF_MAX_FD_LOAD_FACTOR, SWARM_RELIEF_CPU_BUSY, SWARM_RELIEF_COST_WINDOW_MS, SWARM_RELIEF_ALERT_PAUSES, SWARM_RELIEF_ALERT_LOST_MS, SWARM_RELIEF_ALERT_MIN_STEPS, SWARM_RELIEF_ALERT_SUSTAIN_MS, SWARM_LOW_DISK_GB, SWARM_REHYDRATE_MS, SWARM_DRONE_BRIDGE_MS, SWARM_PROD_HEARTBEAT_MS, SWARM_VERSION_CHECK_MS, SWARM_SWEEP_INTERVAL_MS, DRONE_CHANNEL_ENABLED, DRONE_CHANNEL_PORT, DRONE_CHANNEL_URL, DRONE_CHANNEL_SECRET_PATH, DRONE_CHANNEL_GRACE_MS, HEARTBEAT_PATH, HEARTBEAT_STALE_MS, SWARM_REPO, SWARM_SCAN_DEPTH, SWARM_REPO_PATHS, SWARM_SCAN_ROOTS_RAW, REPO_MAP_PATH, SWARM_REPO_MAP_MS, SWARM_REPO_SCAN_TTL_MS, TASKLESS_API, SWARM_SHOT_TIMEOUT_MS, TASKLESS_MCP_PATH, TASKLESS_TOKEN, TASKLESS_WORKSPACE, TASKLESS_WORKSPACE_SLUG, TASKLESS_TASK_URL_BASE, SWARM_VERIFY, SWARM_AUTO_REVIEW, SWARM_AUTO_VERIFY, SWARM_MERGE_QUEUE, REVIEW_CUTOFF_PATH, SWARM_REVIEW_CAP, SWARM_STORM_URL, WEB_PORT, WEB_REDIRECT_URI, SWARM_ANOMALY_RENOTIFY_MS, SWARM_ANOMALY_MAX_REPEATS, SWARM_ANOMALY_RUN_DOWN_WINDOW_MS, SWARM_ANOMALY_FAILED_SPIKE_COUNT, SWARM_ANOMALY_FAILED_SPIKE_WINDOW_MS, SWARM_ANOMALY_QUEUE_STALLED_MS, SWARM_ANOMALY_PR_STUCK_MERGE_MS, SWARM_ANOMALY_PR_NO_REVIEWER_MS, SWARM_ANOMALY_QUESTION_UNANSWERED_MS, SWARM_ANOMALY_OUTBOX_STUCK_MS, SWARM_ANOMALY_RESOURCE_GATE_STALL_MS, SWARM_ANOMALY_DEP_MISSING_MS, SWARM_WATCHDOG_STALL_MS;
|
|
2075
2171
|
var init_config = __esm({
|
|
2076
2172
|
"src/config.ts"() {
|
|
2077
2173
|
"use strict";
|
|
@@ -2144,6 +2240,7 @@ var init_config = __esm({
|
|
|
2144
2240
|
SWARM_VERIFY = process.env.SWARM_VERIFY === "ci" ? "ci" : "local";
|
|
2145
2241
|
SWARM_AUTO_REVIEW = process.env.SWARM_AUTO_REVIEW !== "0";
|
|
2146
2242
|
SWARM_AUTO_VERIFY = process.env.SWARM_AUTO_VERIFY !== "0";
|
|
2243
|
+
SWARM_MERGE_QUEUE = process.env.SWARM_MERGE_QUEUE !== "0";
|
|
2147
2244
|
REVIEW_CUTOFF_PATH = process.env.SWARM_REVIEW_CUTOFF || join4(SWARM_HOME, "review-cutoff.json");
|
|
2148
2245
|
SWARM_REVIEW_CAP = Math.trunc(envNum("SWARM_REVIEW_CAP", 1));
|
|
2149
2246
|
SWARM_STORM_URL = process.env.SWARM_STORM_URL || "";
|
|
@@ -2275,7 +2372,7 @@ var init_package = __esm({
|
|
|
2275
2372
|
"package.json"() {
|
|
2276
2373
|
package_default = {
|
|
2277
2374
|
name: "@taskless-app/swarm",
|
|
2278
|
-
version: "0.6.
|
|
2375
|
+
version: "0.6.19",
|
|
2279
2376
|
type: "module",
|
|
2280
2377
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
2281
2378
|
keywords: [
|
|
@@ -2325,7 +2422,7 @@ var init_package = __esm({
|
|
|
2325
2422
|
execa: "^10.0.0",
|
|
2326
2423
|
zod: "3.25.76"
|
|
2327
2424
|
},
|
|
2328
|
-
gitHead: "
|
|
2425
|
+
gitHead: "a61c26b5e254ef5383d918f14a9f6e8e8a09904a"
|
|
2329
2426
|
};
|
|
2330
2427
|
}
|
|
2331
2428
|
});
|
|
@@ -2492,8 +2589,8 @@ function describeError(e, maxDepth = 4) {
|
|
|
2492
2589
|
const msg = (cur instanceof Error ? cur.message : typeof cur === "string" ? cur : String(cur)).trim();
|
|
2493
2590
|
const code = cur.code;
|
|
2494
2591
|
const codeText = code === void 0 || code === null ? "" : String(code);
|
|
2495
|
-
const
|
|
2496
|
-
if (
|
|
2592
|
+
const label2 = codeText && !msg.includes(codeText) ? `${msg} [code=${codeText}]` : msg;
|
|
2593
|
+
if (label2 && !parts.includes(label2)) parts.push(label2);
|
|
2497
2594
|
cur = cur.cause;
|
|
2498
2595
|
}
|
|
2499
2596
|
return parts.join(" \u2190 ") || String(e);
|
|
@@ -5163,18 +5260,18 @@ function isTransientResourceError(e) {
|
|
|
5163
5260
|
const code = e?.code;
|
|
5164
5261
|
return code === "ENFILE" || code === "EMFILE" || code === "EAGAIN";
|
|
5165
5262
|
}
|
|
5166
|
-
function logTransientSpawnError(
|
|
5263
|
+
function logTransientSpawnError(label2, e) {
|
|
5167
5264
|
if (isTransientResourceError(e)) {
|
|
5168
5265
|
const code = e.code;
|
|
5169
|
-
console.warn(`[overmind] ${
|
|
5266
|
+
console.warn(`[overmind] ${label2}: \u041E\u0421 \u043D\u0435 \u0434\u0430\u0451\u0442 \u0441\u043F\u0430\u0432\u043D\u0438\u0442\u044C \u043F\u0440\u043E\u0446\u0435\u0441\u0441\u044B (${code}) \u2014 \u043F\u0440\u043E\u043F\u0443\u0441\u043A\u0430\u044E \u0441\u0438\u0433\u043D\u0430\u043B \u044D\u0442\u043E\u0433\u043E \u0442\u0438\u043A\u0430, \u043D\u0435 \u043F\u0430\u0434\u0430\u044E`);
|
|
5170
5267
|
} else {
|
|
5171
|
-
console.warn(`[overmind] ${
|
|
5268
|
+
console.warn(`[overmind] ${label2} \u0441\u043E\u0440\u0432\u0430\u043B\u0441\u044F (\u043D\u0435\u0442 \u0434\u0430\u043D\u043D\u044B\u0445 \u0437\u0430 \u044D\u0442\u043E\u0442 \u0442\u0438\u043A): ${String(e)}`);
|
|
5172
5269
|
}
|
|
5173
5270
|
}
|
|
5174
5271
|
function parseVmStatAvailableBytes(vmStatOut) {
|
|
5175
5272
|
const page = Number(vmStatOut.match(/page size of (\d+) bytes/)?.[1]) || 4096;
|
|
5176
|
-
const pages = (
|
|
5177
|
-
const m = vmStatOut.match(new RegExp(`Pages ${
|
|
5273
|
+
const pages = (label2) => {
|
|
5274
|
+
const m = vmStatOut.match(new RegExp(`Pages ${label2}:\\s+(\\d+)`));
|
|
5178
5275
|
return m ? Number(m[1]) : 0;
|
|
5179
5276
|
};
|
|
5180
5277
|
return (pages("free") + pages("inactive") + pages("speculative") + pages("purgeable")) * page;
|
|
@@ -6742,6 +6839,27 @@ var SwarmClient = class _SwarmClient {
|
|
|
6742
6839
|
const sc = res.structuredContent ?? {};
|
|
6743
6840
|
return parsePendingRepoRules(sc.rules);
|
|
6744
6841
|
}
|
|
6842
|
+
/**
|
|
6843
|
+
* ПАМЯТЬ ЗОНЫ (TASWM-466) из того же swarm_repo_config — отдельное поле `zoneMemory`,
|
|
6844
|
+
* карта «зона → заметки», только принятое вердиктом. Демон кладёт заметки НУЖНОЙ зоны в
|
|
6845
|
+
* промпт дрона (см. zoneNotes.ts), поэтому отдаём карту КАК ЕСТЬ, сырым объектом: разбор
|
|
6846
|
+
* и выбор зоны — одно место, и оно рядом с рендером блока.
|
|
6847
|
+
*
|
|
6848
|
+
* Пустая карта — памяти нет / поля в ответе прода нет (прод старее демона) / repo не
|
|
6849
|
+
* смэплен / прод недоступен. Все четыре случая РАБОЧИЕ: промпт собирается как раньше.
|
|
6850
|
+
*/
|
|
6851
|
+
async repoZoneMemory(repoFullName) {
|
|
6852
|
+
let res;
|
|
6853
|
+
try {
|
|
6854
|
+
res = await this.call("swarm_repo_config", { repoFullName });
|
|
6855
|
+
} catch {
|
|
6856
|
+
return {};
|
|
6857
|
+
}
|
|
6858
|
+
if (res?.isError) return {};
|
|
6859
|
+
const sc = res.structuredContent ?? {};
|
|
6860
|
+
const m = sc.zoneMemory;
|
|
6861
|
+
return m && typeof m === "object" && !Array.isArray(m) ? m : {};
|
|
6862
|
+
}
|
|
6745
6863
|
/**
|
|
6746
6864
|
* Live КОМАНДЫ ПОДГОТОВКИ worktree из Taskless (TASWM-312): тот же swarm_repo_config по
|
|
6747
6865
|
* repoFullName — Project.swarmConfig.prepare. Настройка сильнее детекта демона (deps.ts):
|
|
@@ -8439,6 +8557,11 @@ init_config();
|
|
|
8439
8557
|
|
|
8440
8558
|
// src/mergeGate.ts
|
|
8441
8559
|
init_src();
|
|
8560
|
+
|
|
8561
|
+
// src/mergeQueue.ts
|
|
8562
|
+
init_src();
|
|
8563
|
+
|
|
8564
|
+
// src/prNumber.ts
|
|
8442
8565
|
function prNumberOf(ref) {
|
|
8443
8566
|
const s = (ref || "").trim();
|
|
8444
8567
|
if (!s) return null;
|
|
@@ -8447,6 +8570,76 @@ function prNumberOf(ref) {
|
|
|
8447
8570
|
const bare = s.match(/^#?(\d+)$/);
|
|
8448
8571
|
return bare ? Number(bare[1]) : null;
|
|
8449
8572
|
}
|
|
8573
|
+
|
|
8574
|
+
// src/mergeQueue.ts
|
|
8575
|
+
var TERMINAL2 = /* @__PURE__ */ new Set(["done", "failed", "stalled", "stopped", "superseded", "returned"]);
|
|
8576
|
+
function isMergeCandidate(r) {
|
|
8577
|
+
return !!r.pr_url && r.reviews_run_id == null && r.verifies_run_id == null && r.resolves_run_id == null && !TERMINAL2.has(r.status) && prNumberOf(r.pr_url) != null;
|
|
8578
|
+
}
|
|
8579
|
+
function mergeQueueCandidates(runs, repo) {
|
|
8580
|
+
const byPr = /* @__PURE__ */ new Map();
|
|
8581
|
+
for (const r of runs) {
|
|
8582
|
+
if (r.repo !== repo || !isMergeCandidate(r)) continue;
|
|
8583
|
+
const num = prNumberOf(r.pr_url);
|
|
8584
|
+
const seen = byPr.get(num);
|
|
8585
|
+
if (!seen || r.id > seen.id) byPr.set(num, r);
|
|
8586
|
+
}
|
|
8587
|
+
return [...byPr.values()];
|
|
8588
|
+
}
|
|
8589
|
+
var BASE_TTL_MS = 2e4;
|
|
8590
|
+
function makeMergeQueueResolver(deps) {
|
|
8591
|
+
const memo = /* @__PURE__ */ new Map();
|
|
8592
|
+
const evaluate = async (e, prUrl, ready) => {
|
|
8593
|
+
const now = Date.now();
|
|
8594
|
+
let cached = memo.get(prUrl);
|
|
8595
|
+
const ttl = deps.ttlMs ?? BASE_TTL_MS;
|
|
8596
|
+
if (!cached || now - cached.at >= ttl) {
|
|
8597
|
+
const base3 = await deps.baseSync(prUrl).catch(() => null);
|
|
8598
|
+
let checks = "none";
|
|
8599
|
+
if (base3?.behindBy === 0 && deps.checks) {
|
|
8600
|
+
const ci = await deps.checks(prUrl).catch(() => null);
|
|
8601
|
+
checks = ci ? ci.bucket : null;
|
|
8602
|
+
}
|
|
8603
|
+
cached = { at: now, base: base3, checks };
|
|
8604
|
+
memo.set(prUrl, cached);
|
|
8605
|
+
}
|
|
8606
|
+
return computeMergeQueue({ entry: e, ready, behindBy: cached.base ? cached.base.behindBy : null, checks: cached.checks });
|
|
8607
|
+
};
|
|
8608
|
+
return async (run) => {
|
|
8609
|
+
if (!deps.baseSync || !run.pr_url) return null;
|
|
8610
|
+
const num = prNumberOf(run.pr_url);
|
|
8611
|
+
if (num == null) return null;
|
|
8612
|
+
const candidates = mergeQueueCandidates(deps.listRuns(), run.repo);
|
|
8613
|
+
const mine = candidates.find((c) => prNumberOf(c.pr_url) === num);
|
|
8614
|
+
if (!mine) return null;
|
|
8615
|
+
const ready = [];
|
|
8616
|
+
const urlOf = /* @__PURE__ */ new Map();
|
|
8617
|
+
for (const c of candidates) {
|
|
8618
|
+
if (!await deps.gateAllows(c).catch(() => false)) continue;
|
|
8619
|
+
ready.push(entryOf(c));
|
|
8620
|
+
urlOf.set(c.id, c.pr_url);
|
|
8621
|
+
}
|
|
8622
|
+
const entry = entryOf(mine);
|
|
8623
|
+
if (!ready.some((e) => e.runId === entry.runId)) return null;
|
|
8624
|
+
let queue = orderMergeQueue(ready);
|
|
8625
|
+
while (queue.length > 1 && queue[0].runId !== entry.runId) {
|
|
8626
|
+
const head = queue[0];
|
|
8627
|
+
const headUrl = urlOf.get(head.runId);
|
|
8628
|
+
const decision = await evaluate(head, headUrl, queue);
|
|
8629
|
+
if (decision.code !== "checks_red") break;
|
|
8630
|
+
queue = queue.slice(1);
|
|
8631
|
+
}
|
|
8632
|
+
if (queue[0].runId !== entry.runId) {
|
|
8633
|
+
return computeMergeQueue({ entry, ready: queue, behindBy: null, checks: "none" });
|
|
8634
|
+
}
|
|
8635
|
+
return evaluate(entry, mine.pr_url, queue);
|
|
8636
|
+
};
|
|
8637
|
+
}
|
|
8638
|
+
function entryOf(r) {
|
|
8639
|
+
return { runId: r.id, prNumber: prNumberOf(r.pr_url), slug: r.task_slug };
|
|
8640
|
+
}
|
|
8641
|
+
|
|
8642
|
+
// src/mergeGate.ts
|
|
8450
8643
|
function findRunByPr(runs, ref) {
|
|
8451
8644
|
const num = prNumberOf(ref);
|
|
8452
8645
|
if (num == null) return null;
|
|
@@ -8458,17 +8651,34 @@ function findRunByPr(runs, ref) {
|
|
|
8458
8651
|
return best;
|
|
8459
8652
|
}
|
|
8460
8653
|
function makeMergeGateResolver(deps) {
|
|
8461
|
-
return
|
|
8462
|
-
|
|
8463
|
-
|
|
8654
|
+
return makeMergeGateParts(deps).gate;
|
|
8655
|
+
}
|
|
8656
|
+
function makeMergeGateParts(deps) {
|
|
8657
|
+
const gateFor = async (run) => {
|
|
8464
8658
|
const autoReview = deps.autoReview ? await deps.autoReview(run.repo).catch(() => deps.fallbackAutoReview) : deps.fallbackAutoReview;
|
|
8465
|
-
|
|
8659
|
+
return computeMergeGate({
|
|
8466
8660
|
hasRun: true,
|
|
8467
8661
|
autoReview,
|
|
8468
8662
|
reviewVerdict: run.review_verdict,
|
|
8469
8663
|
autoVerify: deps.autoVerify === true,
|
|
8470
8664
|
verifyVerdict: run.verify_verdict ?? null
|
|
8471
8665
|
});
|
|
8666
|
+
};
|
|
8667
|
+
const queueFor = makeMergeQueueResolver({
|
|
8668
|
+
listRuns: deps.listRuns,
|
|
8669
|
+
gateAllows: async (r) => (await gateFor(r)).allowed,
|
|
8670
|
+
...deps.baseSync ? { baseSync: deps.baseSync } : {},
|
|
8671
|
+
...deps.checks ? { checks: deps.checks } : {},
|
|
8672
|
+
...deps.ttlMs != null ? { ttlMs: deps.ttlMs } : {}
|
|
8673
|
+
});
|
|
8674
|
+
const gate = async (ref) => {
|
|
8675
|
+
const run = findRunByPr(deps.listRuns(), ref);
|
|
8676
|
+
if (!run) {
|
|
8677
|
+
return { ...computeMergeDecision(computeMergeGate({ hasRun: false, autoReview: false, reviewVerdict: null }), null), run: null };
|
|
8678
|
+
}
|
|
8679
|
+
const accept = await gateFor(run);
|
|
8680
|
+
const queue = accept.allowed && accept.code !== "unknown_pr" ? await queueFor(run) : null;
|
|
8681
|
+
const decision = computeMergeDecision(accept, queue);
|
|
8472
8682
|
return {
|
|
8473
8683
|
...decision,
|
|
8474
8684
|
run: {
|
|
@@ -8481,6 +8691,7 @@ function makeMergeGateResolver(deps) {
|
|
|
8481
8691
|
}
|
|
8482
8692
|
};
|
|
8483
8693
|
};
|
|
8694
|
+
return { gate, queue: queueFor };
|
|
8484
8695
|
}
|
|
8485
8696
|
|
|
8486
8697
|
// src/web.ts
|
package/dist/overmind.js
CHANGED
|
@@ -311,8 +311,8 @@ function computeReviewPhase(input) {
|
|
|
311
311
|
}
|
|
312
312
|
if (ciRed) {
|
|
313
313
|
const jobs = (input.ciFailing ?? []).filter((j) => j && j !== "?");
|
|
314
|
-
const
|
|
315
|
-
return { kind: "ci_fixing", label:
|
|
314
|
+
const label3 = jobs.length ? `${REVIEW_PHASE_TEXT.ci_fixing}: ${jobs.join(", ")}` : REVIEW_PHASE_TEXT.ci_fixing;
|
|
315
|
+
return { kind: "ci_fixing", label: label3, ready: false };
|
|
316
316
|
}
|
|
317
317
|
if (reviewVerdict === "changes") {
|
|
318
318
|
return { kind: "changes", label: REVIEW_PHASE_TEXT.changes, ready: false };
|
|
@@ -327,8 +327,8 @@ function computeReviewPhase(input) {
|
|
|
327
327
|
if (p && p.total > 0 && p.pass >= p.total) {
|
|
328
328
|
return { kind: "awaiting_reviewer", label: REVIEW_PHASE_TEXT.awaiting_reviewer, ready: false };
|
|
329
329
|
}
|
|
330
|
-
const
|
|
331
|
-
return { kind: "checks", label, ready: false };
|
|
330
|
+
const label2 = p && p.total > 0 ? `${REVIEW_PHASE_TEXT.checks} \u2014 CI ${p.pass}/${p.total}` : REVIEW_PHASE_TEXT.checks;
|
|
331
|
+
return { kind: "checks", label: label2, ready: false };
|
|
332
332
|
}
|
|
333
333
|
var REVIEW_PHASE_TEXT, PHASE_BY_LENGTH;
|
|
334
334
|
var init_reviewPhase = __esm({
|
|
@@ -439,6 +439,92 @@ var init_mergeGate = __esm({
|
|
|
439
439
|
}
|
|
440
440
|
});
|
|
441
441
|
|
|
442
|
+
// ../swarm-core/src/mergeQueue.ts
|
|
443
|
+
function orderMergeQueue(ready) {
|
|
444
|
+
return [...ready].sort((a, b) => a.prNumber - b.prNumber || a.runId - b.runId);
|
|
445
|
+
}
|
|
446
|
+
function label(e) {
|
|
447
|
+
return e.slug ? `#${e.prNumber} (${e.slug})` : `#${e.prNumber}`;
|
|
448
|
+
}
|
|
449
|
+
function computeMergeQueue(input) {
|
|
450
|
+
const queue = orderMergeQueue(input.ready);
|
|
451
|
+
const size = queue.length;
|
|
452
|
+
const idx = queue.findIndex((e) => e.runId === input.entry.runId && e.prNumber === input.entry.prNumber);
|
|
453
|
+
const position = idx + 1;
|
|
454
|
+
const head = queue[0];
|
|
455
|
+
if (head && idx > 0) {
|
|
456
|
+
return {
|
|
457
|
+
allowed: false,
|
|
458
|
+
code: "queue_wait",
|
|
459
|
+
reason: `\u0440\u043E\u0439 \u0432\u043B\u0438\u0432\u0430\u0435\u0442 PR \u043F\u043E \u043E\u0434\u043D\u043E\u043C\u0443: \u0441\u0435\u0439\u0447\u0430\u0441 \u043E\u0447\u0435\u0440\u0435\u0434\u044C PR ${label(head)}, \u044D\u0442\u043E\u0442 \u2014 ${position}-\u0439 \u0438\u0437 ${size}. \u041C\u0435\u0440\u0436\u0438\u0442\u044C \u0435\u0433\u043E \u0441\u0435\u0439\u0447\u0430\u0441 \u043D\u0435\u043B\u044C\u0437\u044F \u2014 \u0434\u043E\u0436\u0434\u0438\u0441\u044C, \u043F\u043E\u043A\u0430 \u043F\u0435\u0440\u0435\u0434 \u043D\u0438\u043C \u043E\u0441\u0432\u043E\u0431\u043E\u0434\u0438\u0442\u0441\u044F (TASWM-472)`,
|
|
460
|
+
position,
|
|
461
|
+
size
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
if (input.behindBy == null) {
|
|
465
|
+
return {
|
|
466
|
+
allowed: false,
|
|
467
|
+
code: "base_unknown",
|
|
468
|
+
reason: "\u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0443\u0437\u043D\u0430\u0442\u044C, \u0441\u043E\u0434\u0435\u0440\u0436\u0438\u0442 \u043B\u0438 \u0432\u0435\u0442\u043A\u0430 PR \u0442\u0435\u043A\u0443\u0449\u0438\u0439 main \u2014 \u0430 \u0431\u0435\u0437 \u044D\u0442\u043E\u0433\u043E \u0437\u0435\u043B\u0451\u043D\u044B\u0439 CI \u043D\u0435 \u0433\u043E\u0432\u043E\u0440\u0438\u0442 \u043D\u0438\u0447\u0435\u0433\u043E \u043F\u0440\u043E main \u043F\u043E\u0441\u043B\u0435 \u0432\u043B\u0438\u0432\u0430\u043D\u0438\u044F. \u042D\u0442\u043E \u0442\u0440\u0430\u043D\u0437\u0438\u0435\u043D\u0442\u043D\u043E (gh \u043D\u0435 \u043E\u0442\u0432\u0435\u0442\u0438\u043B): \u043F\u043E\u0432\u0442\u043E\u0440\u0438 \u0447\u0435\u0440\u0435\u0437 \u043C\u0438\u043D\u0443\u0442\u0443 (TASWM-472)",
|
|
469
|
+
position,
|
|
470
|
+
size
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
if (input.behindBy > 0) {
|
|
474
|
+
return {
|
|
475
|
+
allowed: false,
|
|
476
|
+
code: "base_stale",
|
|
477
|
+
reason: `\u0431\u0430\u0437\u0430 \u0443\u0435\u0445\u0430\u043B\u0430 \u0432\u043F\u0435\u0440\u0451\u0434 \u043D\u0430 ${input.behindBy} \u043A\u043E\u043C\u043C\u0438\u0442(\u043E\u0432) \u0441 \u043C\u043E\u043C\u0435\u043D\u0442\u0430 \u043F\u0440\u043E\u0433\u043E\u043D\u0430 \u043F\u0440\u043E\u0432\u0435\u0440\u043E\u043A \u2014 \u0437\u0435\u043B\u0451\u043D\u044B\u0439 CI \u043D\u0430 \u0441\u0442\u0430\u0440\u043E\u0439 \u0431\u0430\u0437\u0435 \u043D\u0435 \u0434\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442, \u0447\u0442\u043E main \u043E\u0441\u0442\u0430\u043D\u0435\u0442\u0441\u044F \u0437\u0435\u043B\u0451\u043D\u044B\u043C. \u0412\u043B\u0435\u0439 main \u0432 \u0432\u0435\u0442\u043A\u0443 PR \u0438 \u0434\u043E\u0436\u0434\u0438\u0441\u044C \u0437\u0435\u043B\u0451\u043D\u044B\u0445 \u043F\u0440\u043E\u0432\u0435\u0440\u043E\u043A \u043D\u0430 \u043E\u0431\u043D\u043E\u0432\u043B\u0451\u043D\u043D\u043E\u0439 \u0431\u0430\u0437\u0435 (TASWM-472)`,
|
|
478
|
+
position,
|
|
479
|
+
size
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
if (input.checks === null) {
|
|
483
|
+
return {
|
|
484
|
+
allowed: false,
|
|
485
|
+
code: "checks_unknown",
|
|
486
|
+
reason: "\u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u043F\u0440\u043E\u0441\u0438\u0442\u044C \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 PR \u2014 \u0430 \u043D\u0430 \u0441\u0432\u0435\u0436\u0435\u0439 \u0431\u0430\u0437\u0435 \u0438\u043C\u0435\u043D\u043D\u043E \u043E\u043D\u0438 \u0438 \u043E\u0442\u0432\u0435\u0447\u0430\u044E\u0442, \u043E\u0441\u0442\u0430\u043D\u0435\u0442\u0441\u044F \u043B\u0438 main \u0437\u0435\u043B\u0451\u043D\u044B\u043C. \u042D\u0442\u043E \u0442\u0440\u0430\u043D\u0437\u0438\u0435\u043D\u0442\u043D\u043E (gh \u043D\u0435 \u043E\u0442\u0432\u0435\u0442\u0438\u043B): \u043F\u043E\u0432\u0442\u043E\u0440\u0438 \u0447\u0435\u0440\u0435\u0437 \u043C\u0438\u043D\u0443\u0442\u0443 (TASWM-472)",
|
|
487
|
+
position,
|
|
488
|
+
size
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
if (input.checks === "fail") {
|
|
492
|
+
return {
|
|
493
|
+
allowed: false,
|
|
494
|
+
code: "checks_red",
|
|
495
|
+
reason: "\u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u043D\u0430 \u041E\u0411\u041D\u041E\u0412\u041B\u0401\u041D\u041D\u041E\u0419 \u0431\u0430\u0437\u0435 \u043A\u0440\u0430\u0441\u043D\u044B\u0435 \u2014 \u044D\u0442\u043E\u0442 PR \u043B\u043E\u043C\u0430\u0435\u0442 main \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 \u0442\u0435\u043A\u0443\u0449\u0438\u043C \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435\u043C \u0431\u0430\u0437\u044B. \u041C\u0435\u0440\u0436\u0438\u0442\u044C \u043D\u0435\u043B\u044C\u0437\u044F: \u0441\u043D\u0430\u0447\u0430\u043B\u0430 \u0434\u043E\u0440\u0430\u0431\u043E\u0442\u043A\u0430 (TASWM-472)",
|
|
496
|
+
position,
|
|
497
|
+
size
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
if (input.checks === "pending") {
|
|
501
|
+
return {
|
|
502
|
+
allowed: false,
|
|
503
|
+
code: "checks_pending",
|
|
504
|
+
reason: "\u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u043D\u0430 \u043E\u0431\u043D\u043E\u0432\u043B\u0451\u043D\u043D\u043E\u0439 \u0431\u0430\u0437\u0435 \u0435\u0449\u0451 \u0438\u0434\u0443\u0442 \u2014 \u0438\u0445 \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442 \u0438 \u0435\u0441\u0442\u044C \u043E\u0442\u0432\u0435\u0442 \xAB\u043E\u0441\u0442\u0430\u043D\u0435\u0442\u0441\u044F \u043B\u0438 main \u0437\u0435\u043B\u0451\u043D\u044B\u043C\xBB. \u0414\u043E\u0436\u0434\u0438\u0441\u044C (TASWM-472)",
|
|
505
|
+
position,
|
|
506
|
+
size
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
return {
|
|
510
|
+
allowed: true,
|
|
511
|
+
code: "queue_head",
|
|
512
|
+
reason: "\u0433\u043E\u043B\u043E\u0432\u0430 \u043E\u0447\u0435\u0440\u0435\u0434\u0438 \u043C\u0435\u0440\u0436\u0430, \u0431\u0430\u0437\u0430 \u043F\u043E\u0434 PR \u0441\u0432\u0435\u0436\u0430\u044F, \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u043D\u0430 \u043D\u0435\u0439 \u043D\u0435 \u043A\u0440\u0430\u0441\u043D\u044B\u0435 \u2014 \u043C\u0435\u0440\u0436\u0438\u0442\u044C \u043C\u043E\u0436\u043D\u043E",
|
|
513
|
+
position,
|
|
514
|
+
size
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
function computeMergeDecision(gate, queue) {
|
|
518
|
+
if (!gate.allowed || gate.code === "unknown_pr" || !queue) return { ...gate, queue: queue ?? null };
|
|
519
|
+
if (!queue.allowed) return { allowed: false, code: queue.code, reason: queue.reason, queue };
|
|
520
|
+
return { ...gate, reason: `${gate.reason}; ${queue.reason}`, queue };
|
|
521
|
+
}
|
|
522
|
+
var init_mergeQueue = __esm({
|
|
523
|
+
"../swarm-core/src/mergeQueue.ts"() {
|
|
524
|
+
"use strict";
|
|
525
|
+
}
|
|
526
|
+
});
|
|
527
|
+
|
|
442
528
|
// ../swarm-core/src/modelPolicy.ts
|
|
443
529
|
function findProvider(id) {
|
|
444
530
|
const key = typeof id === "string" ? id.trim().toLowerCase() : "";
|
|
@@ -1527,6 +1613,16 @@ var init_queuePlan = __esm({
|
|
|
1527
1613
|
}
|
|
1528
1614
|
});
|
|
1529
1615
|
|
|
1616
|
+
// ../swarm-core/src/zoneMemory.ts
|
|
1617
|
+
var ZONE_NOTES_PER_RUN_MAX;
|
|
1618
|
+
var init_zoneMemory = __esm({
|
|
1619
|
+
"../swarm-core/src/zoneMemory.ts"() {
|
|
1620
|
+
"use strict";
|
|
1621
|
+
init_time();
|
|
1622
|
+
ZONE_NOTES_PER_RUN_MAX = 2;
|
|
1623
|
+
}
|
|
1624
|
+
});
|
|
1625
|
+
|
|
1530
1626
|
// ../swarm-core/src/index.ts
|
|
1531
1627
|
var init_src = __esm({
|
|
1532
1628
|
"../swarm-core/src/index.ts"() {
|
|
@@ -1535,6 +1631,7 @@ var init_src = __esm({
|
|
|
1535
1631
|
init_timeline();
|
|
1536
1632
|
init_reviewPhase();
|
|
1537
1633
|
init_mergeGate();
|
|
1634
|
+
init_mergeQueue();
|
|
1538
1635
|
init_verifyVerdict();
|
|
1539
1636
|
init_modelPolicy();
|
|
1540
1637
|
init_status();
|
|
@@ -1557,6 +1654,7 @@ var init_src = __esm({
|
|
|
1557
1654
|
init_codeZones();
|
|
1558
1655
|
init_effort();
|
|
1559
1656
|
init_queuePlan();
|
|
1657
|
+
init_zoneMemory();
|
|
1560
1658
|
}
|
|
1561
1659
|
});
|
|
1562
1660
|
|
|
@@ -2150,6 +2248,7 @@ __export(config_exports, {
|
|
|
2150
2248
|
SWARM_MAX_FD_LOAD_FACTOR: () => SWARM_MAX_FD_LOAD_FACTOR,
|
|
2151
2249
|
SWARM_MAX_IN_FLIGHT: () => SWARM_MAX_IN_FLIGHT,
|
|
2152
2250
|
SWARM_MAX_LOAD_FACTOR: () => SWARM_MAX_LOAD_FACTOR,
|
|
2251
|
+
SWARM_MERGE_QUEUE: () => SWARM_MERGE_QUEUE,
|
|
2153
2252
|
SWARM_MIN_FREE_GB: () => SWARM_MIN_FREE_GB,
|
|
2154
2253
|
SWARM_OUTBOX: () => SWARM_OUTBOX,
|
|
2155
2254
|
SWARM_PROD_HEARTBEAT_MS: () => SWARM_PROD_HEARTBEAT_MS,
|
|
@@ -2272,7 +2371,7 @@ function reviewCutoffAt() {
|
|
|
2272
2371
|
}
|
|
2273
2372
|
return at;
|
|
2274
2373
|
}
|
|
2275
|
-
var DB_PATH, EXECUTOR, DRONE_HOME, DRONE_HOME_ISOLATION, DRONE_ISOLATION, WORKTREES_NOINDEX_DIR, WORKTREES_LEGACY_DIR, WORKTREES_DIR, RUN_LOGS_DIR, DAEMON_LOG_PATH, DAEMON_LOG_MAX_BYTES, DAEMON_LOG_KEEP, DAEMON_LOG_CHECK_MS, DIST_BUILD, SWARM_BACKEND, SWARM_OUTBOX, SWARM_MAX_IN_FLIGHT, SWARM_CLAIM_INTERVAL_MS, SWARM_MAX_LOAD_FACTOR, SWARM_MIN_FREE_GB, SWARM_MAX_FD_LOAD_FACTOR, SWARM_MAX_CPU_BUSY, SWARM_CPU_WINDOW_MS, SWARM_CPU_SANITY_BUSY, SWARM_CPU_SANITY_LOAD_FACTOR, SWARM_CPU_SANITY_LAG_MS, SWARM_RELIEF_LOAD_FACTOR, SWARM_RELIEF_MIN_FREE_GB, SWARM_RELIEF_MAX_FD_LOAD_FACTOR, SWARM_RELIEF_CPU_BUSY, SWARM_RELIEF_COST_WINDOW_MS, SWARM_RELIEF_ALERT_PAUSES, SWARM_RELIEF_ALERT_LOST_MS, SWARM_RELIEF_ALERT_MIN_STEPS, SWARM_RELIEF_ALERT_SUSTAIN_MS, SWARM_LOW_DISK_GB, SWARM_REHYDRATE_MS, SWARM_DRONE_BRIDGE_MS, SWARM_PROD_HEARTBEAT_MS, SWARM_VERSION_CHECK_MS, SWARM_SWEEP_INTERVAL_MS, DRONE_CHANNEL_ENABLED, DRONE_CHANNEL_PORT, DRONE_CHANNEL_URL, DRONE_CHANNEL_SECRET_PATH, DRONE_CHANNEL_GRACE_MS, HEARTBEAT_PATH, HEARTBEAT_STALE_MS, SWARM_REPO, SWARM_SCAN_DEPTH, SWARM_REPO_PATHS, SWARM_SCAN_ROOTS_RAW, REPO_MAP_PATH, SWARM_REPO_MAP_MS, SWARM_REPO_SCAN_TTL_MS, TASKLESS_API, SWARM_SHOT_TIMEOUT_MS, TASKLESS_MCP_PATH, TASKLESS_TOKEN, TASKLESS_WORKSPACE, TASKLESS_WORKSPACE_SLUG, TASKLESS_TASK_URL_BASE, SWARM_VERIFY, SWARM_AUTO_REVIEW, SWARM_AUTO_VERIFY, REVIEW_CUTOFF_PATH, SWARM_REVIEW_CAP, SWARM_STORM_URL, WEB_PORT, WEB_REDIRECT_URI, SWARM_ANOMALY_RENOTIFY_MS, SWARM_ANOMALY_MAX_REPEATS, SWARM_ANOMALY_RUN_DOWN_WINDOW_MS, SWARM_ANOMALY_FAILED_SPIKE_COUNT, SWARM_ANOMALY_FAILED_SPIKE_WINDOW_MS, SWARM_ANOMALY_QUEUE_STALLED_MS, SWARM_ANOMALY_PR_STUCK_MERGE_MS, SWARM_ANOMALY_PR_NO_REVIEWER_MS, SWARM_ANOMALY_QUESTION_UNANSWERED_MS, SWARM_ANOMALY_OUTBOX_STUCK_MS, SWARM_ANOMALY_RESOURCE_GATE_STALL_MS, SWARM_ANOMALY_DEP_MISSING_MS, SWARM_WATCHDOG_STALL_MS;
|
|
2374
|
+
var DB_PATH, EXECUTOR, DRONE_HOME, DRONE_HOME_ISOLATION, DRONE_ISOLATION, WORKTREES_NOINDEX_DIR, WORKTREES_LEGACY_DIR, WORKTREES_DIR, RUN_LOGS_DIR, DAEMON_LOG_PATH, DAEMON_LOG_MAX_BYTES, DAEMON_LOG_KEEP, DAEMON_LOG_CHECK_MS, DIST_BUILD, SWARM_BACKEND, SWARM_OUTBOX, SWARM_MAX_IN_FLIGHT, SWARM_CLAIM_INTERVAL_MS, SWARM_MAX_LOAD_FACTOR, SWARM_MIN_FREE_GB, SWARM_MAX_FD_LOAD_FACTOR, SWARM_MAX_CPU_BUSY, SWARM_CPU_WINDOW_MS, SWARM_CPU_SANITY_BUSY, SWARM_CPU_SANITY_LOAD_FACTOR, SWARM_CPU_SANITY_LAG_MS, SWARM_RELIEF_LOAD_FACTOR, SWARM_RELIEF_MIN_FREE_GB, SWARM_RELIEF_MAX_FD_LOAD_FACTOR, SWARM_RELIEF_CPU_BUSY, SWARM_RELIEF_COST_WINDOW_MS, SWARM_RELIEF_ALERT_PAUSES, SWARM_RELIEF_ALERT_LOST_MS, SWARM_RELIEF_ALERT_MIN_STEPS, SWARM_RELIEF_ALERT_SUSTAIN_MS, SWARM_LOW_DISK_GB, SWARM_REHYDRATE_MS, SWARM_DRONE_BRIDGE_MS, SWARM_PROD_HEARTBEAT_MS, SWARM_VERSION_CHECK_MS, SWARM_SWEEP_INTERVAL_MS, DRONE_CHANNEL_ENABLED, DRONE_CHANNEL_PORT, DRONE_CHANNEL_URL, DRONE_CHANNEL_SECRET_PATH, DRONE_CHANNEL_GRACE_MS, HEARTBEAT_PATH, HEARTBEAT_STALE_MS, SWARM_REPO, SWARM_SCAN_DEPTH, SWARM_REPO_PATHS, SWARM_SCAN_ROOTS_RAW, REPO_MAP_PATH, SWARM_REPO_MAP_MS, SWARM_REPO_SCAN_TTL_MS, TASKLESS_API, SWARM_SHOT_TIMEOUT_MS, TASKLESS_MCP_PATH, TASKLESS_TOKEN, TASKLESS_WORKSPACE, TASKLESS_WORKSPACE_SLUG, TASKLESS_TASK_URL_BASE, SWARM_VERIFY, SWARM_AUTO_REVIEW, SWARM_AUTO_VERIFY, SWARM_MERGE_QUEUE, REVIEW_CUTOFF_PATH, SWARM_REVIEW_CAP, SWARM_STORM_URL, WEB_PORT, WEB_REDIRECT_URI, SWARM_ANOMALY_RENOTIFY_MS, SWARM_ANOMALY_MAX_REPEATS, SWARM_ANOMALY_RUN_DOWN_WINDOW_MS, SWARM_ANOMALY_FAILED_SPIKE_COUNT, SWARM_ANOMALY_FAILED_SPIKE_WINDOW_MS, SWARM_ANOMALY_QUEUE_STALLED_MS, SWARM_ANOMALY_PR_STUCK_MERGE_MS, SWARM_ANOMALY_PR_NO_REVIEWER_MS, SWARM_ANOMALY_QUESTION_UNANSWERED_MS, SWARM_ANOMALY_OUTBOX_STUCK_MS, SWARM_ANOMALY_RESOURCE_GATE_STALL_MS, SWARM_ANOMALY_DEP_MISSING_MS, SWARM_WATCHDOG_STALL_MS;
|
|
2276
2375
|
var init_config = __esm({
|
|
2277
2376
|
"src/config.ts"() {
|
|
2278
2377
|
"use strict";
|
|
@@ -2345,6 +2444,7 @@ var init_config = __esm({
|
|
|
2345
2444
|
SWARM_VERIFY = process.env.SWARM_VERIFY === "ci" ? "ci" : "local";
|
|
2346
2445
|
SWARM_AUTO_REVIEW = process.env.SWARM_AUTO_REVIEW !== "0";
|
|
2347
2446
|
SWARM_AUTO_VERIFY = process.env.SWARM_AUTO_VERIFY !== "0";
|
|
2447
|
+
SWARM_MERGE_QUEUE = process.env.SWARM_MERGE_QUEUE !== "0";
|
|
2348
2448
|
REVIEW_CUTOFF_PATH = process.env.SWARM_REVIEW_CUTOFF || join5(SWARM_HOME, "review-cutoff.json");
|
|
2349
2449
|
SWARM_REVIEW_CAP = Math.trunc(envNum("SWARM_REVIEW_CAP", 1));
|
|
2350
2450
|
SWARM_STORM_URL = process.env.SWARM_STORM_URL || "";
|
|
@@ -2390,12 +2490,12 @@ function isTransientResourceError(e) {
|
|
|
2390
2490
|
const code = e?.code;
|
|
2391
2491
|
return code === "ENFILE" || code === "EMFILE" || code === "EAGAIN";
|
|
2392
2492
|
}
|
|
2393
|
-
function logTransientSpawnError(
|
|
2493
|
+
function logTransientSpawnError(label2, e) {
|
|
2394
2494
|
if (isTransientResourceError(e)) {
|
|
2395
2495
|
const code = e.code;
|
|
2396
|
-
console.warn(`[overmind] ${
|
|
2496
|
+
console.warn(`[overmind] ${label2}: \u041E\u0421 \u043D\u0435 \u0434\u0430\u0451\u0442 \u0441\u043F\u0430\u0432\u043D\u0438\u0442\u044C \u043F\u0440\u043E\u0446\u0435\u0441\u0441\u044B (${code}) \u2014 \u043F\u0440\u043E\u043F\u0443\u0441\u043A\u0430\u044E \u0441\u0438\u0433\u043D\u0430\u043B \u044D\u0442\u043E\u0433\u043E \u0442\u0438\u043A\u0430, \u043D\u0435 \u043F\u0430\u0434\u0430\u044E`);
|
|
2397
2497
|
} else {
|
|
2398
|
-
console.warn(`[overmind] ${
|
|
2498
|
+
console.warn(`[overmind] ${label2} \u0441\u043E\u0440\u0432\u0430\u043B\u0441\u044F (\u043D\u0435\u0442 \u0434\u0430\u043D\u043D\u044B\u0445 \u0437\u0430 \u044D\u0442\u043E\u0442 \u0442\u0438\u043A): ${String(e)}`);
|
|
2399
2499
|
}
|
|
2400
2500
|
}
|
|
2401
2501
|
function resourcesOk(load1, cpus, freeGb, maxLoadFactor = SWARM_MAX_LOAD_FACTOR, minFreeGb = SWARM_MIN_FREE_GB, fdLoadRatio = null, maxFdLoadFactor = SWARM_MAX_FD_LOAD_FACTOR, cpuBusy = null, maxCpuBusy = SWARM_MAX_CPU_BUSY) {
|
|
@@ -2406,8 +2506,8 @@ function resourcesOk(load1, cpus, freeGb, maxLoadFactor = SWARM_MAX_LOAD_FACTOR,
|
|
|
2406
2506
|
}
|
|
2407
2507
|
function parseVmStatAvailableBytes(vmStatOut) {
|
|
2408
2508
|
const page = Number(vmStatOut.match(/page size of (\d+) bytes/)?.[1]) || 4096;
|
|
2409
|
-
const pages = (
|
|
2410
|
-
const m = vmStatOut.match(new RegExp(`Pages ${
|
|
2509
|
+
const pages = (label2) => {
|
|
2510
|
+
const m = vmStatOut.match(new RegExp(`Pages ${label2}:\\s+(\\d+)`));
|
|
2411
2511
|
return m ? Number(m[1]) : 0;
|
|
2412
2512
|
};
|
|
2413
2513
|
return (pages("free") + pages("inactive") + pages("speculative") + pages("purgeable")) * page;
|
|
@@ -2859,8 +2959,8 @@ function describeError(e, maxDepth = 4) {
|
|
|
2859
2959
|
const msg = (cur instanceof Error ? cur.message : typeof cur === "string" ? cur : String(cur)).trim();
|
|
2860
2960
|
const code = cur.code;
|
|
2861
2961
|
const codeText = code === void 0 || code === null ? "" : String(code);
|
|
2862
|
-
const
|
|
2863
|
-
if (
|
|
2962
|
+
const label2 = codeText && !msg.includes(codeText) ? `${msg} [code=${codeText}]` : msg;
|
|
2963
|
+
if (label2 && !parts.includes(label2)) parts.push(label2);
|
|
2864
2964
|
cur = cur.cause;
|
|
2865
2965
|
}
|
|
2866
2966
|
return parts.join(" \u2190 ") || String(e);
|
|
@@ -3981,37 +4081,37 @@ async function materializeAttachments(opts) {
|
|
|
3981
4081
|
let index = 0;
|
|
3982
4082
|
for (const ref of opts.refs) {
|
|
3983
4083
|
index++;
|
|
3984
|
-
const
|
|
4084
|
+
const label2 = ref.caption || ref.url;
|
|
3985
4085
|
const cls = classifyAttachment(ref);
|
|
3986
4086
|
if ("skip" in cls) {
|
|
3987
|
-
result.skipped.push(`${
|
|
4087
|
+
result.skipped.push(`${label2} \u2014 ${cls.skip}`);
|
|
3988
4088
|
continue;
|
|
3989
4089
|
}
|
|
3990
4090
|
if (result.files.length >= maxFiles) {
|
|
3991
|
-
result.skipped.push(`${
|
|
4091
|
+
result.skipped.push(`${label2} \u2014 \u0441\u0432\u0435\u0440\u0445 \u043B\u0438\u043C\u0438\u0442\u0430 \u0432 ${maxFiles} \u0444\u0430\u0439\u043B\u043E\u0432`);
|
|
3992
4092
|
continue;
|
|
3993
4093
|
}
|
|
3994
4094
|
if (ref.size != null && ref.size > maxFile) {
|
|
3995
|
-
result.skipped.push(`${
|
|
4095
|
+
result.skipped.push(`${label2} \u2014 ${mb(ref.size)} > \u043B\u0438\u043C\u0438\u0442\u0430 ${mb(maxFile)} \u043D\u0430 \u0444\u0430\u0439\u043B`);
|
|
3996
4096
|
continue;
|
|
3997
4097
|
}
|
|
3998
4098
|
let file = null;
|
|
3999
4099
|
try {
|
|
4000
4100
|
file = await opts.fetchFile(ref.url);
|
|
4001
4101
|
} catch (e) {
|
|
4002
|
-
result.skipped.push(`${
|
|
4102
|
+
result.skipped.push(`${label2} \u2014 \u043D\u0435 \u0441\u043A\u0430\u0447\u0430\u043B\u043E\u0441\u044C (${errText(e)})`);
|
|
4003
4103
|
continue;
|
|
4004
4104
|
}
|
|
4005
4105
|
if (!file) {
|
|
4006
|
-
result.skipped.push(`${
|
|
4106
|
+
result.skipped.push(`${label2} \u2014 \u043D\u0435 \u0441\u043A\u0430\u0447\u0430\u043B\u043E\u0441\u044C (\u043D\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u0430 \u0438\u043B\u0438 \u0444\u0430\u0439\u043B \u0443\u0434\u0430\u043B\u0451\u043D)`);
|
|
4007
4107
|
continue;
|
|
4008
4108
|
}
|
|
4009
4109
|
if (file.bytes.byteLength > maxFile) {
|
|
4010
|
-
result.skipped.push(`${
|
|
4110
|
+
result.skipped.push(`${label2} \u2014 ${mb(file.bytes.byteLength)} > \u043B\u0438\u043C\u0438\u0442\u0430 ${mb(maxFile)} \u043D\u0430 \u0444\u0430\u0439\u043B`);
|
|
4011
4111
|
continue;
|
|
4012
4112
|
}
|
|
4013
4113
|
if (total + file.bytes.byteLength > maxTotal) {
|
|
4014
|
-
result.skipped.push(`${
|
|
4114
|
+
result.skipped.push(`${label2} \u2014 \u043D\u0435 \u0432\u043B\u0435\u0437\u043B\u043E \u0432 \u043E\u0431\u0449\u0438\u0439 \u043B\u0438\u043C\u0438\u0442 ${mb(maxTotal)}`);
|
|
4015
4115
|
continue;
|
|
4016
4116
|
}
|
|
4017
4117
|
const name = attachmentFileName(index, ref.caption, attachmentExt(ref, file.contentType));
|
|
@@ -4022,7 +4122,7 @@ async function materializeAttachments(opts) {
|
|
|
4022
4122
|
}
|
|
4023
4123
|
await io.writeFile(join20(dir, name), file.bytes);
|
|
4024
4124
|
} catch (e) {
|
|
4025
|
-
result.skipped.push(`${
|
|
4125
|
+
result.skipped.push(`${label2} \u2014 \u043D\u0435 \u0437\u0430\u043F\u0438\u0441\u0430\u043B\u043E\u0441\u044C \u043D\u0430 \u0434\u0438\u0441\u043A (${errText(e)})`);
|
|
4026
4126
|
continue;
|
|
4027
4127
|
}
|
|
4028
4128
|
total += file.bytes.byteLength;
|
|
@@ -4606,6 +4706,29 @@ function makeTasklessClient(call, workspaceId, taskUrlBase, fetchFile, fetchImpl
|
|
|
4606
4706
|
const text = res.content?.find((c) => c.type === "text")?.text;
|
|
4607
4707
|
return typeof text === "string" && text.trim() ? text : null;
|
|
4608
4708
|
}
|
|
4709
|
+
async function proposeZoneNotes(input) {
|
|
4710
|
+
const res = await safeCall("swarm_zone_note_propose", {
|
|
4711
|
+
repoFullName: input.repoFullName,
|
|
4712
|
+
notes: input.notes,
|
|
4713
|
+
taskSlug: input.taskSlug,
|
|
4714
|
+
...input.by ? { by: input.by } : {},
|
|
4715
|
+
...input.prUrl ? { prUrl: input.prUrl } : {}
|
|
4716
|
+
});
|
|
4717
|
+
if (!res || res.isError) return null;
|
|
4718
|
+
const text = res.content?.find((c) => c.type === "text")?.text;
|
|
4719
|
+
return typeof text === "string" && text.trim() ? text : null;
|
|
4720
|
+
}
|
|
4721
|
+
async function confirmZoneNotes(input) {
|
|
4722
|
+
const res = await safeCall("swarm_zone_note_confirm", {
|
|
4723
|
+
repoFullName: input.repoFullName,
|
|
4724
|
+
notes: input.notes,
|
|
4725
|
+
...input.zone ? { zone: input.zone } : {},
|
|
4726
|
+
...input.by ? { by: input.by } : {}
|
|
4727
|
+
});
|
|
4728
|
+
if (!res || res.isError) return null;
|
|
4729
|
+
const text = res.content?.find((c) => c.type === "text")?.text;
|
|
4730
|
+
return typeof text === "string" && text.trim() ? text : null;
|
|
4731
|
+
}
|
|
4609
4732
|
async function resolveId(idOrSlug) {
|
|
4610
4733
|
const cached = idCache.get(idOrSlug);
|
|
4611
4734
|
if (cached) return cached;
|
|
@@ -4647,7 +4770,7 @@ function makeTasklessClient(call, workspaceId, taskUrlBase, fetchFile, fetchImpl
|
|
|
4647
4770
|
return await safeCall("update_task", { id, assigneeId: userId }) != null;
|
|
4648
4771
|
},
|
|
4649
4772
|
uploadShot: (file) => uploadShot(safeCall, file, fetchImpl),
|
|
4650
|
-
addComment: async (idOrSlug, body,
|
|
4773
|
+
addComment: async (idOrSlug, body, label2, attachments) => {
|
|
4651
4774
|
const id = await resolveId(idOrSlug);
|
|
4652
4775
|
if (!id) {
|
|
4653
4776
|
console.error(`[taskless] add_comment \u043F\u0440\u043E\u043F\u0443\u0449\u0435\u043D: \u0437\u0430\u0434\u0430\u0447\u0430 ${idOrSlug} \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u0430 (resolveId \u2192 null)`);
|
|
@@ -4666,7 +4789,7 @@ function makeTasklessClient(call, workspaceId, taskUrlBase, fetchFile, fetchImpl
|
|
|
4666
4789
|
body: parts[i],
|
|
4667
4790
|
// Метки роя — на КАЖДОЙ части: без них хвост отчёта выглядит в ленте задачи
|
|
4668
4791
|
// чужой репликой без автора (swarmKind/swarmDroneName рисуются чипами).
|
|
4669
|
-
...
|
|
4792
|
+
...label2 ?? {},
|
|
4670
4793
|
// TASWM-294: скрины — к ПЕРВОЙ части, к шапке отчёта. Разносить их по
|
|
4671
4794
|
// частям треда нельзя: человек открывает задачу и должен увидеть, как
|
|
4672
4795
|
// это выглядит, в том же комменте, что и «что сделано».
|
|
@@ -4688,6 +4811,8 @@ function makeTasklessClient(call, workspaceId, taskUrlBase, fetchFile, fetchImpl
|
|
|
4688
4811
|
reportAcceptanceCheck,
|
|
4689
4812
|
proposeRepoRules,
|
|
4690
4813
|
decideRepoRules,
|
|
4814
|
+
proposeZoneNotes,
|
|
4815
|
+
confirmZoneNotes,
|
|
4691
4816
|
createTask: async (input) => {
|
|
4692
4817
|
if (!input.projectId) {
|
|
4693
4818
|
throw new Error("createTask: projectId \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u0435\u043D \u2014 \u0430\u0432\u0442\u043E-\u0441\u043E\u0437\u0434\u0430\u043D\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u0440\u043E\u0435\u043C \u0431\u0435\u0437 \u043F\u0440\u043E\u0435\u043A\u0442\u0430 \u0437\u0430\u043F\u0440\u0435\u0449\u0435\u043D\u043E (TASWM-204)");
|
|
@@ -7641,6 +7766,27 @@ var SwarmClient = class _SwarmClient {
|
|
|
7641
7766
|
const sc = res.structuredContent ?? {};
|
|
7642
7767
|
return parsePendingRepoRules(sc.rules);
|
|
7643
7768
|
}
|
|
7769
|
+
/**
|
|
7770
|
+
* ПАМЯТЬ ЗОНЫ (TASWM-466) из того же swarm_repo_config — отдельное поле `zoneMemory`,
|
|
7771
|
+
* карта «зона → заметки», только принятое вердиктом. Демон кладёт заметки НУЖНОЙ зоны в
|
|
7772
|
+
* промпт дрона (см. zoneNotes.ts), поэтому отдаём карту КАК ЕСТЬ, сырым объектом: разбор
|
|
7773
|
+
* и выбор зоны — одно место, и оно рядом с рендером блока.
|
|
7774
|
+
*
|
|
7775
|
+
* Пустая карта — памяти нет / поля в ответе прода нет (прод старее демона) / repo не
|
|
7776
|
+
* смэплен / прод недоступен. Все четыре случая РАБОЧИЕ: промпт собирается как раньше.
|
|
7777
|
+
*/
|
|
7778
|
+
async repoZoneMemory(repoFullName) {
|
|
7779
|
+
let res;
|
|
7780
|
+
try {
|
|
7781
|
+
res = await this.call("swarm_repo_config", { repoFullName });
|
|
7782
|
+
} catch {
|
|
7783
|
+
return {};
|
|
7784
|
+
}
|
|
7785
|
+
if (res?.isError) return {};
|
|
7786
|
+
const sc = res.structuredContent ?? {};
|
|
7787
|
+
const m = sc.zoneMemory;
|
|
7788
|
+
return m && typeof m === "object" && !Array.isArray(m) ? m : {};
|
|
7789
|
+
}
|
|
7644
7790
|
/**
|
|
7645
7791
|
* Live КОМАНДЫ ПОДГОТОВКИ worktree из Taskless (TASWM-312): тот же swarm_repo_config по
|
|
7646
7792
|
* repoFullName — Project.swarmConfig.prepare. Настройка сильнее детекта демона (deps.ts):
|
|
@@ -10415,6 +10561,22 @@ async function prHeadBranch(prUrl, run = realRunner) {
|
|
|
10415
10561
|
return null;
|
|
10416
10562
|
}
|
|
10417
10563
|
}
|
|
10564
|
+
async function prBaseSync(prUrl, run = realRunner) {
|
|
10565
|
+
const m = prUrl.trim().match(/github\.com\/([^/\s]+)\/([^/\s]+)\/pull\/\d+/i);
|
|
10566
|
+
if (!isGithubPrUrl(prUrl) || !m) return null;
|
|
10567
|
+
const [, owner, repo] = m;
|
|
10568
|
+
try {
|
|
10569
|
+
const j = JSON.parse(await run(["pr", "view", prUrl, "--json", "baseRefName,headRefOid"]));
|
|
10570
|
+
const base3 = j.baseRefName;
|
|
10571
|
+
const head = j.headRefOid;
|
|
10572
|
+
if (!base3 || !head) return null;
|
|
10573
|
+
const out = await run(["api", `repos/${owner}/${repo}/compare/${base3}...${head}?per_page=1`, "--jq", ".behind_by"]);
|
|
10574
|
+
const behindBy = Number(out.trim());
|
|
10575
|
+
return Number.isFinite(behindBy) && behindBy >= 0 ? { behindBy, base: base3 } : null;
|
|
10576
|
+
} catch {
|
|
10577
|
+
return null;
|
|
10578
|
+
}
|
|
10579
|
+
}
|
|
10418
10580
|
async function openPrsForBranch(branch, repoDir, run = realRepoRunner) {
|
|
10419
10581
|
if (!branch || !repoDir) return [];
|
|
10420
10582
|
try {
|
|
@@ -10625,6 +10787,54 @@ init_shotUpload();
|
|
|
10625
10787
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
10626
10788
|
import { z } from "zod";
|
|
10627
10789
|
init_git();
|
|
10790
|
+
|
|
10791
|
+
// src/zoneNotes.ts
|
|
10792
|
+
init_src();
|
|
10793
|
+
function parseZoneMemory(raw, zone) {
|
|
10794
|
+
const key = normalizeZoneLabel(zone);
|
|
10795
|
+
if (!key || !raw || typeof raw !== "object" || Array.isArray(raw)) return [];
|
|
10796
|
+
const notes = raw[key];
|
|
10797
|
+
if (!Array.isArray(notes)) return [];
|
|
10798
|
+
const out = [];
|
|
10799
|
+
for (const item of notes) {
|
|
10800
|
+
if (!item || typeof item !== "object") continue;
|
|
10801
|
+
const n = item;
|
|
10802
|
+
const id = typeof n.id === "string" ? n.id : "";
|
|
10803
|
+
const claim = typeof n.claim === "string" ? n.claim.trim() : "";
|
|
10804
|
+
if (id && claim) out.push({ id, claim });
|
|
10805
|
+
}
|
|
10806
|
+
return out;
|
|
10807
|
+
}
|
|
10808
|
+
function normalizeZoneLabel(zone) {
|
|
10809
|
+
return (zone ?? "").trim().replace(/^area:/i, "").trim().toLowerCase();
|
|
10810
|
+
}
|
|
10811
|
+
function renderZoneMemoryBlock(zone, notes) {
|
|
10812
|
+
const label2 = normalizeZoneLabel(zone);
|
|
10813
|
+
if (!label2) return "";
|
|
10814
|
+
const head = notes.length ? [
|
|
10815
|
+
`\u{1F9E0} \u041F\u0410\u041C\u042F\u0422\u042C \u0417\u041E\u041D\u042B \`${label2}\` \u2014 \u0447\u0442\u043E \u0440\u043E\u0439 \u0443\u0436\u0435 \u0432\u044B\u044F\u0441\u043D\u0438\u043B \u043F\u0440\u043E \u044D\u0442\u043E\u0442 \u043A\u0443\u0441\u043E\u043A \u043A\u043E\u0434\u0430 (\u043F\u0440\u043E\u0432\u0435\u0440\u0435\u043D\u043E \u0440\u0435\u0432\u044C\u044E\u0435\u0440\u043E\u043C, \u043D\u0435 \u043F\u0435\u0440\u0435\u0441\u043A\u0430\u0437 \u043A\u043E\u0434\u0430):`,
|
|
10816
|
+
...notes.map((n) => `\u2022 [${n.id}] ${n.claim}`),
|
|
10817
|
+
"\u042D\u0442\u043E \u043F\u043E\u0434\u0441\u043A\u0430\u0437\u043A\u0438, \u0430 \u043D\u0435 \u0438\u0441\u0442\u0438\u043D\u0430 \u0432 \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0435\u0439 \u0438\u043D\u0441\u0442\u0430\u043D\u0446\u0438\u0438: \u0440\u0430\u0437\u043E\u0448\u043B\u043E\u0441\u044C \u0441 \u043A\u043E\u0434\u043E\u043C \u2014 \u0432\u0435\u0440\u044C \u043A\u043E\u0434\u0443 \u0438 \u0441\u043A\u0430\u0436\u0438 \u043E\u0431 \u044D\u0442\u043E\u043C \u0432 \u0441\u0434\u0430\u0447\u0435.",
|
|
10818
|
+
`\u041F\u0440\u0438\u0433\u043E\u0434\u0438\u043B\u0430\u0441\u044C \u0437\u0430\u043C\u0435\u0442\u043A\u0430 \u2014 \u043D\u0430\u0437\u043E\u0432\u0438 \u0435\u0451 \u0432 done: \`zone_notes_used: ["${notes[0].id}"]\` (id \u0438\u0437 \u0441\u043F\u0438\u0441\u043A\u0430 \u0432\u044B\u0448\u0435 \u0438\u043B\u0438 \u0441\u0430\u043C \u0442\u0435\u043A\u0441\u0442 \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F). \u042D\u0442\u043E \u0435\u0434\u0438\u043D\u0441\u0442\u0432\u0435\u043D\u043D\u043E\u0435, \u0447\u0435\u043C \u0437\u0430\u043C\u0435\u0442\u043A\u0430 \u0436\u0438\u0432\u0451\u0442: \u043F\u0430\u043C\u044F\u0442\u044C \u0437\u043E\u043D\u044B \u043E\u0433\u0440\u0430\u043D\u0438\u0447\u0435\u043D\u0430, \u0438 \u0432\u044B\u0442\u0435\u0441\u043D\u044F\u0435\u0442\u0441\u044F \u0442\u0430, \u0432 \u043A\u043E\u0442\u043E\u0440\u043E\u0439 \u0440\u043E\u0439 \u0434\u043E\u043B\u044C\u0448\u0435 \u0432\u0441\u0435\u0445 \u043D\u0435 \u0443\u0431\u0435\u0436\u0434\u0430\u043B\u0441\u044F. \u041D\u0435 \u043F\u0440\u0438\u0433\u043E\u0434\u0438\u043B\u043E\u0441\u044C \u043D\u0438\u0447\u0435\u0433\u043E \u2014 \u043D\u0435 \u043D\u0430\u0437\u044B\u0432\u0430\u0439 \u043D\u0438\u0447\u0435\u0433\u043E, \u044D\u0442\u043E \u043D\u043E\u0440\u043C\u0430\u043B\u044C\u043D\u044B\u0439 \u0438\u0441\u0445\u043E\u0434.`
|
|
10819
|
+
] : [`\u{1F9E0} \u041F\u0410\u041C\u042F\u0422\u042C \u0417\u041E\u041D\u042B \`${label2}\` \u043F\u0443\u0441\u0442\u0430 \u2014 \u0440\u043E\u0439 \u043F\u0440\u043E \u044D\u0442\u043E\u0442 \u043A\u0443\u0441\u043E\u043A \u043A\u043E\u0434\u0430 \u043F\u043E\u043A\u0430 \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0437\u0430\u043F\u0438\u0441\u0430\u043B.`];
|
|
10820
|
+
return [
|
|
10821
|
+
...head,
|
|
10822
|
+
`\u{1F9E0} \u0417\u0410\u041C\u0415\u0422\u041A\u0410 \u0412 \u041F\u0410\u041C\u042F\u0422\u042C \u0417\u041E\u041D\u042B \u2014 \u0432 \u043A\u043E\u043D\u0446\u0435 \u043F\u0440\u043E\u0433\u043E\u043D\u0430 \u043F\u0440\u0435\u0434\u043B\u043E\u0436\u0438 \u0434\u043E ${ZONE_NOTES_PER_RUN_MAX} \u0448\u0442\u0443\u043A: \`zone_notes: [{ zone: "${label2}", claim: "\u2026", why: "\u2026" }]\` (zone \u043C\u043E\u0436\u043D\u043E \u043D\u0435 \u0443\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u2014 \u0432\u043E\u0437\u044C\u043C\u0451\u0442\u0441\u044F \u0442\u0432\u043E\u044F). \u0427\u0422\u041E \u0433\u043E\u0434\u0438\u0442\u0441\u044F: \u0440\u0435\u0448\u0435\u043D\u0438\u0435 \u0441 \u043F\u0440\u0438\u0447\u0438\u043D\u043E\u0439 (\xAB\u043E\u0447\u0435\u0440\u0435\u0434\u044C \u0447\u0438\u0442\u0430\u044E\u0442 \u0438\u0437 \u043E\u0434\u043D\u043E\u0439 \u0442\u043E\u0447\u043A\u0438, \u043F\u043E\u0442\u043E\u043C\u0443 \u0447\u0442\u043E \u2026\xBB), \u0433\u0440\u0430\u0431\u043B\u0438 \u0441 \u0446\u0435\u043D\u043E\u0439 (\xAB\u043C\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u043D\u0430\u043A\u0430\u0442\u044B\u0432\u0430\u044E\u0442\u0441\u044F \u043D\u0435 \u0442\u0435\u043C, \u0447\u0435\u043C \u043A\u0430\u0436\u0435\u0442\u0441\u044F, \u2014 \u0441\u0442\u043E\u0438\u043B\u043E \u0447\u0430\u0441\u0430\xBB), \u043E\u0442\u0431\u0440\u043E\u0448\u0435\u043D\u043D\u044B\u0439 \u0432\u0430\u0440\u0438\u0430\u043D\u0442 \u0441 \u043F\u0440\u0438\u0447\u0438\u043D\u043E\u0439. \u0427\u0422\u041E \u041D\u0415 \u0433\u043E\u0434\u0438\u0442\u0441\u044F: \u0443\u0441\u0442\u0440\u043E\u0439\u0441\u0442\u0432\u043E \u043A\u043E\u0434\u0430 (\xAB\u0445\u0435\u043D\u0434\u043B\u0435\u0440 \u043B\u0435\u0436\u0438\u0442 \u0432 handlers.ts\xBB, \xAB\u044D\u0442\u0430 \u0444\u0443\u043D\u043A\u0446\u0438\u044F \u0434\u0435\u043B\u0430\u0435\u0442 \u0442\u043E-\u0442\u043E\xBB) \u2014 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0439 \u0434\u0440\u043E\u043D \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u0435\u0442 \u044D\u0442\u043E \u0441\u0430\u043C \u0438 \u0431\u044B\u0441\u0442\u0440\u0435\u0435, \u0447\u0435\u043C \u0442\u0432\u043E\u044E \u0437\u0430\u043C\u0435\u0442\u043A\u0443. \u0420\u0435\u0448\u0430\u0435\u0442 \u0440\u0435\u0432\u044C\u044E\u0435\u0440; \u043D\u0438\u0447\u0435\u0433\u043E \u0442\u0430\u043A\u043E\u0433\u043E \u043D\u0435 \u0431\u044B\u043B\u043E \u2014 \u043D\u0435 \u0432\u044B\u0434\u0443\u043C\u044B\u0432\u0430\u0439, \u043F\u0443\u0441\u0442\u043E\u0439 \u0441\u043F\u0438\u0441\u043E\u043A \u044D\u0442\u043E \u043D\u043E\u0440\u043C\u0430\u043B\u044C\u043D\u044B\u0439 \u0438\u0441\u0445\u043E\u0434 \u043F\u0440\u043E\u0433\u043E\u043D\u0430.`
|
|
10823
|
+
].join("\n");
|
|
10824
|
+
}
|
|
10825
|
+
function collectZoneNoteConfirmations(report) {
|
|
10826
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10827
|
+
const out = [];
|
|
10828
|
+
for (const raw of report.used ?? []) {
|
|
10829
|
+
const s = typeof raw === "string" ? raw.trim() : "";
|
|
10830
|
+
if (!s || seen.has(s)) continue;
|
|
10831
|
+
seen.add(s);
|
|
10832
|
+
out.push(s);
|
|
10833
|
+
}
|
|
10834
|
+
return out;
|
|
10835
|
+
}
|
|
10836
|
+
|
|
10837
|
+
// src/droneServer.ts
|
|
10628
10838
|
init_src();
|
|
10629
10839
|
|
|
10630
10840
|
// src/reviewCycle.ts
|
|
@@ -11014,11 +11224,26 @@ ${notFoundText}` : notFoundText }],
|
|
|
11014
11224
|
).optional().describe(
|
|
11015
11225
|
`\u041F\u0420\u0410\u0412\u0418\u041B\u041E \u041E \u0420\u0415\u041F\u041E\u0417\u0418\u0422\u041E\u0420\u0418\u0418, \u043A\u043E\u0442\u043E\u0440\u043E\u0433\u043E \u0432 \u043D\u0451\u043C \u043D\u0435 \u0437\u0430\u043F\u0438\u0441\u0430\u043D\u043E (TASWM-431) \u2014 \u043D\u0435 \u0431\u043E\u043B\u044C\u0448\u0435 ${DRONE_RULES_PER_RUN_MAX} \u0437\u0430 \u043F\u0440\u043E\u0433\u043E\u043D \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u0442\u043E, \u043E\u0431\u043E \u0447\u0442\u043E \u0442\u044B \u0420\u0415\u0410\u041B\u042C\u041D\u041E \u0441\u043F\u043E\u0442\u043A\u043D\u0443\u043B\u0441\u044F \u0438 \u043F\u043E\u0442\u0440\u0430\u0442\u0438\u043B \u0432\u0440\u0435\u043C\u044F (\xAB\u0438\u043D\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043E\u043D\u043D\u044B\u0435 \u0442\u0435\u0441\u0442\u044B \u0436\u0434\u0443\u0442 \u043F\u043E\u0441\u0442\u0433\u0440\u0435\u0441 \u043D\u0430 5433\xBB). \u041E\u0431\u0449\u0435\u0435 \u043C\u0435\u0441\u0442\u043E (\xAB\u0442\u0435\u0441\u0442\u044B \u0433\u043E\u043D\u044F\u044E\u0442\u0441\u044F \u0447\u0435\u0440\u0435\u0437 pnpm test\xBB) \u043F\u0440\u0430\u0432\u0438\u043B\u043E\u043C \u043D\u0435 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F. \u0423\u0436\u0435 \u0437\u0430\u043F\u0438\u0441\u0430\u043D\u043D\u043E\u0435 \u043E\u0442\u0441\u0435\u0435\u0442\u0441\u044F \u0441\u0430\u043C\u043E. \u0420\u0435\u0448\u0430\u0435\u0442 \u0440\u0435\u0432\u044C\u044E\u0435\u0440 \u0432 \u0441\u0432\u043E\u0451\u043C \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u0435.`
|
|
11016
11226
|
),
|
|
11227
|
+
// TASWM-466: память ЗОНЫ — то же, что правило репозитория, но адресат кусок кода.
|
|
11228
|
+
// Форму судит прод (там бюджет и дедуп), здесь схема свободная по той же причине,
|
|
11229
|
+
// что у rules: гейт в двух местах разъехался бы.
|
|
11230
|
+
zone_notes: z.array(
|
|
11231
|
+
z.object({
|
|
11232
|
+
zone: z.string().optional().describe("\u0437\u043E\u043D\u0430 \u043A\u043E\u0434\u0430 (area:*). \u041D\u0435 \u0443\u043A\u0430\u0437\u0430\u043D\u0430 \u2014 \u0432\u043E\u0437\u044C\u043C\u0451\u0442\u0441\u044F \u0437\u043E\u043D\u0430 \u0442\u0432\u043E\u0435\u0433\u043E \u043F\u0440\u043E\u0433\u043E\u043D\u0430"),
|
|
11233
|
+
claim: z.string().describe("\u0441\u0430\u043C\u043E \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435, \u043E\u0434\u043D\u043E\u0439 \u0444\u0440\u0430\u0437\u043E\u0439"),
|
|
11234
|
+
why: z.string().describe("\u043F\u043E\u0447\u0435\u043C\u0443 \u044D\u0442\u043E \u0442\u0430\u043A \u2014 \u0431\u0435\u0437 \u043F\u0440\u0438\u0447\u0438\u043D\u044B \u0437\u0430\u043C\u0435\u0442\u043A\u0430 \u043D\u0435 \u043F\u0440\u0438\u043D\u0438\u043C\u0430\u0435\u0442\u0441\u044F")
|
|
11235
|
+
})
|
|
11236
|
+
).optional().describe(
|
|
11237
|
+
`\u0417\u0410\u041C\u0415\u0422\u041A\u0410 \u0412 \u041F\u0410\u041C\u042F\u0422\u042C \u0417\u041E\u041D\u042B (TASWM-466) \u2014 \u043D\u0435 \u0431\u043E\u043B\u044C\u0448\u0435 ${ZONE_NOTES_PER_RUN_MAX} \u0437\u0430 \u043F\u0440\u043E\u0433\u043E\u043D: \u0440\u0435\u0448\u0435\u043D\u0438\u0435 \u0441 \u043F\u0440\u0438\u0447\u0438\u043D\u043E\u0439, \u0433\u0440\u0430\u0431\u043B\u0438 \u0441 \u0446\u0435\u043D\u043E\u0439, \u043E\u0442\u0431\u0440\u043E\u0448\u0435\u043D\u043D\u044B\u0439 \u0432\u0430\u0440\u0438\u0430\u043D\u0442 \u0441 \u043F\u0440\u0438\u0447\u0438\u043D\u043E\u0439. \u0423\u0441\u0442\u0440\u043E\u0439\u0441\u0442\u0432\u043E \u043A\u043E\u0434\u0430 (\xAB\u0445\u0435\u043D\u0434\u043B\u0435\u0440 \u043B\u0435\u0436\u0438\u0442 \u0442\u0430\u043C-\u0442\u043E\xBB) \u0437\u0430\u043C\u0435\u0442\u043A\u043E\u0439 \u041D\u0415 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F: \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0439 \u0434\u0440\u043E\u043D \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u0435\u0442 \u044D\u0442\u043E \u0441\u0430\u043C \u0438 \u0431\u044B\u0441\u0442\u0440\u0435\u0435. \u0420\u0435\u0448\u0430\u0435\u0442 \u0440\u0435\u0432\u044C\u044E\u0435\u0440; \u0443\u0436\u0435 \u0437\u0430\u043F\u0438\u0441\u0430\u043D\u043D\u043E\u0435 \u043E\u0442\u0441\u0435\u0435\u0442\u0441\u044F \u0441\u0430\u043C\u043E.`
|
|
11238
|
+
),
|
|
11239
|
+
zone_notes_used: z.array(z.string()).optional().describe(
|
|
11240
|
+
"\u0417\u0410\u041C\u0415\u0422\u041A\u0418 \u0417\u041E\u041D\u042B, \u041A\u041E\u0422\u041E\u0420\u042B\u0415 \u041F\u0420\u0418\u0413\u041E\u0414\u0418\u041B\u0418\u0421\u042C (TASWM-466): id \u0438\u0437 \u0431\u043B\u043E\u043A\u0430 \xAB\u043F\u0430\u043C\u044F\u0442\u044C \u0437\u043E\u043D\u044B\xBB \u0432 \u0442\u0432\u043E\u0451\u043C \u043F\u0440\u043E\u043C\u043F\u0442\u0435 (\u0438\u043B\u0438 \u0441\u0430\u043C \u0442\u0435\u043A\u0441\u0442 \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F). \u0418\u043C \u043F\u043E\u0434\u043D\u0438\u043C\u0435\u0442\u0441\u044F \u0441\u0447\u0451\u0442\u0447\u0438\u043A \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0439 \u2014 \u044D\u0442\u043E \u0435\u0434\u0438\u043D\u0441\u0442\u0432\u0435\u043D\u043D\u043E\u0435, \u0447\u0435\u043C \u0437\u0430\u043C\u0435\u0442\u043A\u0430 \u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044F \u0432 \u043E\u0433\u0440\u0430\u043D\u0438\u0447\u0435\u043D\u043D\u043E\u0439 \u043F\u0430\u043C\u044F\u0442\u0438 \u0437\u043E\u043D\u044B. \u041D\u0435 \u043F\u0440\u0438\u0433\u043E\u0434\u0438\u043B\u043E\u0441\u044C \u043D\u0438\u0447\u0435\u0433\u043E \u2014 \u043D\u0435 \u043D\u0430\u0437\u044B\u0432\u0430\u0439 \u043D\u0438\u0447\u0435\u0433\u043E."
|
|
11241
|
+
),
|
|
11017
11242
|
rule_verdicts: z.array(z.object({ field: z.enum([...RULE_FIELDS]), apply: z.boolean() })).optional().describe(
|
|
11018
11243
|
"\u0422\u041E\u041B\u042C\u041A\u041E \u0414\u041B\u042F \u0420\u0415\u0412\u042C\u042E\u0415\u0420\u0410 (TASWM-431): \u0440\u0435\u0448\u0435\u043D\u0438\u0435 \u043F\u043E \u043F\u0440\u0430\u0432\u0438\u043B\u0430\u043C, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u043F\u0440\u0438\u043D\u0451\u0441 \u0434\u0440\u043E\u043D (\u043E\u043D\u0438 \u043F\u0435\u0440\u0435\u0447\u0438\u0441\u043B\u0435\u043D\u044B \u0432 \u0442\u0432\u043E\u0451\u043C \u043F\u0440\u043E\u043C\u043F\u0442\u0435). apply=true \u2014 \u043F\u0440\u0430\u0432\u0438\u043B\u043E \u043D\u0430\u0441\u0442\u043E\u044F\u0449\u0435\u0435, apply=false \u2014 \u043E\u0442\u043F\u0438\u0441\u043A\u0430, \u0441\u043D\u044F\u0442\u044C. verify/conventions/brief \u043F\u0440\u0438\u043C\u0435\u043D\u044F\u0442\u0441\u044F \u0432 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0443 \u0441\u0440\u0430\u0437\u0443, env/zones/spine \u0443\u0439\u0434\u0443\u0442 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443 \u0432 \u043B\u044E\u0431\u043E\u043C \u0441\u043B\u0443\u0447\u0430\u0435."
|
|
11019
11244
|
)
|
|
11020
11245
|
},
|
|
11021
|
-
guard(async ({ pr_url, verdict, summary, screenshots, rules, rule_verdicts }) => {
|
|
11246
|
+
guard(async ({ pr_url, verdict, summary, screenshots, rules, rule_verdicts, zone_notes, zone_notes_used }) => {
|
|
11022
11247
|
const run = await store.myRun();
|
|
11023
11248
|
let repoFullNameCache = null;
|
|
11024
11249
|
const repoFullNameOnce = () => repoFullNameCache ??= remoteRepoFullName(opts.worktree ?? process.cwd()).catch(() => null);
|
|
@@ -11051,6 +11276,46 @@ ${notFoundText}` : notFoundText }],
|
|
|
11051
11276
|
return `
|
|
11052
11277
|
|
|
11053
11278
|
\u{1F4CC} ${line}`;
|
|
11279
|
+
};
|
|
11280
|
+
const zoneMemoryNote = async (taskSlug) => {
|
|
11281
|
+
const used = collectZoneNoteConfirmations({ used: zone_notes_used });
|
|
11282
|
+
if (!zone_notes?.length && used.length === 0) return "";
|
|
11283
|
+
const zone = normalizeZoneLabel(run?.area);
|
|
11284
|
+
const repoFullName = await repoFullNameOnce();
|
|
11285
|
+
if (!repoFullName) {
|
|
11286
|
+
await store.addEvent(null, "step", "\u0437\u0430\u043C\u0435\u0442\u043A\u0438 \u043E \u0437\u043E\u043D\u0435 \u043D\u0435 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u044B: \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0438\u0442\u044C owner/repo \u043F\u043E origin");
|
|
11287
|
+
return "\n\n\u26A0\uFE0F \u0417\u0430\u043C\u0435\u0442\u043A\u0438 \u043E \u0437\u043E\u043D\u0435 \u043D\u0435 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u044B: \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0438\u0442\u044C owner/repo.";
|
|
11288
|
+
}
|
|
11289
|
+
const lines = [];
|
|
11290
|
+
if (zone_notes?.length) {
|
|
11291
|
+
if (!opts.taskless?.proposeZoneNotes) lines.push("\u0437\u0430\u043C\u0435\u0442\u043A\u0430 \u043E \u0437\u043E\u043D\u0435 \u043D\u0435 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0430: Taskless \u043D\u0435 \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0451\u043D");
|
|
11292
|
+
else if (!taskSlug) lines.push("\u0437\u0430\u043C\u0435\u0442\u043A\u0430 \u043E \u0437\u043E\u043D\u0435 \u043D\u0435 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0430: \u0441\u043B\u0430\u0433 \u0437\u0430\u0434\u0430\u0447\u0438 \u043D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043D");
|
|
11293
|
+
else {
|
|
11294
|
+
const addressed = zone_notes.map((n) => ({ zone: normalizeZoneLabel(n.zone) || zone, claim: n.claim, why: n.why })).filter((n) => n.zone);
|
|
11295
|
+
if (addressed.length < zone_notes.length) lines.push("\u0437\u0430\u043C\u0435\u0442\u043A\u0430 \u0431\u0435\u0437 \u0437\u043E\u043D\u044B \u043D\u0435 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0430: \u0443 \u043F\u0440\u043E\u0433\u043E\u043D\u0430 \u043D\u0435\u0442 area, \u0430 \u0432 \u0441\u0430\u043C\u043E\u0439 \u0437\u0430\u043C\u0435\u0442\u043A\u0435 \u0437\u043E\u043D\u0430 \u043D\u0435 \u043D\u0430\u0437\u0432\u0430\u043D\u0430");
|
|
11296
|
+
if (addressed.length > 0) {
|
|
11297
|
+
const text = await opts.taskless.proposeZoneNotes({
|
|
11298
|
+
repoFullName,
|
|
11299
|
+
notes: addressed,
|
|
11300
|
+
taskSlug,
|
|
11301
|
+
...run?.name ? { by: run.name } : {},
|
|
11302
|
+
prUrl: pr_url
|
|
11303
|
+
}).catch((e) => `\u043D\u0435 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0430: ${e instanceof Error ? e.message : String(e)}`);
|
|
11304
|
+
lines.push(text ?? "\u0437\u0430\u043C\u0435\u0442\u043A\u0430 \u043E \u0437\u043E\u043D\u0435 \u043D\u0435 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0430 (\u043F\u0440\u043E\u0434 \u043E\u0442\u043A\u0430\u0437\u0430\u043B \u0438\u043B\u0438 \u0442\u0443\u043B \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D)");
|
|
11305
|
+
}
|
|
11306
|
+
}
|
|
11307
|
+
}
|
|
11308
|
+
if (used.length > 0) {
|
|
11309
|
+
if (!opts.taskless?.confirmZoneNotes) lines.push("\u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435 \u0437\u0430\u043C\u0435\u0442\u043E\u043A \u043D\u0435 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u043E: Taskless \u043D\u0435 \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0451\u043D");
|
|
11310
|
+
else {
|
|
11311
|
+
const text = await opts.taskless.confirmZoneNotes({ repoFullName, notes: used, ...zone ? { zone } : {}, ...run?.name ? { by: run.name } : {} }).catch((e) => `\u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435 \u043D\u0435 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u043E: ${e instanceof Error ? e.message : String(e)}`);
|
|
11312
|
+
lines.push(text ?? "\u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435 \u0437\u0430\u043C\u0435\u0442\u043E\u043A \u043D\u0435 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u043E (\u043F\u0440\u043E\u0434 \u043E\u0442\u043A\u0430\u0437\u0430\u043B \u0438\u043B\u0438 \u0442\u0443\u043B \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D)");
|
|
11313
|
+
}
|
|
11314
|
+
}
|
|
11315
|
+
for (const line of lines) await store.addEvent(null, "step", `\u043F\u0430\u043C\u044F\u0442\u044C \u0437\u043E\u043D\u044B: ${line}`);
|
|
11316
|
+
return lines.length ? `
|
|
11317
|
+
|
|
11318
|
+
\u{1F9E0} ${lines.join("; ")}` : "";
|
|
11054
11319
|
};
|
|
11055
11320
|
const reportSlug = (slug) => opts.expectedTaskSlug ?? slug;
|
|
11056
11321
|
const uploadShots = async () => {
|
|
@@ -11252,15 +11517,16 @@ ${report}${shots.warning}`,
|
|
|
11252
11517
|
await store.addEvent(null, "pr_opened", pr_url);
|
|
11253
11518
|
await postReport(reportSlug(run.task_slug), t.cycle ?? run.review_cycle ?? 0);
|
|
11254
11519
|
const rulesNote = await offerRules(reportSlug(run.task_slug));
|
|
11520
|
+
const zoneNote = await zoneMemoryNote(reportSlug(run.task_slug));
|
|
11255
11521
|
if (t.isFixIteration) {
|
|
11256
11522
|
await store.addEvent(
|
|
11257
11523
|
null,
|
|
11258
11524
|
"step",
|
|
11259
11525
|
`\u0444\u0438\u043A\u0441-\u0438\u0442\u0435\u0440\u0430\u0446\u0438\u044F: \u043D\u043E\u0432\u044B\u0435 \u043A\u043E\u043C\u043C\u0438\u0442\u044B \u043F\u043E\u0441\u043B\u0435 \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u0430 \xAB\u043D\u0443\u0436\u043D\u044B \u043F\u0440\u0430\u0432\u043A\u0438\xBB \u2014 \u043E\u0442\u043A\u0440\u044B\u0442 \u0446\u0438\u043A\u043B \u0440\u0435-\u0440\u0435\u0432\u044C\u044E #${t.cycle}`
|
|
11260
11526
|
);
|
|
11261
|
-
return { content: [{ type: "text", text: `\u043F\u0440\u0438\u043D\u044F\u0442\u043E, \u0443\u0448\u043B\u043E \u043D\u0430 \u0440\u0435-\u0440\u0435\u0432\u044C\u044E (\u0444\u0438\u043A\u0441-\u0438\u0442\u0435\u0440\u0430\u0446\u0438\u044F)${shotsNote(shots)}${rulesNote}` }] };
|
|
11527
|
+
return { content: [{ type: "text", text: `\u043F\u0440\u0438\u043D\u044F\u0442\u043E, \u0443\u0448\u043B\u043E \u043D\u0430 \u0440\u0435-\u0440\u0435\u0432\u044C\u044E (\u0444\u0438\u043A\u0441-\u0438\u0442\u0435\u0440\u0430\u0446\u0438\u044F)${shotsNote(shots)}${rulesNote}${zoneNote}` }] };
|
|
11262
11528
|
}
|
|
11263
|
-
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}` }] };
|
|
11529
|
+
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}` }] };
|
|
11264
11530
|
}
|
|
11265
11531
|
await store.updateRun(null, { status: "review", pr_url, ...branchFix?.patch ?? {} });
|
|
11266
11532
|
await store.addEvent(null, "pr_opened", pr_url);
|
|
@@ -11268,7 +11534,8 @@ ${report}${shots.warning}`,
|
|
|
11268
11534
|
if (fallbackSlug) await postReport(fallbackSlug, void 0);
|
|
11269
11535
|
else await store.addEvent(null, "step", `\u043E\u0442\u0447\u0451\u0442 \u0434\u0440\u043E\u043D\u0430 (\u0437\u0430\u0434\u0430\u0447\u0430 \u043D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u0430 \u2014 \u043F\u0440\u043E\u0433\u043E\u043D\u0430 \u043D\u0435\u0442 \u0432 \u0441\u0442\u043E\u0440\u0435): ${report}`);
|
|
11270
11536
|
const fallbackRulesNote = await offerRules(fallbackSlug);
|
|
11271
|
-
|
|
11537
|
+
const fallbackZoneNote = await zoneMemoryNote(fallbackSlug);
|
|
11538
|
+
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)}${fallbackRulesNote}${fallbackZoneNote}` }] };
|
|
11272
11539
|
}
|
|
11273
11540
|
await store.updateRun(null, { status: "done" });
|
|
11274
11541
|
await store.addEvent(null, "done", pr_url ? `\u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u043E \u0431\u0435\u0437 GitHub-PR (${pr_url})` : "\u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u043E \u0431\u0435\u0437 GitHub-PR");
|
|
@@ -12346,6 +12613,11 @@ function makeDroneCapReader(opts) {
|
|
|
12346
12613
|
|
|
12347
12614
|
// src/mergeGate.ts
|
|
12348
12615
|
init_src();
|
|
12616
|
+
|
|
12617
|
+
// src/mergeQueue.ts
|
|
12618
|
+
init_src();
|
|
12619
|
+
|
|
12620
|
+
// src/prNumber.ts
|
|
12349
12621
|
function prNumberOf(ref) {
|
|
12350
12622
|
const s = (ref || "").trim();
|
|
12351
12623
|
if (!s) return null;
|
|
@@ -12354,6 +12626,79 @@ function prNumberOf(ref) {
|
|
|
12354
12626
|
const bare = s.match(/^#?(\d+)$/);
|
|
12355
12627
|
return bare ? Number(bare[1]) : null;
|
|
12356
12628
|
}
|
|
12629
|
+
|
|
12630
|
+
// src/mergeQueue.ts
|
|
12631
|
+
var TERMINAL2 = /* @__PURE__ */ new Set(["done", "failed", "stalled", "stopped", "superseded", "returned"]);
|
|
12632
|
+
function isMergeCandidate(r) {
|
|
12633
|
+
return !!r.pr_url && r.reviews_run_id == null && r.verifies_run_id == null && r.resolves_run_id == null && !TERMINAL2.has(r.status) && prNumberOf(r.pr_url) != null;
|
|
12634
|
+
}
|
|
12635
|
+
function mergeQueueCandidates(runs, repo) {
|
|
12636
|
+
const byPr = /* @__PURE__ */ new Map();
|
|
12637
|
+
for (const r of runs) {
|
|
12638
|
+
if (r.repo !== repo || !isMergeCandidate(r)) continue;
|
|
12639
|
+
const num = prNumberOf(r.pr_url);
|
|
12640
|
+
const seen = byPr.get(num);
|
|
12641
|
+
if (!seen || r.id > seen.id) byPr.set(num, r);
|
|
12642
|
+
}
|
|
12643
|
+
return [...byPr.values()];
|
|
12644
|
+
}
|
|
12645
|
+
var BASE_TTL_MS = 2e4;
|
|
12646
|
+
function makeMergeQueueResolver(deps) {
|
|
12647
|
+
const memo = /* @__PURE__ */ new Map();
|
|
12648
|
+
const evaluate = async (e, prUrl, ready) => {
|
|
12649
|
+
const now = Date.now();
|
|
12650
|
+
let cached = memo.get(prUrl);
|
|
12651
|
+
const ttl = deps.ttlMs ?? BASE_TTL_MS;
|
|
12652
|
+
if (!cached || now - cached.at >= ttl) {
|
|
12653
|
+
const base3 = await deps.baseSync(prUrl).catch(() => null);
|
|
12654
|
+
let checks = "none";
|
|
12655
|
+
if (base3?.behindBy === 0 && deps.checks) {
|
|
12656
|
+
const ci = await deps.checks(prUrl).catch(() => null);
|
|
12657
|
+
checks = ci ? ci.bucket : null;
|
|
12658
|
+
}
|
|
12659
|
+
cached = { at: now, base: base3, checks };
|
|
12660
|
+
memo.set(prUrl, cached);
|
|
12661
|
+
}
|
|
12662
|
+
return computeMergeQueue({ entry: e, ready, behindBy: cached.base ? cached.base.behindBy : null, checks: cached.checks });
|
|
12663
|
+
};
|
|
12664
|
+
return async (run) => {
|
|
12665
|
+
if (!deps.baseSync || !run.pr_url) return null;
|
|
12666
|
+
const num = prNumberOf(run.pr_url);
|
|
12667
|
+
if (num == null) return null;
|
|
12668
|
+
const candidates = mergeQueueCandidates(deps.listRuns(), run.repo);
|
|
12669
|
+
const mine = candidates.find((c) => prNumberOf(c.pr_url) === num);
|
|
12670
|
+
if (!mine) return null;
|
|
12671
|
+
const ready = [];
|
|
12672
|
+
const urlOf = /* @__PURE__ */ new Map();
|
|
12673
|
+
for (const c of candidates) {
|
|
12674
|
+
if (!await deps.gateAllows(c).catch(() => false)) continue;
|
|
12675
|
+
ready.push(entryOf(c));
|
|
12676
|
+
urlOf.set(c.id, c.pr_url);
|
|
12677
|
+
}
|
|
12678
|
+
const entry = entryOf(mine);
|
|
12679
|
+
if (!ready.some((e) => e.runId === entry.runId)) return null;
|
|
12680
|
+
let queue = orderMergeQueue(ready);
|
|
12681
|
+
while (queue.length > 1 && queue[0].runId !== entry.runId) {
|
|
12682
|
+
const head = queue[0];
|
|
12683
|
+
const headUrl = urlOf.get(head.runId);
|
|
12684
|
+
const decision = await evaluate(head, headUrl, queue);
|
|
12685
|
+
if (decision.code !== "checks_red") break;
|
|
12686
|
+
queue = queue.slice(1);
|
|
12687
|
+
}
|
|
12688
|
+
if (queue[0].runId !== entry.runId) {
|
|
12689
|
+
return computeMergeQueue({ entry, ready: queue, behindBy: null, checks: "none" });
|
|
12690
|
+
}
|
|
12691
|
+
return evaluate(entry, mine.pr_url, queue);
|
|
12692
|
+
};
|
|
12693
|
+
}
|
|
12694
|
+
function entryOf(r) {
|
|
12695
|
+
return { runId: r.id, prNumber: prNumberOf(r.pr_url), slug: r.task_slug };
|
|
12696
|
+
}
|
|
12697
|
+
function needsBaseRefresh(d) {
|
|
12698
|
+
return d?.code === "base_stale";
|
|
12699
|
+
}
|
|
12700
|
+
|
|
12701
|
+
// src/mergeGate.ts
|
|
12357
12702
|
function findRunByPr(runs, ref) {
|
|
12358
12703
|
const num = prNumberOf(ref);
|
|
12359
12704
|
if (num == null) return null;
|
|
@@ -12365,17 +12710,34 @@ function findRunByPr(runs, ref) {
|
|
|
12365
12710
|
return best;
|
|
12366
12711
|
}
|
|
12367
12712
|
function makeMergeGateResolver(deps) {
|
|
12368
|
-
return
|
|
12369
|
-
|
|
12370
|
-
|
|
12713
|
+
return makeMergeGateParts(deps).gate;
|
|
12714
|
+
}
|
|
12715
|
+
function makeMergeGateParts(deps) {
|
|
12716
|
+
const gateFor = async (run) => {
|
|
12371
12717
|
const autoReview = deps.autoReview ? await deps.autoReview(run.repo).catch(() => deps.fallbackAutoReview) : deps.fallbackAutoReview;
|
|
12372
|
-
|
|
12718
|
+
return computeMergeGate({
|
|
12373
12719
|
hasRun: true,
|
|
12374
12720
|
autoReview,
|
|
12375
12721
|
reviewVerdict: run.review_verdict,
|
|
12376
12722
|
autoVerify: deps.autoVerify === true,
|
|
12377
12723
|
verifyVerdict: run.verify_verdict ?? null
|
|
12378
12724
|
});
|
|
12725
|
+
};
|
|
12726
|
+
const queueFor = makeMergeQueueResolver({
|
|
12727
|
+
listRuns: deps.listRuns,
|
|
12728
|
+
gateAllows: async (r) => (await gateFor(r)).allowed,
|
|
12729
|
+
...deps.baseSync ? { baseSync: deps.baseSync } : {},
|
|
12730
|
+
...deps.checks ? { checks: deps.checks } : {},
|
|
12731
|
+
...deps.ttlMs != null ? { ttlMs: deps.ttlMs } : {}
|
|
12732
|
+
});
|
|
12733
|
+
const gate = async (ref) => {
|
|
12734
|
+
const run = findRunByPr(deps.listRuns(), ref);
|
|
12735
|
+
if (!run) {
|
|
12736
|
+
return { ...computeMergeDecision(computeMergeGate({ hasRun: false, autoReview: false, reviewVerdict: null }), null), run: null };
|
|
12737
|
+
}
|
|
12738
|
+
const accept = await gateFor(run);
|
|
12739
|
+
const queue = accept.allowed && accept.code !== "unknown_pr" ? await queueFor(run) : null;
|
|
12740
|
+
const decision = computeMergeDecision(accept, queue);
|
|
12379
12741
|
return {
|
|
12380
12742
|
...decision,
|
|
12381
12743
|
run: {
|
|
@@ -12388,6 +12750,7 @@ function makeMergeGateResolver(deps) {
|
|
|
12388
12750
|
}
|
|
12389
12751
|
};
|
|
12390
12752
|
};
|
|
12753
|
+
return { gate, queue: queueFor };
|
|
12391
12754
|
}
|
|
12392
12755
|
|
|
12393
12756
|
// src/envGate.ts
|
|
@@ -12828,7 +13191,7 @@ async function changedPaths(worktree, opts = {}) {
|
|
|
12828
13191
|
// package.json
|
|
12829
13192
|
var package_default = {
|
|
12830
13193
|
name: "@taskless-app/swarm",
|
|
12831
|
-
version: "0.6.
|
|
13194
|
+
version: "0.6.19",
|
|
12832
13195
|
type: "module",
|
|
12833
13196
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
12834
13197
|
keywords: [
|
|
@@ -12878,7 +13241,7 @@ var package_default = {
|
|
|
12878
13241
|
execa: "^10.0.0",
|
|
12879
13242
|
zod: "3.25.76"
|
|
12880
13243
|
},
|
|
12881
|
-
gitHead: "
|
|
13244
|
+
gitHead: "a61c26b5e254ef5383d918f14a9f6e8e8a09904a"
|
|
12882
13245
|
};
|
|
12883
13246
|
|
|
12884
13247
|
// src/version.ts
|
|
@@ -14581,8 +14944,8 @@ async function executeHostCommands(opts) {
|
|
|
14581
14944
|
}
|
|
14582
14945
|
async function executeOne(cmd, opts) {
|
|
14583
14946
|
const { effects, ack, statePath } = opts;
|
|
14584
|
-
const
|
|
14585
|
-
effects.narrate(`\u{1F4DF} \u041A\u043E\u043C\u0430\u043D\u0434\u0430 \u0438\u0437 Taskless: ${
|
|
14947
|
+
const label2 = hostCommandLabel(cmd);
|
|
14948
|
+
effects.narrate(`\u{1F4DF} \u041A\u043E\u043C\u0430\u043D\u0434\u0430 \u0438\u0437 Taskless: ${label2}`);
|
|
14586
14949
|
try {
|
|
14587
14950
|
switch (cmd.kind) {
|
|
14588
14951
|
case "pause":
|
|
@@ -15465,6 +15828,14 @@ function lastConflictAttemptMs(db, runId) {
|
|
|
15465
15828
|
if (!evs.length) return null;
|
|
15466
15829
|
return Date.parse(evs[evs.length - 1].at.replace(" ", "T") + "Z");
|
|
15467
15830
|
}
|
|
15831
|
+
async function needsBaseRefreshNow(deps, run, stormActive, now) {
|
|
15832
|
+
if (!deps.mergeQueue || !deps.resolveConflict || stormActive) return false;
|
|
15833
|
+
if (deps.db.activeResolverFor(run.id)) return false;
|
|
15834
|
+
if (deps.db.resolverCountFor(run.id) >= RESOLVE_LIMIT) return false;
|
|
15835
|
+
const last = lastConflictAttemptMs(deps.db, run.id);
|
|
15836
|
+
if (last != null && now - last < CONFLICT_RESOLVE_COOLDOWN_MS) return false;
|
|
15837
|
+
return needsBaseRefresh(await deps.mergeQueue(run).catch(() => null));
|
|
15838
|
+
}
|
|
15468
15839
|
function lastCiCheckMs(db, runId) {
|
|
15469
15840
|
const evs = db.events(runId).filter((e) => e.kind === "ci_wake" || e.kind === "ci_checked");
|
|
15470
15841
|
if (!evs.length) return null;
|
|
@@ -15812,7 +16183,7 @@ ${priorReview}` : `\u0417\u0430\u043C\u0435\u0447\u0430\u043D\u0438\u044F \u2014
|
|
|
15812
16183
|
}
|
|
15813
16184
|
var HERO_CONTINUE_NUDGE = "\u0422\u0435\u0431\u044F \u0440\u0430\u0437\u0431\u0443\u0434\u0438\u043B\u0438, \u0413\u0435\u0440\u043E\u0439: \u0432 \u043E\u0442\u0440\u044F\u0434\u0435 \u0447\u0442\u043E-\u0442\u043E \u043F\u0440\u043E\u0438\u0437\u043E\u0448\u043B\u043E (\u0434\u0440\u043E\u043D \u0437\u0430\u0434\u0430\u043B \u0432\u043E\u043F\u0440\u043E\u0441, \u0441\u0434\u0430\u043B PR \u0438\u043B\u0438 \u0443\u043C\u0435\u0440) \u2014 \u043B\u0438\u0431\u043E \u0442\u0435\u0431\u044F \u043F\u043E\u0437\u0432\u0430\u043B \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440. \u0422\u044B headless, \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0430\u0435\u0448\u044C \u0422\u041E\u0422 \u0416\u0415 \u044D\u043F\u0438\u043A: \u0443\u0441\u0442\u0430\u0432 \u0438 \u0442\u0435\u043B\u043E \u044D\u043F\u0438\u043A\u0430 \u0443\u0436\u0435 \u0432 \u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442\u0435 \u043F\u0440\u043E\u0448\u043B\u043E\u0439 \u0441\u0435\u0441\u0441\u0438\u0438. \u0413\u043B\u044F\u043D\u044C \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435 \u043E\u0442\u0440\u044F\u0434\u0430 (squad_status) \u0438 \u0440\u0430\u0437\u0431\u0435\u0440\u0438\u0441\u044C, \u0447\u0442\u043E \u0438\u0437\u043C\u0435\u043D\u0438\u043B\u043E\u0441\u044C: \u0442\u0435\u0445\u043D\u0438\u0447\u0435\u0441\u043A\u0438\u0435 \u0432\u043E\u043F\u0440\u043E\u0441\u044B \u0434\u0440\u043E\u043D\u043E\u0432 \u0437\u0430\u043A\u0440\u044B\u0432\u0430\u0439 answer_drone; \u043F\u0440\u043E\u0434\u0443\u043A\u0442\u043E\u0432\u043E\u0435/\u0434\u0438\u0437\u0430\u0439\u043D/scope \u2014 \u044D\u0441\u043A\u0430\u043B\u0438\u0440\u0443\u0439 \u0447\u0435\u0440\u0435\u0437 ask. \u041A\u043E\u0434 \u043D\u0435 \u043F\u0438\u0448\u0438, PR \u043D\u0435 \u043C\u0435\u0440\u0436\u0438, done \u041D\u0415 \u0437\u043E\u0432\u0438. \u0420\u0430\u0437\u043E\u0431\u0440\u0430\u043B\u0441\u044F \u0441 \u0440\u044B\u0432\u043A\u043E\u043C \u2014 \u0441\u043D\u043E\u0432\u0430 \u0437\u043E\u0432\u0438 rest(summary) \u0438 \u0437\u0430\u043C\u0440\u0438. \u0412\u043E\u043F\u0440\u043E\u0441\u043E\u0432 \u0432 stdout \u043D\u0435 \u0437\u0430\u0434\u0430\u0432\u0430\u0439 \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u0447\u0435\u0440\u0435\u0437 ask.";
|
|
15814
16185
|
var HEADLESS_BLOCK = "\u26D4 HEADLESS-\u0420\u0415\u0416\u0418\u041C \u2014 \u0416\u0401\u0421\u0422\u041A\u041E. \u0418\u043D\u0442\u0435\u0440\u0430\u043A\u0442\u0438\u0432\u043D\u043E\u0433\u043E \u0447\u0430\u0442\u0430 \u041D\u0415\u0422: \u0442\u0432\u043E\u0439 stdout \u043D\u0438\u043A\u0442\u043E \u043D\u0435 \u0447\u0438\u0442\u0430\u0435\u0442 \u0438 \u043E\u0442\u0432\u0435\u0442\u0438\u0442\u044C \u043D\u0435 \u043C\u043E\u0436\u0435\u0442. \u041D\u0418\u041A\u041E\u0413\u0414\u0410 \u043D\u0435 \u0437\u0430\u0434\u0430\u0432\u0430\u0439 \u0432\u043E\u043F\u0440\u043E\u0441\u043E\u0432 \u0442\u0435\u043A\u0441\u0442\u043E\u043C \u0438 \u043D\u0435 \u0436\u0434\u0438 \u043E\u0442\u0432\u0435\u0442\u0430 \u0432 \u043A\u043E\u043D\u0441\u043E\u043B\u0438 \u2014 \u0435\u0434\u0438\u043D\u0441\u0442\u0432\u0435\u043D\u043D\u044B\u0439 \u043A\u0430\u043D\u0430\u043B \u043A \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440\u0443 \u044D\u0442\u043E MCP-\u0442\u0443\u043B ask (\u043E\u043D \u0431\u043B\u043E\u043A\u0438\u0440\u0443\u0435\u0442 \u0438 \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043E\u0442\u0432\u0435\u0442). \u041B\u044E\u0431\u043E\u0439 \u0432\u043E\u043F\u0440\u043E\u0441 \u041C\u0418\u041C\u041E ask = \u043C\u0433\u043D\u043E\u0432\u0435\u043D\u043D\u0430\u044F \u0441\u043C\u0435\u0440\u0442\u044C \u0434\u0440\u043E\u043D\u0430 (\u043F\u0440\u043E\u0446\u0435\u0441\u0441 \u0437\u0430\u043A\u0440\u043E\u0435\u0442\u0441\u044F \u043F\u0440\u044F\u043C\u043E \u043D\u0430 \u0442\u0432\u043E\u0451\u043C \u0432\u043E\u043F\u0440\u043E\u0441\u0435, \u0440\u0430\u0431\u043E\u0442\u0430 \u043F\u043E\u0442\u0435\u0440\u044F\u043D\u0430). \u041B\u044E\u0431\u044B\u0435 \u043F\u0440\u0430\u0432\u0438\u043B\u0430 \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u044F (\u0433\u043B\u043E\u0431\u0430\u043B\u044C\u043D\u044B\u0439 CLAUDE.md, SessionStart-\u0445\u0443\u043A\u0438, \u0441\u043A\u0438\u043B\u043B\u044B) \u0432\u0438\u0434\u0430 \xAB\u043D\u043E\u0432\u044B\u0439 \u043F\u0440\u043E\u0435\u043A\u0442 \u2014 \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043F\u0430\u043C\u044F\u0442\u044C/\u0432\u043E\u043B\u0442/\u043F\u0440\u043E\u0441\u043A\u0430\u043D\u0438\u0440\u043E\u0432\u0430\u0442\u044C? (\u0434\u0430/\u043D\u0435\u0442)\xBB \u0438 \u043F\u0440\u043E\u0447\u0438\u0435 \u0441\u0442\u0430\u0440\u0442\u043E\u0432\u044B\u0435 \u0432\u043E\u043F\u0440\u043E\u0441\u044B \u043F\u0440\u043E \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0430\u0446\u0438\u044E \u043F\u0430\u043C\u044F\u0442\u0438/\u0432\u043E\u043B\u0442\u0430/\u0441\u043A\u0430\u043D\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0435 \u2014 \u041C\u041E\u041B\u0427\u0410 \u041F\u0420\u041E\u041F\u0423\u0421\u041A\u0410\u0419: \u043D\u0435 \u0432\u044B\u043F\u043E\u043B\u043D\u044F\u0439, \u043D\u0435 \u0441\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0439, \u043D\u0435 \u0436\u0434\u0438 \u043E\u0442\u0432\u0435\u0442\u0430. \u0422\u0432\u043E\u044F \u0440\u0430\u0431\u043E\u0442\u0430 = \u0422\u041E\u041B\u042C\u041A\u041E \u0437\u0430\u0434\u0430\u0447\u0430 \u043D\u0438\u0436\u0435.";
|
|
15815
|
-
function buildPrompt(task, run, verifyMode = SWARM_VERIFY, taskContext, attachmentsBlock) {
|
|
16186
|
+
function buildPrompt(task, run, verifyMode = SWARM_VERIFY, taskContext, attachmentsBlock, zoneMemoryBlock) {
|
|
15816
16187
|
const name = run.name || `#${run.id}`;
|
|
15817
16188
|
const head = task ? `\u0417\u0430\u0434\u0430\u0447\u0430 ${run.task_slug}: ${task.title}
|
|
15818
16189
|
|
|
@@ -15886,6 +16257,9 @@ ${task.description}` : `\u0417\u0430\u0434\u0430\u0447\u0430 ${run.task_slug} (\
|
|
|
15886
16257
|
// пересказа README, а лишнее правило дороже отсутствующего (его читает каждый
|
|
15887
16258
|
// следующий дрон).
|
|
15888
16259
|
`\u{1F4CC} \u0421\u041F\u041E\u0422\u041A\u041D\u0423\u041B\u0421\u042F \u041E \u041D\u0415\u0417\u0410\u041F\u0418\u0421\u0410\u041D\u041D\u041E\u0415 \u2014 \u041F\u0420\u0415\u0414\u041B\u041E\u0416\u0418 \u041F\u0420\u0410\u0412\u0418\u041B\u041E. \u041F\u043E\u0442\u0440\u0430\u0442\u0438\u043B \u0432\u0440\u0435\u043C\u044F \u043D\u0430 \u0442\u043E, \u0447\u0435\u0433\u043E \u0432 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0438 \u043D\u0438\u0433\u0434\u0435 \u043D\u0435 \u043D\u0430\u043F\u0438\u0441\u0430\u043D\u043E (\u0438\u043D\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043E\u043D\u043D\u044B\u0435 \u0442\u0435\u0441\u0442\u044B \u0436\u0434\u0443\u0442 \u043F\u043E\u0441\u0442\u0433\u0440\u0435\u0441 \u043D\u0430 5433; \u043C\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u043D\u0430\u043A\u0430\u0442\u044B\u0432\u0430\u044E\u0442\u0441\u044F \u043D\u0435 \u0442\u0435\u043C, \u0447\u0435\u043C \u043A\u0430\u0436\u0435\u0442\u0441\u044F; \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u0437\u0435\u043B\u0451\u043D\u0430\u044F \u0442\u043E\u043B\u044C\u043A\u043E \u0441 \u0442\u0430\u043A\u0438\u043C \u0444\u043B\u0430\u0433\u043E\u043C) \u2014 \u043F\u0435\u0440\u0435\u0434\u0430\u0439 \u044D\u0442\u043E \u0432 done: \`rules: [{ field: "verify"|"conventions"|"brief"|"env"|"zones"|"spine", value: <\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u043F\u043E\u043B\u044F \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0438>, why: "\u043E\u0431\u043E \u0447\u0442\u043E \u0441\u043F\u043E\u0442\u043A\u043D\u0443\u043B\u0441\u044F \u0438 \u0447\u0435\u0433\u043E \u044D\u0442\u043E \u0441\u0442\u043E\u0438\u043B\u043E" }]\`. \u041D\u0435 \u0431\u043E\u043B\u044C\u0448\u0435 ${DRONE_RULES_PER_RUN_MAX} \u0437\u0430 \u043F\u0440\u043E\u0433\u043E\u043D \u0438 \u0422\u041E\u041B\u042C\u041A\u041E \u0442\u043E, \u043E\u0431\u043E \u0447\u0442\u043E \u0440\u0435\u0430\u043B\u044C\u043D\u043E \u0441\u043F\u043E\u0442\u043A\u043D\u0443\u043B\u0441\u044F: \xAB\u0442\u0435\u0441\u0442\u044B \u0433\u043E\u043D\u044F\u044E\u0442\u0441\u044F \u043E\u0434\u043D\u043E\u0439 \u043A\u043E\u043C\u0430\u043D\u0434\u043E\u0439, \u043E\u043D\u0430 \u0432 README\xBB \u2014 \u043D\u0435 \u043F\u0440\u0430\u0432\u0438\u043B\u043E, \u0430 \u043F\u0435\u0440\u0435\u0441\u043A\u0430\u0437 README. \u0423\u0436\u0435 \u0437\u0430\u043F\u0438\u0441\u0430\u043D\u043D\u043E\u0435 \u043E\u0442\u0441\u0435\u0435\u0442\u0441\u044F \u0441\u0430\u043C\u043E; \u0440\u0435\u0448\u0438\u0442 \u0440\u0435\u0432\u044C\u044E\u0435\u0440 \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u043E\u043C. \u041D\u0438\u0447\u0435\u0433\u043E \u0442\u0430\u043A\u043E\u0433\u043E \u043D\u0435 \u0431\u044B\u043B\u043E \u2014 \u043D\u0435 \u0432\u044B\u0434\u0443\u043C\u044B\u0432\u0430\u0439, \u043F\u0443\u0441\u0442\u043E\u0439 \u0441\u043F\u0438\u0441\u043E\u043A \u044D\u0442\u043E \u043D\u043E\u0440\u043C\u0430\u043B\u044C\u043D\u044B\u0439 \u0438\u0441\u0445\u043E\u0434 \u043F\u0440\u043E\u0433\u043E\u043D\u0430.`,
|
|
16260
|
+
// TASWM-466: рядом с правилом о репозитории — у них один смысл (знание, добытое
|
|
16261
|
+
// прогоном, переживает прогон) и одна цена ошибки: лишняя заметка дороже отсутствующей.
|
|
16262
|
+
...zoneMemoryBlock ? [zoneMemoryBlock] : [],
|
|
15889
16263
|
"\u0421\u043A\u0438\u043B\u043B\u044B \u043F\u0440\u0438\u0445\u043E\u0434\u044F\u0442 \u043A \u0442\u0435\u0431\u0435 \u0414\u0412\u0423\u041C\u042F \u043D\u0430\u0431\u043E\u0440\u0430\u043C\u0438, \u0438 \u043E\u0431\u0430 \u0443\u0436\u0435 \u043F\u043E\u0434\u0445\u0432\u0430\u0447\u0435\u043D\u044B (\u0441\u043F\u0430\u0432\u043D \u0438\u0437\u043E\u043B\u0438\u0440\u043E\u0432\u0430\u043D \u043E\u0442 \u044E\u0437\u0435\u0440\u0441\u043A\u043E\u0433\u043E ~/.claude, \u043F\u043E\u044D\u0442\u043E\u043C\u0443 \u041B\u0418\u0427\u041D\u042B\u0415 \u0441\u043A\u0438\u043B\u043B\u044B \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440\u0430 \u0442\u0435\u0431\u0435 \u043D\u0435 \u0432\u0438\u0434\u043D\u044B). \u2460 \u0420\u043E\u0439\u043D\u044B\u0435 `swarm-drone:*` \u0435\u0434\u0443\u0442 \u0441 \u0420\u041E\u0415\u041C \u0432 \u043B\u044E\u0431\u043E\u0439 \u043F\u0440\u043E\u0435\u043A\u0442 \u2014 \u0434\u0438\u0441\u0446\u0438\u043F\u043B\u0438\u043D\u0430, \u0432\u0435\u0440\u043D\u0430\u044F \u0432\u0435\u0437\u0434\u0435: swarm-save-often (\u043D\u0435\u0437\u0430\u043F\u0443\u0448\u0435\u043D\u043D\u043E\u0435 \u0443\u043C\u0438\u0440\u0430\u0435\u0442 \u0441 \u0434\u0440\u043E\u043D\u043E\u043C), swarm-merge-main (\u0431\u0430\u0437\u043E\u0432\u0443\u044E \u0432\u0435\u0442\u043A\u0443 \u0432\u043B\u0438\u0432\u0430\u0442\u044C, \u0430 \u043D\u0435 \u0440\u0435\u0431\u0435\u0439\u0437\u0438\u0442\u044C \u0437\u0430\u043F\u0443\u0448\u0435\u043D\u043D\u0443\u044E), swarm-await-process (\u0436\u0434\u0430\u0442\u044C \u0443\u0441\u043B\u043E\u0432\u0438\u0435, \u043D\u0435 sleep), swarm-verify-green (\u0447\u0442\u043E \u0441\u0447\u0438\u0442\u0430\u0442\u044C \u0437\u0435\u043B\u0451\u043D\u044B\u043C), systematic-debugging (\u043F\u0435\u0440\u0432\u043E\u043F\u0440\u0438\u0447\u0438\u043D\u0430 \u0434\u043E \u0444\u0438\u043A\u0441\u0430). \u2461 \u0421\u043A\u0438\u043B\u043B\u044B \u0420\u0415\u041F\u041E\u0417\u0418\u0422\u041E\u0420\u0418\u042F (.claude/skills, \u0441\u043E\u0441\u0442\u0430\u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043E\u0442 \u043F\u0440\u043E\u0435\u043A\u0442\u0430) \u2014 \u0437\u043D\u0430\u043D\u0438\u044F \u043E\u0431 \u044D\u0442\u043E\u043C \u043F\u0440\u043E\u0435\u043A\u0442\u0435: \u043A\u0430\u043A \u043F\u043E\u0434\u043D\u044F\u0442\u044C \u0441\u0442\u0435\u043A, \u043A\u0430\u043A \u0433\u043E\u043D\u044F\u0442\u044C \u0442\u0435\u0441\u0442\u044B \u0438 \u0447\u0442\u043E \u0437\u0434\u0435\u0441\u044C \u0437\u0435\u043B\u0451\u043D\u043E\u0435, UI-\u043F\u0440\u0430\u0432\u0438\u043B\u0430. \u041F\u043E\u043B\u044C\u0437\u0443\u0439\u0441\u044F \u043E\u0431\u043E\u0438\u043C\u0438, \u043D\u0435 \u043F\u0435\u0440\u0435\u0438\u0437\u043E\u0431\u0440\u0435\u0442\u0430\u0439; \u043D\u0435\u0442 \u043D\u0443\u0436\u043D\u043E\u0433\u043E \u0437\u043D\u0430\u043D\u0438\u044F \u043E \u043F\u0440\u043E\u0435\u043A\u0442\u0435 \u2014 \u044D\u0442\u043E \u043F\u0440\u043E\u0431\u0435\u043B \u0435\u0433\u043E \u0441\u043A\u0438\u043B\u043B\u043E\u0432, \u0441\u043A\u0430\u0436\u0438 note(), \u0430 \u043D\u0435 \u0432\u044B\u0434\u0443\u043C\u044B\u0432\u0430\u0439 \u043A\u043E\u043C\u0430\u043D\u0434\u044B."
|
|
15890
16264
|
];
|
|
15891
16265
|
if (run.decision) {
|
|
@@ -17488,7 +17862,8 @@ async function tickOnce(deps) {
|
|
|
17488
17862
|
continue;
|
|
17489
17863
|
}
|
|
17490
17864
|
await retireOutdatedReviewers(deps, run);
|
|
17491
|
-
|
|
17865
|
+
const baseStale = !st.conflicting && await needsBaseRefreshNow(deps, run, stormActive, now);
|
|
17866
|
+
if ((st.conflicting || baseStale) && deps.resolveConflict && !stormActive) {
|
|
17492
17867
|
if (deps.resourcesOk && !deps.resourcesOk()) continue;
|
|
17493
17868
|
if (countActiveDrones(deps.db) >= droneCap) continue;
|
|
17494
17869
|
if (!await projectQuotaGateAllows(deps, run)) continue;
|
|
@@ -17501,7 +17876,11 @@ async function tickOnce(deps) {
|
|
|
17501
17876
|
}
|
|
17502
17877
|
const last = lastConflictAttemptMs(deps.db, run.id);
|
|
17503
17878
|
if (last != null && now - last < CONFLICT_RESOLVE_COOLDOWN_MS) continue;
|
|
17504
|
-
deps.db.addEvent(
|
|
17879
|
+
deps.db.addEvent(
|
|
17880
|
+
run.id,
|
|
17881
|
+
"conflict",
|
|
17882
|
+
st.conflicting ? "PR \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442\u0443\u0435\u0442 \u0441 main \u2014 \u0440\u043E\u0439 \u0432\u043B\u0438\u0432\u0430\u0435\u0442 main (merge-main-in)" : "\u043E\u0447\u0435\u0440\u0435\u0434\u044C \u043C\u0435\u0440\u0436\u0430: \u0431\u0430\u0437\u0430 \u043F\u043E\u0434 PR \u0443\u0435\u0445\u0430\u043B\u0430 \u0432\u043F\u0435\u0440\u0451\u0434 \u2014 \u0440\u043E\u0439 \u0432\u043B\u0438\u0432\u0430\u0435\u0442 main \u0438 \u043F\u0435\u0440\u0435\u0433\u043E\u043D\u044F\u0435\u0442 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u043D\u0430 \u043E\u0431\u043D\u043E\u0432\u043B\u0451\u043D\u043D\u043E\u0439 \u0431\u0430\u0437\u0435 (TASWM-472)"
|
|
17883
|
+
);
|
|
17505
17884
|
try {
|
|
17506
17885
|
await deps.resolveConflict(run);
|
|
17507
17886
|
} catch (e) {
|
|
@@ -18157,10 +18536,13 @@ async function respawnRun(deps, run, mode, nudge) {
|
|
|
18157
18536
|
deps.db.updateRun(run.id, { status: "running", pid: pid2 });
|
|
18158
18537
|
return;
|
|
18159
18538
|
}
|
|
18160
|
-
const [task, verifyMode, projectBase] = await Promise.all([
|
|
18539
|
+
const [task, verifyMode, projectBase, zoneNotes] = await Promise.all([
|
|
18161
18540
|
deps.getTask(run.task_slug, run.workspace_id),
|
|
18162
18541
|
deps.verifyMode ? deps.verifyMode(repo) : Promise.resolve(void 0),
|
|
18163
|
-
deps.baseBranch ? deps.baseBranch(repo) : Promise.resolve("")
|
|
18542
|
+
deps.baseBranch ? deps.baseBranch(repo) : Promise.resolve(""),
|
|
18543
|
+
// TASWM-466: память зоны — тем же параллельным чтением. Отвалилась → пустой список:
|
|
18544
|
+
// оживление дрона не должно зависеть от того, доехала ли подсказка.
|
|
18545
|
+
deps.zoneMemory && run.area ? deps.zoneMemory(repo, run.area).catch(() => []) : Promise.resolve([])
|
|
18164
18546
|
]);
|
|
18165
18547
|
const base3 = effectiveBaseBranch(run.base_branch, projectBase);
|
|
18166
18548
|
const runToSpawn = base3 && run.base_branch !== base3 ? deps.db.updateRun(run.id, { base_branch: base3 }) ?? run : run;
|
|
@@ -18184,7 +18566,7 @@ async function respawnRun(deps, run, mode, nudge) {
|
|
|
18184
18566
|
fetchFile: deps.fetchFile,
|
|
18185
18567
|
onEvent: (text) => deps.db.addEvent(run.id, "step", text)
|
|
18186
18568
|
});
|
|
18187
|
-
const freshPrompt = runToSpawn.kind === "hero" ? buildHeroPrompt(task, runToSpawn, taskContext, attachments) : buildPrompt(task, runToSpawn, verifyMode, taskContext, attachments);
|
|
18569
|
+
const freshPrompt = runToSpawn.kind === "hero" ? buildHeroPrompt(task, runToSpawn, taskContext, attachments) : buildPrompt(task, runToSpawn, verifyMode, taskContext, attachments, renderZoneMemoryBlock(runToSpawn.area, zoneNotes));
|
|
18188
18570
|
const notice = depsPromptNotice(depsReport);
|
|
18189
18571
|
const prompt = [freshPrompt, notice, nudge].filter(Boolean).join("\n\n");
|
|
18190
18572
|
const pid = deps.launch({ worktree: wt, run: runToSpawn, prompt });
|
|
@@ -18653,12 +19035,17 @@ async function runDaemon(opts) {
|
|
|
18653
19035
|
let projectDroneCap;
|
|
18654
19036
|
let autoReviewProject;
|
|
18655
19037
|
let pendingRepoRules;
|
|
19038
|
+
let zoneMemoryReader;
|
|
18656
19039
|
if (SWARM_BACKEND === "client" && db instanceof SwarmClient) {
|
|
18657
19040
|
const client = db;
|
|
18658
19041
|
pendingRepoRules = async (repo, taskSlug) => {
|
|
18659
19042
|
const repoFullName = await remoteRepoFullName(repo).catch(() => null);
|
|
18660
19043
|
return repoFullName ? client.repoPendingRules(repoFullName, taskSlug) : [];
|
|
18661
19044
|
};
|
|
19045
|
+
zoneMemoryReader = async (repo, zone) => {
|
|
19046
|
+
const repoFullName = await remoteRepoFullName(repo).catch(() => null);
|
|
19047
|
+
return repoFullName ? parseZoneMemory(await client.repoZoneMemory(repoFullName), zone) : [];
|
|
19048
|
+
};
|
|
18662
19049
|
verifyModeReader = makeVerifyModeReader({
|
|
18663
19050
|
fetch: async (repo) => {
|
|
18664
19051
|
const repoFullName = await remoteRepoFullName(repo).catch(() => null);
|
|
@@ -18816,17 +19203,33 @@ async function runDaemon(opts) {
|
|
|
18816
19203
|
};
|
|
18817
19204
|
control.set = setPaused;
|
|
18818
19205
|
const restart = initialRestartState();
|
|
19206
|
+
const mergeParts = makeMergeGateParts({
|
|
19207
|
+
listRuns: () => db.listRuns(),
|
|
19208
|
+
...autoReviewProject ? { autoReview: autoReviewProject } : {},
|
|
19209
|
+
fallbackAutoReview: SWARM_AUTO_REVIEW,
|
|
19210
|
+
autoVerify: SWARM_AUTO_VERIFY,
|
|
19211
|
+
// TASWM-344: вторая ось приёмки — вердикт верификатора
|
|
19212
|
+
// TASWM-472: третья ось — ОЧЕРЕДЬ. Вливаем по одному и только на свежей базе; ридер
|
|
19213
|
+
// свежести ходит в gh (`compare/base...head` → behind_by). Ключа нет при
|
|
19214
|
+
// SWARM_MERGE_QUEUE=0 — тогда гейт отвечает ровно как до TASWM-472.
|
|
19215
|
+
...SWARM_MERGE_QUEUE ? { baseSync: (url) => prBaseSync(url), checks: (url) => prCiStatus(url) } : {}
|
|
19216
|
+
});
|
|
18819
19217
|
const deps = {
|
|
18820
19218
|
db,
|
|
19219
|
+
// TASWM-472: реконсайлу от очереди нужен ровно исход `base_stale` (см. needsBaseRefreshNow).
|
|
19220
|
+
...SWARM_MERGE_QUEUE ? { mergeQueue: mergeParts.queue } : {},
|
|
18821
19221
|
narrate: narrator.narrate,
|
|
18822
19222
|
control,
|
|
18823
19223
|
spawn: async (run) => {
|
|
18824
19224
|
const repoOfRun = normalizeRepo(run.repo || opts.repo);
|
|
18825
19225
|
const taskClient = tlFor(run.workspace_id);
|
|
18826
|
-
const [rawTask, verifyMode, projectBase] = await Promise.all([
|
|
19226
|
+
const [rawTask, verifyMode, projectBase, zoneNotes] = await Promise.all([
|
|
18827
19227
|
taskClient ? taskClient.getTask(run.task_slug) : Promise.resolve(null),
|
|
18828
19228
|
verifyModeReader ? verifyModeReader(repoOfRun) : Promise.resolve(void 0),
|
|
18829
|
-
baseBranchReader ? baseBranchReader(repoOfRun) : Promise.resolve("")
|
|
19229
|
+
baseBranchReader ? baseBranchReader(repoOfRun) : Promise.resolve(""),
|
|
19230
|
+
// TASWM-466: память зоны прогона — тем же параллельным чтением, что и остальные
|
|
19231
|
+
// живые ручки. Зоны у прогона нет (герой, разметка без area) → читать нечего.
|
|
19232
|
+
zoneMemoryReader && run.area ? zoneMemoryReader(repoOfRun, run.area).catch(() => []) : Promise.resolve([])
|
|
18830
19233
|
]);
|
|
18831
19234
|
const task = taskClient ? requireTaskBody(rawTask, run.task_slug, run.workspace_id) : null;
|
|
18832
19235
|
const healed = healTaskSlug(db, run, task);
|
|
@@ -18843,7 +19246,7 @@ async function runDaemon(opts) {
|
|
|
18843
19246
|
fetchFile: taskClient?.fetchFile?.bind(taskClient),
|
|
18844
19247
|
onEvent: (text) => db.addEvent(r.id, "step", text)
|
|
18845
19248
|
});
|
|
18846
|
-
return r.kind === "hero" ? buildHeroPrompt(task, r, taskContext, attachments) : buildPrompt(task, r, verifyMode, taskContext, attachments);
|
|
19249
|
+
return r.kind === "hero" ? buildHeroPrompt(task, r, taskContext, attachments) : buildPrompt(task, r, verifyMode, taskContext, attachments, renderZoneMemoryBlock(r.area, zoneNotes));
|
|
18847
19250
|
}
|
|
18848
19251
|
},
|
|
18849
19252
|
runToSpawn
|
|
@@ -18896,7 +19299,7 @@ async function runDaemon(opts) {
|
|
|
18896
19299
|
// TasklessClient.addComment + gh/git хелперы. Без tl (нет токена) ключи не задаём —
|
|
18897
19300
|
// postAdoptionReport/postScrapedVerdictReport становятся no-op, как раньше.
|
|
18898
19301
|
...tl ? {
|
|
18899
|
-
reportComment: (slug, body,
|
|
19302
|
+
reportComment: (slug, body, label2, ws) => tl.forWorkspace(ws).addComment(slug, body, label2)
|
|
18900
19303
|
} : {},
|
|
18901
19304
|
prCommitTitles: (prUrl) => prCommitTitles(prUrl),
|
|
18902
19305
|
prHeadBranch: (prUrl) => prHeadBranch(prUrl),
|
|
@@ -19055,6 +19458,9 @@ async function runDaemon(opts) {
|
|
|
19055
19458
|
return client ? requireTaskBody(await client.getTask(slug), slug, ws) : null;
|
|
19056
19459
|
},
|
|
19057
19460
|
...verifyModeReader ? { verifyMode: verifyModeReader } : {},
|
|
19461
|
+
// TASWM-466: тот же ридер памяти зоны, что на спавне — оживлённый дрон строит
|
|
19462
|
+
// промпт с нуля и без него потерял бы память своей зоны.
|
|
19463
|
+
...zoneMemoryReader ? { zoneMemory: zoneMemoryReader } : {},
|
|
19058
19464
|
getTaskContext: (task, ws) => {
|
|
19059
19465
|
const client = tlFor(ws);
|
|
19060
19466
|
return client ? fetchTaskContext(client, task) : Promise.resolve(void 0);
|
|
@@ -19369,13 +19775,7 @@ async function runDaemon(opts) {
|
|
|
19369
19775
|
// TASWM-396: тот же ридер решает и подъём ревьюера, не только мерж — иначе проектная
|
|
19370
19776
|
// настройка «ревью не нужно» ничего не выключала, а машина продолжала платить.
|
|
19371
19777
|
...autoReviewProject ? { autoReviewForRepo: autoReviewProject } : {},
|
|
19372
|
-
mergeGate:
|
|
19373
|
-
listRuns: () => db.listRuns(),
|
|
19374
|
-
...autoReviewProject ? { autoReview: autoReviewProject } : {},
|
|
19375
|
-
fallbackAutoReview: SWARM_AUTO_REVIEW,
|
|
19376
|
-
autoVerify: SWARM_AUTO_VERIFY
|
|
19377
|
-
// TASWM-344: вторая ось приёмки — вердикт верификатора
|
|
19378
|
-
}),
|
|
19778
|
+
mergeGate: mergeParts.gate,
|
|
19379
19779
|
// Оператор-пауза + «Оживить» (TASWM-214 Фаза 2): тот же shared-флаг, что читает тик;
|
|
19380
19780
|
// narrate — операторские действия видны в ленте роя; revive — сброс залипшего шторма.
|
|
19381
19781
|
control,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taskless-app/swarm",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.19",
|
|
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": [
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"execa": "^10.0.0",
|
|
39
39
|
"zod": "3.25.76"
|
|
40
40
|
},
|
|
41
|
-
"gitHead": "
|
|
41
|
+
"gitHead": "a61c26b5e254ef5383d918f14a9f6e8e8a09904a",
|
|
42
42
|
"scripts": {
|
|
43
43
|
"overmind": "NODE_OPTIONS=\"${NODE_OPTIONS:-} --conditions=development\" tsx src/overmind.ts",
|
|
44
44
|
"swarm": "NODE_OPTIONS=\"${NODE_OPTIONS:-} --conditions=development\" tsx src/cli.ts",
|