@taskless-app/swarm 0.6.31 → 0.6.33
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 +82 -17
- package/dist/overmind.js +1082 -505
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -2390,7 +2390,7 @@ function tokenFromFile() {
|
|
|
2390
2390
|
return "";
|
|
2391
2391
|
}
|
|
2392
2392
|
}
|
|
2393
|
-
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_REST_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;
|
|
2393
|
+
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, ENV_CACHE_DIR, ENV_CACHE_ENABLED, ENV_CACHE_KEEP, 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_REST_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;
|
|
2394
2394
|
var init_config = __esm({
|
|
2395
2395
|
"src/config.ts"() {
|
|
2396
2396
|
"use strict";
|
|
@@ -2416,6 +2416,9 @@ var init_config = __esm({
|
|
|
2416
2416
|
SWARM_OUTBOX = process.env.SWARM_OUTBOX || join5(SWARM_HOME, "outbox.jsonl");
|
|
2417
2417
|
SWARM_MAX_IN_FLIGHT = Math.trunc(envNum("SWARM_MAX_IN_FLIGHT", 3));
|
|
2418
2418
|
SWARM_CLAIM_INTERVAL_MS = envNum("SWARM_CLAIM_INTERVAL_MS", 6e4);
|
|
2419
|
+
ENV_CACHE_DIR = process.env.SWARM_ENV_CACHE_DIR || join5(SWARM_HOME, "env-cache");
|
|
2420
|
+
ENV_CACHE_ENABLED = process.env.SWARM_ENV_CACHE !== "0";
|
|
2421
|
+
ENV_CACHE_KEEP = Math.trunc(envNum("SWARM_ENV_CACHE_KEEP", 4));
|
|
2419
2422
|
SWARM_MAX_LOAD_FACTOR = envNum("SWARM_MAX_LOAD_FACTOR", 0.9);
|
|
2420
2423
|
SWARM_MIN_FREE_GB = envNum("SWARM_MIN_FREE_GB", 1.5);
|
|
2421
2424
|
SWARM_MAX_FD_LOAD_FACTOR = envNum("SWARM_MAX_FD_LOAD_FACTOR", 0.9);
|
|
@@ -3239,7 +3242,7 @@ var init_package = __esm({
|
|
|
3239
3242
|
"package.json"() {
|
|
3240
3243
|
package_default = {
|
|
3241
3244
|
name: "@taskless-app/swarm",
|
|
3242
|
-
version: "0.6.
|
|
3245
|
+
version: "0.6.33",
|
|
3243
3246
|
type: "module",
|
|
3244
3247
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
3245
3248
|
keywords: [
|
|
@@ -3290,7 +3293,7 @@ var init_package = __esm({
|
|
|
3290
3293
|
execa: "^10.0.0",
|
|
3291
3294
|
zod: "3.25.76"
|
|
3292
3295
|
},
|
|
3293
|
-
gitHead: "
|
|
3296
|
+
gitHead: "7b17b06b041af953afde46fbd41fc68ebc6dc4e9"
|
|
3294
3297
|
};
|
|
3295
3298
|
}
|
|
3296
3299
|
});
|
|
@@ -3362,6 +3365,40 @@ function noteTimedOut(scope, call, timeoutMs, outcome, warn = console.warn) {
|
|
|
3362
3365
|
function noiseKey(scope, call) {
|
|
3363
3366
|
return `timeout:${scope}:${call}`;
|
|
3364
3367
|
}
|
|
3368
|
+
function callFailureWord(f) {
|
|
3369
|
+
switch (f.reason) {
|
|
3370
|
+
case "timeout":
|
|
3371
|
+
return "\u043D\u0435 \u043E\u0442\u0432\u0435\u0442\u0438\u043B \u0437\u0430 \u043E\u0442\u0432\u0435\u0434\u0451\u043D\u043D\u043E\u0435 \u0432\u0440\u0435\u043C\u044F (\u043F\u0440\u0435\u0440\u0432\u0430\u043D)";
|
|
3372
|
+
case "unreadable":
|
|
3373
|
+
return "\u043E\u0442\u0432\u0435\u0442\u0438\u043B, \u043D\u043E \u0432\u044B\u0432\u043E\u0434 \u043D\u0435 \u0440\u0430\u0437\u043E\u0431\u0440\u0430\u043D";
|
|
3374
|
+
case "crashed":
|
|
3375
|
+
return "\u043D\u0435 \u0437\u0430\u043F\u0443\u0441\u0442\u0438\u043B\u0441\u044F";
|
|
3376
|
+
default:
|
|
3377
|
+
return "\u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043B\u0441\u044F \u0431\u0435\u0437 \u0432\u044B\u0432\u043E\u0434\u0430";
|
|
3378
|
+
}
|
|
3379
|
+
}
|
|
3380
|
+
function classifyCallFailure(outcome) {
|
|
3381
|
+
if (isTimedOut(outcome)) return { reason: "timeout", detail: firstLineOf(errText(outcome)) };
|
|
3382
|
+
const code = outcome?.code;
|
|
3383
|
+
if (code === "ENOENT") return { reason: "crashed", detail: firstLineOf(errText(outcome)) };
|
|
3384
|
+
return { reason: "empty", detail: firstLineOf(errText(outcome)) };
|
|
3385
|
+
}
|
|
3386
|
+
function errText(outcome) {
|
|
3387
|
+
const o = outcome;
|
|
3388
|
+
for (const v of [o?.stderr, o?.shortMessage, o?.message]) if (typeof v === "string" && v.trim()) return v;
|
|
3389
|
+
return "";
|
|
3390
|
+
}
|
|
3391
|
+
function firstLineOf(s) {
|
|
3392
|
+
return s.split("\n").map((l) => l.trim()).find((l) => l.length > 0) ?? "";
|
|
3393
|
+
}
|
|
3394
|
+
function noteCallFailure(scope, call, outcome, warn = console.warn) {
|
|
3395
|
+
const f = classifyCallFailure(outcome);
|
|
3396
|
+
if (f.reason === "timeout") return f;
|
|
3397
|
+
const line = `[${scope}] \u2716 \u0432\u044B\u0437\u043E\u0432 ${callFailureWord(f)}: ${call}${f.detail ? ` \u2014 ${f.detail}` : ""} \u2014 \u0440\u0435\u043A\u043E\u043D\u0441\u0430\u0439\u043B \u0438\u0434\u0451\u0442 \u0434\u0430\u043B\u044C\u0448\u0435`;
|
|
3398
|
+
const say = timeoutNoise.say(noiseKey(scope, call), line, Date.now());
|
|
3399
|
+
if (say) warn(say);
|
|
3400
|
+
return f;
|
|
3401
|
+
}
|
|
3365
3402
|
function humanMs(ms) {
|
|
3366
3403
|
return ms >= 1e3 ? `${Math.round(ms / 1e3)}\u0441` : `${ms}\u043C\u0441`;
|
|
3367
3404
|
}
|
|
@@ -9875,7 +9912,12 @@ import { basename as basename3 } from "path";
|
|
|
9875
9912
|
async function runGh(args, timeoutMs, cwd) {
|
|
9876
9913
|
const label2 = callLabel("gh", args) + (cwd ? ` (repo ${basename3(cwd)})` : "");
|
|
9877
9914
|
const child = cwd ? $4({ cwd, timeout: timeoutMs })`gh ${args}` : $4({ timeout: timeoutMs })`gh ${args}`;
|
|
9878
|
-
|
|
9915
|
+
try {
|
|
9916
|
+
return (await withHardTimeout(child, "gh", label2, timeoutMs)).stdout;
|
|
9917
|
+
} catch (e) {
|
|
9918
|
+
noteCallFailure("gh", label2, e);
|
|
9919
|
+
throw e;
|
|
9920
|
+
}
|
|
9879
9921
|
}
|
|
9880
9922
|
function ghRunner(timeoutMs = GH_CALL_TIMEOUT_MS) {
|
|
9881
9923
|
return (args) => runGh(args, timeoutMs);
|
|
@@ -9908,36 +9950,59 @@ var DENIED_STDERR = /(?:^|\D)403(?:\D|$)|not accessible by integration|must have
|
|
|
9908
9950
|
function firstLine(s) {
|
|
9909
9951
|
return s.split("\n").map((l) => l.trim()).find((l) => l.length > 0) ?? "gh \u0432\u0435\u0440\u043D\u0443\u043B 403";
|
|
9910
9952
|
}
|
|
9953
|
+
var GhCallFailedError = class extends Error {
|
|
9954
|
+
failure;
|
|
9955
|
+
constructor(call, failure) {
|
|
9956
|
+
super(`${call}: ${failure.reason}${failure.detail ? ` \u2014 ${failure.detail}` : ""}`);
|
|
9957
|
+
this.name = "GhCallFailedError";
|
|
9958
|
+
this.failure = failure;
|
|
9959
|
+
}
|
|
9960
|
+
};
|
|
9911
9961
|
var realChecksRunner = async (pr) => {
|
|
9912
|
-
const
|
|
9913
|
-
|
|
9914
|
-
"gh",
|
|
9915
|
-
callLabel("gh", ["pr", "checks", pr]),
|
|
9916
|
-
15e3
|
|
9917
|
-
);
|
|
9962
|
+
const label2 = callLabel("gh", ["pr", "checks", pr]);
|
|
9963
|
+
const r = await withHardTimeout($4({ reject: false, timeout: 15e3 })`gh pr checks ${pr} --json state,name,bucket,link`, "gh", label2, 15e3);
|
|
9918
9964
|
const stdout = r.stdout ?? "";
|
|
9919
9965
|
const stderr = r.stderr ?? "";
|
|
9966
|
+
if (isTimedOut(r)) throw new GhCallFailedError(label2, classifyCallFailure(r));
|
|
9920
9967
|
if (!stdout.trim() && NO_CHECKS_STDERR.test(stderr)) return "[]";
|
|
9921
9968
|
if (!stdout.trim() && DENIED_STDERR.test(stderr)) throw new CiAccessDeniedError(firstLine(stderr));
|
|
9969
|
+
if (!stdout.trim()) throw new GhCallFailedError(label2, noteCallFailure("gh", label2, r));
|
|
9922
9970
|
return stdout;
|
|
9923
9971
|
};
|
|
9924
9972
|
async function prCheckRows(pr, run) {
|
|
9973
|
+
let out;
|
|
9925
9974
|
try {
|
|
9926
|
-
|
|
9927
|
-
const rows = JSON.parse(out);
|
|
9928
|
-
if (!Array.isArray(rows)) return null;
|
|
9929
|
-
return rows.map((r) => ({ name: r.name ?? "?", bucket: (r.bucket ?? "").toLowerCase(), link: r.link ?? "" }));
|
|
9975
|
+
out = await run(pr);
|
|
9930
9976
|
} catch (e) {
|
|
9931
9977
|
if (e instanceof CiAccessDeniedError) return { denied: e.detail };
|
|
9932
|
-
return
|
|
9978
|
+
return { unavailable: e instanceof GhCallFailedError ? e.failure : classifyCallFailure(e) };
|
|
9933
9979
|
}
|
|
9980
|
+
let parsed;
|
|
9981
|
+
try {
|
|
9982
|
+
parsed = JSON.parse(out);
|
|
9983
|
+
} catch {
|
|
9984
|
+
return { unavailable: { reason: "unreadable", detail: headOfOutput(out) } };
|
|
9985
|
+
}
|
|
9986
|
+
if (!Array.isArray(parsed)) return { unavailable: { reason: "unreadable", detail: "\u043E\u0442\u0432\u0435\u0442 gh \u2014 \u043D\u0435 \u0441\u043F\u0438\u0441\u043E\u043A \u0447\u0435\u043A\u043E\u0432" } };
|
|
9987
|
+
return parsed.map((r) => ({
|
|
9988
|
+
name: r.name ?? "?",
|
|
9989
|
+
bucket: (r.bucket ?? "").toLowerCase(),
|
|
9990
|
+
link: r.link ?? ""
|
|
9991
|
+
}));
|
|
9992
|
+
}
|
|
9993
|
+
function headOfOutput(out) {
|
|
9994
|
+
const head = firstLine(out).slice(0, 120);
|
|
9995
|
+
return head === "gh \u0432\u0435\u0440\u043D\u0443\u043B 403" ? "\u043F\u0443\u0441\u0442\u043E" : head;
|
|
9934
9996
|
}
|
|
9935
9997
|
function isDenied(rows) {
|
|
9936
|
-
return
|
|
9998
|
+
return !Array.isArray(rows) && "denied" in rows;
|
|
9999
|
+
}
|
|
10000
|
+
function isUnavailable(rows) {
|
|
10001
|
+
return !Array.isArray(rows) && "unavailable" in rows;
|
|
9937
10002
|
}
|
|
9938
10003
|
async function ghChecks(pr, run = realChecksRunner) {
|
|
9939
10004
|
const rows = await prCheckRows(pr, run);
|
|
9940
|
-
if (
|
|
10005
|
+
if (isDenied(rows) || isUnavailable(rows) || rows.length === 0) return null;
|
|
9941
10006
|
let pass = 0, fail = 0, pending2 = 0;
|
|
9942
10007
|
for (const r of rows) {
|
|
9943
10008
|
if (r.bucket === "pass") pass++;
|