@taskless-app/swarm 0.6.62 → 0.6.63
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 +421 -182
- package/dist/overmind.js +571 -310
- package/package.json +2 -2
package/dist/overmind.js
CHANGED
|
@@ -592,10 +592,10 @@ function pick(rows) {
|
|
|
592
592
|
return newest(rows.filter((r) => r.author)) ?? newest(rows);
|
|
593
593
|
}
|
|
594
594
|
function pickRunForPr(rows, ref, ctxRepo) {
|
|
595
|
-
const
|
|
596
|
-
if (
|
|
595
|
+
const num2 = prNumberOf(ref);
|
|
596
|
+
if (num2 == null) return null;
|
|
597
597
|
const target = repoKeyOf(ref) ?? repoKeyOf(ctxRepo);
|
|
598
|
-
const hits = rows.filter((r) => r.prUrl && prNumberOf(r.prUrl) ===
|
|
598
|
+
const hits = rows.filter((r) => r.prUrl && prNumberOf(r.prUrl) === num2);
|
|
599
599
|
if (hits.length === 0) return null;
|
|
600
600
|
if (target) {
|
|
601
601
|
const mine = hits.filter((r) => keyOf(r) === target);
|
|
@@ -647,6 +647,9 @@ var init_returnReason = __esm({
|
|
|
647
647
|
});
|
|
648
648
|
|
|
649
649
|
// ../swarm-core/src/modelPolicy.ts
|
|
650
|
+
function isHarnessDefaultModel(model) {
|
|
651
|
+
return typeof model === "string" && model.trim().toLowerCase() === HARNESS_DEFAULT_MODEL;
|
|
652
|
+
}
|
|
650
653
|
function findProvider(id) {
|
|
651
654
|
const key = typeof id === "string" ? id.trim().toLowerCase() : "";
|
|
652
655
|
return MODEL_PROVIDERS.find((p) => p.id === key) ?? null;
|
|
@@ -698,6 +701,17 @@ var init_modelPolicy = __esm({
|
|
|
698
701
|
selectable: true,
|
|
699
702
|
roles: { executor: "glm-5.3", review: "glm-5.3" }
|
|
700
703
|
},
|
|
704
|
+
// Grok CLI. Каталог — живой `grok models` (16.10.2026), целиком и без выдуманных
|
|
705
|
+
// имён: grok-4.7 (дефолт CLI и исполнителя), grok-4.7-build-fast, grok-4.6, grok-4.5
|
|
706
|
+
// (проверка — младшая, та же идея, что sonnet против opus). Тарифа нет: цену пишет CLI.
|
|
707
|
+
{
|
|
708
|
+
id: "xai",
|
|
709
|
+
label: "xAI (Grok)",
|
|
710
|
+
executorId: "grok",
|
|
711
|
+
selectable: true,
|
|
712
|
+
roles: { executor: "grok-4.7", review: "grok-4.5" },
|
|
713
|
+
models: ["grok-4.7", "grok-4.7-build-fast", "grok-4.6", "grok-4.5"]
|
|
714
|
+
},
|
|
701
715
|
// TASWM-565 · шаг 1 из четырёх: провайдер в реестре ЕСТЬ, выбрать его ещё нельзя.
|
|
702
716
|
// Имён моделей здесь нет СОЗНАТЕЛЬНО: у владельца подписка, состав моделей в ней нам
|
|
703
717
|
// неизвестен, а выдуманное имя хуже маркера «решает Codex».
|
|
@@ -1183,18 +1197,18 @@ var init_hosts = __esm({
|
|
|
1183
1197
|
function parseHostResources(raw) {
|
|
1184
1198
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
1185
1199
|
const v = raw;
|
|
1186
|
-
const
|
|
1187
|
-
const memFreeGb =
|
|
1188
|
-
const memTotalGb =
|
|
1200
|
+
const num2 = (x) => typeof x === "number" && Number.isFinite(x) ? x : null;
|
|
1201
|
+
const memFreeGb = num2(v.memFreeGb);
|
|
1202
|
+
const memTotalGb = num2(v.memTotalGb);
|
|
1189
1203
|
if (memFreeGb == null || memTotalGb == null) return null;
|
|
1190
1204
|
if (typeof v.measuredAt !== "string" || Number.isNaN(Date.parse(v.measuredAt))) return null;
|
|
1191
|
-
const cpu =
|
|
1205
|
+
const cpu = num2(v.cpuBusyPct);
|
|
1192
1206
|
return {
|
|
1193
1207
|
cpuBusyPct: cpu == null ? null : Math.min(100, Math.max(0, cpu)),
|
|
1194
1208
|
memFreeGb,
|
|
1195
1209
|
memTotalGb,
|
|
1196
|
-
diskFreeGb:
|
|
1197
|
-
diskTotalGb:
|
|
1210
|
+
diskFreeGb: num2(v.diskFreeGb),
|
|
1211
|
+
diskTotalGb: num2(v.diskTotalGb),
|
|
1198
1212
|
measuredAt: v.measuredAt
|
|
1199
1213
|
};
|
|
1200
1214
|
}
|
|
@@ -1211,6 +1225,7 @@ var init_hostPool = __esm({
|
|
|
1211
1225
|
"../swarm-core/src/hostPool.ts"() {
|
|
1212
1226
|
"use strict";
|
|
1213
1227
|
init_hosts();
|
|
1228
|
+
init_modelPolicy();
|
|
1214
1229
|
HOST_REJECTION_TEXT = {
|
|
1215
1230
|
offline: "\u043D\u0435 \u043D\u0430 \u0441\u0432\u044F\u0437\u0438",
|
|
1216
1231
|
tick_stalled: `\u0446\u0438\u043A\u043B \u0440\u0435\u043A\u043E\u043D\u0441\u0430\u0439\u043B\u0430 \u0432\u0441\u0442\u0430\u043B \u2014 \u043F\u0443\u043B\u044C\u0441 \u0438\u0434\u0451\u0442, \u0440\u0430\u0431\u043E\u0442\u0443 \u043D\u0435 \u0431\u0435\u0440\u0451\u0442; ${HOST_TICK_STALLED_ACTION}`,
|
|
@@ -2330,10 +2345,10 @@ function launchCostUsd(result, model) {
|
|
|
2330
2345
|
return costFromUsage(result.usage, model);
|
|
2331
2346
|
}
|
|
2332
2347
|
function launchSpend(result) {
|
|
2333
|
-
const
|
|
2348
|
+
const num2 = (v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? v : 0;
|
|
2334
2349
|
const sum = (u) => ({
|
|
2335
|
-
tokensIn:
|
|
2336
|
-
tokensOut:
|
|
2350
|
+
tokensIn: num2(u.input_tokens) + num2(u.cache_creation_input_tokens) + num2(u.cache_read_input_tokens),
|
|
2351
|
+
tokensOut: num2(u.output_tokens)
|
|
2337
2352
|
});
|
|
2338
2353
|
const spend = sum(result.usage ?? {});
|
|
2339
2354
|
if (spend.tokensIn === 0 && spend.tokensOut === 0 && result.modelUsage) {
|
|
@@ -2343,7 +2358,7 @@ function launchSpend(result) {
|
|
|
2343
2358
|
spend.tokensOut += perModel.tokensOut;
|
|
2344
2359
|
}
|
|
2345
2360
|
}
|
|
2346
|
-
return { ...spend, durationMs:
|
|
2361
|
+
return { ...spend, durationMs: num2(result.duration_ms) };
|
|
2347
2362
|
}
|
|
2348
2363
|
function asTokenUsage(m) {
|
|
2349
2364
|
return {
|
|
@@ -2435,9 +2450,9 @@ function transcriptSpendInWindow(worktree, fromMs, toMs, opts = {}) {
|
|
|
2435
2450
|
unpriced += 1;
|
|
2436
2451
|
unpricedModel ??= model;
|
|
2437
2452
|
}
|
|
2438
|
-
const
|
|
2439
|
-
tokensIn +=
|
|
2440
|
-
tokensOut +=
|
|
2453
|
+
const num2 = (v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? v : 0;
|
|
2454
|
+
tokensIn += num2(usage.input_tokens) + num2(usage.cache_creation_input_tokens) + num2(usage.cache_read_input_tokens);
|
|
2455
|
+
tokensOut += num2(usage.output_tokens);
|
|
2441
2456
|
if (firstAt === null || at < firstAt) firstAt = at;
|
|
2442
2457
|
if (lastAt === null || at > lastAt) lastAt = at;
|
|
2443
2458
|
replies += 1;
|
|
@@ -2665,13 +2680,15 @@ var init_swarmHome = __esm({
|
|
|
2665
2680
|
});
|
|
2666
2681
|
|
|
2667
2682
|
// src/executors/codex.ts
|
|
2668
|
-
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync as readdirSync4, statSync as statSync3, symlinkSync } from "fs";
|
|
2683
|
+
import { copyFileSync as copyFileSync2, existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync as readdirSync4, statSync as statSync3, symlinkSync } from "fs";
|
|
2669
2684
|
import { join as join6 } from "path";
|
|
2670
2685
|
function resolveCodexBin(env = process.env) {
|
|
2671
2686
|
return (env.SWARM_CODEX_BIN ?? "").trim() || "codex";
|
|
2672
2687
|
}
|
|
2673
2688
|
function codexHomePath(worktree, swarmHome = SWARM_HOME) {
|
|
2674
|
-
|
|
2689
|
+
const folded = worktree.replace(/[/.]/g, "-");
|
|
2690
|
+
const key = /[:\\]/.test(folded) ? worktree.replace(/[^A-Za-z0-9]+/g, "-").replace(/^-|-$/g, "") || "worktree" : folded;
|
|
2691
|
+
return join6(swarmHome, "executor-state", "codex", key);
|
|
2675
2692
|
}
|
|
2676
2693
|
function ensureCodexHome(worktree, realHome, env = process.env, swarmHome = SWARM_HOME) {
|
|
2677
2694
|
const home = codexHomePath(worktree, swarmHome);
|
|
@@ -2684,6 +2701,10 @@ function ensureCodexHome(worktree, realHome, env = process.env, swarmHome = SWAR
|
|
|
2684
2701
|
try {
|
|
2685
2702
|
symlinkSync(target, link2);
|
|
2686
2703
|
} catch {
|
|
2704
|
+
try {
|
|
2705
|
+
copyFileSync2(target, link2);
|
|
2706
|
+
} catch {
|
|
2707
|
+
}
|
|
2687
2708
|
}
|
|
2688
2709
|
}
|
|
2689
2710
|
return home;
|
|
@@ -2834,6 +2855,206 @@ ${notice}` : spec.prompt;
|
|
|
2834
2855
|
}
|
|
2835
2856
|
});
|
|
2836
2857
|
|
|
2858
|
+
// src/executors/grok.ts
|
|
2859
|
+
import { copyFileSync as copyFileSync3, existsSync as existsSync5, mkdirSync as mkdirSync4, readdirSync as readdirSync5, statSync as statSync4, symlinkSync as symlinkSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
2860
|
+
import { join as join7 } from "path";
|
|
2861
|
+
function resolveGrokBin(env = process.env) {
|
|
2862
|
+
return (env.SWARM_GROK_BIN ?? "").trim() || "grok";
|
|
2863
|
+
}
|
|
2864
|
+
function grokHomePath(worktree, swarmHome = SWARM_HOME) {
|
|
2865
|
+
const key = worktree.replace(/[^A-Za-z0-9]+/g, "-").replace(/^-|-$/g, "") || "worktree";
|
|
2866
|
+
return join7(swarmHome, "executor-state", "grok", key);
|
|
2867
|
+
}
|
|
2868
|
+
function grokSessionDir(worktree, swarmHome = SWARM_HOME) {
|
|
2869
|
+
return join7(grokHomePath(worktree, swarmHome), "sessions", encodeURIComponent(worktree));
|
|
2870
|
+
}
|
|
2871
|
+
function tomlBasic(value) {
|
|
2872
|
+
const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r");
|
|
2873
|
+
return `"${escaped}"`;
|
|
2874
|
+
}
|
|
2875
|
+
function grokMcpToml(spec) {
|
|
2876
|
+
const env = Object.entries(spec.mcp.env).map(([k, v]) => `${k} = ${tomlBasic(v)}`).join(", ");
|
|
2877
|
+
const args = spec.mcp.args.map((a) => tomlBasic(a)).join(", ");
|
|
2878
|
+
return [
|
|
2879
|
+
"[mcp_servers." + spec.mcp.name + "]",
|
|
2880
|
+
"command = " + tomlBasic(spec.mcp.command),
|
|
2881
|
+
"args = [" + args + "]",
|
|
2882
|
+
"env = { " + env + " }",
|
|
2883
|
+
""
|
|
2884
|
+
].join("\n");
|
|
2885
|
+
}
|
|
2886
|
+
function ensureGrokHome(worktree, realHome, env = process.env, swarmHome = SWARM_HOME) {
|
|
2887
|
+
const home = grokHomePath(worktree, swarmHome);
|
|
2888
|
+
mkdirSync4(home, { recursive: true });
|
|
2889
|
+
const real = (env.GROK_HOME ?? "").trim() || join7(realHome, ".grok");
|
|
2890
|
+
const target = join7(real, "auth.json");
|
|
2891
|
+
const link2 = join7(home, "auth.json");
|
|
2892
|
+
if (existsSync5(target) && !existsSync5(link2)) {
|
|
2893
|
+
try {
|
|
2894
|
+
symlinkSync2(target, link2);
|
|
2895
|
+
} catch {
|
|
2896
|
+
try {
|
|
2897
|
+
copyFileSync3(target, link2);
|
|
2898
|
+
} catch {
|
|
2899
|
+
}
|
|
2900
|
+
}
|
|
2901
|
+
}
|
|
2902
|
+
return home;
|
|
2903
|
+
}
|
|
2904
|
+
function modelArgs(model) {
|
|
2905
|
+
if (!model || isHarnessDefaultModel(model)) return [];
|
|
2906
|
+
return ["--model", model];
|
|
2907
|
+
}
|
|
2908
|
+
function denyArgs(paths) {
|
|
2909
|
+
return paths.flatMap((p) => ["--deny", `Read(${p}) Edit(${p}) Write(${p})`]);
|
|
2910
|
+
}
|
|
2911
|
+
function newestSessionMtime(dir, depth = 3) {
|
|
2912
|
+
let entries;
|
|
2913
|
+
try {
|
|
2914
|
+
entries = readdirSync5(dir, { withFileTypes: true });
|
|
2915
|
+
} catch {
|
|
2916
|
+
return null;
|
|
2917
|
+
}
|
|
2918
|
+
let latest = null;
|
|
2919
|
+
for (const entry of entries) {
|
|
2920
|
+
const full = join7(dir, entry.name);
|
|
2921
|
+
try {
|
|
2922
|
+
if (entry.isDirectory()) {
|
|
2923
|
+
if (depth <= 0) continue;
|
|
2924
|
+
const nested = newestSessionMtime(full, depth - 1);
|
|
2925
|
+
if (nested != null && (latest == null || nested > latest)) latest = nested;
|
|
2926
|
+
} else if (entry.isFile()) {
|
|
2927
|
+
const mtime2 = statSync4(full).mtimeMs;
|
|
2928
|
+
if (latest == null || mtime2 > latest) latest = mtime2;
|
|
2929
|
+
}
|
|
2930
|
+
} catch {
|
|
2931
|
+
}
|
|
2932
|
+
}
|
|
2933
|
+
return latest;
|
|
2934
|
+
}
|
|
2935
|
+
function num(v) {
|
|
2936
|
+
return typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
2937
|
+
}
|
|
2938
|
+
function grokAbort(rec) {
|
|
2939
|
+
if (rec.type === "error") {
|
|
2940
|
+
const raw = typeof rec.message === "string" && rec.message ? rec.message : "error";
|
|
2941
|
+
const kind = /tool/i.test(raw) ? "tools" : /401|unauthorized|network|fetch|ECONN|api/i.test(raw) ? "link" : "other";
|
|
2942
|
+
return { kind, raw: raw.slice(0, 300) };
|
|
2943
|
+
}
|
|
2944
|
+
const stop = typeof rec.stopReason === "string" ? rec.stopReason : "";
|
|
2945
|
+
if (rec.is_error === true || stop === "error" || stop.startsWith("error_")) {
|
|
2946
|
+
const raw = stop || "is_error";
|
|
2947
|
+
return { kind: /tool/i.test(raw) ? "tools" : "other", raw };
|
|
2948
|
+
}
|
|
2949
|
+
return void 0;
|
|
2950
|
+
}
|
|
2951
|
+
function parseGrokResult(raw) {
|
|
2952
|
+
const trimmed = raw.trim();
|
|
2953
|
+
if (!trimmed) return null;
|
|
2954
|
+
let parsed;
|
|
2955
|
+
try {
|
|
2956
|
+
parsed = JSON.parse(trimmed);
|
|
2957
|
+
} catch {
|
|
2958
|
+
return null;
|
|
2959
|
+
}
|
|
2960
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return null;
|
|
2961
|
+
const rec = parsed;
|
|
2962
|
+
const hasShape = typeof rec.text === "string" || typeof rec.stopReason === "string" || typeof rec.sessionId === "string" || rec.type === "error";
|
|
2963
|
+
if (!hasShape) return null;
|
|
2964
|
+
const reported = typeof rec.total_cost_usd === "number" && Number.isFinite(rec.total_cost_usd);
|
|
2965
|
+
const usage = rec.usage;
|
|
2966
|
+
let tokensIn;
|
|
2967
|
+
let tokensOut;
|
|
2968
|
+
if (typeof usage === "object" && usage !== null) {
|
|
2969
|
+
const u = usage;
|
|
2970
|
+
const hasAny = ["input_tokens", "output_tokens", "cache_read_input_tokens", "cache_creation_input_tokens"].some(
|
|
2971
|
+
(k) => typeof u[k] === "number"
|
|
2972
|
+
);
|
|
2973
|
+
if (hasAny) {
|
|
2974
|
+
tokensIn = num(u.input_tokens) + num(u.cache_read_input_tokens) + num(u.cache_creation_input_tokens);
|
|
2975
|
+
tokensOut = num(u.output_tokens);
|
|
2976
|
+
}
|
|
2977
|
+
}
|
|
2978
|
+
const aborted = grokAbort(rec);
|
|
2979
|
+
const result = {
|
|
2980
|
+
costUsd: reported ? rec.total_cost_usd : 0
|
|
2981
|
+
};
|
|
2982
|
+
if (!reported) result.warning = "grok: total_cost_usd \u043D\u0435\u0442 \u2014 \u0441\u0442\u043E\u0438\u043C\u043E\u0441\u0442\u044C \u043F\u0440\u043E\u0433\u043E\u043D\u0430 \u043D\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0430 (\u044D\u0442\u043E \u043D\u0435 \u043D\u043E\u043B\u044C)";
|
|
2983
|
+
if (tokensIn != null && tokensOut != null) {
|
|
2984
|
+
result.tokensIn = tokensIn;
|
|
2985
|
+
result.tokensOut = tokensOut;
|
|
2986
|
+
}
|
|
2987
|
+
if (aborted) result.aborted = aborted;
|
|
2988
|
+
return result;
|
|
2989
|
+
}
|
|
2990
|
+
var grokExecutor;
|
|
2991
|
+
var init_grok = __esm({
|
|
2992
|
+
"src/executors/grok.ts"() {
|
|
2993
|
+
"use strict";
|
|
2994
|
+
init_src();
|
|
2995
|
+
init_swarmHome();
|
|
2996
|
+
init_swarmFiles();
|
|
2997
|
+
init_codex();
|
|
2998
|
+
grokExecutor = {
|
|
2999
|
+
id: "grok",
|
|
3000
|
+
title: "Grok CLI (grok)",
|
|
3001
|
+
binEnv: "SWARM_GROK_BIN",
|
|
3002
|
+
install: {
|
|
3003
|
+
what: "Grok CLI (xAI). \u0421\u0442\u0430\u0432\u0438\u0442\u0441\u044F \u043E\u0444\u0438\u0446\u0438\u0430\u043B\u044C\u043D\u044B\u043C \u0438\u043D\u0441\u0442\u0430\u043B\u043B\u0435\u0440\u043E\u043C, \u043D\u0435 \u0447\u0435\u0440\u0435\u0437 npm.",
|
|
3004
|
+
pkg: "grok",
|
|
3005
|
+
command: "curl -fsSL https://x.ai/cli/install.sh | bash",
|
|
3006
|
+
windowsCommand: "irm https://x.ai/cli/install.ps1 | iex"
|
|
3007
|
+
},
|
|
3008
|
+
resolveBin: (env) => resolveGrokBin(env ?? process.env),
|
|
3009
|
+
plan: (spec) => {
|
|
3010
|
+
const home = ensureGrokHome(spec.worktree, spec.realHome);
|
|
3011
|
+
writeFileSync4(join7(home, "config.toml"), grokMcpToml(spec));
|
|
3012
|
+
writeFileSync4(
|
|
3013
|
+
join7(spec.worktree, SWARM_MCP_CONFIG_FILE),
|
|
3014
|
+
JSON.stringify(
|
|
3015
|
+
{ mcpServers: { [spec.mcp.name]: { command: spec.mcp.command, args: spec.mcp.args, env: spec.mcp.env } } },
|
|
3016
|
+
null,
|
|
3017
|
+
2
|
|
3018
|
+
)
|
|
3019
|
+
);
|
|
3020
|
+
const notice = skillsNotice(spec.skillDirs);
|
|
3021
|
+
const prompt = notice ? `${spec.prompt}
|
|
3022
|
+
|
|
3023
|
+
${notice}` : spec.prompt;
|
|
3024
|
+
const args = [
|
|
3025
|
+
// `--cwd` стоит первым: по нему реконсайл узнаёт worktree живого процесса.
|
|
3026
|
+
// Флаг настоящий. Выдуманный `--mcp-config` grok отверг бы и дрон не стартовал.
|
|
3027
|
+
"--cwd",
|
|
3028
|
+
spec.worktree,
|
|
3029
|
+
"--no-auto-update",
|
|
3030
|
+
"--output-format",
|
|
3031
|
+
"json",
|
|
3032
|
+
"--yolo",
|
|
3033
|
+
...spec.continueSession ? ["--continue"] : [],
|
|
3034
|
+
...modelArgs(spec.model),
|
|
3035
|
+
...spec.effort ? ["--effort", spec.effort] : [],
|
|
3036
|
+
...denyArgs(spec.denyPaths),
|
|
3037
|
+
"-p",
|
|
3038
|
+
prompt
|
|
3039
|
+
];
|
|
3040
|
+
return { bin: resolveGrokBin(), args, env: { GROK_HOME: home } };
|
|
3041
|
+
},
|
|
3042
|
+
parseResult(raw) {
|
|
3043
|
+
return parseGrokResult(raw);
|
|
3044
|
+
},
|
|
3045
|
+
session: {
|
|
3046
|
+
exists: (worktree) => newestSessionMtime(grokSessionDir(worktree)) !== null,
|
|
3047
|
+
mtimeMs: (worktree) => newestSessionMtime(grokSessionDir(worktree))
|
|
3048
|
+
},
|
|
3049
|
+
probe: {
|
|
3050
|
+
args: ["-p", "ok", "--output-format", "json", "--yolo", "--max-turns", "1", "--no-auto-update"],
|
|
3051
|
+
limitPattern: /usage limit/i,
|
|
3052
|
+
authPattern: /not logged in|unauthorized|\b401\b|authentication required|auth required/i
|
|
3053
|
+
}
|
|
3054
|
+
};
|
|
3055
|
+
}
|
|
3056
|
+
});
|
|
3057
|
+
|
|
2837
3058
|
// src/swarmModels.ts
|
|
2838
3059
|
function pick2(v) {
|
|
2839
3060
|
const s = typeof v === "string" ? v.trim() : "";
|
|
@@ -2849,10 +3070,22 @@ function forKind(kind, swarm, norm) {
|
|
|
2849
3070
|
if (!swarm) return null;
|
|
2850
3071
|
return isReviewKind(kind) ? norm(swarm.reviewer) ?? norm(swarm.drone) : norm(swarm.drone);
|
|
2851
3072
|
}
|
|
3073
|
+
function providersFromEnv(env = process.env) {
|
|
3074
|
+
const raw = (env.SWARM_PROVIDERS ?? "").trim();
|
|
3075
|
+
if (!raw) return null;
|
|
3076
|
+
const known = new Set(MODEL_PROVIDERS.map((p) => p.id));
|
|
3077
|
+
const list = [...new Set(raw.split(/[\s,]+/).map((p) => p.trim().toLowerCase()).filter((p) => known.has(p)))];
|
|
3078
|
+
return list.length ? list : null;
|
|
3079
|
+
}
|
|
2852
3080
|
function resolveRunModelRef(run, swarm, env = process.env) {
|
|
2853
|
-
const
|
|
2854
|
-
|
|
2855
|
-
);
|
|
3081
|
+
const pinned = parseModelRef(pick2(run.model));
|
|
3082
|
+
if (pinned) return pinned;
|
|
3083
|
+
const configured = parseModelRef(forKind(run.kind, swarm, pick2) ?? pick2(env.SWARM_DRONE_MODEL));
|
|
3084
|
+
const own = providersFromEnv(env);
|
|
3085
|
+
if (own) {
|
|
3086
|
+
if (configured && own.includes(configured.providerId)) return configured;
|
|
3087
|
+
return { providerId: own[0], model: defaultModelFor(modelRoleOf(run.kind), own[0]) };
|
|
3088
|
+
}
|
|
2856
3089
|
if (configured) return configured;
|
|
2857
3090
|
const providerId = pick2(env.SWARM_MODEL_PROVIDER) ?? DEFAULT_PROVIDER_ID;
|
|
2858
3091
|
return { providerId, model: defaultModelFor(modelRoleOf(run.kind), providerId) };
|
|
@@ -2899,14 +3132,17 @@ var init_executors = __esm({
|
|
|
2899
3132
|
init_src();
|
|
2900
3133
|
init_claudeCode();
|
|
2901
3134
|
init_codex();
|
|
3135
|
+
init_grok();
|
|
2902
3136
|
init_swarmModels();
|
|
2903
3137
|
init_types2();
|
|
2904
3138
|
init_claudeCode();
|
|
2905
3139
|
init_codex();
|
|
3140
|
+
init_grok();
|
|
2906
3141
|
DEFAULT_EXECUTOR_ID = "claude-code";
|
|
2907
3142
|
EXECUTORS = {
|
|
2908
3143
|
[claudeCodeExecutor.id]: claudeCodeExecutor,
|
|
2909
|
-
[codexExecutor.id]: codexExecutor
|
|
3144
|
+
[codexExecutor.id]: codexExecutor,
|
|
3145
|
+
[grokExecutor.id]: grokExecutor
|
|
2910
3146
|
};
|
|
2911
3147
|
}
|
|
2912
3148
|
});
|
|
@@ -3013,8 +3249,8 @@ __export(config_exports, {
|
|
|
3013
3249
|
restEndpoint: () => restEndpoint,
|
|
3014
3250
|
reviewCutoffAt: () => reviewCutoffAt
|
|
3015
3251
|
});
|
|
3016
|
-
import { basename, join as
|
|
3017
|
-
import { readFileSync as readFileSync4, realpathSync, renameSync as renameSync2, writeFileSync as
|
|
3252
|
+
import { basename, join as join8, resolve } from "path";
|
|
3253
|
+
import { readFileSync as readFileSync4, realpathSync, renameSync as renameSync2, writeFileSync as writeFileSync5 } from "fs";
|
|
3018
3254
|
function normalizeRepo(repo) {
|
|
3019
3255
|
const r = (repo ?? "").trim();
|
|
3020
3256
|
if (!r) return "";
|
|
@@ -3028,10 +3264,10 @@ function effectiveRepoOf(repo, fallback) {
|
|
|
3028
3264
|
return normalizeRepo(repo || fallback || "");
|
|
3029
3265
|
}
|
|
3030
3266
|
function droneWorktreePath(worktreesDir, repo, slug) {
|
|
3031
|
-
return
|
|
3267
|
+
return join8(droneWorktreeRoot(worktreesDir, repo), slug);
|
|
3032
3268
|
}
|
|
3033
3269
|
function droneWorktreeRoot(worktreesDir, repo) {
|
|
3034
|
-
return
|
|
3270
|
+
return join8(worktreesDir, basename(normalizeRepo(repo)));
|
|
3035
3271
|
}
|
|
3036
3272
|
function resolveEffectiveWorktreesDir(deps) {
|
|
3037
3273
|
if (deps.envOverride) return deps.envOverride;
|
|
@@ -3079,7 +3315,7 @@ function mcpEndpoint(api, path = TASKLESS_MCP_PATH) {
|
|
|
3079
3315
|
}
|
|
3080
3316
|
function tokenFromFile() {
|
|
3081
3317
|
try {
|
|
3082
|
-
return readFileSync4(
|
|
3318
|
+
return readFileSync4(join8(SWARM_HOME, "token"), "utf8").trim();
|
|
3083
3319
|
} catch {
|
|
3084
3320
|
return "";
|
|
3085
3321
|
}
|
|
@@ -3093,7 +3329,7 @@ function reviewCutoffAt() {
|
|
|
3093
3329
|
const at = stamp();
|
|
3094
3330
|
try {
|
|
3095
3331
|
const tmp = `${REVIEW_CUTOFF_PATH}.tmp`;
|
|
3096
|
-
|
|
3332
|
+
writeFileSync5(tmp, JSON.stringify({ at }));
|
|
3097
3333
|
renameSync2(tmp, REVIEW_CUTOFF_PATH);
|
|
3098
3334
|
} catch {
|
|
3099
3335
|
}
|
|
@@ -3107,25 +3343,25 @@ var init_config = __esm({
|
|
|
3107
3343
|
init_executors();
|
|
3108
3344
|
init_swarmHome();
|
|
3109
3345
|
init_swarmHome();
|
|
3110
|
-
DB_PATH = process.env.SWARM_DB ||
|
|
3346
|
+
DB_PATH = process.env.SWARM_DB || join8(SWARM_HOME, "swarm.db");
|
|
3111
3347
|
EXECUTOR = resolveExecutor(process.env.SWARM_EXECUTOR);
|
|
3112
|
-
DRONE_HOME = process.env.SWARM_DRONE_HOME ||
|
|
3348
|
+
DRONE_HOME = process.env.SWARM_DRONE_HOME || join8(SWARM_HOME, "drone-home");
|
|
3113
3349
|
DRONE_HOME_ISOLATION = process.env.SWARM_DRONE_ISOLATE_HOME !== "0" && process.platform !== "win32";
|
|
3114
3350
|
DRONE_ISOLATION = DRONE_HOME_ISOLATION ? { home: DRONE_HOME, swarmHome: SWARM_HOME } : void 0;
|
|
3115
|
-
WORKTREES_NOINDEX_DIR =
|
|
3116
|
-
WORKTREES_LEGACY_DIR =
|
|
3351
|
+
WORKTREES_NOINDEX_DIR = join8(SWARM_HOME, "worktrees.noindex");
|
|
3352
|
+
WORKTREES_LEGACY_DIR = join8(SWARM_HOME, "worktrees");
|
|
3117
3353
|
WORKTREES_DIR = process.env.SWARM_WORKTREES || WORKTREES_NOINDEX_DIR;
|
|
3118
|
-
RUN_LOGS_DIR = process.env.SWARM_RUN_LOGS ||
|
|
3119
|
-
DAEMON_LOG_PATH = process.env.SWARM_DAEMON_LOG ||
|
|
3354
|
+
RUN_LOGS_DIR = process.env.SWARM_RUN_LOGS || join8(SWARM_HOME, "run-logs");
|
|
3355
|
+
DAEMON_LOG_PATH = process.env.SWARM_DAEMON_LOG || join8(SWARM_HOME, "overmind.log");
|
|
3120
3356
|
DAEMON_LOG_MAX_BYTES = envNum("SWARM_DAEMON_LOG_MAX_BYTES", 16 * 1024 * 1024);
|
|
3121
3357
|
DAEMON_LOG_KEEP = envNum("SWARM_DAEMON_LOG_KEEP", 2);
|
|
3122
3358
|
DAEMON_LOG_CHECK_MS = envNum("SWARM_DAEMON_LOG_CHECK_MS", 6e4);
|
|
3123
3359
|
DIST_BUILD = true;
|
|
3124
3360
|
SWARM_BACKEND = process.env.SWARM_BACKEND === "client" ? "client" : process.env.SWARM_BACKEND === "sqlite" ? "sqlite" : DIST_BUILD ? "client" : "sqlite";
|
|
3125
|
-
SWARM_OUTBOX = process.env.SWARM_OUTBOX ||
|
|
3361
|
+
SWARM_OUTBOX = process.env.SWARM_OUTBOX || join8(SWARM_HOME, "outbox.jsonl");
|
|
3126
3362
|
SWARM_MAX_IN_FLIGHT = Math.trunc(envNum("SWARM_MAX_IN_FLIGHT", 3));
|
|
3127
3363
|
SWARM_CLAIM_INTERVAL_MS = envNum("SWARM_CLAIM_INTERVAL_MS", 6e4);
|
|
3128
|
-
ENV_CACHE_DIR = process.env.SWARM_ENV_CACHE_DIR ||
|
|
3364
|
+
ENV_CACHE_DIR = process.env.SWARM_ENV_CACHE_DIR || join8(SWARM_HOME, "env-cache");
|
|
3129
3365
|
ENV_CACHE_ENABLED = process.env.SWARM_ENV_CACHE !== "0";
|
|
3130
3366
|
ENV_CACHE_KEEP = Math.trunc(envNum("SWARM_ENV_CACHE_KEEP", 4));
|
|
3131
3367
|
SWARM_MAX_LOAD_FACTOR = envNum("SWARM_MAX_LOAD_FACTOR", 0.9);
|
|
@@ -3155,15 +3391,15 @@ var init_config = __esm({
|
|
|
3155
3391
|
DRONE_CHANNEL_ENABLED = process.env.SWARM_DRONE_CHANNEL !== "0";
|
|
3156
3392
|
DRONE_CHANNEL_PORT = Number(process.env.SWARM_DRONE_CHANNEL_PORT) || 7421;
|
|
3157
3393
|
DRONE_CHANNEL_URL = process.env.SWARM_DRONE_CHANNEL_URL || `http://127.0.0.1:${DRONE_CHANNEL_PORT}`;
|
|
3158
|
-
DRONE_CHANNEL_SECRET_PATH = process.env.SWARM_DRONE_CHANNEL_SECRET ||
|
|
3394
|
+
DRONE_CHANNEL_SECRET_PATH = process.env.SWARM_DRONE_CHANNEL_SECRET || join8(SWARM_HOME, "drone-channel.key");
|
|
3159
3395
|
DRONE_CHANNEL_GRACE_MS = envNum("SWARM_DRONE_CHANNEL_GRACE_MS", 12e4);
|
|
3160
|
-
HEARTBEAT_PATH = process.env.SWARM_HEARTBEAT ||
|
|
3396
|
+
HEARTBEAT_PATH = process.env.SWARM_HEARTBEAT || join8(SWARM_HOME, "overmind.heartbeat");
|
|
3161
3397
|
HEARTBEAT_STALE_MS = Number(process.env.SWARM_HEARTBEAT_STALE_MS) || 3e4;
|
|
3162
3398
|
SWARM_REPO = process.env.SWARM_REPO || "";
|
|
3163
3399
|
SWARM_SCAN_DEPTH = Number(process.env.SWARM_SCAN_DEPTH) || 3;
|
|
3164
3400
|
SWARM_REPO_PATHS = (process.env.SWARM_REPOS || SWARM_REPO).split(",").map((s) => s.trim()).filter(Boolean);
|
|
3165
3401
|
SWARM_SCAN_ROOTS_RAW = process.env.SWARM_SCAN_ROOTS || "";
|
|
3166
|
-
REPO_MAP_PATH = process.env.SWARM_REPO_MAP ||
|
|
3402
|
+
REPO_MAP_PATH = process.env.SWARM_REPO_MAP || join8(SWARM_HOME, "repo-map.json");
|
|
3167
3403
|
SWARM_REPO_MAP_MS = envNum("SWARM_REPO_MAP_MS", 15 * 6e4);
|
|
3168
3404
|
SWARM_REPO_SCAN_TTL_MS = envNum("SWARM_REPO_SCAN_TTL_MS", 24 * 60 * 6e4);
|
|
3169
3405
|
TASKLESS_API = process.env.TASKLESS_API || "https://taskless.ru";
|
|
@@ -3178,7 +3414,7 @@ var init_config = __esm({
|
|
|
3178
3414
|
SWARM_AUTO_REVIEW = process.env.SWARM_AUTO_REVIEW !== "0";
|
|
3179
3415
|
SWARM_AUTO_VERIFY = process.env.SWARM_AUTO_VERIFY !== "0";
|
|
3180
3416
|
SWARM_MERGE_QUEUE = process.env.SWARM_MERGE_QUEUE !== "0";
|
|
3181
|
-
REVIEW_CUTOFF_PATH = process.env.SWARM_REVIEW_CUTOFF ||
|
|
3417
|
+
REVIEW_CUTOFF_PATH = process.env.SWARM_REVIEW_CUTOFF || join8(SWARM_HOME, "review-cutoff.json");
|
|
3182
3418
|
SWARM_REVIEW_CAP = Math.trunc(envNum("SWARM_REVIEW_CAP", 1));
|
|
3183
3419
|
SWARM_STORM_URL = process.env.SWARM_STORM_URL || "";
|
|
3184
3420
|
WEB_PORT = Number(process.env.SWARM_WEB_PORT) || 7420;
|
|
@@ -3702,8 +3938,8 @@ var init_store = __esm({
|
|
|
3702
3938
|
});
|
|
3703
3939
|
|
|
3704
3940
|
// src/agentToken.ts
|
|
3705
|
-
import { readFileSync as readFileSync6, writeFileSync as
|
|
3706
|
-
import { join as
|
|
3941
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync6, unlinkSync as unlinkSync2 } from "fs";
|
|
3942
|
+
import { join as join9 } from "path";
|
|
3707
3943
|
function loadAgentToken() {
|
|
3708
3944
|
try {
|
|
3709
3945
|
const s = JSON.parse(readFileSync6(STORE_PATH, "utf8"));
|
|
@@ -3759,7 +3995,7 @@ var init_agentToken = __esm({
|
|
|
3759
3995
|
"src/agentToken.ts"() {
|
|
3760
3996
|
"use strict";
|
|
3761
3997
|
init_config();
|
|
3762
|
-
STORE_PATH =
|
|
3998
|
+
STORE_PATH = join9(SWARM_HOME, "agent.json");
|
|
3763
3999
|
base = (api) => api.replace(/\/$/, "");
|
|
3764
4000
|
TOKEN_PROBE_TIMEOUT_MS = 8e3;
|
|
3765
4001
|
}
|
|
@@ -3873,10 +4109,10 @@ var init_toolFailure = __esm({
|
|
|
3873
4109
|
});
|
|
3874
4110
|
|
|
3875
4111
|
// src/heartbeat.ts
|
|
3876
|
-
import { readFileSync as readFileSync8, renameSync as renameSync4, writeFileSync as
|
|
4112
|
+
import { readFileSync as readFileSync8, renameSync as renameSync4, writeFileSync as writeFileSync8 } from "fs";
|
|
3877
4113
|
function writeHeartbeat(path, now) {
|
|
3878
4114
|
const tmp = `${path}.tmp`;
|
|
3879
|
-
|
|
4115
|
+
writeFileSync8(tmp, String(now));
|
|
3880
4116
|
renameSync4(tmp, path);
|
|
3881
4117
|
}
|
|
3882
4118
|
function readHeartbeat(path) {
|
|
@@ -4367,9 +4603,9 @@ var init_procCleanup = __esm({
|
|
|
4367
4603
|
});
|
|
4368
4604
|
|
|
4369
4605
|
// src/git.ts
|
|
4370
|
-
import { existsSync as
|
|
4606
|
+
import { existsSync as existsSync13, readdirSync as readdirSync13, realpathSync as realpathSync2, statSync as statSync11 } from "fs";
|
|
4371
4607
|
import { appendFile, chmod, mkdir, readFile, rename, rm, writeFile } from "fs/promises";
|
|
4372
|
-
import { isAbsolute as isAbsolute3, join as
|
|
4608
|
+
import { isAbsolute as isAbsolute3, join as join22, resolve as resolve3, sep as sep2 } from "path";
|
|
4373
4609
|
import { $ as $2 } from "execa";
|
|
4374
4610
|
function gitNet(repo, args, timeoutMs) {
|
|
4375
4611
|
return withHardTimeout(
|
|
@@ -4391,14 +4627,14 @@ async function reclaimStaleWorktree(repo, worktree) {
|
|
|
4391
4627
|
await detachWorktree(repo, worktree);
|
|
4392
4628
|
}
|
|
4393
4629
|
async function inspectWorktreePath(path) {
|
|
4394
|
-
if (!
|
|
4630
|
+
if (!existsSync13(path)) return "free";
|
|
4395
4631
|
try {
|
|
4396
|
-
if (
|
|
4632
|
+
if (readdirSync13(path).length === 0) return "free";
|
|
4397
4633
|
} catch {
|
|
4398
4634
|
return "orphan";
|
|
4399
4635
|
}
|
|
4400
4636
|
try {
|
|
4401
|
-
if (
|
|
4637
|
+
if (statSync11(join22(path, ".git")).isDirectory()) return "main-checkout";
|
|
4402
4638
|
} catch {
|
|
4403
4639
|
}
|
|
4404
4640
|
const top = await $2({ reject: false })`git -C ${path} rev-parse --show-toplevel`;
|
|
@@ -4437,7 +4673,7 @@ async function clearWorktreePath(repo, path, branch, opts = {}) {
|
|
|
4437
4673
|
await detachWorktree(repo, path);
|
|
4438
4674
|
opts.onStaleReclaim?.(path);
|
|
4439
4675
|
}
|
|
4440
|
-
if (!
|
|
4676
|
+
if (!existsSync13(path)) return;
|
|
4441
4677
|
await parkOrphanDir(repo, path, branch);
|
|
4442
4678
|
}
|
|
4443
4679
|
async function parkOrphanDir(repo, path, branch) {
|
|
@@ -4458,7 +4694,7 @@ async function parkOrphanDir(repo, path, branch) {
|
|
|
4458
4694
|
}
|
|
4459
4695
|
function isLinkedWorktree(dir) {
|
|
4460
4696
|
try {
|
|
4461
|
-
return
|
|
4697
|
+
return statSync11(join22(dir, ".git")).isFile();
|
|
4462
4698
|
} catch {
|
|
4463
4699
|
return false;
|
|
4464
4700
|
}
|
|
@@ -4470,7 +4706,7 @@ async function detachWorktree(repo, worktree) {
|
|
|
4470
4706
|
}
|
|
4471
4707
|
}
|
|
4472
4708
|
async function ensureWorktreeDirGone(worktree) {
|
|
4473
|
-
if (!
|
|
4709
|
+
if (!existsSync13(worktree)) return false;
|
|
4474
4710
|
if (!isLinkedWorktree(worktree)) {
|
|
4475
4711
|
console.error(
|
|
4476
4712
|
`[git] ${worktree} \u2014 \u043D\u0435 \u043F\u0440\u0438\u0441\u0442\u0451\u0433\u043D\u0443\u0442\u044B\u0439 worktree (.git \u043D\u0435 \u0444\u0430\u0439\u043B): \u043A\u0430\u0442\u0430\u043B\u043E\u0433 \u041D\u0415 \u0442\u0440\u043E\u0433\u0430\u044E. \u0415\u0441\u043B\u0438 \u044D\u0442\u043E \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u043E worktree \u0434\u0440\u043E\u043D\u0430 \u2014 \u0443\u0431\u0435\u0440\u0438\u0442\u0435 \u0435\u0433\u043E \u0440\u0443\u043A\u0430\u043C\u0438; \u0435\u0441\u043B\u0438 \u044D\u0442\u043E \u043E\u0441\u043D\u043E\u0432\u043D\u043E\u0439 \u0447\u0435\u043A\u0430\u0443\u0442, \u0437\u043D\u0430\u0447\u0438\u0442 \u0432\u0435\u0442\u043A\u0430 \u0441\u043B\u0430\u0433\u0430 \u0447\u0435\u043A\u043D\u0443\u0442\u0430 \u0432 \u043D\u0451\u043C (git checkout <slug>) \u2014 \u043F\u0435\u0440\u0435\u043A\u043B\u044E\u0447\u0438\u0442\u0435 \u0435\u0433\u043E \u043D\u0430 \u0434\u0440\u0443\u0433\u0443\u044E \u0432\u0435\u0442\u043A\u0443.`
|
|
@@ -4485,7 +4721,7 @@ async function ensureWorktreeDirGone(worktree) {
|
|
|
4485
4721
|
);
|
|
4486
4722
|
return true;
|
|
4487
4723
|
}
|
|
4488
|
-
if (
|
|
4724
|
+
if (existsSync13(worktree)) {
|
|
4489
4725
|
console.error(`[git] \u043A\u0430\u0442\u0430\u043B\u043E\u0433 worktree ${worktree} \u043F\u0435\u0440\u0435\u0436\u0438\u043B rm \u2014 \u0443\u0431\u0435\u0440\u0438\u0442\u0435 \u0440\u0443\u043A\u0430\u043C\u0438, \u0438\u043D\u0430\u0447\u0435 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0439 \u0441\u043F\u0430\u0432\u043D \u0441\u043B\u0430\u0433\u0430 \u0432\u0441\u0442\u0430\u043D\u0435\u0442.`);
|
|
4490
4726
|
}
|
|
4491
4727
|
return true;
|
|
@@ -4534,7 +4770,7 @@ async function checkoutWorktree(repo, path, branch, opts) {
|
|
|
4534
4770
|
}
|
|
4535
4771
|
const busyAt = await worktreeForBranch(repo, branch);
|
|
4536
4772
|
if (busyAt) {
|
|
4537
|
-
const exists =
|
|
4773
|
+
const exists = existsSync13(busyAt);
|
|
4538
4774
|
const live = exists && (opts.isWorktreeHeldLive ? await opts.isWorktreeHeldLive(busyAt) : true);
|
|
4539
4775
|
if (live) throw new WorktreeBusyError(branch, busyAt);
|
|
4540
4776
|
if (exists && await worktreeDirty(busyAt)) throw new WorktreeBusyError(branch, busyAt);
|
|
@@ -4570,8 +4806,8 @@ async function ensureGitExcluded(worktree, pattern) {
|
|
|
4570
4806
|
try {
|
|
4571
4807
|
const commonDir = await gitPath(worktree, "--git-common-dir");
|
|
4572
4808
|
if (!commonDir) return false;
|
|
4573
|
-
const infoDir =
|
|
4574
|
-
const excludeFile =
|
|
4809
|
+
const infoDir = join22(commonDir, "info");
|
|
4810
|
+
const excludeFile = join22(infoDir, "exclude");
|
|
4575
4811
|
let current = "";
|
|
4576
4812
|
try {
|
|
4577
4813
|
current = await readFile(excludeFile, "utf8");
|
|
@@ -4591,7 +4827,7 @@ async function gitPath(worktree, flag) {
|
|
|
4591
4827
|
const out = await $2({ reject: false })`git -C ${worktree} rev-parse ${flag}`;
|
|
4592
4828
|
const raw = out.stdout.trim();
|
|
4593
4829
|
if (out.exitCode !== 0 || !raw) return null;
|
|
4594
|
-
return isAbsolute3(raw) ? raw :
|
|
4830
|
+
return isAbsolute3(raw) ? raw : join22(worktree, raw);
|
|
4595
4831
|
}
|
|
4596
4832
|
async function ensureWorktreeHygiene(worktree) {
|
|
4597
4833
|
for (const pattern of SWARM_EXCLUDE_PATTERNS) await ensureGitExcluded(worktree, pattern);
|
|
@@ -4601,12 +4837,12 @@ async function installGuardHooks(worktree) {
|
|
|
4601
4837
|
try {
|
|
4602
4838
|
const gitDir = await gitPath(worktree, "--git-dir");
|
|
4603
4839
|
if (!gitDir) return false;
|
|
4604
|
-
const hooksDir =
|
|
4840
|
+
const hooksDir = join22(gitDir, "swarm-hooks");
|
|
4605
4841
|
const prev = await previousHooksPath(worktree);
|
|
4606
4842
|
await mkdir(hooksDir, { recursive: true });
|
|
4607
4843
|
for (const hook of GUARD_HOOKS) {
|
|
4608
|
-
await writeFile(
|
|
4609
|
-
await chmod(
|
|
4844
|
+
await writeFile(join22(hooksDir, hook), guardHookScript(hook, prev ? `${posix(prev)}/${hook}` : null));
|
|
4845
|
+
await chmod(join22(hooksDir, hook), 493);
|
|
4610
4846
|
}
|
|
4611
4847
|
await $2`git -C ${worktree} config extensions.worktreeConfig true`;
|
|
4612
4848
|
await $2`git -C ${worktree} config --worktree core.hooksPath ${posix(hooksDir)}`;
|
|
@@ -4625,7 +4861,7 @@ async function previousHooksPath(worktree) {
|
|
|
4625
4861
|
if (out.exitCode === 0 && value) return value;
|
|
4626
4862
|
}
|
|
4627
4863
|
const commonDir = await gitPath(worktree, "--git-common-dir");
|
|
4628
|
-
return commonDir ?
|
|
4864
|
+
return commonDir ? join22(commonDir, "hooks") : null;
|
|
4629
4865
|
}
|
|
4630
4866
|
async function removeWorktree(repo, path) {
|
|
4631
4867
|
const branch = (await $2({ reject: false })`git -C ${path} symbolic-ref --quiet --short HEAD`).stdout.trim();
|
|
@@ -4650,7 +4886,7 @@ async function worktreeDirty(path) {
|
|
|
4650
4886
|
async function repairMovedWorktrees(targetDir) {
|
|
4651
4887
|
const subdirs = (dir) => {
|
|
4652
4888
|
try {
|
|
4653
|
-
return
|
|
4889
|
+
return readdirSync13(dir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => join22(dir, d.name));
|
|
4654
4890
|
} catch {
|
|
4655
4891
|
return [];
|
|
4656
4892
|
}
|
|
@@ -4787,7 +5023,7 @@ __export(droneChannel_exports, {
|
|
|
4787
5023
|
verifyLocalCliToken: () => verifyLocalCliToken
|
|
4788
5024
|
});
|
|
4789
5025
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
4790
|
-
import { chmodSync as chmodSync2, mkdirSync as
|
|
5026
|
+
import { chmodSync as chmodSync2, mkdirSync as mkdirSync11, readFileSync as readFileSync19, writeFileSync as writeFileSync13 } from "fs";
|
|
4791
5027
|
import { dirname as dirname5 } from "path";
|
|
4792
5028
|
import { serve } from "@hono/node-server";
|
|
4793
5029
|
function loadChannelSecret(path) {
|
|
@@ -4797,8 +5033,8 @@ function loadChannelSecret(path) {
|
|
|
4797
5033
|
} catch {
|
|
4798
5034
|
}
|
|
4799
5035
|
const secret = randomBytes(32).toString("hex");
|
|
4800
|
-
|
|
4801
|
-
|
|
5036
|
+
mkdirSync11(dirname5(path), { recursive: true });
|
|
5037
|
+
writeFileSync13(path, secret, { mode: 384 });
|
|
4802
5038
|
try {
|
|
4803
5039
|
chmodSync2(path, 384);
|
|
4804
5040
|
} catch {
|
|
@@ -4916,13 +5152,13 @@ function makeChannelHandler(deps) {
|
|
|
4916
5152
|
log(`[\u043A\u0430\u043D\u0430\u043B] \u0432\u043E\u043F\u0440\u043E\u0441\u044B \u043F\u0440\u043E\u0433\u043E\u043D\u0430 #${id} \u043D\u0435 \u0434\u043E\u0447\u0438\u0442\u0430\u043B\u0438\u0441\u044C \u0438\u0437 \u043F\u0440\u043E\u0434\u0430 (\u043E\u0442\u0432\u0435\u0447\u0430\u044E \u043F\u043E \u0437\u0435\u0440\u043A\u0430\u043B\u0443): ${e instanceof Error ? e.message : String(e)}`);
|
|
4917
5153
|
}
|
|
4918
5154
|
};
|
|
4919
|
-
const
|
|
5155
|
+
const num2 = (v) => typeof v === "number" && Number.isFinite(v) ? v : null;
|
|
4920
5156
|
const str2 = (v) => typeof v === "string" ? v : "";
|
|
4921
5157
|
switch (method) {
|
|
4922
5158
|
case "myRun":
|
|
4923
5159
|
return Response.json({ run });
|
|
4924
5160
|
case "getRun": {
|
|
4925
|
-
const id =
|
|
5161
|
+
const id = num2(p.id);
|
|
4926
5162
|
if (id == null || !inScope(id)) return bad(403, "\u043F\u0440\u043E\u0433\u043E\u043D \u0432\u043D\u0435 \u0441\u043A\u043E\u0443\u043F\u0430 \u043A\u0430\u043D\u0430\u043B\u0430");
|
|
4927
5163
|
return Response.json({ run: deps.store.getRun(id) });
|
|
4928
5164
|
}
|
|
@@ -4986,7 +5222,7 @@ function makeChannelHandler(deps) {
|
|
|
4986
5222
|
}
|
|
4987
5223
|
case "answer": {
|
|
4988
5224
|
if (!heroOnly()) return bad(403, "\u043E\u0442\u0432\u0435\u0447\u0430\u0442\u044C \u0434\u0440\u043E\u043D\u0430\u043C \u043C\u043E\u0436\u0435\u0442 \u0442\u043E\u043B\u044C\u043A\u043E \u0413\u0435\u0440\u043E\u0439");
|
|
4989
|
-
const qid =
|
|
5225
|
+
const qid = num2(p.id);
|
|
4990
5226
|
if (qid == null) return bad(400, "\u043D\u0443\u0436\u0435\u043D id \u0432\u043E\u043F\u0440\u043E\u0441\u0430");
|
|
4991
5227
|
const q = deps.store.getQuestion(qid);
|
|
4992
5228
|
const squad = new Set(deps.store.squadRuns(run.id).map((r) => r.id));
|
|
@@ -5188,7 +5424,7 @@ var init_droneChannel = __esm({
|
|
|
5188
5424
|
|
|
5189
5425
|
// src/attachments.ts
|
|
5190
5426
|
import { mkdir as mkdir3, rm as rm3, writeFile as writeFile3 } from "fs/promises";
|
|
5191
|
-
import { join as
|
|
5427
|
+
import { join as join27 } from "path";
|
|
5192
5428
|
function attachmentsFromDoc(doc, origin) {
|
|
5193
5429
|
const out = [];
|
|
5194
5430
|
const walk2 = (node) => {
|
|
@@ -5256,9 +5492,9 @@ function slugifyCaption(caption) {
|
|
|
5256
5492
|
return translit.replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40).replace(/-+$/, "");
|
|
5257
5493
|
}
|
|
5258
5494
|
function attachmentFileName(index, caption, ext) {
|
|
5259
|
-
const
|
|
5495
|
+
const num2 = String(index).padStart(2, "0");
|
|
5260
5496
|
const slug = slugifyCaption(caption) || "attachment";
|
|
5261
|
-
return `${
|
|
5497
|
+
return `${num2}-${slug}.${ext}`;
|
|
5262
5498
|
}
|
|
5263
5499
|
function attachmentExt(ref, contentType) {
|
|
5264
5500
|
const fromName = extOf(ref.caption) || extOf(pathOf(ref.url));
|
|
@@ -5279,7 +5515,7 @@ async function materializeAttachments(opts) {
|
|
|
5279
5515
|
};
|
|
5280
5516
|
const result = { files: [], skipped: [] };
|
|
5281
5517
|
if (opts.refs.length === 0) return result;
|
|
5282
|
-
const dir =
|
|
5518
|
+
const dir = join27(opts.worktree, ATTACHMENTS_DIR);
|
|
5283
5519
|
await io.removeDir(dir);
|
|
5284
5520
|
let dirReady = false;
|
|
5285
5521
|
let total = 0;
|
|
@@ -5325,7 +5561,7 @@ async function materializeAttachments(opts) {
|
|
|
5325
5561
|
await io.mkdir(dir);
|
|
5326
5562
|
dirReady = true;
|
|
5327
5563
|
}
|
|
5328
|
-
await io.writeFile(
|
|
5564
|
+
await io.writeFile(join27(dir, name), file.bytes);
|
|
5329
5565
|
} catch (e) {
|
|
5330
5566
|
result.skipped.push(`${label2} \u2014 \u043D\u0435 \u0437\u0430\u043F\u0438\u0441\u0430\u043B\u043E\u0441\u044C \u043D\u0430 \u0434\u0438\u0441\u043A (${errText2(e)})`);
|
|
5331
5567
|
continue;
|
|
@@ -5478,7 +5714,7 @@ var init_attachments = __esm({
|
|
|
5478
5714
|
|
|
5479
5715
|
// src/shotUpload.ts
|
|
5480
5716
|
import { readFile as fsReadFile } from "fs/promises";
|
|
5481
|
-
import { basename as basename4, isAbsolute as isAbsolute4, join as
|
|
5717
|
+
import { basename as basename4, isAbsolute as isAbsolute4, join as join28 } from "path";
|
|
5482
5718
|
function shotMimetype(path) {
|
|
5483
5719
|
const dot = path.lastIndexOf(".");
|
|
5484
5720
|
if (dot < 0) return null;
|
|
@@ -5504,7 +5740,7 @@ async function readShots(paths, opts) {
|
|
|
5504
5740
|
}
|
|
5505
5741
|
let bytes;
|
|
5506
5742
|
try {
|
|
5507
|
-
bytes = await read(isAbsolute4(path) ? path :
|
|
5743
|
+
bytes = await read(isAbsolute4(path) ? path : join28(opts.worktree, path));
|
|
5508
5744
|
} catch (e) {
|
|
5509
5745
|
skipped.push({ path, reason: `\u043D\u0435 \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u043D: ${e instanceof Error ? e.message : String(e)}` });
|
|
5510
5746
|
continue;
|
|
@@ -5585,8 +5821,8 @@ var init_shotUpload = __esm({
|
|
|
5585
5821
|
|
|
5586
5822
|
// src/oauth.ts
|
|
5587
5823
|
import { createHash as createHash3, randomBytes as randomBytes2 } from "crypto";
|
|
5588
|
-
import { readFileSync as readFileSync20, writeFileSync as
|
|
5589
|
-
import { join as
|
|
5824
|
+
import { readFileSync as readFileSync20, writeFileSync as writeFileSync14, unlinkSync as unlinkSync4 } from "fs";
|
|
5825
|
+
import { join as join29 } from "path";
|
|
5590
5826
|
function makePkce() {
|
|
5591
5827
|
const verifier = randomBytes2(48).toString("base64url");
|
|
5592
5828
|
const challenge = createHash3("sha256").update(verifier).digest("base64url");
|
|
@@ -5676,7 +5912,7 @@ function loadStore() {
|
|
|
5676
5912
|
}
|
|
5677
5913
|
}
|
|
5678
5914
|
function saveStore(s) {
|
|
5679
|
-
|
|
5915
|
+
writeFileSync14(STORE_PATH2, JSON.stringify(s, null, 2), { mode: 384 });
|
|
5680
5916
|
}
|
|
5681
5917
|
function clearStore() {
|
|
5682
5918
|
try {
|
|
@@ -5695,7 +5931,7 @@ async function ensureClientId(api, redirectUri, fetchFn = fetch) {
|
|
|
5695
5931
|
const existing = loadClientId();
|
|
5696
5932
|
if (existing) return existing;
|
|
5697
5933
|
const clientId = await registerClient({ api, redirectUri }, fetchFn);
|
|
5698
|
-
|
|
5934
|
+
writeFileSync14(CLIENT_PATH, JSON.stringify({ clientId }, null, 2), { mode: 384 });
|
|
5699
5935
|
return clientId;
|
|
5700
5936
|
}
|
|
5701
5937
|
async function ensureAccess(store, opts = {}) {
|
|
@@ -5721,8 +5957,8 @@ var init_oauth = __esm({
|
|
|
5721
5957
|
AUTHORIZE = "/api/oauth/authorize";
|
|
5722
5958
|
TOKEN = "/api/oauth/token";
|
|
5723
5959
|
SCOPE = "openid profile email taskless:full";
|
|
5724
|
-
STORE_PATH2 =
|
|
5725
|
-
CLIENT_PATH =
|
|
5960
|
+
STORE_PATH2 = join29(SWARM_HOME, "oauth.json");
|
|
5961
|
+
CLIENT_PATH = join29(SWARM_HOME, "oauth-client.json");
|
|
5726
5962
|
base2 = (api) => api.replace(/\/$/, "");
|
|
5727
5963
|
}
|
|
5728
5964
|
});
|
|
@@ -5768,8 +6004,8 @@ var init_authState = __esm({
|
|
|
5768
6004
|
});
|
|
5769
6005
|
|
|
5770
6006
|
// src/workspace.ts
|
|
5771
|
-
import { readFileSync as readFileSync21, writeFileSync as
|
|
5772
|
-
import { join as
|
|
6007
|
+
import { readFileSync as readFileSync21, writeFileSync as writeFileSync15, unlinkSync as unlinkSync5 } from "fs";
|
|
6008
|
+
import { join as join30 } from "path";
|
|
5773
6009
|
function loadWorkspace() {
|
|
5774
6010
|
try {
|
|
5775
6011
|
const w = JSON.parse(readFileSync21(WORKSPACE_PATH, "utf8"));
|
|
@@ -5786,7 +6022,7 @@ var init_workspace = __esm({
|
|
|
5786
6022
|
"src/workspace.ts"() {
|
|
5787
6023
|
"use strict";
|
|
5788
6024
|
init_config();
|
|
5789
|
-
WORKSPACE_PATH =
|
|
6025
|
+
WORKSPACE_PATH = join30(SWARM_HOME, "workspace.json");
|
|
5790
6026
|
}
|
|
5791
6027
|
});
|
|
5792
6028
|
|
|
@@ -6389,7 +6625,7 @@ __export(db_exports, {
|
|
|
6389
6625
|
});
|
|
6390
6626
|
import { createRequire as createRequire2 } from "module";
|
|
6391
6627
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
6392
|
-
import { existsSync as
|
|
6628
|
+
import { existsSync as existsSync17 } from "fs";
|
|
6393
6629
|
import { resolve as resolve4 } from "path";
|
|
6394
6630
|
function rowToQuestion(row) {
|
|
6395
6631
|
return {
|
|
@@ -7053,7 +7289,7 @@ CREATE TABLE IF NOT EXISTS imports (
|
|
|
7053
7289
|
const repoN = normalizeRepo(repo);
|
|
7054
7290
|
const already = this.db.prepare("SELECT run_count FROM imports WHERE source = ?").get(abs);
|
|
7055
7291
|
if (already) return { imported: false, runs: already.run_count };
|
|
7056
|
-
if (!
|
|
7292
|
+
if (!existsSync17(abs)) throw new Error(`import-db: \u0444\u0430\u0439\u043B\u0430 \u043D\u0435\u0442: ${abs}`);
|
|
7057
7293
|
const src = new this.databaseCtor(abs);
|
|
7058
7294
|
try {
|
|
7059
7295
|
const runs = src.prepare("SELECT * FROM runs ORDER BY id").all();
|
|
@@ -7423,8 +7659,8 @@ var init_droneStore = __esm({
|
|
|
7423
7659
|
|
|
7424
7660
|
// src/overmind.ts
|
|
7425
7661
|
import { homedir as homedir7 } from "os";
|
|
7426
|
-
import { existsSync as
|
|
7427
|
-
import { basename as basename6, dirname as dirname6, join as
|
|
7662
|
+
import { existsSync as existsSync22, readFileSync as readFileSync25, readdirSync as readdirSync15, renameSync as renameSync12, statSync as statSync14 } from "fs";
|
|
7663
|
+
import { basename as basename6, dirname as dirname6, join as join37 } from "path";
|
|
7428
7664
|
import { fileURLToPath as fileURLToPath3, pathToFileURL } from "url";
|
|
7429
7665
|
import { spawn as spawn4 } from "child_process";
|
|
7430
7666
|
|
|
@@ -7504,7 +7740,7 @@ init_config();
|
|
|
7504
7740
|
init_resources();
|
|
7505
7741
|
init_names2();
|
|
7506
7742
|
init_storm();
|
|
7507
|
-
import { appendFileSync, existsSync as
|
|
7743
|
+
import { appendFileSync, existsSync as existsSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync7 } from "fs";
|
|
7508
7744
|
import { dirname as dirname2 } from "path";
|
|
7509
7745
|
import { randomUUID } from "crypto";
|
|
7510
7746
|
|
|
@@ -7562,12 +7798,12 @@ init_store();
|
|
|
7562
7798
|
init_toolFailure();
|
|
7563
7799
|
|
|
7564
7800
|
// src/logTail.ts
|
|
7565
|
-
import { closeSync, existsSync as
|
|
7566
|
-
import { join as
|
|
7801
|
+
import { closeSync, existsSync as existsSync7, openSync, readSync, readdirSync as readdirSync7, statSync as statSync6 } from "fs";
|
|
7802
|
+
import { join as join11 } from "path";
|
|
7567
7803
|
|
|
7568
7804
|
// src/runLogDir.ts
|
|
7569
|
-
import { existsSync as
|
|
7570
|
-
import { join as
|
|
7805
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync6, readdirSync as readdirSync6, renameSync as renameSync3, statSync as statSync5 } from "fs";
|
|
7806
|
+
import { join as join10 } from "path";
|
|
7571
7807
|
var LEGACY_RUN_LOGS_SUBDIR = "legacy";
|
|
7572
7808
|
function runLogDirName(runLogKey) {
|
|
7573
7809
|
const safe2 = runLogKey.replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^[-_]+|[-_]+$/g, "");
|
|
@@ -7575,12 +7811,12 @@ function runLogDirName(runLogKey) {
|
|
|
7575
7811
|
return /^\d+$/.test(safe2) ? `k-${safe2}` : safe2;
|
|
7576
7812
|
}
|
|
7577
7813
|
function runLogDirPath(runLogsDir, runLogKey) {
|
|
7578
|
-
return
|
|
7814
|
+
return join10(runLogsDir, runLogDirName(runLogKey));
|
|
7579
7815
|
}
|
|
7580
7816
|
function findRunLogDir(runLogsDir, keys) {
|
|
7581
7817
|
for (const key of keys) {
|
|
7582
7818
|
const dir = runLogDirPath(runLogsDir, key);
|
|
7583
|
-
if (
|
|
7819
|
+
if (existsSync6(dir)) return dir;
|
|
7584
7820
|
}
|
|
7585
7821
|
return null;
|
|
7586
7822
|
}
|
|
@@ -7590,10 +7826,10 @@ function runLogDirForWrite(runLogsDir, keys) {
|
|
|
7590
7826
|
return findRunLogDir(runLogsDir, keys) ?? runLogDirPath(runLogsDir, canonical);
|
|
7591
7827
|
}
|
|
7592
7828
|
function sweepLegacyRunLogs(runLogsDir) {
|
|
7593
|
-
const legacyDir =
|
|
7829
|
+
const legacyDir = join10(runLogsDir, LEGACY_RUN_LOGS_SUBDIR);
|
|
7594
7830
|
let entries;
|
|
7595
7831
|
try {
|
|
7596
|
-
entries =
|
|
7832
|
+
entries = readdirSync6(runLogsDir);
|
|
7597
7833
|
} catch {
|
|
7598
7834
|
return { moved: 0, failed: 0, legacyDir };
|
|
7599
7835
|
}
|
|
@@ -7601,12 +7837,12 @@ function sweepLegacyRunLogs(runLogsDir) {
|
|
|
7601
7837
|
let failed = 0;
|
|
7602
7838
|
for (const name of entries) {
|
|
7603
7839
|
if (!/^\d+$/.test(name)) continue;
|
|
7604
|
-
const from =
|
|
7840
|
+
const from = join10(runLogsDir, name);
|
|
7605
7841
|
try {
|
|
7606
|
-
if (!
|
|
7607
|
-
|
|
7608
|
-
let to =
|
|
7609
|
-
for (let n = 2;
|
|
7842
|
+
if (!statSync5(from).isDirectory()) continue;
|
|
7843
|
+
mkdirSync6(legacyDir, { recursive: true });
|
|
7844
|
+
let to = join10(legacyDir, name);
|
|
7845
|
+
for (let n = 2; existsSync6(to) && n < 100; n++) to = join10(legacyDir, `${name}-${n}`);
|
|
7610
7846
|
renameSync3(from, to);
|
|
7611
7847
|
moved++;
|
|
7612
7848
|
} catch {
|
|
@@ -7626,7 +7862,7 @@ function fileHeader(name, size, shown) {
|
|
|
7626
7862
|
function readTail(path, opts) {
|
|
7627
7863
|
let size;
|
|
7628
7864
|
try {
|
|
7629
|
-
size =
|
|
7865
|
+
size = statSync6(path).size;
|
|
7630
7866
|
} catch {
|
|
7631
7867
|
return null;
|
|
7632
7868
|
}
|
|
@@ -7661,7 +7897,7 @@ function latestRunLaunch(runLogsDir, runLogKeys) {
|
|
|
7661
7897
|
if (!dir) return null;
|
|
7662
7898
|
let files;
|
|
7663
7899
|
try {
|
|
7664
|
-
files =
|
|
7900
|
+
files = readdirSync7(dir);
|
|
7665
7901
|
} catch {
|
|
7666
7902
|
return null;
|
|
7667
7903
|
}
|
|
@@ -7672,8 +7908,8 @@ function latestRunLaunch(runLogsDir, runLogKeys) {
|
|
|
7672
7908
|
}
|
|
7673
7909
|
if (indexes.size === 0) return null;
|
|
7674
7910
|
const index = Math.max(...indexes);
|
|
7675
|
-
const out = [
|
|
7676
|
-
const err =
|
|
7911
|
+
const out = [join11(dir, `${index}.json`), join11(dir, `${index}.json.done`)].find((p) => existsSync7(p)) ?? null;
|
|
7912
|
+
const err = existsSync7(join11(dir, `${index}.err.log`)) ? join11(dir, `${index}.err.log`) : null;
|
|
7677
7913
|
return { index, total: indexes.size, out, err };
|
|
7678
7914
|
}
|
|
7679
7915
|
function runLogTail(runLogsDir, runLogKeys, opts) {
|
|
@@ -7943,25 +8179,25 @@ var SwarmClient = class _SwarmClient {
|
|
|
7943
8179
|
this.repoFullNames = registry.map((e) => e.repoFullName);
|
|
7944
8180
|
this.repoPathByFullName = new Map(registry.map((e) => [e.repoFullName, normalizeRepo(e.path)]));
|
|
7945
8181
|
this.host = opts.host ?? null;
|
|
7946
|
-
this.repoExists = opts.repoExists ??
|
|
8182
|
+
this.repoExists = opts.repoExists ?? existsSync8;
|
|
7947
8183
|
this.questionSyncMs = opts.questionSyncMs ?? 3e3;
|
|
7948
8184
|
this.executorId = opts.executorId ?? EXECUTOR.id;
|
|
7949
8185
|
this.outboxPath = opts.outboxPath;
|
|
7950
8186
|
this.mapPath = `${opts.outboxPath}.prodmap.json`;
|
|
7951
8187
|
this.stormPath = `${opts.outboxPath}.storm.jsonl`;
|
|
7952
|
-
|
|
8188
|
+
mkdirSync7(dirname2(this.outboxPath), { recursive: true });
|
|
7953
8189
|
this.recover();
|
|
7954
8190
|
}
|
|
7955
8191
|
// ── рестарт: поднять outbox (незаписанные операции) и карту runKey→prodId ─────
|
|
7956
8192
|
recover() {
|
|
7957
|
-
if (
|
|
8193
|
+
if (existsSync8(this.mapPath)) {
|
|
7958
8194
|
try {
|
|
7959
8195
|
const obj = JSON.parse(readFileSync7(this.mapPath, "utf8"));
|
|
7960
8196
|
for (const [k, v] of Object.entries(obj)) this.prodIdByKey.set(k, v);
|
|
7961
8197
|
} catch {
|
|
7962
8198
|
}
|
|
7963
8199
|
}
|
|
7964
|
-
if (
|
|
8200
|
+
if (existsSync8(this.outboxPath)) {
|
|
7965
8201
|
const txt = readFileSync7(this.outboxPath, "utf8");
|
|
7966
8202
|
for (const line of txt.split("\n")) {
|
|
7967
8203
|
const s = line.trim();
|
|
@@ -7982,7 +8218,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
7982
8218
|
// eventsLog ПЕРВЫМИ (до hydrate), в порядке файла (= хронологический); id
|
|
7983
8219
|
// переприсваиваем локально (id событий — только порядок, не корреляция с продом).
|
|
7984
8220
|
replayGlobalEvents() {
|
|
7985
|
-
if (!
|
|
8221
|
+
if (!existsSync8(this.stormPath)) return;
|
|
7986
8222
|
let txt;
|
|
7987
8223
|
try {
|
|
7988
8224
|
txt = readFileSync7(this.stormPath, "utf8");
|
|
@@ -8982,7 +9218,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
8982
9218
|
* транзиентным сбоем ОС, который этот PR должен переживать, а не превращать в мор.
|
|
8983
9219
|
*/
|
|
8984
9220
|
reconcileRuntime(opts) {
|
|
8985
|
-
const wtExists = opts.worktreeExists ??
|
|
9221
|
+
const wtExists = opts.worktreeExists ?? existsSync8;
|
|
8986
9222
|
const pidByWorktree = /* @__PURE__ */ new Map();
|
|
8987
9223
|
try {
|
|
8988
9224
|
for (const p of opts.listProcesses()) if (p.worktree) pidByWorktree.set(p.worktree, p.pid);
|
|
@@ -9602,7 +9838,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
9602
9838
|
*
|
|
9603
9839
|
* Прод недоступен / ответ без поручений → пустые списки (демон работает дальше).
|
|
9604
9840
|
*/
|
|
9605
|
-
async heartbeat(daemonVersion, pause, capacity, resources, storm, worktreesDir, signIn, tick, executors) {
|
|
9841
|
+
async heartbeat(daemonVersion, pause, capacity, resources, storm, worktreesDir, signIn, tick, executors, providers) {
|
|
9606
9842
|
try {
|
|
9607
9843
|
const args = this.repoFullNames.length ? { repoFullNames: this.repoFullNames } : {};
|
|
9608
9844
|
if (daemonVersion) args.daemonVersion = daemonVersion;
|
|
@@ -9633,6 +9869,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
9633
9869
|
args.tick = { seq: Math.max(0, Math.trunc(tick.seq)), ageMs: Math.max(0, Math.trunc(tick.ageMs)), intervalMs: Math.trunc(tick.intervalMs) };
|
|
9634
9870
|
}
|
|
9635
9871
|
if (executors) args.executorsAvailable = executors;
|
|
9872
|
+
if (providers) args.providersAvailable = providers;
|
|
9636
9873
|
const res = await this.call("swarm_heartbeat", args);
|
|
9637
9874
|
if (res?.isError) return EMPTY_HEARTBEAT_REPLY;
|
|
9638
9875
|
this.heartbeatOkAt = this.now();
|
|
@@ -10220,13 +10457,13 @@ var SwarmClient = class _SwarmClient {
|
|
|
10220
10457
|
}
|
|
10221
10458
|
persistPending() {
|
|
10222
10459
|
try {
|
|
10223
|
-
|
|
10460
|
+
writeFileSync7(this.outboxPath, this.pending.map((e) => JSON.stringify(e)).join("\n") + (this.pending.length ? "\n" : ""));
|
|
10224
10461
|
} catch {
|
|
10225
10462
|
}
|
|
10226
10463
|
}
|
|
10227
10464
|
persistMap() {
|
|
10228
10465
|
try {
|
|
10229
|
-
|
|
10466
|
+
writeFileSync7(this.mapPath, JSON.stringify(Object.fromEntries(this.prodIdByKey)));
|
|
10230
10467
|
} catch {
|
|
10231
10468
|
}
|
|
10232
10469
|
}
|
|
@@ -10297,20 +10534,20 @@ function tickPulse(health, now, intervalMs) {
|
|
|
10297
10534
|
}
|
|
10298
10535
|
|
|
10299
10536
|
// src/logRotate.ts
|
|
10300
|
-
import { copyFileSync as
|
|
10537
|
+
import { copyFileSync as copyFileSync4, renameSync as renameSync5, statSync as statSync7, fstatSync, truncateSync, unlinkSync as unlinkSync3, existsSync as existsSync9 } from "fs";
|
|
10301
10538
|
var realIo = {
|
|
10302
10539
|
size: (path) => {
|
|
10303
10540
|
try {
|
|
10304
|
-
return
|
|
10541
|
+
return statSync7(path).size;
|
|
10305
10542
|
} catch {
|
|
10306
10543
|
return null;
|
|
10307
10544
|
}
|
|
10308
10545
|
},
|
|
10309
|
-
copy:
|
|
10546
|
+
copy: copyFileSync4,
|
|
10310
10547
|
rename: renameSync5,
|
|
10311
10548
|
truncate: (path) => truncateSync(path, 0),
|
|
10312
10549
|
unlink: unlinkSync3,
|
|
10313
|
-
exists:
|
|
10550
|
+
exists: existsSync9
|
|
10314
10551
|
};
|
|
10315
10552
|
var realOwnerIo = {
|
|
10316
10553
|
statFd: (fd) => {
|
|
@@ -10323,7 +10560,7 @@ var realOwnerIo = {
|
|
|
10323
10560
|
},
|
|
10324
10561
|
statPath: (path) => {
|
|
10325
10562
|
try {
|
|
10326
|
-
const s =
|
|
10563
|
+
const s = statSync7(path);
|
|
10327
10564
|
return { dev: s.dev, ino: s.ino };
|
|
10328
10565
|
} catch {
|
|
10329
10566
|
return null;
|
|
@@ -10457,13 +10694,13 @@ async function buildRepoRegistry(paths) {
|
|
|
10457
10694
|
}
|
|
10458
10695
|
|
|
10459
10696
|
// src/repoMemory.ts
|
|
10460
|
-
import { readFileSync as readFileSync10, writeFileSync as
|
|
10461
|
-
import { join as
|
|
10697
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync9 } from "fs";
|
|
10698
|
+
import { join as join12 } from "path";
|
|
10462
10699
|
var FILE = "repos.json";
|
|
10463
10700
|
function loadRememberedRepos(home) {
|
|
10464
10701
|
let raw;
|
|
10465
10702
|
try {
|
|
10466
|
-
raw = readFileSync10(
|
|
10703
|
+
raw = readFileSync10(join12(home, FILE), "utf8");
|
|
10467
10704
|
} catch {
|
|
10468
10705
|
return [];
|
|
10469
10706
|
}
|
|
@@ -10478,7 +10715,7 @@ function loadRememberedRepos(home) {
|
|
|
10478
10715
|
function rememberRepos(home, paths, now = () => /* @__PURE__ */ new Date()) {
|
|
10479
10716
|
const clean = paths.filter((p) => p.trim().length > 0);
|
|
10480
10717
|
if (clean.length === 0) return;
|
|
10481
|
-
|
|
10718
|
+
writeFileSync9(join12(home, FILE), `${JSON.stringify({ paths: clean, at: now().toISOString() }, null, 2)}
|
|
10482
10719
|
`);
|
|
10483
10720
|
}
|
|
10484
10721
|
function pickRepoPaths(args) {
|
|
@@ -10493,12 +10730,12 @@ init_src();
|
|
|
10493
10730
|
init_config();
|
|
10494
10731
|
init_linkFailure();
|
|
10495
10732
|
import { homedir as homedir5 } from "os";
|
|
10496
|
-
import { readFileSync as readFileSync12, renameSync as renameSync6, writeFileSync as
|
|
10497
|
-
import { isAbsolute, join as
|
|
10733
|
+
import { readFileSync as readFileSync12, renameSync as renameSync6, writeFileSync as writeFileSync10 } from "fs";
|
|
10734
|
+
import { isAbsolute, join as join14, resolve as resolve2 } from "path";
|
|
10498
10735
|
|
|
10499
10736
|
// src/repoScan.ts
|
|
10500
|
-
import { readdirSync as
|
|
10501
|
-
import { join as
|
|
10737
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync11, statSync as statSync8 } from "fs";
|
|
10738
|
+
import { join as join13 } from "path";
|
|
10502
10739
|
var SKIP = /* @__PURE__ */ new Set([
|
|
10503
10740
|
"node_modules",
|
|
10504
10741
|
"vendor",
|
|
@@ -10528,7 +10765,7 @@ function parseOriginFromGitConfig(text) {
|
|
|
10528
10765
|
}
|
|
10529
10766
|
function originOf(dir) {
|
|
10530
10767
|
try {
|
|
10531
|
-
return parseOriginFromGitConfig(readFileSync11(
|
|
10768
|
+
return parseOriginFromGitConfig(readFileSync11(join13(dir, ".git", "config"), "utf8"));
|
|
10532
10769
|
} catch {
|
|
10533
10770
|
return null;
|
|
10534
10771
|
}
|
|
@@ -10557,15 +10794,15 @@ function walk(dir, depth, maxDepth, found) {
|
|
|
10557
10794
|
}
|
|
10558
10795
|
let entries;
|
|
10559
10796
|
try {
|
|
10560
|
-
entries =
|
|
10797
|
+
entries = readdirSync8(dir);
|
|
10561
10798
|
} catch {
|
|
10562
10799
|
return;
|
|
10563
10800
|
}
|
|
10564
10801
|
for (const name of entries) {
|
|
10565
10802
|
if (name.startsWith(".") || SKIP.has(name)) continue;
|
|
10566
|
-
const child =
|
|
10803
|
+
const child = join13(dir, name);
|
|
10567
10804
|
try {
|
|
10568
|
-
if (!
|
|
10805
|
+
if (!statSync8(child).isDirectory()) continue;
|
|
10569
10806
|
} catch {
|
|
10570
10807
|
continue;
|
|
10571
10808
|
}
|
|
@@ -10585,7 +10822,7 @@ function defaultScanRoots(home, knownPaths = []) {
|
|
|
10585
10822
|
if (parent && parent !== p) add(parent);
|
|
10586
10823
|
}
|
|
10587
10824
|
for (const name of ["projects", "code", "src", "dev", "work", "repos", "git", "Projects", "Code", "Developer", "Documents/GitHub", "go/src"]) {
|
|
10588
|
-
add(
|
|
10825
|
+
add(join13(home, name));
|
|
10589
10826
|
}
|
|
10590
10827
|
return out;
|
|
10591
10828
|
}
|
|
@@ -10599,7 +10836,7 @@ function resolveScanRoots(raw, home = homedir5(), knownPaths = []) {
|
|
|
10599
10836
|
for (const part of v.split(",")) {
|
|
10600
10837
|
const p = part.trim();
|
|
10601
10838
|
if (!p) continue;
|
|
10602
|
-
const abs = p === "~" ? home : p.startsWith("~/") ?
|
|
10839
|
+
const abs = p === "~" ? home : p.startsWith("~/") ? join14(home, p.slice(2)) : isAbsolute(p) ? p : resolve2(home, p);
|
|
10603
10840
|
if (!out.includes(abs)) out.push(abs);
|
|
10604
10841
|
}
|
|
10605
10842
|
return out;
|
|
@@ -10828,7 +11065,7 @@ function loadRepoMapCache(path) {
|
|
|
10828
11065
|
function writeRepoMapCache(path, entries, scannedAt = stamp()) {
|
|
10829
11066
|
try {
|
|
10830
11067
|
const tmp = `${path}.tmp`;
|
|
10831
|
-
|
|
11068
|
+
writeFileSync10(tmp, JSON.stringify({ at: stamp(), scannedAt, entries }, null, 2));
|
|
10832
11069
|
renameSync6(tmp, path);
|
|
10833
11070
|
} catch {
|
|
10834
11071
|
}
|
|
@@ -10836,17 +11073,17 @@ function writeRepoMapCache(path, entries, scannedAt = stamp()) {
|
|
|
10836
11073
|
|
|
10837
11074
|
// src/hostIdentity.ts
|
|
10838
11075
|
import { hostname } from "os";
|
|
10839
|
-
import { existsSync as
|
|
10840
|
-
import { join as
|
|
11076
|
+
import { existsSync as existsSync10, readFileSync as readFileSync13, renameSync as renameSync7, writeFileSync as writeFileSync11 } from "fs";
|
|
11077
|
+
import { join as join15 } from "path";
|
|
10841
11078
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
10842
11079
|
function hostIdentityPath(home) {
|
|
10843
|
-
return
|
|
11080
|
+
return join15(home, "host.json");
|
|
10844
11081
|
}
|
|
10845
11082
|
function loadHostIdentity(deps) {
|
|
10846
|
-
const exists = deps.exists ??
|
|
11083
|
+
const exists = deps.exists ?? existsSync10;
|
|
10847
11084
|
const readFile2 = deps.readFile ?? ((p) => readFileSync13(p, "utf8"));
|
|
10848
11085
|
const writeFile4 = deps.writeFile ?? ((p, data) => {
|
|
10849
|
-
|
|
11086
|
+
writeFileSync11(`${p}.tmp`, data);
|
|
10850
11087
|
renameSync7(`${p}.tmp`, p);
|
|
10851
11088
|
});
|
|
10852
11089
|
const host = deps.hostname ?? hostname;
|
|
@@ -10939,8 +11176,8 @@ function pickResumeCandidate(pausedForRelief) {
|
|
|
10939
11176
|
}
|
|
10940
11177
|
|
|
10941
11178
|
// src/reliefLoop.ts
|
|
10942
|
-
import { existsSync as
|
|
10943
|
-
import { join as
|
|
11179
|
+
import { existsSync as existsSync11, readFileSync as readFileSync14, renameSync as renameSync8, writeFileSync as writeFileSync12 } from "fs";
|
|
11180
|
+
import { join as join16 } from "path";
|
|
10944
11181
|
var numEnv3 = (name, def) => {
|
|
10945
11182
|
const v = Number(process.env[name]);
|
|
10946
11183
|
return Number.isFinite(v) && v > 0 ? v : def;
|
|
@@ -10975,10 +11212,10 @@ function reliefLoopTripped(entry, cfg = DEFAULT_RELIEF_LOOP_CONFIG) {
|
|
|
10975
11212
|
return !!entry && entry.pauses >= cfg.limit;
|
|
10976
11213
|
}
|
|
10977
11214
|
function reliefLoopStatePath(home) {
|
|
10978
|
-
return
|
|
11215
|
+
return join16(home, "relief-loop.json");
|
|
10979
11216
|
}
|
|
10980
11217
|
function loadReliefLoopState(home, now = Date.now(), io = {}, cfg = DEFAULT_RELIEF_LOOP_CONFIG) {
|
|
10981
|
-
const exists = io.exists ??
|
|
11218
|
+
const exists = io.exists ?? existsSync11;
|
|
10982
11219
|
const readFile2 = io.readFile ?? ((p) => readFileSync14(p, "utf8"));
|
|
10983
11220
|
const path = reliefLoopStatePath(home);
|
|
10984
11221
|
if (!exists(path)) return {};
|
|
@@ -11001,7 +11238,7 @@ function loadReliefLoopState(home, now = Date.now(), io = {}, cfg = DEFAULT_RELI
|
|
|
11001
11238
|
function saveReliefLoopState(home, state, io = {}) {
|
|
11002
11239
|
const path = reliefLoopStatePath(home);
|
|
11003
11240
|
const writeFile4 = io.writeFile ?? ((p, data) => {
|
|
11004
|
-
|
|
11241
|
+
writeFileSync12(`${p}.tmp`, data);
|
|
11005
11242
|
renameSync8(`${p}.tmp`, p);
|
|
11006
11243
|
});
|
|
11007
11244
|
writeFile4(path, JSON.stringify(state, null, 2));
|
|
@@ -11163,15 +11400,15 @@ function buildReliefCostCandidates(cost, t, sustainMs, build) {
|
|
|
11163
11400
|
|
|
11164
11401
|
// src/launcher.ts
|
|
11165
11402
|
import { spawn as spawn2 } from "child_process";
|
|
11166
|
-
import { closeSync as closeSync3, existsSync as
|
|
11403
|
+
import { closeSync as closeSync3, existsSync as existsSync12, mkdirSync as mkdirSync9, openSync as openSync3, readdirSync as readdirSync10 } from "fs";
|
|
11167
11404
|
import { createRequire } from "module";
|
|
11168
11405
|
import { homedir as homedir6 } from "os";
|
|
11169
|
-
import { dirname as dirname3, join as
|
|
11406
|
+
import { dirname as dirname3, join as join18 } from "path";
|
|
11170
11407
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
11171
11408
|
|
|
11172
11409
|
// src/droneHome.ts
|
|
11173
|
-
import { lstatSync, mkdirSync as
|
|
11174
|
-
import { join as
|
|
11410
|
+
import { lstatSync, mkdirSync as mkdirSync8, readdirSync as readdirSync9, rmSync, statSync as statSync9, symlinkSync as symlinkSync3 } from "fs";
|
|
11411
|
+
import { join as join17, relative, sep } from "path";
|
|
11175
11412
|
var DRONE_HOME_DENY_DEFAULT = [".taskless-swarm", ".bash_history", ".zsh_history"];
|
|
11176
11413
|
function droneHomeDeny(env = process.env) {
|
|
11177
11414
|
const extra = (env.SWARM_DRONE_HOME_DENY || "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
@@ -11189,34 +11426,34 @@ function buildDroneHome(opts) {
|
|
|
11189
11426
|
const { realHome, droneHome } = opts;
|
|
11190
11427
|
const deny = opts.deny ?? droneHomeDeny();
|
|
11191
11428
|
const platform = opts.platform ?? process.platform;
|
|
11192
|
-
|
|
11193
|
-
const wanted = new Set(mirroredEntries(
|
|
11429
|
+
mkdirSync8(droneHome, { recursive: true, mode: 448 });
|
|
11430
|
+
const wanted = new Set(mirroredEntries(readdirSync9(realHome), deny, platform));
|
|
11194
11431
|
const rel = relative(realHome, droneHome);
|
|
11195
11432
|
if (rel && !rel.startsWith("..") && !rel.includes(sep)) wanted.delete(rel);
|
|
11196
|
-
for (const existing of
|
|
11433
|
+
for (const existing of readdirSync9(droneHome)) {
|
|
11197
11434
|
if (wanted.has(existing)) continue;
|
|
11198
|
-
const p =
|
|
11435
|
+
const p = join17(droneHome, existing);
|
|
11199
11436
|
try {
|
|
11200
11437
|
if (lstatSync(p).isSymbolicLink()) rmSync(p);
|
|
11201
11438
|
} catch {
|
|
11202
11439
|
}
|
|
11203
11440
|
}
|
|
11204
11441
|
for (const name of wanted) {
|
|
11205
|
-
const link2 =
|
|
11442
|
+
const link2 = join17(droneHome, name);
|
|
11206
11443
|
try {
|
|
11207
11444
|
lstatSync(link2);
|
|
11208
11445
|
continue;
|
|
11209
11446
|
} catch {
|
|
11210
11447
|
}
|
|
11211
|
-
const target =
|
|
11448
|
+
const target = join17(realHome, name);
|
|
11212
11449
|
let isDir;
|
|
11213
11450
|
try {
|
|
11214
|
-
isDir =
|
|
11451
|
+
isDir = statSync9(target).isDirectory();
|
|
11215
11452
|
} catch {
|
|
11216
11453
|
continue;
|
|
11217
11454
|
}
|
|
11218
11455
|
try {
|
|
11219
|
-
|
|
11456
|
+
symlinkSync3(target, link2, isDir ? "junction" : "file");
|
|
11220
11457
|
} catch (e) {
|
|
11221
11458
|
if (e.code !== "EEXIST") throw e;
|
|
11222
11459
|
}
|
|
@@ -11229,7 +11466,7 @@ var REAL_PATH_ENV_PINS = [
|
|
|
11229
11466
|
{ env: "YARN_GLOBAL_FOLDER", segments: [".yarn", "berry"] }
|
|
11230
11467
|
];
|
|
11231
11468
|
function realPathEnvPins(realHome) {
|
|
11232
|
-
return Object.fromEntries(REAL_PATH_ENV_PINS.map(({ env, segments }) => [env,
|
|
11469
|
+
return Object.fromEntries(REAL_PATH_ENV_PINS.map(({ env, segments }) => [env, join17(realHome, ...segments)]));
|
|
11233
11470
|
}
|
|
11234
11471
|
function dronePrivatePaths(realHome, swarmHome) {
|
|
11235
11472
|
return [
|
|
@@ -11312,7 +11549,7 @@ function droneEnv(worktree, base3 = process.env, isolation, droneCap = null) {
|
|
|
11312
11549
|
const env = { ...base3 };
|
|
11313
11550
|
const isolate = base3.SWARM_TURBO_ISOLATE !== "0";
|
|
11314
11551
|
if (isolate && !base3.TURBO_CACHE_DIR) {
|
|
11315
|
-
env.TURBO_CACHE_DIR =
|
|
11552
|
+
env.TURBO_CACHE_DIR = join18(worktree, ".turbo", "cache");
|
|
11316
11553
|
}
|
|
11317
11554
|
Object.assign(env, droneTestEnv(droneCap, base3));
|
|
11318
11555
|
for (const key of DAEMON_STATE_ENV) delete env[key];
|
|
@@ -11343,21 +11580,21 @@ var DAEMON_STATE_ENV = [
|
|
|
11343
11580
|
...PROVIDER_TOKEN_ENV
|
|
11344
11581
|
];
|
|
11345
11582
|
function bundledRoleDir(kind) {
|
|
11346
|
-
return
|
|
11583
|
+
return join18(dirname3(fileURLToPath2(import.meta.url)), "..", "roles", kind);
|
|
11347
11584
|
}
|
|
11348
11585
|
function roleDir(worktree, kind) {
|
|
11349
|
-
return
|
|
11586
|
+
return join18(worktree, ".claude", "roles", kind);
|
|
11350
11587
|
}
|
|
11351
11588
|
function roleDirs(worktree, kind) {
|
|
11352
|
-
return [bundledRoleDir(kind), roleDir(worktree, kind)].filter((dir) =>
|
|
11589
|
+
return [bundledRoleDir(kind), roleDir(worktree, kind)].filter((dir) => existsSync12(dir));
|
|
11353
11590
|
}
|
|
11354
11591
|
function nextRunLogPath(runLogsDir, runLogKeys) {
|
|
11355
11592
|
const dir = runLogDirForWrite(runLogsDir, runLogKeys);
|
|
11356
11593
|
if (!dir) throw new Error("\u043D\u0435\u0447\u0435\u043C \u0430\u0434\u0440\u0435\u0441\u043E\u0432\u0430\u0442\u044C \u043A\u0430\u0442\u0430\u043B\u043E\u0433 run-log'\u043E\u0432: \u0443 \u043F\u0440\u043E\u0433\u043E\u043D\u0430 \u043D\u0435\u0442 \u0441\u0442\u0430\u0431\u0438\u043B\u044C\u043D\u043E\u0433\u043E \u043A\u043B\u044E\u0447\u0430 (SwarmStore.runLogKeys)");
|
|
11357
|
-
|
|
11594
|
+
mkdirSync9(dir, { recursive: true });
|
|
11358
11595
|
let files = [];
|
|
11359
11596
|
try {
|
|
11360
|
-
files =
|
|
11597
|
+
files = readdirSync10(dir);
|
|
11361
11598
|
} catch {
|
|
11362
11599
|
}
|
|
11363
11600
|
let next = 0;
|
|
@@ -11365,7 +11602,7 @@ function nextRunLogPath(runLogsDir, runLogKeys) {
|
|
|
11365
11602
|
const m = /^(\d+)\.json/.exec(f);
|
|
11366
11603
|
if (m) next = Math.max(next, Number(m[1]) + 1);
|
|
11367
11604
|
}
|
|
11368
|
-
return
|
|
11605
|
+
return join18(dir, `${next}.json`);
|
|
11369
11606
|
}
|
|
11370
11607
|
function openNextRunLog(runLogsDir, runLogKeys) {
|
|
11371
11608
|
for (let attempt = 0; attempt < 50; attempt++) {
|
|
@@ -11457,9 +11694,9 @@ function makeLauncher(cfg) {
|
|
|
11457
11694
|
}
|
|
11458
11695
|
const realHome = cfg.droneIsolation?.realHome ?? homedir6();
|
|
11459
11696
|
const home = cfg.droneIsolation ? buildDroneHome({ realHome, droneHome: cfg.droneIsolation.home }) : void 0;
|
|
11460
|
-
if (cfg.droneIsolation && process.env.TASKLESS_TOKEN && !
|
|
11697
|
+
if (cfg.droneIsolation && process.env.TASKLESS_TOKEN && !existsSync12(join18(cfg.droneIsolation.swarmHome, "token"))) {
|
|
11461
11698
|
console.error(
|
|
11462
|
-
`[launcher] TASKLESS_TOKEN \u0437\u0430\u0434\u0430\u043D \u0442\u043E\u043B\u044C\u043A\u043E \u0432 env \u0434\u0435\u043C\u043E\u043D\u0430 \u2014 \u0434\u0440\u043E\u043D\u0443 \u043E\u043D \u043D\u0435 \u043D\u0430\u0441\u043B\u0435\u0434\u0443\u0435\u0442\u0441\u044F (TASWM-289), \u0430 \u0444\u0430\u0439\u043B\u0430 ${
|
|
11699
|
+
`[launcher] TASKLESS_TOKEN \u0437\u0430\u0434\u0430\u043D \u0442\u043E\u043B\u044C\u043A\u043E \u0432 env \u0434\u0435\u043C\u043E\u043D\u0430 \u2014 \u0434\u0440\u043E\u043D\u0443 \u043E\u043D \u043D\u0435 \u043D\u0430\u0441\u043B\u0435\u0434\u0443\u0435\u0442\u0441\u044F (TASWM-289), \u0430 \u0444\u0430\u0439\u043B\u0430 ${join18(cfg.droneIsolation.swarmHome, "token")} \u043D\u0435\u0442. read_task \u0434\u0440\u043E\u043D\u0430 \u0431\u0443\u0434\u0435\u0442 slug-only. \u041F\u043E\u0447\u0438\u043D\u0438: \`swarm login\` (oauth.json) \u0438\u043B\u0438 \u043F\u043E\u043B\u043E\u0436\u0438 \u0442\u043E\u043A\u0435\u043D \u0432 \u044D\u0442\u043E\u0442 \u0444\u0430\u0439\u043B.`
|
|
11463
11700
|
);
|
|
11464
11701
|
}
|
|
11465
11702
|
const executor = cfg.executor ?? executorForRun(run, cfg.swarmModels?.() ?? null);
|
|
@@ -11521,8 +11758,8 @@ function makeLauncher(cfg) {
|
|
|
11521
11758
|
init_procCleanup();
|
|
11522
11759
|
|
|
11523
11760
|
// src/cost.ts
|
|
11524
|
-
import { readFileSync as readFileSync15, readdirSync as
|
|
11525
|
-
import { join as
|
|
11761
|
+
import { readFileSync as readFileSync15, readdirSync as readdirSync11, renameSync as renameSync9, statSync as statSync10 } from "fs";
|
|
11762
|
+
import { join as join19 } from "path";
|
|
11526
11763
|
init_executors();
|
|
11527
11764
|
init_swarmModels();
|
|
11528
11765
|
var UNPROCESSED_LOG_RE = /^\d+\.json$/;
|
|
@@ -11530,7 +11767,7 @@ var SEGMENT_LOG_RE = /^(\d+)\.json(\.done)?$/;
|
|
|
11530
11767
|
var RESCUE_OPEN_WINDOW_MAX_MS = 12 * 60 * 60 * 1e3;
|
|
11531
11768
|
function unprocessedLogFiles(dir) {
|
|
11532
11769
|
try {
|
|
11533
|
-
return
|
|
11770
|
+
return readdirSync11(dir).filter((f) => UNPROCESSED_LOG_RE.test(f));
|
|
11534
11771
|
} catch {
|
|
11535
11772
|
return [];
|
|
11536
11773
|
}
|
|
@@ -11539,7 +11776,7 @@ function segmentStarts(dir) {
|
|
|
11539
11776
|
const starts = /* @__PURE__ */ new Map();
|
|
11540
11777
|
let entries;
|
|
11541
11778
|
try {
|
|
11542
|
-
entries =
|
|
11779
|
+
entries = readdirSync11(dir);
|
|
11543
11780
|
} catch {
|
|
11544
11781
|
return starts;
|
|
11545
11782
|
}
|
|
@@ -11547,7 +11784,7 @@ function segmentStarts(dir) {
|
|
|
11547
11784
|
const m = SEGMENT_LOG_RE.exec(f);
|
|
11548
11785
|
if (!m) continue;
|
|
11549
11786
|
try {
|
|
11550
|
-
const st =
|
|
11787
|
+
const st = statSync10(join19(dir, f));
|
|
11551
11788
|
starts.set(Number(m[1]), st.birthtimeMs > 0 ? st.birthtimeMs : st.ctimeMs);
|
|
11552
11789
|
} catch {
|
|
11553
11790
|
}
|
|
@@ -11600,7 +11837,7 @@ function accountRunCost(deps, run) {
|
|
|
11600
11837
|
let unmeasured = 0;
|
|
11601
11838
|
const processed = [];
|
|
11602
11839
|
for (const f of files) {
|
|
11603
|
-
const full =
|
|
11840
|
+
const full = join19(dir, f);
|
|
11604
11841
|
let raw = null;
|
|
11605
11842
|
try {
|
|
11606
11843
|
raw = readFileSync15(full, "utf8");
|
|
@@ -11657,8 +11894,8 @@ function makeCostSweeper(deps) {
|
|
|
11657
11894
|
}
|
|
11658
11895
|
|
|
11659
11896
|
// src/runOutcome.ts
|
|
11660
|
-
import { readdirSync as
|
|
11661
|
-
import { join as
|
|
11897
|
+
import { readdirSync as readdirSync12, readFileSync as readFileSync16 } from "fs";
|
|
11898
|
+
import { join as join20 } from "path";
|
|
11662
11899
|
init_executors();
|
|
11663
11900
|
function endedItself(outcome) {
|
|
11664
11901
|
return outcome === "graceful" || outcome === "budget" || outcome === "aborted";
|
|
@@ -11672,7 +11909,7 @@ function readLatestResultRaw(runLogsDir, runLogKeys) {
|
|
|
11672
11909
|
if (!dir) return null;
|
|
11673
11910
|
let files;
|
|
11674
11911
|
try {
|
|
11675
|
-
files =
|
|
11912
|
+
files = readdirSync12(dir);
|
|
11676
11913
|
} catch {
|
|
11677
11914
|
return null;
|
|
11678
11915
|
}
|
|
@@ -11685,7 +11922,7 @@ function readLatestResultRaw(runLogsDir, runLogKeys) {
|
|
|
11685
11922
|
}
|
|
11686
11923
|
if (!latest) return null;
|
|
11687
11924
|
try {
|
|
11688
|
-
return readFileSync16(
|
|
11925
|
+
return readFileSync16(join20(dir, latest.name), "utf8");
|
|
11689
11926
|
} catch {
|
|
11690
11927
|
return null;
|
|
11691
11928
|
}
|
|
@@ -11717,9 +11954,11 @@ init_claudeCode();
|
|
|
11717
11954
|
init_swarmModels();
|
|
11718
11955
|
|
|
11719
11956
|
// src/executors/detect.ts
|
|
11957
|
+
init_src();
|
|
11958
|
+
init_swarmModels();
|
|
11720
11959
|
init_executors();
|
|
11721
11960
|
import { accessSync, constants } from "fs";
|
|
11722
|
-
import { delimiter, join as
|
|
11961
|
+
import { delimiter, join as join21 } from "path";
|
|
11723
11962
|
function binRunnable(bin, env) {
|
|
11724
11963
|
if (!bin) return false;
|
|
11725
11964
|
if (bin.includes("/") || bin.includes("\\")) {
|
|
@@ -11735,7 +11974,7 @@ function binRunnable(bin, env) {
|
|
|
11735
11974
|
if (!dir) continue;
|
|
11736
11975
|
for (const ext of exts) {
|
|
11737
11976
|
try {
|
|
11738
|
-
accessSync(
|
|
11977
|
+
accessSync(join21(dir, bin + ext), constants.X_OK);
|
|
11739
11978
|
return true;
|
|
11740
11979
|
} catch {
|
|
11741
11980
|
}
|
|
@@ -11766,26 +12005,36 @@ function cachedInstalledExecutorIds(now = Date.now(), ttlMs = 3e5, env = process
|
|
|
11766
12005
|
}
|
|
11767
12006
|
return cachedIds;
|
|
11768
12007
|
}
|
|
12008
|
+
function availableProviders(installedExecutors, env = process.env) {
|
|
12009
|
+
const explicit = providersFromEnv(env);
|
|
12010
|
+
if (explicit) return explicit;
|
|
12011
|
+
const installed2 = new Set(installedExecutors);
|
|
12012
|
+
return MODEL_PROVIDERS.filter((p) => installed2.has(p.executorId)).map((p) => p.id);
|
|
12013
|
+
}
|
|
12014
|
+
function providerUnavailableReason(providerId, available) {
|
|
12015
|
+
if (available.length === 0 || available.includes(providerId)) return null;
|
|
12016
|
+
return `provider_unavailable: \u043C\u043E\u0434\u0435\u043B\u044C \u043F\u0440\u043E\u0433\u043E\u043D\u0430 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043F\u0440\u043E\u0432\u0430\u0439\u0434\u0435\u0440\u0430 \xAB${providerId}\xBB, \u0430 \u043D\u0430 \u044D\u0442\u043E\u0439 \u043C\u0430\u0448\u0438\u043D\u0435 \u0442\u043E\u043B\u044C\u043A\u043E ${available.join(", ")} \u2014 \u043F\u0440\u043E\u0433\u043E\u043D \u043D\u0435 \u0431\u0435\u0440\u0443, \u0435\u0433\u043E \u0432\u043E\u0437\u044C\u043C\u0451\u0442 \u0434\u0440\u0443\u0433\u0430\u044F \u043C\u0430\u0448\u0438\u043D\u0430`;
|
|
12017
|
+
}
|
|
11769
12018
|
|
|
11770
12019
|
// src/orchestrator.ts
|
|
11771
12020
|
init_src();
|
|
11772
12021
|
init_git();
|
|
11773
12022
|
|
|
11774
12023
|
// src/deps.ts
|
|
11775
|
-
import { existsSync as
|
|
11776
|
-
import { join as
|
|
12024
|
+
import { existsSync as existsSync15, readdirSync as readdirSync14, readFileSync as readFileSync18 } from "fs";
|
|
12025
|
+
import { join as join25 } from "path";
|
|
11777
12026
|
import { execa } from "execa";
|
|
11778
12027
|
|
|
11779
12028
|
// src/prepareLock.ts
|
|
11780
12029
|
import { createHash } from "crypto";
|
|
11781
|
-
import { closeSync as closeSync4, openSync as openSync4, rmSync as rmSync2, statSync as
|
|
11782
|
-
import { join as
|
|
12030
|
+
import { closeSync as closeSync4, openSync as openSync4, rmSync as rmSync2, statSync as statSync12, writeSync } from "fs";
|
|
12031
|
+
import { join as join23 } from "path";
|
|
11783
12032
|
import { tmpdir } from "os";
|
|
11784
12033
|
var WAIT_TIMEOUT_MS = 5 * 6e4;
|
|
11785
12034
|
var POLL_MS = 300;
|
|
11786
12035
|
var STALE_MS = 20 * 6e4;
|
|
11787
12036
|
function machineLockPath(key, dir = tmpdir()) {
|
|
11788
|
-
return
|
|
12037
|
+
return join23(dir, `swarm-prepare-${createHash("sha1").update(key).digest("hex").slice(0, 16)}.lock`);
|
|
11789
12038
|
}
|
|
11790
12039
|
function defaultTryCreate(path, content) {
|
|
11791
12040
|
try {
|
|
@@ -11802,7 +12051,7 @@ function defaultTryCreate(path, content) {
|
|
|
11802
12051
|
}
|
|
11803
12052
|
function defaultAgeMs(path) {
|
|
11804
12053
|
try {
|
|
11805
|
-
return Date.now() -
|
|
12054
|
+
return Date.now() - statSync12(path).mtimeMs;
|
|
11806
12055
|
} catch {
|
|
11807
12056
|
return null;
|
|
11808
12057
|
}
|
|
@@ -11846,8 +12095,8 @@ init_config();
|
|
|
11846
12095
|
init_config();
|
|
11847
12096
|
import { createHash as createHash2 } from "crypto";
|
|
11848
12097
|
import { cp, link, lstat, mkdir as mkdir2, readdir, readlink, rename as rename2, rm as rm2, stat, symlink, utimes, writeFile as writeFile2 } from "fs/promises";
|
|
11849
|
-
import { existsSync as
|
|
11850
|
-
import { join as
|
|
12098
|
+
import { existsSync as existsSync14, readFileSync as readFileSync17 } from "fs";
|
|
12099
|
+
import { join as join24 } from "path";
|
|
11851
12100
|
function fingerprint(parts) {
|
|
11852
12101
|
const h = createHash2("sha256");
|
|
11853
12102
|
for (const p of parts) {
|
|
@@ -11861,8 +12110,8 @@ async function cloneTree(src, dst) {
|
|
|
11861
12110
|
const entries = await readdir(src, { withFileTypes: true });
|
|
11862
12111
|
await Promise.all(
|
|
11863
12112
|
entries.map(async (e) => {
|
|
11864
|
-
const from =
|
|
11865
|
-
const to =
|
|
12113
|
+
const from = join24(src, e.name);
|
|
12114
|
+
const to = join24(dst, e.name);
|
|
11866
12115
|
if (e.isDirectory()) return cloneTree(from, to);
|
|
11867
12116
|
if (e.isSymbolicLink()) {
|
|
11868
12117
|
return symlink(await readlink(from), to).catch(() => cp(from, to, { recursive: true, verbatimSymlinks: true }));
|
|
@@ -11875,11 +12124,11 @@ function cacheRoot(io) {
|
|
|
11875
12124
|
return io.root ?? ENV_CACHE_DIR;
|
|
11876
12125
|
}
|
|
11877
12126
|
function snapshotDir(io, key) {
|
|
11878
|
-
return
|
|
12127
|
+
return join24(cacheRoot(io), key);
|
|
11879
12128
|
}
|
|
11880
12129
|
function readManifest(dir) {
|
|
11881
12130
|
try {
|
|
11882
|
-
const parsed = JSON.parse(readFileSync17(
|
|
12131
|
+
const parsed = JSON.parse(readFileSync17(join24(dir, "manifest.json"), "utf8"));
|
|
11883
12132
|
if (!parsed || typeof parsed !== "object") return null;
|
|
11884
12133
|
const m = parsed;
|
|
11885
12134
|
if (typeof m.key !== "string" || !Array.isArray(m.dirs)) return null;
|
|
@@ -11891,11 +12140,11 @@ function readManifest(dir) {
|
|
|
11891
12140
|
}
|
|
11892
12141
|
}
|
|
11893
12142
|
function hasEnvSnapshot(key, io = {}) {
|
|
11894
|
-
const exists = io.exists ??
|
|
11895
|
-
return exists(
|
|
12143
|
+
const exists = io.exists ?? existsSync14;
|
|
12144
|
+
return exists(join24(snapshotDir(io, key), "manifest.json"));
|
|
11896
12145
|
}
|
|
11897
12146
|
async function restoreEnvSnapshot(worktree, key, io = {}) {
|
|
11898
|
-
const exists = io.exists ??
|
|
12147
|
+
const exists = io.exists ?? existsSync14;
|
|
11899
12148
|
const clone = io.clone ?? cloneTree;
|
|
11900
12149
|
const dir = snapshotDir(io, key);
|
|
11901
12150
|
const manifest = readManifest(dir);
|
|
@@ -11904,13 +12153,13 @@ async function restoreEnvSnapshot(worktree, key, io = {}) {
|
|
|
11904
12153
|
try {
|
|
11905
12154
|
for (let i = 0; i < manifest.dirs.length; i++) {
|
|
11906
12155
|
const rel = manifest.dirs[i] ?? "";
|
|
11907
|
-
const target =
|
|
12156
|
+
const target = join24(worktree, rel);
|
|
11908
12157
|
if (exists(target)) continue;
|
|
11909
|
-
await clone(
|
|
12158
|
+
await clone(join24(dir, "trees", String(i)), target);
|
|
11910
12159
|
made.push(rel);
|
|
11911
12160
|
}
|
|
11912
12161
|
} catch {
|
|
11913
|
-
for (const rel of made) await rm2(
|
|
12162
|
+
for (const rel of made) await rm2(join24(worktree, rel), { recursive: true, force: true }).catch(() => {
|
|
11914
12163
|
});
|
|
11915
12164
|
return null;
|
|
11916
12165
|
}
|
|
@@ -11923,19 +12172,19 @@ async function touch(dir) {
|
|
|
11923
12172
|
});
|
|
11924
12173
|
}
|
|
11925
12174
|
async function saveEnvSnapshot(worktree, key, dirs, io = {}) {
|
|
11926
|
-
const exists = io.exists ??
|
|
12175
|
+
const exists = io.exists ?? existsSync14;
|
|
11927
12176
|
const clone = io.clone ?? cloneTree;
|
|
11928
12177
|
if (hasEnvSnapshot(key, io)) return true;
|
|
11929
|
-
const present = dirs.filter((rel) => exists(
|
|
12178
|
+
const present = dirs.filter((rel) => exists(join24(worktree, rel)));
|
|
11930
12179
|
if (!present.length) return false;
|
|
11931
12180
|
const root = cacheRoot(io);
|
|
11932
|
-
const tmp =
|
|
12181
|
+
const tmp = join24(root, `.tmp-${key}-${process.pid}`);
|
|
11933
12182
|
try {
|
|
11934
12183
|
await rm2(tmp, { recursive: true, force: true });
|
|
11935
|
-
await mkdir2(
|
|
11936
|
-
for (let i = 0; i < present.length; i++) await clone(
|
|
12184
|
+
await mkdir2(join24(tmp, "trees"), { recursive: true });
|
|
12185
|
+
for (let i = 0; i < present.length; i++) await clone(join24(worktree, present[i] ?? ""), join24(tmp, "trees", String(i)));
|
|
11937
12186
|
const manifest = { key, dirs: present, createdAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
11938
|
-
await writeFile2(
|
|
12187
|
+
await writeFile2(join24(tmp, "manifest.json"), JSON.stringify(manifest, null, 2));
|
|
11939
12188
|
await rename2(tmp, snapshotDir(io, key));
|
|
11940
12189
|
return true;
|
|
11941
12190
|
} catch {
|
|
@@ -11955,13 +12204,13 @@ async function pruneEnvSnapshots(io = {}) {
|
|
|
11955
12204
|
}
|
|
11956
12205
|
const withTime = [];
|
|
11957
12206
|
for (const name of names) {
|
|
11958
|
-
const s = await stat(
|
|
12207
|
+
const s = await stat(join24(root, name)).catch(() => null);
|
|
11959
12208
|
if (s) withTime.push({ name, mtime: s.mtimeMs });
|
|
11960
12209
|
}
|
|
11961
12210
|
withTime.sort((a, b) => b.mtime - a.mtime);
|
|
11962
12211
|
let removed = 0;
|
|
11963
12212
|
for (const { name } of withTime.slice(Math.max(0, keep))) {
|
|
11964
|
-
await rm2(
|
|
12213
|
+
await rm2(join24(root, name), { recursive: true, force: true }).catch(() => {
|
|
11965
12214
|
});
|
|
11966
12215
|
removed++;
|
|
11967
12216
|
}
|
|
@@ -11977,9 +12226,9 @@ async function sweepEnvCacheTemp(io = {}) {
|
|
|
11977
12226
|
}
|
|
11978
12227
|
let removed = 0;
|
|
11979
12228
|
for (const name of names) {
|
|
11980
|
-
const s = await lstat(
|
|
12229
|
+
const s = await lstat(join24(root, name)).catch(() => null);
|
|
11981
12230
|
if (!s || Date.now() - s.mtimeMs < 60 * 6e4) continue;
|
|
11982
|
-
await rm2(
|
|
12231
|
+
await rm2(join24(root, name), { recursive: true, force: true }).catch(() => {
|
|
11983
12232
|
});
|
|
11984
12233
|
removed++;
|
|
11985
12234
|
}
|
|
@@ -12013,14 +12262,14 @@ function safeReadText(p) {
|
|
|
12013
12262
|
}
|
|
12014
12263
|
function safeListDirs(p) {
|
|
12015
12264
|
try {
|
|
12016
|
-
return
|
|
12265
|
+
return readdirSync14(p, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
12017
12266
|
} catch {
|
|
12018
12267
|
return [];
|
|
12019
12268
|
}
|
|
12020
12269
|
}
|
|
12021
12270
|
function safeListFiles(p) {
|
|
12022
12271
|
try {
|
|
12023
|
-
return
|
|
12272
|
+
return readdirSync14(p, { withFileTypes: true }).filter((e) => e.isFile()).map((e) => e.name);
|
|
12024
12273
|
} catch {
|
|
12025
12274
|
return [];
|
|
12026
12275
|
}
|
|
@@ -12046,21 +12295,21 @@ function overridePlan(override) {
|
|
|
12046
12295
|
};
|
|
12047
12296
|
}
|
|
12048
12297
|
function detectPackageManager(worktree, io = {}) {
|
|
12049
|
-
const exists = io.exists ??
|
|
12298
|
+
const exists = io.exists ?? existsSync15;
|
|
12050
12299
|
const readText = io.readText ?? safeReadText;
|
|
12051
|
-
const hasPkgJson = exists(
|
|
12300
|
+
const hasPkgJson = exists(join25(worktree, "package.json"));
|
|
12052
12301
|
if (!hasPkgJson) {
|
|
12053
|
-
if (exists(
|
|
12302
|
+
if (exists(join25(worktree, "deno.json")) || exists(join25(worktree, "deno.jsonc")) || exists(join25(worktree, "deno.lock"))) return "deno";
|
|
12054
12303
|
return null;
|
|
12055
12304
|
}
|
|
12056
|
-
const pkg = readJson(readText,
|
|
12305
|
+
const pkg = readJson(readText, join25(worktree, "package.json"));
|
|
12057
12306
|
const declared = typeof pkg?.packageManager === "string" ? pkg.packageManager.split("@")[0] : void 0;
|
|
12058
12307
|
if (declared === "pnpm" || declared === "bun" || declared === "npm" || declared === "yarn") return declared;
|
|
12059
|
-
if (exists(
|
|
12060
|
-
if (exists(
|
|
12061
|
-
if (exists(
|
|
12062
|
-
if (exists(
|
|
12063
|
-
if (exists(
|
|
12308
|
+
if (exists(join25(worktree, "bun.lock")) || exists(join25(worktree, "bun.lockb"))) return "bun";
|
|
12309
|
+
if (exists(join25(worktree, "pnpm-lock.yaml"))) return "pnpm";
|
|
12310
|
+
if (exists(join25(worktree, "yarn.lock"))) return "yarn";
|
|
12311
|
+
if (exists(join25(worktree, "package-lock.json"))) return "npm";
|
|
12312
|
+
if (exists(join25(worktree, "deno.lock"))) return "deno";
|
|
12064
12313
|
return "npm";
|
|
12065
12314
|
}
|
|
12066
12315
|
function jsInstallCommand(pm) {
|
|
@@ -12116,7 +12365,7 @@ var ECOSYSTEM_MARKERS = [
|
|
|
12116
12365
|
// конфигурация — дело сборки, не подготовки
|
|
12117
12366
|
];
|
|
12118
12367
|
function detectPlan(worktree, io) {
|
|
12119
|
-
const exists = io.exists ??
|
|
12368
|
+
const exists = io.exists ?? existsSync15;
|
|
12120
12369
|
const listFiles = io.listFiles ?? safeListFiles;
|
|
12121
12370
|
const pm = detectPackageManager(worktree, io);
|
|
12122
12371
|
if (pm) {
|
|
@@ -12124,7 +12373,7 @@ function detectPlan(worktree, io) {
|
|
|
12124
12373
|
// node_modules на месте — установку пропускаем (быстрый путь переиспользованного worktree).
|
|
12125
12374
|
// У deno каталога может не быть вовсе (кэш в DENO_DIR) — тогда `deno install` отработает
|
|
12126
12375
|
// заново, но он дешёвый: тянет из того же общего кэша.
|
|
12127
|
-
{ label: `${pm} install`, run: jsInstallCommand(pm), skipIfExists:
|
|
12376
|
+
{ label: `${pm} install`, run: jsInstallCommand(pm), skipIfExists: join25(worktree, "node_modules"), source: "detect" }
|
|
12128
12377
|
];
|
|
12129
12378
|
for (const target of workspaceBuildTargets(worktree, io)) {
|
|
12130
12379
|
commands.push({ label: `\u0441\u0431\u043E\u0440\u043A\u0430 ${target.name}`, run: jsRunScript(pm, "build"), cwd: target.dir, source: "detect" });
|
|
@@ -12133,12 +12382,12 @@ function detectPlan(worktree, io) {
|
|
|
12133
12382
|
return { source: "detect", ecosystem: `node/${pm}`, commands };
|
|
12134
12383
|
}
|
|
12135
12384
|
for (const marker of ECOSYSTEM_MARKERS) {
|
|
12136
|
-
const hit = marker.files.some((f) => exists(
|
|
12385
|
+
const hit = marker.files.some((f) => exists(join25(worktree, f))) || marker.ext !== void 0 && listFiles(worktree).some((n) => n.endsWith(marker.ext));
|
|
12137
12386
|
if (!hit) continue;
|
|
12138
12387
|
let ecosystem = marker.ecosystem;
|
|
12139
12388
|
let command = marker.command;
|
|
12140
12389
|
for (const refine of marker.refine ?? []) {
|
|
12141
|
-
if (!exists(
|
|
12390
|
+
if (!exists(join25(worktree, refine.file))) continue;
|
|
12142
12391
|
ecosystem = refine.ecosystem;
|
|
12143
12392
|
command = refine.command;
|
|
12144
12393
|
break;
|
|
@@ -12195,12 +12444,12 @@ var CI_INSTALL_PATTERNS = [
|
|
|
12195
12444
|
function ciWorkflowPlan(worktree, io) {
|
|
12196
12445
|
const readText = io.readText ?? safeReadText;
|
|
12197
12446
|
const listFiles = io.listFiles ?? safeListFiles;
|
|
12198
|
-
const dir =
|
|
12447
|
+
const dir = join25(worktree, ".github", "workflows");
|
|
12199
12448
|
const files = listFiles(dir).filter((n) => n.endsWith(".yml") || n.endsWith(".yaml"));
|
|
12200
12449
|
const seen = /* @__PURE__ */ new Set();
|
|
12201
12450
|
const commands = [];
|
|
12202
12451
|
for (const name of files.sort()) {
|
|
12203
|
-
const yaml = readText(
|
|
12452
|
+
const yaml = readText(join25(dir, name));
|
|
12204
12453
|
if (yaml === null) continue;
|
|
12205
12454
|
for (const raw of workflowRunLines(yaml)) {
|
|
12206
12455
|
const line = raw.replace(/\s+/g, " ").trim();
|
|
@@ -12215,7 +12464,7 @@ function ciWorkflowPlan(worktree, io) {
|
|
|
12215
12464
|
return commands.length ? { source: "ci-workflow", ecosystem: "ci-\u043A\u043E\u043D\u0444\u0438\u0433", commands } : null;
|
|
12216
12465
|
}
|
|
12217
12466
|
function workspaceGlobs(worktree, readText) {
|
|
12218
|
-
const yaml = readText(
|
|
12467
|
+
const yaml = readText(join25(worktree, "pnpm-workspace.yaml"));
|
|
12219
12468
|
if (yaml !== null) {
|
|
12220
12469
|
const globs = [];
|
|
12221
12470
|
let inPackages = false;
|
|
@@ -12235,7 +12484,7 @@ function workspaceGlobs(worktree, readText) {
|
|
|
12235
12484
|
}
|
|
12236
12485
|
if (globs.length) return globs;
|
|
12237
12486
|
}
|
|
12238
|
-
const pkg = readJson(readText,
|
|
12487
|
+
const pkg = readJson(readText, join25(worktree, "package.json"));
|
|
12239
12488
|
const ws = pkg?.workspaces;
|
|
12240
12489
|
const list = Array.isArray(ws) ? ws : Array.isArray(ws?.packages) ? ws.packages : [];
|
|
12241
12490
|
return list.filter((g) => typeof g === "string");
|
|
@@ -12246,14 +12495,14 @@ function workspaceDirs(worktree, globs, io) {
|
|
|
12246
12495
|
if (glob.startsWith("!")) continue;
|
|
12247
12496
|
const star = glob.indexOf("*");
|
|
12248
12497
|
if (star === -1) {
|
|
12249
|
-
const dir =
|
|
12250
|
-
if (io.exists(
|
|
12498
|
+
const dir = join25(worktree, glob);
|
|
12499
|
+
if (io.exists(join25(dir, "package.json"))) dirs.add(dir);
|
|
12251
12500
|
continue;
|
|
12252
12501
|
}
|
|
12253
|
-
const base3 =
|
|
12502
|
+
const base3 = join25(worktree, glob.slice(0, star).replace(/\/$/, ""));
|
|
12254
12503
|
for (const name of io.listDirs(base3)) {
|
|
12255
|
-
const dir =
|
|
12256
|
-
if (io.exists(
|
|
12504
|
+
const dir = join25(base3, name);
|
|
12505
|
+
if (io.exists(join25(dir, "package.json"))) dirs.add(dir);
|
|
12257
12506
|
}
|
|
12258
12507
|
}
|
|
12259
12508
|
return [...dirs];
|
|
@@ -12274,18 +12523,18 @@ function entryPaths(pkg) {
|
|
|
12274
12523
|
return out;
|
|
12275
12524
|
}
|
|
12276
12525
|
function workspaceBuildTargets(worktree, io = {}) {
|
|
12277
|
-
const exists = io.exists ??
|
|
12526
|
+
const exists = io.exists ?? existsSync15;
|
|
12278
12527
|
const readText = io.readText ?? safeReadText;
|
|
12279
12528
|
const listDirs = io.listDirs ?? safeListDirs;
|
|
12280
12529
|
const globs = workspaceGlobs(worktree, readText);
|
|
12281
12530
|
if (!globs.length) return [];
|
|
12282
12531
|
const pkgs = [];
|
|
12283
12532
|
for (const dir of workspaceDirs(worktree, globs, { exists, listDirs })) {
|
|
12284
|
-
const pkg = readJson(readText,
|
|
12533
|
+
const pkg = readJson(readText, join25(dir, "package.json"));
|
|
12285
12534
|
if (!pkg || typeof pkg.name !== "string") continue;
|
|
12286
12535
|
const scripts = pkg.scripts ?? {};
|
|
12287
12536
|
const entries = entryPaths(pkg);
|
|
12288
|
-
const needsBuild = typeof scripts.build === "string" && entries.length > 0 && entries.some((e) => !exists(
|
|
12537
|
+
const needsBuild = typeof scripts.build === "string" && entries.length > 0 && entries.some((e) => !exists(join25(dir, e)));
|
|
12289
12538
|
const deps = Object.keys({ ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} });
|
|
12290
12539
|
pkgs.push({ name: pkg.name, dir, deps, needsBuild });
|
|
12291
12540
|
}
|
|
@@ -12313,7 +12562,7 @@ function devDatabaseUrl(worktree, io = {}) {
|
|
|
12313
12562
|
const fromEnv = (io.env ?? process.env).DATABASE_URL;
|
|
12314
12563
|
if (fromEnv && fromEnv.trim()) return fromEnv.trim();
|
|
12315
12564
|
for (const file of [".env", ".env.example"]) {
|
|
12316
|
-
const raw = readText(
|
|
12565
|
+
const raw = readText(join25(worktree, file));
|
|
12317
12566
|
if (raw === null) continue;
|
|
12318
12567
|
const m = /^\s*(?:export\s+)?DATABASE_URL\s*=\s*(.*)$/m.exec(raw);
|
|
12319
12568
|
const value = (m?.[1] ?? "").trim().replace(/^['"]|['"]$/g, "");
|
|
@@ -12329,11 +12578,11 @@ function isLocalDatabase(url) {
|
|
|
12329
12578
|
}
|
|
12330
12579
|
}
|
|
12331
12580
|
function prismaPackages(worktree, io) {
|
|
12332
|
-
const exists = io.exists ??
|
|
12581
|
+
const exists = io.exists ?? existsSync15;
|
|
12333
12582
|
const readText = io.readText ?? safeReadText;
|
|
12334
12583
|
const listDirs = io.listDirs ?? safeListDirs;
|
|
12335
12584
|
const dirs = [worktree, ...workspaceDirs(worktree, workspaceGlobs(worktree, readText), { exists, listDirs })];
|
|
12336
|
-
return dirs.filter((dir) => exists(
|
|
12585
|
+
return dirs.filter((dir) => exists(join25(dir, "prisma", "schema.prisma")) && listDirs(join25(dir, "prisma", "migrations")).length > 0);
|
|
12337
12586
|
}
|
|
12338
12587
|
function jsExecBin(pm, command) {
|
|
12339
12588
|
switch (pm) {
|
|
@@ -12363,25 +12612,25 @@ function migrateCommands(worktree, pm, io) {
|
|
|
12363
12612
|
var ENV_DEFINING_FILES = ["pnpm-lock.yaml", "package-lock.json", "yarn.lock", "bun.lock", "bun.lockb", "deno.lock", "pnpm-workspace.yaml"];
|
|
12364
12613
|
function envCachePlan(worktree, io = {}) {
|
|
12365
12614
|
if (!ENV_CACHE_ENABLED) return null;
|
|
12366
|
-
const exists = io.exists ??
|
|
12615
|
+
const exists = io.exists ?? existsSync15;
|
|
12367
12616
|
const readText = io.readText ?? safeReadText;
|
|
12368
12617
|
const listDirs = io.listDirs ?? safeListDirs;
|
|
12369
12618
|
const pm = detectPackageManager(worktree, io);
|
|
12370
12619
|
if (!pm) return null;
|
|
12371
12620
|
const parts = [`pm:${pm}`];
|
|
12372
12621
|
for (const name of ENV_DEFINING_FILES) {
|
|
12373
|
-
const raw = readText(
|
|
12622
|
+
const raw = readText(join25(worktree, name));
|
|
12374
12623
|
if (raw !== null) parts.push(`${name}
|
|
12375
12624
|
${raw}`);
|
|
12376
12625
|
}
|
|
12377
12626
|
const pkgDirs = workspaceDirs(worktree, workspaceGlobs(worktree, readText), { exists, listDirs });
|
|
12378
12627
|
const rels = pkgDirs.map((dir) => dir.slice(worktree.length + 1)).sort();
|
|
12379
12628
|
for (const rel of ["", ...rels]) {
|
|
12380
|
-
const raw = readText(
|
|
12629
|
+
const raw = readText(join25(worktree, rel, "package.json"));
|
|
12381
12630
|
if (raw !== null) parts.push(`${rel}/package.json
|
|
12382
12631
|
${raw}`);
|
|
12383
12632
|
}
|
|
12384
|
-
return { key: fingerprint(parts), dirs: ["node_modules", ...rels.map((rel) =>
|
|
12633
|
+
return { key: fingerprint(parts), dirs: ["node_modules", ...rels.map((rel) => join25(rel, "node_modules"))] };
|
|
12385
12634
|
}
|
|
12386
12635
|
function planPrepare(worktree, io = {}) {
|
|
12387
12636
|
const plan = overridePlan(io.override) ?? detectPlan(worktree, io) ?? ciWorkflowPlan(worktree, io);
|
|
@@ -12389,7 +12638,7 @@ function planPrepare(worktree, io = {}) {
|
|
|
12389
12638
|
return { ...plan, commands: plan.commands.slice(0, MAX_PLAN_COMMANDS) };
|
|
12390
12639
|
}
|
|
12391
12640
|
async function ensureWorktreeDeps(worktree, io = {}) {
|
|
12392
|
-
const exists = io.exists ??
|
|
12641
|
+
const exists = io.exists ?? existsSync15;
|
|
12393
12642
|
const exec = io.exec ?? ((cmd) => runCommand(cmd, worktree));
|
|
12394
12643
|
const approve = io.approve ?? (() => true);
|
|
12395
12644
|
const cachePlan = envCachePlan(worktree, io);
|
|
@@ -12406,7 +12655,7 @@ async function ensureWorktreeDeps(worktree, io = {}) {
|
|
|
12406
12655
|
restored: [],
|
|
12407
12656
|
cached: false
|
|
12408
12657
|
};
|
|
12409
|
-
if (cachePlan && !exists(
|
|
12658
|
+
if (cachePlan && !exists(join25(worktree, "node_modules"))) {
|
|
12410
12659
|
report.restored = await restoreEnvSnapshot(worktree, cachePlan.key, cacheIO) ?? [];
|
|
12411
12660
|
}
|
|
12412
12661
|
const plan = planPrepare(worktree, io);
|
|
@@ -12493,10 +12742,10 @@ function depsPromptNotice(report) {
|
|
|
12493
12742
|
|
|
12494
12743
|
// src/orchestrator.ts
|
|
12495
12744
|
init_config();
|
|
12496
|
-
import { existsSync as
|
|
12497
|
-
import { join as
|
|
12745
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync10, rmSync as rmSync3 } from "fs";
|
|
12746
|
+
import { join as join26, dirname as dirname4 } from "path";
|
|
12498
12747
|
function repolessRunDir(worktreesDir, taskSlug) {
|
|
12499
|
-
return
|
|
12748
|
+
return join26(dirname4(worktreesDir), "runs", taskSlug);
|
|
12500
12749
|
}
|
|
12501
12750
|
var WORKTREE_HELD_STATUSES = /* @__PURE__ */ new Set(["running", "blocked", "review", "paused", "storm_dead"]);
|
|
12502
12751
|
function worktreePathHeldLive(db, path, exceptRunId) {
|
|
@@ -12541,11 +12790,11 @@ function healTaskSlug(db, run, task) {
|
|
|
12541
12790
|
async function spawnDrone(deps, run) {
|
|
12542
12791
|
if (run.repoless) {
|
|
12543
12792
|
const workdir = repolessRunDir(deps.worktreesDir, run.task_slug);
|
|
12544
|
-
if (
|
|
12793
|
+
if (existsSync16(workdir)) {
|
|
12545
12794
|
rmSync3(workdir, { recursive: true, force: true });
|
|
12546
12795
|
deps.db.addEvent(run.id, "step", `\u0440\u0435\u043A\u043B\u0435\u0439\u043C \u043E\u0441\u0438\u0440\u043E\u0442\u0435\u0432\u0448\u0435\u0433\u043E \u0441\u043A\u0440\u0430\u0442\u0447-\u043A\u0430\u0442\u0430\u043B\u043E\u0433\u0430 ${workdir} (\u0434\u0435\u0440\u0436\u0430\u043B \u043C\u0451\u0440\u0442\u0432\u044B\u0439 \u043F\u0440\u043E\u0433\u043E\u043D)`);
|
|
12547
12796
|
}
|
|
12548
|
-
|
|
12797
|
+
mkdirSync10(workdir, { recursive: true });
|
|
12549
12798
|
if (run.area && deps.db.runningAreas("").includes(run.area)) throw new AreaBusyError(run.area);
|
|
12550
12799
|
deps.db.addEvent(run.id, "step", `repoless-\u043F\u0440\u043E\u0433\u043E\u043D: \u0441\u043A\u0440\u0430\u0442\u0447-\u043A\u0430\u0442\u0430\u043B\u043E\u0433 ${workdir} (\u0431\u0435\u0437 worktree/\u0432\u0435\u0442\u043A\u0438/PR \u2014 TASWM-595)`);
|
|
12551
12800
|
const built2 = await deps.buildPrompt(run, workdir);
|
|
@@ -12760,7 +13009,7 @@ function parkReasonUnretriable(reason) {
|
|
|
12760
13009
|
// package.json
|
|
12761
13010
|
var package_default = {
|
|
12762
13011
|
name: "@taskless-app/swarm",
|
|
12763
|
-
version: "0.6.
|
|
13012
|
+
version: "0.6.63",
|
|
12764
13013
|
type: "module",
|
|
12765
13014
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
12766
13015
|
keywords: [
|
|
@@ -12811,7 +13060,7 @@ var package_default = {
|
|
|
12811
13060
|
execa: "^10.0.0",
|
|
12812
13061
|
zod: "3.25.76"
|
|
12813
13062
|
},
|
|
12814
|
-
gitHead: "
|
|
13063
|
+
gitHead: "8d438b6288da036308528cff1160a157b4b64abd"
|
|
12815
13064
|
};
|
|
12816
13065
|
|
|
12817
13066
|
// src/version.ts
|
|
@@ -13599,8 +13848,8 @@ import { z } from "zod";
|
|
|
13599
13848
|
init_git();
|
|
13600
13849
|
|
|
13601
13850
|
// src/diff.ts
|
|
13602
|
-
import { statSync as
|
|
13603
|
-
import { join as
|
|
13851
|
+
import { statSync as statSync13 } from "fs";
|
|
13852
|
+
import { join as join31 } from "path";
|
|
13604
13853
|
import { $ as $4 } from "execa";
|
|
13605
13854
|
var MAX_FILES = 200;
|
|
13606
13855
|
var MAX_LINES_PER_FILE = 1500;
|
|
@@ -13743,7 +13992,7 @@ async function resolveBase(wt, baseBranch) {
|
|
|
13743
13992
|
}
|
|
13744
13993
|
function mtime(path) {
|
|
13745
13994
|
try {
|
|
13746
|
-
return
|
|
13995
|
+
return statSync13(path).mtimeMs;
|
|
13747
13996
|
} catch {
|
|
13748
13997
|
return 0;
|
|
13749
13998
|
}
|
|
@@ -13768,7 +14017,7 @@ async function collectRunDiff(worktree, opts = {}) {
|
|
|
13768
14017
|
files.push(pf);
|
|
13769
14018
|
}
|
|
13770
14019
|
}
|
|
13771
|
-
files.sort((a, b) => mtime(
|
|
14020
|
+
files.sort((a, b) => mtime(join31(worktree, b.path)) - mtime(join31(worktree, a.path)));
|
|
13772
14021
|
const truncatedFiles = files.length > MAX_FILES;
|
|
13773
14022
|
if (truncatedFiles) files = files.slice(0, MAX_FILES);
|
|
13774
14023
|
const added = files.reduce((s, f) => s + f.added, 0);
|
|
@@ -15768,9 +16017,9 @@ function mergeQueueCandidates(runs, repo, repoFallback) {
|
|
|
15768
16017
|
const byPr = /* @__PURE__ */ new Map();
|
|
15769
16018
|
for (const r of runs) {
|
|
15770
16019
|
if (effectiveRepoOf(r.repo, repoFallback) !== repo || !isMergeCandidate(r)) continue;
|
|
15771
|
-
const
|
|
15772
|
-
const seen = byPr.get(
|
|
15773
|
-
if (!seen || r.id > seen.id) byPr.set(
|
|
16020
|
+
const num2 = prNumberOf(r.pr_url);
|
|
16021
|
+
const seen = byPr.get(num2);
|
|
16022
|
+
if (!seen || r.id > seen.id) byPr.set(num2, r);
|
|
15774
16023
|
}
|
|
15775
16024
|
return [...byPr.values()];
|
|
15776
16025
|
}
|
|
@@ -15783,10 +16032,10 @@ function makeMergeQueueResolver(deps) {
|
|
|
15783
16032
|
};
|
|
15784
16033
|
return async (run) => {
|
|
15785
16034
|
if (!deps.baseSync || !run.pr_url) return null;
|
|
15786
|
-
const
|
|
15787
|
-
if (
|
|
16035
|
+
const num2 = prNumberOf(run.pr_url);
|
|
16036
|
+
if (num2 == null) return null;
|
|
15788
16037
|
const candidates = mergeQueueCandidates(deps.listRuns(), effectiveRepoOf(run.repo, deps.repoFallback), deps.repoFallback);
|
|
15789
|
-
const mine = candidates.find((c) => prNumberOf(c.pr_url) ===
|
|
16038
|
+
const mine = candidates.find((c) => prNumberOf(c.pr_url) === num2);
|
|
15790
16039
|
if (!mine) return null;
|
|
15791
16040
|
const ready = [];
|
|
15792
16041
|
const urlOf = /* @__PURE__ */ new Map();
|
|
@@ -15902,10 +16151,10 @@ function makeMergeIntentResolver(deps) {
|
|
|
15902
16151
|
};
|
|
15903
16152
|
return async (run) => {
|
|
15904
16153
|
if (!deps.baseSync || !run.pr_url || !hasMergeIntent(run)) return null;
|
|
15905
|
-
const
|
|
15906
|
-
if (
|
|
16154
|
+
const num2 = prNumberOf(run.pr_url);
|
|
16155
|
+
if (num2 == null) return null;
|
|
15907
16156
|
const marked = mergeQueueCandidates(deps.listRuns(), effectiveRepoOf(run.repo, deps.repoFallback), deps.repoFallback).filter(hasMergeIntent);
|
|
15908
|
-
const mine = marked.find((c) => prNumberOf(c.pr_url) ===
|
|
16157
|
+
const mine = marked.find((c) => prNumberOf(c.pr_url) === num2);
|
|
15909
16158
|
if (!mine) return null;
|
|
15910
16159
|
const queue = orderMergeQueue(marked.map(entryOf));
|
|
15911
16160
|
const entry = entryOf(mine);
|
|
@@ -16062,22 +16311,22 @@ async function prodClearMergeIntent(runId, deps = {}) {
|
|
|
16062
16311
|
}
|
|
16063
16312
|
|
|
16064
16313
|
// src/envGate.ts
|
|
16065
|
-
import { existsSync as
|
|
16066
|
-
import { join as
|
|
16314
|
+
import { existsSync as existsSync19 } from "fs";
|
|
16315
|
+
import { join as join33 } from "path";
|
|
16067
16316
|
import { createConnection } from "net";
|
|
16068
16317
|
import { execa as execa2 } from "execa";
|
|
16069
16318
|
|
|
16070
16319
|
// src/platform.ts
|
|
16071
|
-
import { existsSync as
|
|
16072
|
-
import { delimiter as delimiter2, join as
|
|
16320
|
+
import { existsSync as existsSync18, readFileSync as readFileSync22 } from "fs";
|
|
16321
|
+
import { delimiter as delimiter2, join as join32 } from "path";
|
|
16073
16322
|
function resolveCommandPath(name, env = process.env, platform = process.platform) {
|
|
16074
|
-
if (name.includes("/") || name.includes("\\")) return
|
|
16323
|
+
if (name.includes("/") || name.includes("\\")) return existsSync18(name) ? name : null;
|
|
16075
16324
|
const dirs = (env.PATH ?? env.Path ?? "").split(delimiter2).filter(Boolean);
|
|
16076
16325
|
const exts = platform === "win32" ? (env.PATHEXT ?? ".EXE;.CMD;.BAT").split(";").filter(Boolean) : [""];
|
|
16077
16326
|
for (const dir of dirs) {
|
|
16078
16327
|
for (const ext of exts) {
|
|
16079
|
-
const candidate =
|
|
16080
|
-
if (
|
|
16328
|
+
const candidate = join32(dir, name + ext);
|
|
16329
|
+
if (existsSync18(candidate)) return candidate;
|
|
16081
16330
|
}
|
|
16082
16331
|
}
|
|
16083
16332
|
return null;
|
|
@@ -16160,8 +16409,8 @@ var COMPOSE_MARKERS = [
|
|
|
16160
16409
|
"compose.yaml"
|
|
16161
16410
|
];
|
|
16162
16411
|
function detectRequirements(repo, io = {}) {
|
|
16163
|
-
const exists = io.exists ??
|
|
16164
|
-
const marker = COMPOSE_MARKERS.find((f) => exists(
|
|
16412
|
+
const exists = io.exists ?? existsSync19;
|
|
16413
|
+
const marker = COMPOSE_MARKERS.find((f) => exists(join33(repo, f)));
|
|
16165
16414
|
return marker ? [{ kind: "docker", raw: `docker (\u0434\u0435\u0442\u0435\u043A\u0442: ${marker})` }] : [];
|
|
16166
16415
|
}
|
|
16167
16416
|
function resolveRequirements(repo, declared, io = {}) {
|
|
@@ -17916,10 +18165,10 @@ function closeWebServer(server) {
|
|
|
17916
18165
|
|
|
17917
18166
|
// src/hostCommands.ts
|
|
17918
18167
|
init_src();
|
|
17919
|
-
import { readFileSync as readFileSync23, renameSync as renameSync10, writeFileSync as
|
|
17920
|
-
import { join as
|
|
18168
|
+
import { readFileSync as readFileSync23, renameSync as renameSync10, writeFileSync as writeFileSync16 } from "fs";
|
|
18169
|
+
import { join as join34 } from "path";
|
|
17921
18170
|
function hostCommandStatePath(home) {
|
|
17922
|
-
return
|
|
18171
|
+
return join34(home, "host-command.json");
|
|
17923
18172
|
}
|
|
17924
18173
|
function readState(path) {
|
|
17925
18174
|
try {
|
|
@@ -17930,7 +18179,7 @@ function readState(path) {
|
|
|
17930
18179
|
}
|
|
17931
18180
|
function writeState(path, state) {
|
|
17932
18181
|
try {
|
|
17933
|
-
|
|
18182
|
+
writeFileSync16(`${path}.tmp`, JSON.stringify(state));
|
|
17934
18183
|
renameSync10(`${path}.tmp`, path);
|
|
17935
18184
|
} catch {
|
|
17936
18185
|
}
|
|
@@ -18093,8 +18342,8 @@ async function doRestart(cmd, opts, note) {
|
|
|
18093
18342
|
|
|
18094
18343
|
// src/selfUpdate.ts
|
|
18095
18344
|
init_git();
|
|
18096
|
-
import { existsSync as
|
|
18097
|
-
import { join as
|
|
18345
|
+
import { existsSync as existsSync20 } from "fs";
|
|
18346
|
+
import { join as join35 } from "path";
|
|
18098
18347
|
import { $ as $5 } from "execa";
|
|
18099
18348
|
var DAEMON_PACKAGE = "@taskless-app/swarm";
|
|
18100
18349
|
var defaultRun = async (cmd, args, cwd) => {
|
|
@@ -18107,7 +18356,7 @@ function tail(text, max = 400) {
|
|
|
18107
18356
|
}
|
|
18108
18357
|
async function runSelfUpdate(io) {
|
|
18109
18358
|
const run = io.run ?? defaultRun;
|
|
18110
|
-
const exists = io.exists ??
|
|
18359
|
+
const exists = io.exists ?? existsSync20;
|
|
18111
18360
|
const repo = io.repo;
|
|
18112
18361
|
await io.onStep("fetch", "\u0442\u044F\u043D\u0443 \u0441\u0432\u0435\u0436\u0438\u0439 \u043A\u043E\u0434");
|
|
18113
18362
|
const fetched = await run("git", ["-C", repo, "fetch", "--quiet", "origin"], repo);
|
|
@@ -18136,7 +18385,7 @@ async function runSelfUpdate(io) {
|
|
|
18136
18385
|
};
|
|
18137
18386
|
}
|
|
18138
18387
|
await io.onStep("install", "\u0441\u0442\u0430\u0432\u043B\u044E \u0437\u0430\u0432\u0438\u0441\u0438\u043C\u043E\u0441\u0442\u0438");
|
|
18139
|
-
if (!exists(
|
|
18388
|
+
if (!exists(join35(repo, "pnpm-lock.yaml"))) {
|
|
18140
18389
|
return { ok: false, step: "install", message: "\u0432 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0438 \u0434\u0435\u043C\u043E\u043D\u0430 \u043D\u0435\u0442 pnpm-lock.yaml \u2014 \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0442\u044C \u0435\u0433\u043E \u044D\u0442\u0438\u043C \u043F\u0443\u0442\u0451\u043C \u043D\u0435 \u0431\u0435\u0440\u0443\u0441\u044C" };
|
|
18141
18390
|
}
|
|
18142
18391
|
const installed2 = await run("pnpm", ["install", "--frozen-lockfile"], repo);
|
|
@@ -18301,18 +18550,18 @@ async function fetchExternalStorm(url, opts = {}) {
|
|
|
18301
18550
|
}
|
|
18302
18551
|
|
|
18303
18552
|
// src/anomalyState.ts
|
|
18304
|
-
import { existsSync as
|
|
18305
|
-
import { join as
|
|
18553
|
+
import { existsSync as existsSync21, readFileSync as readFileSync24, renameSync as renameSync11, writeFileSync as writeFileSync17 } from "fs";
|
|
18554
|
+
import { join as join36 } from "path";
|
|
18306
18555
|
var KEY_TTL_MS = 7 * 24 * 60 * 6e4;
|
|
18307
18556
|
var MAX_RESOLVED = 200;
|
|
18308
18557
|
function emptyState() {
|
|
18309
18558
|
return { since: {}, lastFiredAt: {}, fires: {}, resolved: [], stopQuiet: null };
|
|
18310
18559
|
}
|
|
18311
18560
|
function anomalyStatePath(home) {
|
|
18312
|
-
return
|
|
18561
|
+
return join36(home, "anomaly-state.json");
|
|
18313
18562
|
}
|
|
18314
18563
|
function loadAnomalyState(home, now = Date.now(), io = {}) {
|
|
18315
|
-
const exists = io.exists ??
|
|
18564
|
+
const exists = io.exists ?? existsSync21;
|
|
18316
18565
|
const readFile2 = io.readFile ?? ((p) => readFileSync24(p, "utf8"));
|
|
18317
18566
|
const path = anomalyStatePath(home);
|
|
18318
18567
|
if (!exists(path)) return emptyState();
|
|
@@ -18343,7 +18592,7 @@ function loadAnomalyState(home, now = Date.now(), io = {}) {
|
|
|
18343
18592
|
function saveAnomalyState(home, state, io = {}) {
|
|
18344
18593
|
const path = anomalyStatePath(home);
|
|
18345
18594
|
const writeFile4 = io.writeFile ?? ((p, data) => {
|
|
18346
|
-
|
|
18595
|
+
writeFileSync17(`${p}.tmp`, data);
|
|
18347
18596
|
renameSync11(`${p}.tmp`, p);
|
|
18348
18597
|
});
|
|
18349
18598
|
writeFile4(path, JSON.stringify(state, null, 2));
|
|
@@ -18870,8 +19119,16 @@ function worktreeFromCmd(args) {
|
|
|
18870
19119
|
const quoted = args.match(/--mcp-config\s+"([^"]+[/\\]\.swarm-mcp\.json)"/);
|
|
18871
19120
|
const bare = quoted ? null : args.match(/--mcp-config\s+(\S+[/\\]\.swarm-mcp\.json)/);
|
|
18872
19121
|
const path = quoted?.[1] ?? bare?.[1];
|
|
18873
|
-
if (
|
|
18874
|
-
return
|
|
19122
|
+
if (path) return path.replace(/[/\\]\.swarm-mcp\.json$/, "");
|
|
19123
|
+
return worktreeFromGrokCwd(args);
|
|
19124
|
+
}
|
|
19125
|
+
function worktreeFromGrokCwd(args) {
|
|
19126
|
+
const trimmed = args.trim();
|
|
19127
|
+
const first = trimmed.startsWith('"') ? trimmed.slice(1, trimmed.indexOf('"', 1)) : trimmed.split(/\s/)[0] ?? "";
|
|
19128
|
+
if (!/(?:^|[\\/])grok(?:\.exe)?$/i.test(first)) return null;
|
|
19129
|
+
const cwdQuoted = args.match(/--cwd\s+"([^"]+)"/);
|
|
19130
|
+
const cwdBare = cwdQuoted ? null : args.match(/--cwd\s+(\S+)/);
|
|
19131
|
+
return cwdQuoted?.[1] ?? cwdBare?.[1] ?? null;
|
|
18875
19132
|
}
|
|
18876
19133
|
function listDroneProcesses() {
|
|
18877
19134
|
const rows = [];
|
|
@@ -19616,7 +19873,7 @@ ${task.description}` : `\u0417\u0430\u0434\u0430\u0447\u0430 ${run.task_slug} (\
|
|
|
19616
19873
|
}
|
|
19617
19874
|
return parts.join("\n");
|
|
19618
19875
|
}
|
|
19619
|
-
var HERO_CHARTER_PATH =
|
|
19876
|
+
var HERO_CHARTER_PATH = join37(dirname6(THIS_FILE), "..", "docs", "HERO.md");
|
|
19620
19877
|
function buildHeroPrompt(task, run, taskContext, attachmentsBlock) {
|
|
19621
19878
|
const name = run.name || `#${run.id}`;
|
|
19622
19879
|
const charter = readFileSync25(HERO_CHARTER_PATH, "utf8");
|
|
@@ -19676,7 +19933,7 @@ function ciTrustLine(prUrl, verifyMode) {
|
|
|
19676
19933
|
}
|
|
19677
19934
|
return `\u041D\u0435 \u043F\u0435\u0440\u0435\u0433\u043E\u043D\u044F\u0439 \u0442\u0435\u0441\u0442-\u0441\u044C\u044E\u0442/typecheck \u0437\u0430\u043D\u043E\u0432\u043E \u2014 \u044D\u0442\u043E \u0443\u0436\u0435 \u0441\u0434\u0435\u043B\u0430\u043B CI \u043D\u0430 \u044D\u0442\u043E\u043C \u0436\u0435 \u043A\u043E\u043C\u043C\u0438\u0442\u0435 (\u0434\u0432\u043E\u0439\u043D\u043E\u0439 \u043F\u0440\u043E\u0433\u043E\u043D \u043D\u0430 \u043C\u0430\u0448\u0438\u043D\u0435 \u0432\u043B\u0430\u0434\u0435\u043B\u044C\u0446\u0430 \u043E\u0442\u043C\u0435\u043D\u0451\u043D, TASWM-249). \u041F\u0440\u043E\u0447\u0438\u0442\u0430\u0439 \u0435\u0433\u043E \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442 \u0441\u0430\u043C: ${readChecks}. \u0414\u0430\u043B\u044C\u0448\u0435 \u0442\u0440\u0438 \u0440\u0430\u0437\u043D\u044B\u0445 \u0441\u043B\u0443\u0447\u0430\u044F: \u2460 \u0445\u043E\u0442\u044C \u043E\u0434\u0438\u043D \u0447\u0435\u043A \u0435\u0449\u0451 PENDING \u2014 \u0432\u0435\u0440\u0434\u0438\u043A\u0442 \u0432\u043E\u043E\u0431\u0449\u0435 \u043D\u0435 \u0432\u044B\u043D\u043E\u0441\u0438: \u043D\u0435 \u043F\u043E\u0441\u0442\u0438 REQUEST CHANGES, \u043D\u0435 \u0437\u043E\u0432\u0438 done(), \u043F\u0440\u043E\u0441\u0442\u043E \u0437\u0430\u0432\u0435\u0440\u0448\u0438 \u0441\u0435\u0441\u0441\u0438\u044E \u043A\u0430\u043A \u0435\u0441\u0442\u044C \u2014 \u0440\u043E\u0439 \u0441\u0430\u043C \u0437\u0430\u043C\u0435\u0442\u0438\u0442, \u0447\u0442\u043E \u0442\u044B \u0436\u0434\u0451\u0448\u044C CI, \u0438 \u0440\u0430\u0437\u0431\u0443\u0434\u0438\u0442 \u0434\u043E\u0434\u0435\u043B\u0430\u0442\u044C \u0440\u0435\u0432\u044C\u044E, \u043A\u043E\u0433\u0434\u0430 \u0432\u0441\u0435 \u0447\u0435\u043A\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0442\u0441\u044F (\u044D\u0442\u043E \u0448\u0442\u0430\u0442\u043D\u044B\u0439 \u043F\u0443\u0442\u044C, \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440\u0430 \u0437\u0432\u0430\u0442\u044C \u043D\u0435 \u043D\u0443\u0436\u043D\u043E). \u2461 \u0432\u0441\u0435 \u0447\u0435\u043A\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043B\u0438\u0441\u044C \u0438 \u0435\u0441\u0442\u044C FAIL \u2014 REQUEST CHANGES, \u043D\u0430\u0437\u043E\u0432\u0438 \u043F\u043E\u0438\u043C\u0451\u043D\u043D\u043E, \u0447\u0442\u043E \u0443\u043F\u0430\u043B\u043E. \u2462 \u043D\u0430 \u044D\u0442\u043E\u043C \u043A\u043E\u043C\u043C\u0438\u0442\u0435 \u0447\u0435\u043A\u043E\u0432 \u043D\u0435\u0442 \u0432\u043E\u0432\u0441\u0435 \u2014 \u0442\u043E\u0436\u0435 REQUEST CHANGES: \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C \u043D\u0435\u0447\u0435\u043C (\u0443 \u044D\u0442\u043E\u0433\u043E \u043F\u0440\u043E\u0435\u043A\u0442\u0430 verifyMode=ci, \u0442\u043E \u0435\u0441\u0442\u044C CI \u043E\u0431\u044F\u0437\u0430\u043D \u0431\u044B\u0442\u044C). ${dontTrustAuthor}`;
|
|
19678
19935
|
}
|
|
19679
|
-
var REVIEW_SKILL_PATH =
|
|
19936
|
+
var REVIEW_SKILL_PATH = join37(bundledRoleDir("drone"), "skills", "taskless-review", "SKILL.md");
|
|
19680
19937
|
function reviewDefectClasses(skillPath = REVIEW_SKILL_PATH) {
|
|
19681
19938
|
const text = readFileSync25(skillPath, "utf8");
|
|
19682
19939
|
const m = /^## Классы дефектов\n([\s\S]*?)(?=^## |(?![\s\S]))/m.exec(text);
|
|
@@ -19942,7 +20199,7 @@ async function wakeRun(deps, runId, opts = {}) {
|
|
|
19942
20199
|
if (run.status === "review" && run.pr_url && !needsFixIteration(run) && !stoppedForHuman) {
|
|
19943
20200
|
return { ok: false, why: `\u043F\u0440\u043E\u0433\u043E\u043D #${runId} \u0443\u0436\u0435 \u0441\u0434\u0430\u043D \u043D\u0430 \u0440\u0435\u0432\u044C\u044E (${run.pr_url}) \u2014 \u0431\u0443\u0434\u0438\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E; \u043F\u0440\u0430\u0432\u043A\u0438 \u043F\u043E\u0434\u043D\u0438\u043C\u0435\u0442 \u0440\u043E\u0439 \u043F\u043E \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u0443` };
|
|
19944
20201
|
}
|
|
19945
|
-
const worktreeExists = deps.worktreeExists ??
|
|
20202
|
+
const worktreeExists = deps.worktreeExists ?? existsSync22;
|
|
19946
20203
|
const hasTranscript = deps.hasTranscript ?? executorHasSession;
|
|
19947
20204
|
const wt = run.worktree_path;
|
|
19948
20205
|
const canContinue = !!wt && worktreeExists(wt) && hasTranscript(run);
|
|
@@ -20067,9 +20324,9 @@ function repoHasCi(deps, run) {
|
|
|
20067
20324
|
function repoHasCiWorkflows(worktreePath, repo) {
|
|
20068
20325
|
for (const base3 of [worktreePath, repo]) {
|
|
20069
20326
|
if (!base3) continue;
|
|
20070
|
-
const dir =
|
|
20327
|
+
const dir = join37(base3, ".github", "workflows");
|
|
20071
20328
|
try {
|
|
20072
|
-
if (
|
|
20329
|
+
if (readdirSync15(dir).some((f) => f.endsWith(".yml") || f.endsWith(".yaml"))) return true;
|
|
20073
20330
|
} catch {
|
|
20074
20331
|
}
|
|
20075
20332
|
}
|
|
@@ -20268,7 +20525,7 @@ async function wakeReviewerOnCiReady(deps, run, over) {
|
|
|
20268
20525
|
return true;
|
|
20269
20526
|
}
|
|
20270
20527
|
function worktreeAndTranscriptAlive(deps, run) {
|
|
20271
|
-
const exists = deps.worktreeExists ??
|
|
20528
|
+
const exists = deps.worktreeExists ?? existsSync22;
|
|
20272
20529
|
const transcript = deps.hasTranscript ?? executorHasSession;
|
|
20273
20530
|
const wt = run.worktree_path;
|
|
20274
20531
|
return !!wt && exists(wt) && transcript(run);
|
|
@@ -20368,7 +20625,7 @@ async function wakeAuthorOnChanges(deps, snapshot, now, droneCap) {
|
|
|
20368
20625
|
}
|
|
20369
20626
|
const wt = run.worktree_path;
|
|
20370
20627
|
const wtPath = wt || (deps.worktreesDir ? droneWorktreePath(deps.worktreesDir, normalizeRepo(run.repo || deps.repoFallback || ""), run.task_slug) : null);
|
|
20371
|
-
const worktreeReady = !!wtPath && (deps.worktreeExists ??
|
|
20628
|
+
const worktreeReady = !!wtPath && (deps.worktreeExists ?? existsSync22)(wtPath);
|
|
20372
20629
|
if (!worktreeReady && !await freshChangesWakeAllowed(deps, run, prUrl, now)) return false;
|
|
20373
20630
|
try {
|
|
20374
20631
|
await deps.respawn(run, "fix");
|
|
@@ -20451,7 +20708,7 @@ async function zoneConflictFor(db, models, activeFiles, run, repo, repoFallback)
|
|
|
20451
20708
|
activeFiles.prune(holders.map((r) => r.id));
|
|
20452
20709
|
const fileExists = (p) => {
|
|
20453
20710
|
try {
|
|
20454
|
-
return
|
|
20711
|
+
return statSync14(join37(repo, p), { throwIfNoEntry: false })?.isFile() ?? false;
|
|
20455
20712
|
} catch {
|
|
20456
20713
|
return false;
|
|
20457
20714
|
}
|
|
@@ -20687,6 +20944,8 @@ async function trySpawnQueuedRun(deps, run) {
|
|
|
20687
20944
|
if (!await projectQuotaGateAllows(deps, run)) return "skipped";
|
|
20688
20945
|
const prodOverride = await prodOverrideReason(deps, run, ["queued"]);
|
|
20689
20946
|
if (prodOverride) return deferSpawn(deps, run, prodOverride, { event: false });
|
|
20947
|
+
const providerGap = deps.providerGap?.(run) ?? null;
|
|
20948
|
+
if (providerGap) return deferSpawn(deps, run, providerGap);
|
|
20690
20949
|
if (deps.db.takeRun && !await deps.db.takeRun(run.id)) {
|
|
20691
20950
|
return deferSpawn(deps, run, "\u043D\u0435 \u0432\u0437\u044F\u043B \u043F\u0440\u043E\u0433\u043E\u043D \u043D\u0430 \u0441\u0432\u043E\u044E \u043C\u0430\u0448\u0438\u043D\u0443 \u2014 \u0441\u0435\u0440\u0432\u0435\u0440 \u043E\u0442\u0434\u0430\u043B \u0435\u0433\u043E \u0434\u0440\u0443\u0433\u043E\u043C\u0443 \u0434\u0435\u043C\u043E\u043D\u0443 (TASWM-281)");
|
|
20692
20951
|
}
|
|
@@ -20843,7 +21102,7 @@ async function liftReturners(deps, returners, now, droneCap) {
|
|
|
20843
21102
|
deps.returners?.delete(run.id);
|
|
20844
21103
|
continue;
|
|
20845
21104
|
}
|
|
20846
|
-
lifted = await wakeAuthorOnRedCi(deps, run, now, entry.ci, deps.worktreeExists ??
|
|
21105
|
+
lifted = await wakeAuthorOnRedCi(deps, run, now, entry.ci, deps.worktreeExists ?? existsSync22, deps.hasTranscript ?? executorHasSession, droneCap);
|
|
20847
21106
|
}
|
|
20848
21107
|
if (lifted) deps.returners?.delete(run.id);
|
|
20849
21108
|
}
|
|
@@ -20862,7 +21121,7 @@ async function resumeWatchdogParked(deps, droneCap) {
|
|
|
20862
21121
|
}
|
|
20863
21122
|
if (!candidate) return;
|
|
20864
21123
|
if (candidate.pid != null && deps.isAlive(candidate.pid)) return;
|
|
20865
|
-
const worktreeExists = deps.worktreeExists ??
|
|
21124
|
+
const worktreeExists = deps.worktreeExists ?? existsSync22;
|
|
20866
21125
|
const hasTranscript = deps.hasTranscript ?? executorHasSession;
|
|
20867
21126
|
const wt = candidate.worktree_path;
|
|
20868
21127
|
const canContinue = !!wt && worktreeExists(wt) && hasTranscript(candidate);
|
|
@@ -21649,7 +21908,7 @@ function buildEscalationCandidates(db) {
|
|
|
21649
21908
|
}
|
|
21650
21909
|
async function tickOnce(deps) {
|
|
21651
21910
|
const now = deps.now ? deps.now() : Date.now();
|
|
21652
|
-
const worktreeExists = deps.worktreeExists ??
|
|
21911
|
+
const worktreeExists = deps.worktreeExists ?? existsSync22;
|
|
21653
21912
|
const hasTranscript = deps.hasTranscript ?? executorHasSession;
|
|
21654
21913
|
deps.sampleHost?.();
|
|
21655
21914
|
if (deps.rehydrate) {
|
|
@@ -22550,7 +22809,7 @@ async function resolveConflict(deps, reviewRun) {
|
|
|
22550
22809
|
model: reviewRun.model,
|
|
22551
22810
|
review_model: reviewRun.review_model
|
|
22552
22811
|
});
|
|
22553
|
-
const wt =
|
|
22812
|
+
const wt = join37(deps.worktreesDir, basename6(repo), `${reviewRun.task_slug}-resolve-${resolver.id}`);
|
|
22554
22813
|
try {
|
|
22555
22814
|
await deps.git.prepareDetachedWorktree(repo, branch, wt);
|
|
22556
22815
|
await deps.git.setWorktreeIdentity(wt, resolver.name);
|
|
@@ -22630,7 +22889,7 @@ async function spawnReviewer(deps, reviewRun, files) {
|
|
|
22630
22889
|
// (своей у ревьюера нет, TASWM-204), и коммент с вердиктом должен уехать именно туда.
|
|
22631
22890
|
workspace_id: reviewRun.workspace_id
|
|
22632
22891
|
});
|
|
22633
|
-
const wt =
|
|
22892
|
+
const wt = join37(deps.worktreesDir, basename6(repo), `${reviewRun.task_slug}-review-${reviewer.id}`);
|
|
22634
22893
|
try {
|
|
22635
22894
|
await deps.git.prepareDetachedWorktree(repo, branch, wt);
|
|
22636
22895
|
await deps.git.setWorktreeIdentity(wt, reviewer.name);
|
|
@@ -22711,7 +22970,7 @@ async function spawnVerifier(deps, verifiedRun, files) {
|
|
|
22711
22970
|
// штамп цикла: фикс-итерацию проверяет свежий верификатор
|
|
22712
22971
|
workspace_id: verifiedRun.workspace_id
|
|
22713
22972
|
});
|
|
22714
|
-
const wt =
|
|
22973
|
+
const wt = join37(deps.worktreesDir, basename6(repo), `${verifiedRun.task_slug}-verify-${verifier.id}`);
|
|
22715
22974
|
try {
|
|
22716
22975
|
await deps.git.prepareDetachedWorktree(repo, branch, wt);
|
|
22717
22976
|
await deps.git.setWorktreeIdentity(wt, verifier.name);
|
|
@@ -22759,7 +23018,7 @@ async function respawnRun(deps, run, mode, nudge) {
|
|
|
22759
23018
|
]);
|
|
22760
23019
|
const base3 = effectiveBaseBranch(run.base_branch, projectBase);
|
|
22761
23020
|
const runToSpawn = base3 && run.base_branch !== base3 ? deps.db.updateRun(run.id, { base_branch: base3 }) ?? run : run;
|
|
22762
|
-
if (!
|
|
23021
|
+
if (!existsSync22(wt)) {
|
|
22763
23022
|
const branch = runToSpawn.branch || runToSpawn.task_slug;
|
|
22764
23023
|
const source = await addWorktree(repo, wt, branch, {
|
|
22765
23024
|
...base3 ? { base: await remoteBaseRef(repo, base3) } : {},
|
|
@@ -22800,7 +23059,7 @@ function worktreePathPatch(run, wt) {
|
|
|
22800
23059
|
return run.worktree_path === wt ? {} : { worktree_path: wt };
|
|
22801
23060
|
}
|
|
22802
23061
|
async function syncCrashedOnStartup(deps) {
|
|
22803
|
-
const worktreeExists = deps.worktreeExists ??
|
|
23062
|
+
const worktreeExists = deps.worktreeExists ?? existsSync22;
|
|
22804
23063
|
let orphaned = 0;
|
|
22805
23064
|
let merged = 0;
|
|
22806
23065
|
let requeued = 0;
|
|
@@ -22954,10 +23213,10 @@ async function migrateWorktreesAtStartup() {
|
|
|
22954
23213
|
legacyDir: WORKTREES_LEGACY_DIR,
|
|
22955
23214
|
targetDir: WORKTREES_DIR,
|
|
22956
23215
|
envOverride: process.env.SWARM_WORKTREES || "",
|
|
22957
|
-
exists: (d) =>
|
|
23216
|
+
exists: (d) => existsSync22(d),
|
|
22958
23217
|
isNonEmptyDir: (d) => {
|
|
22959
23218
|
try {
|
|
22960
|
-
return
|
|
23219
|
+
return readdirSync15(d).length > 0;
|
|
22961
23220
|
} catch {
|
|
22962
23221
|
return false;
|
|
22963
23222
|
}
|
|
@@ -22969,7 +23228,7 @@ async function migrateWorktreesAtStartup() {
|
|
|
22969
23228
|
});
|
|
22970
23229
|
} catch (e) {
|
|
22971
23230
|
console.error("[migrate] \u043C\u0438\u0433\u0440\u0430\u0446\u0438\u044F worktrees \u0441\u043E\u0440\u0432\u0430\u043B\u0430\u0441\u044C \u2014 \u0444\u043E\u043B\u0431\u044D\u043A:", e);
|
|
22972
|
-
return
|
|
23231
|
+
return existsSync22(WORKTREES_DIR) ? WORKTREES_DIR : WORKTREES_LEGACY_DIR;
|
|
22973
23232
|
}
|
|
22974
23233
|
}
|
|
22975
23234
|
async function reportWorkspaceAccess(tl, db) {
|
|
@@ -23153,7 +23412,8 @@ async function runDaemon(opts) {
|
|
|
23153
23412
|
// настенным временем. Не «демон запущен», а «цикл прокрутился».
|
|
23154
23413
|
tickPulse(tickHealth, Date.now(), tickIntervalMs),
|
|
23155
23414
|
// TASWM-592: установленные агенты машины — справочник для парка машин.
|
|
23156
|
-
cachedInstalledExecutorIds()
|
|
23415
|
+
cachedInstalledExecutorIds(),
|
|
23416
|
+
availableProviders(cachedInstalledExecutorIds())
|
|
23157
23417
|
);
|
|
23158
23418
|
if (reply.maxDrones !== void 0) operatorMaxDrones = reply.maxDrones;
|
|
23159
23419
|
if (reply.commands.length) onHostCommands(reply.commands);
|
|
@@ -23594,6 +23854,7 @@ async function runDaemon(opts) {
|
|
|
23594
23854
|
// TASWM-364: swarmModels — ТОТ ЖЕ снимок, что уехал в launcher: цена токенов считается
|
|
23595
23855
|
// по модели, на которой прогон реально работал. TASWM-592: исполнитель НЕ пинится —
|
|
23596
23856
|
// аккаунтант сам резолвит его по прогону (итог писал харнесс ЭТОГО прогона).
|
|
23857
|
+
providerGap: (run) => providerUnavailableReason(resolveRunModelRef(run, lastSwarmModels).providerId, availableProviders(cachedInstalledExecutorIds())),
|
|
23597
23858
|
accountCost: makeCostAccountant({ runLogsDir: RUN_LOGS_DIR, db, swarmModels: () => lastSwarmModels, modelRefFor: (run) => runModelRefPin.get(run.id) ?? null }),
|
|
23598
23859
|
// TASWM-413: тот же аккаунтант, но поводом служит завершённый ЗАПУСК, а не смерть
|
|
23599
23860
|
// прогона в running — иначе сданный через done() прогон не получает цену никогда.
|
|
@@ -23659,7 +23920,7 @@ async function runDaemon(opts) {
|
|
|
23659
23920
|
isDirty: (p) => worktreeDirty(p),
|
|
23660
23921
|
releaseWorktree: (repo, p) => releaseWorktree(repo || opts.repo, p),
|
|
23661
23922
|
pruneWorktrees: (repo) => pruneWorktrees(repo || opts.repo),
|
|
23662
|
-
worktreeExists:
|
|
23923
|
+
worktreeExists: existsSync22,
|
|
23663
23924
|
liveWorktrees: () => new Set(listDroneProcesses().map((p) => p.worktree)),
|
|
23664
23925
|
narrate: narrator.narrate
|
|
23665
23926
|
});
|
|
@@ -23794,7 +24055,7 @@ async function runDaemon(opts) {
|
|
|
23794
24055
|
mode,
|
|
23795
24056
|
nudge
|
|
23796
24057
|
),
|
|
23797
|
-
worktreeExists: (p) =>
|
|
24058
|
+
worktreeExists: (p) => existsSync22(p),
|
|
23798
24059
|
// TASWM-514: с этого момента считаем попытки спавна — счётчик живёт ровно одну жизнь
|
|
23799
24060
|
// процесса демона и рестарт не переживает (см. preStartAttempts).
|
|
23800
24061
|
startedAt: Date.now(),
|