@taskless-app/swarm 0.6.18 → 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 +195 -14
- package/dist/overmind.js +267 -46
- 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() : "";
|
|
@@ -1471,6 +1557,7 @@ var init_src = __esm({
|
|
|
1471
1557
|
init_timeline();
|
|
1472
1558
|
init_reviewPhase();
|
|
1473
1559
|
init_mergeGate();
|
|
1560
|
+
init_mergeQueue();
|
|
1474
1561
|
init_verifyVerdict();
|
|
1475
1562
|
init_modelPolicy();
|
|
1476
1563
|
init_status();
|
|
@@ -2080,7 +2167,7 @@ function tokenFromFile() {
|
|
|
2080
2167
|
return "";
|
|
2081
2168
|
}
|
|
2082
2169
|
}
|
|
2083
|
-
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;
|
|
2084
2171
|
var init_config = __esm({
|
|
2085
2172
|
"src/config.ts"() {
|
|
2086
2173
|
"use strict";
|
|
@@ -2153,6 +2240,7 @@ var init_config = __esm({
|
|
|
2153
2240
|
SWARM_VERIFY = process.env.SWARM_VERIFY === "ci" ? "ci" : "local";
|
|
2154
2241
|
SWARM_AUTO_REVIEW = process.env.SWARM_AUTO_REVIEW !== "0";
|
|
2155
2242
|
SWARM_AUTO_VERIFY = process.env.SWARM_AUTO_VERIFY !== "0";
|
|
2243
|
+
SWARM_MERGE_QUEUE = process.env.SWARM_MERGE_QUEUE !== "0";
|
|
2156
2244
|
REVIEW_CUTOFF_PATH = process.env.SWARM_REVIEW_CUTOFF || join4(SWARM_HOME, "review-cutoff.json");
|
|
2157
2245
|
SWARM_REVIEW_CAP = Math.trunc(envNum("SWARM_REVIEW_CAP", 1));
|
|
2158
2246
|
SWARM_STORM_URL = process.env.SWARM_STORM_URL || "";
|
|
@@ -2284,7 +2372,7 @@ var init_package = __esm({
|
|
|
2284
2372
|
"package.json"() {
|
|
2285
2373
|
package_default = {
|
|
2286
2374
|
name: "@taskless-app/swarm",
|
|
2287
|
-
version: "0.6.
|
|
2375
|
+
version: "0.6.19",
|
|
2288
2376
|
type: "module",
|
|
2289
2377
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
2290
2378
|
keywords: [
|
|
@@ -2334,7 +2422,7 @@ var init_package = __esm({
|
|
|
2334
2422
|
execa: "^10.0.0",
|
|
2335
2423
|
zod: "3.25.76"
|
|
2336
2424
|
},
|
|
2337
|
-
gitHead: "
|
|
2425
|
+
gitHead: "a61c26b5e254ef5383d918f14a9f6e8e8a09904a"
|
|
2338
2426
|
};
|
|
2339
2427
|
}
|
|
2340
2428
|
});
|
|
@@ -2501,8 +2589,8 @@ function describeError(e, maxDepth = 4) {
|
|
|
2501
2589
|
const msg = (cur instanceof Error ? cur.message : typeof cur === "string" ? cur : String(cur)).trim();
|
|
2502
2590
|
const code = cur.code;
|
|
2503
2591
|
const codeText = code === void 0 || code === null ? "" : String(code);
|
|
2504
|
-
const
|
|
2505
|
-
if (
|
|
2592
|
+
const label2 = codeText && !msg.includes(codeText) ? `${msg} [code=${codeText}]` : msg;
|
|
2593
|
+
if (label2 && !parts.includes(label2)) parts.push(label2);
|
|
2506
2594
|
cur = cur.cause;
|
|
2507
2595
|
}
|
|
2508
2596
|
return parts.join(" \u2190 ") || String(e);
|
|
@@ -5172,18 +5260,18 @@ function isTransientResourceError(e) {
|
|
|
5172
5260
|
const code = e?.code;
|
|
5173
5261
|
return code === "ENFILE" || code === "EMFILE" || code === "EAGAIN";
|
|
5174
5262
|
}
|
|
5175
|
-
function logTransientSpawnError(
|
|
5263
|
+
function logTransientSpawnError(label2, e) {
|
|
5176
5264
|
if (isTransientResourceError(e)) {
|
|
5177
5265
|
const code = e.code;
|
|
5178
|
-
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`);
|
|
5179
5267
|
} else {
|
|
5180
|
-
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)}`);
|
|
5181
5269
|
}
|
|
5182
5270
|
}
|
|
5183
5271
|
function parseVmStatAvailableBytes(vmStatOut) {
|
|
5184
5272
|
const page = Number(vmStatOut.match(/page size of (\d+) bytes/)?.[1]) || 4096;
|
|
5185
|
-
const pages = (
|
|
5186
|
-
const m = vmStatOut.match(new RegExp(`Pages ${
|
|
5273
|
+
const pages = (label2) => {
|
|
5274
|
+
const m = vmStatOut.match(new RegExp(`Pages ${label2}:\\s+(\\d+)`));
|
|
5187
5275
|
return m ? Number(m[1]) : 0;
|
|
5188
5276
|
};
|
|
5189
5277
|
return (pages("free") + pages("inactive") + pages("speculative") + pages("purgeable")) * page;
|
|
@@ -8469,6 +8557,11 @@ init_config();
|
|
|
8469
8557
|
|
|
8470
8558
|
// src/mergeGate.ts
|
|
8471
8559
|
init_src();
|
|
8560
|
+
|
|
8561
|
+
// src/mergeQueue.ts
|
|
8562
|
+
init_src();
|
|
8563
|
+
|
|
8564
|
+
// src/prNumber.ts
|
|
8472
8565
|
function prNumberOf(ref) {
|
|
8473
8566
|
const s = (ref || "").trim();
|
|
8474
8567
|
if (!s) return null;
|
|
@@ -8477,6 +8570,76 @@ function prNumberOf(ref) {
|
|
|
8477
8570
|
const bare = s.match(/^#?(\d+)$/);
|
|
8478
8571
|
return bare ? Number(bare[1]) : null;
|
|
8479
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
|
|
8480
8643
|
function findRunByPr(runs, ref) {
|
|
8481
8644
|
const num = prNumberOf(ref);
|
|
8482
8645
|
if (num == null) return null;
|
|
@@ -8488,17 +8651,34 @@ function findRunByPr(runs, ref) {
|
|
|
8488
8651
|
return best;
|
|
8489
8652
|
}
|
|
8490
8653
|
function makeMergeGateResolver(deps) {
|
|
8491
|
-
return
|
|
8492
|
-
|
|
8493
|
-
|
|
8654
|
+
return makeMergeGateParts(deps).gate;
|
|
8655
|
+
}
|
|
8656
|
+
function makeMergeGateParts(deps) {
|
|
8657
|
+
const gateFor = async (run) => {
|
|
8494
8658
|
const autoReview = deps.autoReview ? await deps.autoReview(run.repo).catch(() => deps.fallbackAutoReview) : deps.fallbackAutoReview;
|
|
8495
|
-
|
|
8659
|
+
return computeMergeGate({
|
|
8496
8660
|
hasRun: true,
|
|
8497
8661
|
autoReview,
|
|
8498
8662
|
reviewVerdict: run.review_verdict,
|
|
8499
8663
|
autoVerify: deps.autoVerify === true,
|
|
8500
8664
|
verifyVerdict: run.verify_verdict ?? null
|
|
8501
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);
|
|
8502
8682
|
return {
|
|
8503
8683
|
...decision,
|
|
8504
8684
|
run: {
|
|
@@ -8511,6 +8691,7 @@ function makeMergeGateResolver(deps) {
|
|
|
8511
8691
|
}
|
|
8512
8692
|
};
|
|
8513
8693
|
};
|
|
8694
|
+
return { gate, queue: queueFor };
|
|
8514
8695
|
}
|
|
8515
8696
|
|
|
8516
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() : "";
|
|
@@ -1545,6 +1631,7 @@ var init_src = __esm({
|
|
|
1545
1631
|
init_timeline();
|
|
1546
1632
|
init_reviewPhase();
|
|
1547
1633
|
init_mergeGate();
|
|
1634
|
+
init_mergeQueue();
|
|
1548
1635
|
init_verifyVerdict();
|
|
1549
1636
|
init_modelPolicy();
|
|
1550
1637
|
init_status();
|
|
@@ -2161,6 +2248,7 @@ __export(config_exports, {
|
|
|
2161
2248
|
SWARM_MAX_FD_LOAD_FACTOR: () => SWARM_MAX_FD_LOAD_FACTOR,
|
|
2162
2249
|
SWARM_MAX_IN_FLIGHT: () => SWARM_MAX_IN_FLIGHT,
|
|
2163
2250
|
SWARM_MAX_LOAD_FACTOR: () => SWARM_MAX_LOAD_FACTOR,
|
|
2251
|
+
SWARM_MERGE_QUEUE: () => SWARM_MERGE_QUEUE,
|
|
2164
2252
|
SWARM_MIN_FREE_GB: () => SWARM_MIN_FREE_GB,
|
|
2165
2253
|
SWARM_OUTBOX: () => SWARM_OUTBOX,
|
|
2166
2254
|
SWARM_PROD_HEARTBEAT_MS: () => SWARM_PROD_HEARTBEAT_MS,
|
|
@@ -2283,7 +2371,7 @@ function reviewCutoffAt() {
|
|
|
2283
2371
|
}
|
|
2284
2372
|
return at;
|
|
2285
2373
|
}
|
|
2286
|
-
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;
|
|
2287
2375
|
var init_config = __esm({
|
|
2288
2376
|
"src/config.ts"() {
|
|
2289
2377
|
"use strict";
|
|
@@ -2356,6 +2444,7 @@ var init_config = __esm({
|
|
|
2356
2444
|
SWARM_VERIFY = process.env.SWARM_VERIFY === "ci" ? "ci" : "local";
|
|
2357
2445
|
SWARM_AUTO_REVIEW = process.env.SWARM_AUTO_REVIEW !== "0";
|
|
2358
2446
|
SWARM_AUTO_VERIFY = process.env.SWARM_AUTO_VERIFY !== "0";
|
|
2447
|
+
SWARM_MERGE_QUEUE = process.env.SWARM_MERGE_QUEUE !== "0";
|
|
2359
2448
|
REVIEW_CUTOFF_PATH = process.env.SWARM_REVIEW_CUTOFF || join5(SWARM_HOME, "review-cutoff.json");
|
|
2360
2449
|
SWARM_REVIEW_CAP = Math.trunc(envNum("SWARM_REVIEW_CAP", 1));
|
|
2361
2450
|
SWARM_STORM_URL = process.env.SWARM_STORM_URL || "";
|
|
@@ -2401,12 +2490,12 @@ function isTransientResourceError(e) {
|
|
|
2401
2490
|
const code = e?.code;
|
|
2402
2491
|
return code === "ENFILE" || code === "EMFILE" || code === "EAGAIN";
|
|
2403
2492
|
}
|
|
2404
|
-
function logTransientSpawnError(
|
|
2493
|
+
function logTransientSpawnError(label2, e) {
|
|
2405
2494
|
if (isTransientResourceError(e)) {
|
|
2406
2495
|
const code = e.code;
|
|
2407
|
-
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`);
|
|
2408
2497
|
} else {
|
|
2409
|
-
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)}`);
|
|
2410
2499
|
}
|
|
2411
2500
|
}
|
|
2412
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) {
|
|
@@ -2417,8 +2506,8 @@ function resourcesOk(load1, cpus, freeGb, maxLoadFactor = SWARM_MAX_LOAD_FACTOR,
|
|
|
2417
2506
|
}
|
|
2418
2507
|
function parseVmStatAvailableBytes(vmStatOut) {
|
|
2419
2508
|
const page = Number(vmStatOut.match(/page size of (\d+) bytes/)?.[1]) || 4096;
|
|
2420
|
-
const pages = (
|
|
2421
|
-
const m = vmStatOut.match(new RegExp(`Pages ${
|
|
2509
|
+
const pages = (label2) => {
|
|
2510
|
+
const m = vmStatOut.match(new RegExp(`Pages ${label2}:\\s+(\\d+)`));
|
|
2422
2511
|
return m ? Number(m[1]) : 0;
|
|
2423
2512
|
};
|
|
2424
2513
|
return (pages("free") + pages("inactive") + pages("speculative") + pages("purgeable")) * page;
|
|
@@ -2870,8 +2959,8 @@ function describeError(e, maxDepth = 4) {
|
|
|
2870
2959
|
const msg = (cur instanceof Error ? cur.message : typeof cur === "string" ? cur : String(cur)).trim();
|
|
2871
2960
|
const code = cur.code;
|
|
2872
2961
|
const codeText = code === void 0 || code === null ? "" : String(code);
|
|
2873
|
-
const
|
|
2874
|
-
if (
|
|
2962
|
+
const label2 = codeText && !msg.includes(codeText) ? `${msg} [code=${codeText}]` : msg;
|
|
2963
|
+
if (label2 && !parts.includes(label2)) parts.push(label2);
|
|
2875
2964
|
cur = cur.cause;
|
|
2876
2965
|
}
|
|
2877
2966
|
return parts.join(" \u2190 ") || String(e);
|
|
@@ -3992,37 +4081,37 @@ async function materializeAttachments(opts) {
|
|
|
3992
4081
|
let index = 0;
|
|
3993
4082
|
for (const ref of opts.refs) {
|
|
3994
4083
|
index++;
|
|
3995
|
-
const
|
|
4084
|
+
const label2 = ref.caption || ref.url;
|
|
3996
4085
|
const cls = classifyAttachment(ref);
|
|
3997
4086
|
if ("skip" in cls) {
|
|
3998
|
-
result.skipped.push(`${
|
|
4087
|
+
result.skipped.push(`${label2} \u2014 ${cls.skip}`);
|
|
3999
4088
|
continue;
|
|
4000
4089
|
}
|
|
4001
4090
|
if (result.files.length >= maxFiles) {
|
|
4002
|
-
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`);
|
|
4003
4092
|
continue;
|
|
4004
4093
|
}
|
|
4005
4094
|
if (ref.size != null && ref.size > maxFile) {
|
|
4006
|
-
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`);
|
|
4007
4096
|
continue;
|
|
4008
4097
|
}
|
|
4009
4098
|
let file = null;
|
|
4010
4099
|
try {
|
|
4011
4100
|
file = await opts.fetchFile(ref.url);
|
|
4012
4101
|
} catch (e) {
|
|
4013
|
-
result.skipped.push(`${
|
|
4102
|
+
result.skipped.push(`${label2} \u2014 \u043D\u0435 \u0441\u043A\u0430\u0447\u0430\u043B\u043E\u0441\u044C (${errText(e)})`);
|
|
4014
4103
|
continue;
|
|
4015
4104
|
}
|
|
4016
4105
|
if (!file) {
|
|
4017
|
-
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)`);
|
|
4018
4107
|
continue;
|
|
4019
4108
|
}
|
|
4020
4109
|
if (file.bytes.byteLength > maxFile) {
|
|
4021
|
-
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`);
|
|
4022
4111
|
continue;
|
|
4023
4112
|
}
|
|
4024
4113
|
if (total + file.bytes.byteLength > maxTotal) {
|
|
4025
|
-
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)}`);
|
|
4026
4115
|
continue;
|
|
4027
4116
|
}
|
|
4028
4117
|
const name = attachmentFileName(index, ref.caption, attachmentExt(ref, file.contentType));
|
|
@@ -4033,7 +4122,7 @@ async function materializeAttachments(opts) {
|
|
|
4033
4122
|
}
|
|
4034
4123
|
await io.writeFile(join20(dir, name), file.bytes);
|
|
4035
4124
|
} catch (e) {
|
|
4036
|
-
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)})`);
|
|
4037
4126
|
continue;
|
|
4038
4127
|
}
|
|
4039
4128
|
total += file.bytes.byteLength;
|
|
@@ -4681,7 +4770,7 @@ function makeTasklessClient(call, workspaceId, taskUrlBase, fetchFile, fetchImpl
|
|
|
4681
4770
|
return await safeCall("update_task", { id, assigneeId: userId }) != null;
|
|
4682
4771
|
},
|
|
4683
4772
|
uploadShot: (file) => uploadShot(safeCall, file, fetchImpl),
|
|
4684
|
-
addComment: async (idOrSlug, body,
|
|
4773
|
+
addComment: async (idOrSlug, body, label2, attachments) => {
|
|
4685
4774
|
const id = await resolveId(idOrSlug);
|
|
4686
4775
|
if (!id) {
|
|
4687
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)`);
|
|
@@ -4700,7 +4789,7 @@ function makeTasklessClient(call, workspaceId, taskUrlBase, fetchFile, fetchImpl
|
|
|
4700
4789
|
body: parts[i],
|
|
4701
4790
|
// Метки роя — на КАЖДОЙ части: без них хвост отчёта выглядит в ленте задачи
|
|
4702
4791
|
// чужой репликой без автора (swarmKind/swarmDroneName рисуются чипами).
|
|
4703
|
-
...
|
|
4792
|
+
...label2 ?? {},
|
|
4704
4793
|
// TASWM-294: скрины — к ПЕРВОЙ части, к шапке отчёта. Разносить их по
|
|
4705
4794
|
// частям треда нельзя: человек открывает задачу и должен увидеть, как
|
|
4706
4795
|
// это выглядит, в том же комменте, что и «что сделано».
|
|
@@ -10472,6 +10561,22 @@ async function prHeadBranch(prUrl, run = realRunner) {
|
|
|
10472
10561
|
return null;
|
|
10473
10562
|
}
|
|
10474
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
|
+
}
|
|
10475
10580
|
async function openPrsForBranch(branch, repoDir, run = realRepoRunner) {
|
|
10476
10581
|
if (!branch || !repoDir) return [];
|
|
10477
10582
|
try {
|
|
@@ -10704,17 +10809,17 @@ function normalizeZoneLabel(zone) {
|
|
|
10704
10809
|
return (zone ?? "").trim().replace(/^area:/i, "").trim().toLowerCase();
|
|
10705
10810
|
}
|
|
10706
10811
|
function renderZoneMemoryBlock(zone, notes) {
|
|
10707
|
-
const
|
|
10708
|
-
if (!
|
|
10812
|
+
const label2 = normalizeZoneLabel(zone);
|
|
10813
|
+
if (!label2) return "";
|
|
10709
10814
|
const head = notes.length ? [
|
|
10710
|
-
`\u{1F9E0} \u041F\u0410\u041C\u042F\u0422\u042C \u0417\u041E\u041D\u042B \`${
|
|
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):`,
|
|
10711
10816
|
...notes.map((n) => `\u2022 [${n.id}] ${n.claim}`),
|
|
10712
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.",
|
|
10713
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.`
|
|
10714
|
-
] : [`\u{1F9E0} \u041F\u0410\u041C\u042F\u0422\u042C \u0417\u041E\u041D\u042B \`${
|
|
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.`];
|
|
10715
10820
|
return [
|
|
10716
10821
|
...head,
|
|
10717
|
-
`\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: "${
|
|
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.`
|
|
10718
10823
|
].join("\n");
|
|
10719
10824
|
}
|
|
10720
10825
|
function collectZoneNoteConfirmations(report) {
|
|
@@ -12508,6 +12613,11 @@ function makeDroneCapReader(opts) {
|
|
|
12508
12613
|
|
|
12509
12614
|
// src/mergeGate.ts
|
|
12510
12615
|
init_src();
|
|
12616
|
+
|
|
12617
|
+
// src/mergeQueue.ts
|
|
12618
|
+
init_src();
|
|
12619
|
+
|
|
12620
|
+
// src/prNumber.ts
|
|
12511
12621
|
function prNumberOf(ref) {
|
|
12512
12622
|
const s = (ref || "").trim();
|
|
12513
12623
|
if (!s) return null;
|
|
@@ -12516,6 +12626,79 @@ function prNumberOf(ref) {
|
|
|
12516
12626
|
const bare = s.match(/^#?(\d+)$/);
|
|
12517
12627
|
return bare ? Number(bare[1]) : null;
|
|
12518
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
|
|
12519
12702
|
function findRunByPr(runs, ref) {
|
|
12520
12703
|
const num = prNumberOf(ref);
|
|
12521
12704
|
if (num == null) return null;
|
|
@@ -12527,17 +12710,34 @@ function findRunByPr(runs, ref) {
|
|
|
12527
12710
|
return best;
|
|
12528
12711
|
}
|
|
12529
12712
|
function makeMergeGateResolver(deps) {
|
|
12530
|
-
return
|
|
12531
|
-
|
|
12532
|
-
|
|
12713
|
+
return makeMergeGateParts(deps).gate;
|
|
12714
|
+
}
|
|
12715
|
+
function makeMergeGateParts(deps) {
|
|
12716
|
+
const gateFor = async (run) => {
|
|
12533
12717
|
const autoReview = deps.autoReview ? await deps.autoReview(run.repo).catch(() => deps.fallbackAutoReview) : deps.fallbackAutoReview;
|
|
12534
|
-
|
|
12718
|
+
return computeMergeGate({
|
|
12535
12719
|
hasRun: true,
|
|
12536
12720
|
autoReview,
|
|
12537
12721
|
reviewVerdict: run.review_verdict,
|
|
12538
12722
|
autoVerify: deps.autoVerify === true,
|
|
12539
12723
|
verifyVerdict: run.verify_verdict ?? null
|
|
12540
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);
|
|
12541
12741
|
return {
|
|
12542
12742
|
...decision,
|
|
12543
12743
|
run: {
|
|
@@ -12550,6 +12750,7 @@ function makeMergeGateResolver(deps) {
|
|
|
12550
12750
|
}
|
|
12551
12751
|
};
|
|
12552
12752
|
};
|
|
12753
|
+
return { gate, queue: queueFor };
|
|
12553
12754
|
}
|
|
12554
12755
|
|
|
12555
12756
|
// src/envGate.ts
|
|
@@ -12990,7 +13191,7 @@ async function changedPaths(worktree, opts = {}) {
|
|
|
12990
13191
|
// package.json
|
|
12991
13192
|
var package_default = {
|
|
12992
13193
|
name: "@taskless-app/swarm",
|
|
12993
|
-
version: "0.6.
|
|
13194
|
+
version: "0.6.19",
|
|
12994
13195
|
type: "module",
|
|
12995
13196
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
12996
13197
|
keywords: [
|
|
@@ -13040,7 +13241,7 @@ var package_default = {
|
|
|
13040
13241
|
execa: "^10.0.0",
|
|
13041
13242
|
zod: "3.25.76"
|
|
13042
13243
|
},
|
|
13043
|
-
gitHead: "
|
|
13244
|
+
gitHead: "a61c26b5e254ef5383d918f14a9f6e8e8a09904a"
|
|
13044
13245
|
};
|
|
13045
13246
|
|
|
13046
13247
|
// src/version.ts
|
|
@@ -14743,8 +14944,8 @@ async function executeHostCommands(opts) {
|
|
|
14743
14944
|
}
|
|
14744
14945
|
async function executeOne(cmd, opts) {
|
|
14745
14946
|
const { effects, ack, statePath } = opts;
|
|
14746
|
-
const
|
|
14747
|
-
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}`);
|
|
14748
14949
|
try {
|
|
14749
14950
|
switch (cmd.kind) {
|
|
14750
14951
|
case "pause":
|
|
@@ -15627,6 +15828,14 @@ function lastConflictAttemptMs(db, runId) {
|
|
|
15627
15828
|
if (!evs.length) return null;
|
|
15628
15829
|
return Date.parse(evs[evs.length - 1].at.replace(" ", "T") + "Z");
|
|
15629
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
|
+
}
|
|
15630
15839
|
function lastCiCheckMs(db, runId) {
|
|
15631
15840
|
const evs = db.events(runId).filter((e) => e.kind === "ci_wake" || e.kind === "ci_checked");
|
|
15632
15841
|
if (!evs.length) return null;
|
|
@@ -17653,7 +17862,8 @@ async function tickOnce(deps) {
|
|
|
17653
17862
|
continue;
|
|
17654
17863
|
}
|
|
17655
17864
|
await retireOutdatedReviewers(deps, run);
|
|
17656
|
-
|
|
17865
|
+
const baseStale = !st.conflicting && await needsBaseRefreshNow(deps, run, stormActive, now);
|
|
17866
|
+
if ((st.conflicting || baseStale) && deps.resolveConflict && !stormActive) {
|
|
17657
17867
|
if (deps.resourcesOk && !deps.resourcesOk()) continue;
|
|
17658
17868
|
if (countActiveDrones(deps.db) >= droneCap) continue;
|
|
17659
17869
|
if (!await projectQuotaGateAllows(deps, run)) continue;
|
|
@@ -17666,7 +17876,11 @@ async function tickOnce(deps) {
|
|
|
17666
17876
|
}
|
|
17667
17877
|
const last = lastConflictAttemptMs(deps.db, run.id);
|
|
17668
17878
|
if (last != null && now - last < CONFLICT_RESOLVE_COOLDOWN_MS) continue;
|
|
17669
|
-
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
|
+
);
|
|
17670
17884
|
try {
|
|
17671
17885
|
await deps.resolveConflict(run);
|
|
17672
17886
|
} catch (e) {
|
|
@@ -18989,8 +19203,21 @@ async function runDaemon(opts) {
|
|
|
18989
19203
|
};
|
|
18990
19204
|
control.set = setPaused;
|
|
18991
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
|
+
});
|
|
18992
19217
|
const deps = {
|
|
18993
19218
|
db,
|
|
19219
|
+
// TASWM-472: реконсайлу от очереди нужен ровно исход `base_stale` (см. needsBaseRefreshNow).
|
|
19220
|
+
...SWARM_MERGE_QUEUE ? { mergeQueue: mergeParts.queue } : {},
|
|
18994
19221
|
narrate: narrator.narrate,
|
|
18995
19222
|
control,
|
|
18996
19223
|
spawn: async (run) => {
|
|
@@ -19072,7 +19299,7 @@ async function runDaemon(opts) {
|
|
|
19072
19299
|
// TasklessClient.addComment + gh/git хелперы. Без tl (нет токена) ключи не задаём —
|
|
19073
19300
|
// postAdoptionReport/postScrapedVerdictReport становятся no-op, как раньше.
|
|
19074
19301
|
...tl ? {
|
|
19075
|
-
reportComment: (slug, body,
|
|
19302
|
+
reportComment: (slug, body, label2, ws) => tl.forWorkspace(ws).addComment(slug, body, label2)
|
|
19076
19303
|
} : {},
|
|
19077
19304
|
prCommitTitles: (prUrl) => prCommitTitles(prUrl),
|
|
19078
19305
|
prHeadBranch: (prUrl) => prHeadBranch(prUrl),
|
|
@@ -19548,13 +19775,7 @@ async function runDaemon(opts) {
|
|
|
19548
19775
|
// TASWM-396: тот же ридер решает и подъём ревьюера, не только мерж — иначе проектная
|
|
19549
19776
|
// настройка «ревью не нужно» ничего не выключала, а машина продолжала платить.
|
|
19550
19777
|
...autoReviewProject ? { autoReviewForRepo: autoReviewProject } : {},
|
|
19551
|
-
mergeGate:
|
|
19552
|
-
listRuns: () => db.listRuns(),
|
|
19553
|
-
...autoReviewProject ? { autoReview: autoReviewProject } : {},
|
|
19554
|
-
fallbackAutoReview: SWARM_AUTO_REVIEW,
|
|
19555
|
-
autoVerify: SWARM_AUTO_VERIFY
|
|
19556
|
-
// TASWM-344: вторая ось приёмки — вердикт верификатора
|
|
19557
|
-
}),
|
|
19778
|
+
mergeGate: mergeParts.gate,
|
|
19558
19779
|
// Оператор-пауза + «Оживить» (TASWM-214 Фаза 2): тот же shared-флаг, что читает тик;
|
|
19559
19780
|
// narrate — операторские действия видны в ленте роя; revive — сброс залипшего шторма.
|
|
19560
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",
|