@taskless-app/swarm 0.6.18 → 0.6.20
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 +201 -16
- package/dist/overmind.js +558 -57
- 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, SWARM_WORKTREE_REAP_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";
|
|
@@ -2129,6 +2216,7 @@ var init_config = __esm({
|
|
|
2129
2216
|
SWARM_PROD_HEARTBEAT_MS = envNum("SWARM_PROD_HEARTBEAT_MS", 15e3);
|
|
2130
2217
|
SWARM_VERSION_CHECK_MS = envNum("SWARM_VERSION_CHECK_MS", 5 * 6e4);
|
|
2131
2218
|
SWARM_SWEEP_INTERVAL_MS = envNum("SWARM_SWEEP_INTERVAL_MS", 10 * 6e4);
|
|
2219
|
+
SWARM_WORKTREE_REAP_INTERVAL_MS = envNum("SWARM_WORKTREE_REAP_INTERVAL_MS", 5 * 6e4);
|
|
2132
2220
|
DRONE_CHANNEL_ENABLED = process.env.SWARM_DRONE_CHANNEL !== "0";
|
|
2133
2221
|
DRONE_CHANNEL_PORT = Number(process.env.SWARM_DRONE_CHANNEL_PORT) || 7421;
|
|
2134
2222
|
DRONE_CHANNEL_URL = process.env.SWARM_DRONE_CHANNEL_URL || `http://127.0.0.1:${DRONE_CHANNEL_PORT}`;
|
|
@@ -2153,6 +2241,7 @@ var init_config = __esm({
|
|
|
2153
2241
|
SWARM_VERIFY = process.env.SWARM_VERIFY === "ci" ? "ci" : "local";
|
|
2154
2242
|
SWARM_AUTO_REVIEW = process.env.SWARM_AUTO_REVIEW !== "0";
|
|
2155
2243
|
SWARM_AUTO_VERIFY = process.env.SWARM_AUTO_VERIFY !== "0";
|
|
2244
|
+
SWARM_MERGE_QUEUE = process.env.SWARM_MERGE_QUEUE !== "0";
|
|
2156
2245
|
REVIEW_CUTOFF_PATH = process.env.SWARM_REVIEW_CUTOFF || join4(SWARM_HOME, "review-cutoff.json");
|
|
2157
2246
|
SWARM_REVIEW_CAP = Math.trunc(envNum("SWARM_REVIEW_CAP", 1));
|
|
2158
2247
|
SWARM_STORM_URL = process.env.SWARM_STORM_URL || "";
|
|
@@ -2284,7 +2373,7 @@ var init_package = __esm({
|
|
|
2284
2373
|
"package.json"() {
|
|
2285
2374
|
package_default = {
|
|
2286
2375
|
name: "@taskless-app/swarm",
|
|
2287
|
-
version: "0.6.
|
|
2376
|
+
version: "0.6.20",
|
|
2288
2377
|
type: "module",
|
|
2289
2378
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
2290
2379
|
keywords: [
|
|
@@ -2334,7 +2423,7 @@ var init_package = __esm({
|
|
|
2334
2423
|
execa: "^10.0.0",
|
|
2335
2424
|
zod: "3.25.76"
|
|
2336
2425
|
},
|
|
2337
|
-
gitHead: "
|
|
2426
|
+
gitHead: "2d05a2e2b7c197ab916f7ff756e3a829b138df16"
|
|
2338
2427
|
};
|
|
2339
2428
|
}
|
|
2340
2429
|
});
|
|
@@ -2501,8 +2590,8 @@ function describeError(e, maxDepth = 4) {
|
|
|
2501
2590
|
const msg = (cur instanceof Error ? cur.message : typeof cur === "string" ? cur : String(cur)).trim();
|
|
2502
2591
|
const code = cur.code;
|
|
2503
2592
|
const codeText = code === void 0 || code === null ? "" : String(code);
|
|
2504
|
-
const
|
|
2505
|
-
if (
|
|
2593
|
+
const label2 = codeText && !msg.includes(codeText) ? `${msg} [code=${codeText}]` : msg;
|
|
2594
|
+
if (label2 && !parts.includes(label2)) parts.push(label2);
|
|
2506
2595
|
cur = cur.cause;
|
|
2507
2596
|
}
|
|
2508
2597
|
return parts.join(" \u2190 ") || String(e);
|
|
@@ -5172,18 +5261,18 @@ function isTransientResourceError(e) {
|
|
|
5172
5261
|
const code = e?.code;
|
|
5173
5262
|
return code === "ENFILE" || code === "EMFILE" || code === "EAGAIN";
|
|
5174
5263
|
}
|
|
5175
|
-
function logTransientSpawnError(
|
|
5264
|
+
function logTransientSpawnError(label2, e) {
|
|
5176
5265
|
if (isTransientResourceError(e)) {
|
|
5177
5266
|
const code = e.code;
|
|
5178
|
-
console.warn(`[overmind] ${
|
|
5267
|
+
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
5268
|
} else {
|
|
5180
|
-
console.warn(`[overmind] ${
|
|
5269
|
+
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
5270
|
}
|
|
5182
5271
|
}
|
|
5183
5272
|
function parseVmStatAvailableBytes(vmStatOut) {
|
|
5184
5273
|
const page = Number(vmStatOut.match(/page size of (\d+) bytes/)?.[1]) || 4096;
|
|
5185
|
-
const pages = (
|
|
5186
|
-
const m = vmStatOut.match(new RegExp(`Pages ${
|
|
5274
|
+
const pages = (label2) => {
|
|
5275
|
+
const m = vmStatOut.match(new RegExp(`Pages ${label2}:\\s+(\\d+)`));
|
|
5187
5276
|
return m ? Number(m[1]) : 0;
|
|
5188
5277
|
};
|
|
5189
5278
|
return (pages("free") + pages("inactive") + pages("speculative") + pages("purgeable")) * page;
|
|
@@ -8469,6 +8558,11 @@ init_config();
|
|
|
8469
8558
|
|
|
8470
8559
|
// src/mergeGate.ts
|
|
8471
8560
|
init_src();
|
|
8561
|
+
|
|
8562
|
+
// src/mergeQueue.ts
|
|
8563
|
+
init_src();
|
|
8564
|
+
|
|
8565
|
+
// src/prNumber.ts
|
|
8472
8566
|
function prNumberOf(ref) {
|
|
8473
8567
|
const s = (ref || "").trim();
|
|
8474
8568
|
if (!s) return null;
|
|
@@ -8477,6 +8571,76 @@ function prNumberOf(ref) {
|
|
|
8477
8571
|
const bare = s.match(/^#?(\d+)$/);
|
|
8478
8572
|
return bare ? Number(bare[1]) : null;
|
|
8479
8573
|
}
|
|
8574
|
+
|
|
8575
|
+
// src/mergeQueue.ts
|
|
8576
|
+
var TERMINAL2 = /* @__PURE__ */ new Set(["done", "failed", "stalled", "stopped", "superseded", "returned"]);
|
|
8577
|
+
function isMergeCandidate(r) {
|
|
8578
|
+
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;
|
|
8579
|
+
}
|
|
8580
|
+
function mergeQueueCandidates(runs, repo) {
|
|
8581
|
+
const byPr = /* @__PURE__ */ new Map();
|
|
8582
|
+
for (const r of runs) {
|
|
8583
|
+
if (r.repo !== repo || !isMergeCandidate(r)) continue;
|
|
8584
|
+
const num = prNumberOf(r.pr_url);
|
|
8585
|
+
const seen = byPr.get(num);
|
|
8586
|
+
if (!seen || r.id > seen.id) byPr.set(num, r);
|
|
8587
|
+
}
|
|
8588
|
+
return [...byPr.values()];
|
|
8589
|
+
}
|
|
8590
|
+
var BASE_TTL_MS = 2e4;
|
|
8591
|
+
function makeMergeQueueResolver(deps) {
|
|
8592
|
+
const memo = /* @__PURE__ */ new Map();
|
|
8593
|
+
const evaluate = async (e, prUrl, ready) => {
|
|
8594
|
+
const now = Date.now();
|
|
8595
|
+
let cached = memo.get(prUrl);
|
|
8596
|
+
const ttl = deps.ttlMs ?? BASE_TTL_MS;
|
|
8597
|
+
if (!cached || now - cached.at >= ttl) {
|
|
8598
|
+
const base3 = await deps.baseSync(prUrl).catch(() => null);
|
|
8599
|
+
let checks = "none";
|
|
8600
|
+
if (base3?.behindBy === 0 && deps.checks) {
|
|
8601
|
+
const ci = await deps.checks(prUrl).catch(() => null);
|
|
8602
|
+
checks = ci ? ci.bucket : null;
|
|
8603
|
+
}
|
|
8604
|
+
cached = { at: now, base: base3, checks };
|
|
8605
|
+
memo.set(prUrl, cached);
|
|
8606
|
+
}
|
|
8607
|
+
return computeMergeQueue({ entry: e, ready, behindBy: cached.base ? cached.base.behindBy : null, checks: cached.checks });
|
|
8608
|
+
};
|
|
8609
|
+
return async (run) => {
|
|
8610
|
+
if (!deps.baseSync || !run.pr_url) return null;
|
|
8611
|
+
const num = prNumberOf(run.pr_url);
|
|
8612
|
+
if (num == null) return null;
|
|
8613
|
+
const candidates = mergeQueueCandidates(deps.listRuns(), run.repo);
|
|
8614
|
+
const mine = candidates.find((c) => prNumberOf(c.pr_url) === num);
|
|
8615
|
+
if (!mine) return null;
|
|
8616
|
+
const ready = [];
|
|
8617
|
+
const urlOf = /* @__PURE__ */ new Map();
|
|
8618
|
+
for (const c of candidates) {
|
|
8619
|
+
if (!await deps.gateAllows(c).catch(() => false)) continue;
|
|
8620
|
+
ready.push(entryOf(c));
|
|
8621
|
+
urlOf.set(c.id, c.pr_url);
|
|
8622
|
+
}
|
|
8623
|
+
const entry = entryOf(mine);
|
|
8624
|
+
if (!ready.some((e) => e.runId === entry.runId)) return null;
|
|
8625
|
+
let queue = orderMergeQueue(ready);
|
|
8626
|
+
while (queue.length > 1 && queue[0].runId !== entry.runId) {
|
|
8627
|
+
const head = queue[0];
|
|
8628
|
+
const headUrl = urlOf.get(head.runId);
|
|
8629
|
+
const decision = await evaluate(head, headUrl, queue);
|
|
8630
|
+
if (decision.code !== "checks_red") break;
|
|
8631
|
+
queue = queue.slice(1);
|
|
8632
|
+
}
|
|
8633
|
+
if (queue[0].runId !== entry.runId) {
|
|
8634
|
+
return computeMergeQueue({ entry, ready: queue, behindBy: null, checks: "none" });
|
|
8635
|
+
}
|
|
8636
|
+
return evaluate(entry, mine.pr_url, queue);
|
|
8637
|
+
};
|
|
8638
|
+
}
|
|
8639
|
+
function entryOf(r) {
|
|
8640
|
+
return { runId: r.id, prNumber: prNumberOf(r.pr_url), slug: r.task_slug };
|
|
8641
|
+
}
|
|
8642
|
+
|
|
8643
|
+
// src/mergeGate.ts
|
|
8480
8644
|
function findRunByPr(runs, ref) {
|
|
8481
8645
|
const num = prNumberOf(ref);
|
|
8482
8646
|
if (num == null) return null;
|
|
@@ -8488,17 +8652,34 @@ function findRunByPr(runs, ref) {
|
|
|
8488
8652
|
return best;
|
|
8489
8653
|
}
|
|
8490
8654
|
function makeMergeGateResolver(deps) {
|
|
8491
|
-
return
|
|
8492
|
-
|
|
8493
|
-
|
|
8655
|
+
return makeMergeGateParts(deps).gate;
|
|
8656
|
+
}
|
|
8657
|
+
function makeMergeGateParts(deps) {
|
|
8658
|
+
const gateFor = async (run) => {
|
|
8494
8659
|
const autoReview = deps.autoReview ? await deps.autoReview(run.repo).catch(() => deps.fallbackAutoReview) : deps.fallbackAutoReview;
|
|
8495
|
-
|
|
8660
|
+
return computeMergeGate({
|
|
8496
8661
|
hasRun: true,
|
|
8497
8662
|
autoReview,
|
|
8498
8663
|
reviewVerdict: run.review_verdict,
|
|
8499
8664
|
autoVerify: deps.autoVerify === true,
|
|
8500
8665
|
verifyVerdict: run.verify_verdict ?? null
|
|
8501
8666
|
});
|
|
8667
|
+
};
|
|
8668
|
+
const queueFor = makeMergeQueueResolver({
|
|
8669
|
+
listRuns: deps.listRuns,
|
|
8670
|
+
gateAllows: async (r) => (await gateFor(r)).allowed,
|
|
8671
|
+
...deps.baseSync ? { baseSync: deps.baseSync } : {},
|
|
8672
|
+
...deps.checks ? { checks: deps.checks } : {},
|
|
8673
|
+
...deps.ttlMs != null ? { ttlMs: deps.ttlMs } : {}
|
|
8674
|
+
});
|
|
8675
|
+
const gate = async (ref) => {
|
|
8676
|
+
const run = findRunByPr(deps.listRuns(), ref);
|
|
8677
|
+
if (!run) {
|
|
8678
|
+
return { ...computeMergeDecision(computeMergeGate({ hasRun: false, autoReview: false, reviewVerdict: null }), null), run: null };
|
|
8679
|
+
}
|
|
8680
|
+
const accept = await gateFor(run);
|
|
8681
|
+
const queue = accept.allowed && accept.code !== "unknown_pr" ? await queueFor(run) : null;
|
|
8682
|
+
const decision = computeMergeDecision(accept, queue);
|
|
8502
8683
|
return {
|
|
8503
8684
|
...decision,
|
|
8504
8685
|
run: {
|
|
@@ -8511,6 +8692,7 @@ function makeMergeGateResolver(deps) {
|
|
|
8511
8692
|
}
|
|
8512
8693
|
};
|
|
8513
8694
|
};
|
|
8695
|
+
return { gate, queue: queueFor };
|
|
8514
8696
|
}
|
|
8515
8697
|
|
|
8516
8698
|
// src/web.ts
|
|
@@ -10841,12 +11023,15 @@ async function previousHooksPath(worktree) {
|
|
|
10841
11023
|
}
|
|
10842
11024
|
async function removeWorktree(repo, path) {
|
|
10843
11025
|
const branch = (await $5({ reject: false })`git -C ${path} symbolic-ref --quiet --short HEAD`).stdout.trim();
|
|
11026
|
+
await releaseWorktree(repo, path);
|
|
11027
|
+
if (branch) await $5({ reject: false })`git -C ${repo} branch -D ${branch}`;
|
|
11028
|
+
}
|
|
11029
|
+
async function releaseWorktree(repo, path) {
|
|
10844
11030
|
await cleanupWorktreeProcesses(path);
|
|
10845
11031
|
await detachWorktree(repo, path);
|
|
10846
|
-
if (branch) await $5({ reject: false })`git -C ${repo} branch -D ${branch}`;
|
|
10847
11032
|
}
|
|
10848
11033
|
async function worktreeDirty(path) {
|
|
10849
|
-
const st = await $5({ reject: false })`git -C ${path} status --porcelain`;
|
|
11034
|
+
const st = await $5({ reject: false })`git -C ${path} status --porcelain --untracked-files=all`;
|
|
10850
11035
|
if (st.exitCode !== 0) return true;
|
|
10851
11036
|
const status = st.stdout.trim();
|
|
10852
11037
|
if (status) return true;
|