@taskless-app/swarm 0.6.61 → 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 +432 -182
- package/dist/overmind.js +673 -308
- 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,8 +5023,8 @@ __export(droneChannel_exports, {
|
|
|
4787
5023
|
verifyLocalCliToken: () => verifyLocalCliToken
|
|
4788
5024
|
});
|
|
4789
5025
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
4790
|
-
import { chmodSync as chmodSync2, mkdirSync as
|
|
4791
|
-
import { dirname as
|
|
5026
|
+
import { chmodSync as chmodSync2, mkdirSync as mkdirSync11, readFileSync as readFileSync19, writeFileSync as writeFileSync13 } from "fs";
|
|
5027
|
+
import { dirname as dirname5 } from "path";
|
|
4792
5028
|
import { serve } from "@hono/node-server";
|
|
4793
5029
|
function loadChannelSecret(path) {
|
|
4794
5030
|
try {
|
|
@@ -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 {
|
|
@@ -6471,6 +6707,8 @@ function rowToRun(row) {
|
|
|
6471
6707
|
// базовая ветка PR (TASWM-285); null → дефолтная
|
|
6472
6708
|
workspace_id: row.workspace_id ?? null,
|
|
6473
6709
|
// воркспейс задачи прогона (TASWM-288); null → глобальный пин
|
|
6710
|
+
// TASWM-597: repoless-прогон (офлайн-проект, без worktree/PR). null/0 → код-конвейер.
|
|
6711
|
+
repoless: row.repoless === 1,
|
|
6474
6712
|
created_at: row.created_at,
|
|
6475
6713
|
updated_at: row.updated_at
|
|
6476
6714
|
};
|
|
@@ -6542,6 +6780,7 @@ CREATE TABLE IF NOT EXISTS runs (
|
|
|
6542
6780
|
priority INTEGER NOT NULL DEFAULT 0,
|
|
6543
6781
|
base_branch TEXT,
|
|
6544
6782
|
workspace_id TEXT,
|
|
6783
|
+
repoless INTEGER,
|
|
6545
6784
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
6546
6785
|
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
6547
6786
|
);
|
|
@@ -6639,6 +6878,8 @@ CREATE TABLE IF NOT EXISTS imports (
|
|
|
6639
6878
|
"ALTER TABLE runs ADD COLUMN base_branch TEXT",
|
|
6640
6879
|
// Воркспейс задачи прогона (TASWM-288): им пинятся задачные MCP-вызовы прогона.
|
|
6641
6880
|
"ALTER TABLE runs ADD COLUMN workspace_id TEXT",
|
|
6881
|
+
// TASWM-597: repoless-прогон — задача офлайн-проекта, спавн без worktree/ветки/PR.
|
|
6882
|
+
"ALTER TABLE runs ADD COLUMN repoless INTEGER",
|
|
6642
6883
|
// Чем обошёлся прогон, кроме денег (TASWM-353): токены вход/выход и время работы.
|
|
6643
6884
|
"ALTER TABLE runs ADD COLUMN tokens_in INTEGER NOT NULL DEFAULT 0",
|
|
6644
6885
|
"ALTER TABLE runs ADD COLUMN tokens_out INTEGER NOT NULL DEFAULT 0",
|
|
@@ -6815,6 +7056,7 @@ CREATE TABLE IF NOT EXISTS imports (
|
|
|
6815
7056
|
const arr = v;
|
|
6816
7057
|
return arr && arr.length ? JSON.stringify(arr) : null;
|
|
6817
7058
|
}
|
|
7059
|
+
if (f === "repoless") return v === true ? 1 : v === false ? 0 : null;
|
|
6818
7060
|
if (f === "area" && typeof v === "string") return normalizeZoneLabel(v) || null;
|
|
6819
7061
|
return v;
|
|
6820
7062
|
});
|
|
@@ -7047,7 +7289,7 @@ CREATE TABLE IF NOT EXISTS imports (
|
|
|
7047
7289
|
const repoN = normalizeRepo(repo);
|
|
7048
7290
|
const already = this.db.prepare("SELECT run_count FROM imports WHERE source = ?").get(abs);
|
|
7049
7291
|
if (already) return { imported: false, runs: already.run_count };
|
|
7050
|
-
if (!
|
|
7292
|
+
if (!existsSync17(abs)) throw new Error(`import-db: \u0444\u0430\u0439\u043B\u0430 \u043D\u0435\u0442: ${abs}`);
|
|
7051
7293
|
const src = new this.databaseCtor(abs);
|
|
7052
7294
|
try {
|
|
7053
7295
|
const runs = src.prepare("SELECT * FROM runs ORDER BY id").all();
|
|
@@ -7417,8 +7659,8 @@ var init_droneStore = __esm({
|
|
|
7417
7659
|
|
|
7418
7660
|
// src/overmind.ts
|
|
7419
7661
|
import { homedir as homedir7 } from "os";
|
|
7420
|
-
import { existsSync as
|
|
7421
|
-
import { basename as basename6, dirname 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";
|
|
7422
7664
|
import { fileURLToPath as fileURLToPath3, pathToFileURL } from "url";
|
|
7423
7665
|
import { spawn as spawn4 } from "child_process";
|
|
7424
7666
|
|
|
@@ -7498,7 +7740,7 @@ init_config();
|
|
|
7498
7740
|
init_resources();
|
|
7499
7741
|
init_names2();
|
|
7500
7742
|
init_storm();
|
|
7501
|
-
import { appendFileSync, existsSync as
|
|
7743
|
+
import { appendFileSync, existsSync as existsSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync7 } from "fs";
|
|
7502
7744
|
import { dirname as dirname2 } from "path";
|
|
7503
7745
|
import { randomUUID } from "crypto";
|
|
7504
7746
|
|
|
@@ -7556,12 +7798,12 @@ init_store();
|
|
|
7556
7798
|
init_toolFailure();
|
|
7557
7799
|
|
|
7558
7800
|
// src/logTail.ts
|
|
7559
|
-
import { closeSync, existsSync as
|
|
7560
|
-
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";
|
|
7561
7803
|
|
|
7562
7804
|
// src/runLogDir.ts
|
|
7563
|
-
import { existsSync as
|
|
7564
|
-
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";
|
|
7565
7807
|
var LEGACY_RUN_LOGS_SUBDIR = "legacy";
|
|
7566
7808
|
function runLogDirName(runLogKey) {
|
|
7567
7809
|
const safe2 = runLogKey.replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^[-_]+|[-_]+$/g, "");
|
|
@@ -7569,12 +7811,12 @@ function runLogDirName(runLogKey) {
|
|
|
7569
7811
|
return /^\d+$/.test(safe2) ? `k-${safe2}` : safe2;
|
|
7570
7812
|
}
|
|
7571
7813
|
function runLogDirPath(runLogsDir, runLogKey) {
|
|
7572
|
-
return
|
|
7814
|
+
return join10(runLogsDir, runLogDirName(runLogKey));
|
|
7573
7815
|
}
|
|
7574
7816
|
function findRunLogDir(runLogsDir, keys) {
|
|
7575
7817
|
for (const key of keys) {
|
|
7576
7818
|
const dir = runLogDirPath(runLogsDir, key);
|
|
7577
|
-
if (
|
|
7819
|
+
if (existsSync6(dir)) return dir;
|
|
7578
7820
|
}
|
|
7579
7821
|
return null;
|
|
7580
7822
|
}
|
|
@@ -7584,10 +7826,10 @@ function runLogDirForWrite(runLogsDir, keys) {
|
|
|
7584
7826
|
return findRunLogDir(runLogsDir, keys) ?? runLogDirPath(runLogsDir, canonical);
|
|
7585
7827
|
}
|
|
7586
7828
|
function sweepLegacyRunLogs(runLogsDir) {
|
|
7587
|
-
const legacyDir =
|
|
7829
|
+
const legacyDir = join10(runLogsDir, LEGACY_RUN_LOGS_SUBDIR);
|
|
7588
7830
|
let entries;
|
|
7589
7831
|
try {
|
|
7590
|
-
entries =
|
|
7832
|
+
entries = readdirSync6(runLogsDir);
|
|
7591
7833
|
} catch {
|
|
7592
7834
|
return { moved: 0, failed: 0, legacyDir };
|
|
7593
7835
|
}
|
|
@@ -7595,12 +7837,12 @@ function sweepLegacyRunLogs(runLogsDir) {
|
|
|
7595
7837
|
let failed = 0;
|
|
7596
7838
|
for (const name of entries) {
|
|
7597
7839
|
if (!/^\d+$/.test(name)) continue;
|
|
7598
|
-
const from =
|
|
7840
|
+
const from = join10(runLogsDir, name);
|
|
7599
7841
|
try {
|
|
7600
|
-
if (!
|
|
7601
|
-
|
|
7602
|
-
let to =
|
|
7603
|
-
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}`);
|
|
7604
7846
|
renameSync3(from, to);
|
|
7605
7847
|
moved++;
|
|
7606
7848
|
} catch {
|
|
@@ -7620,7 +7862,7 @@ function fileHeader(name, size, shown) {
|
|
|
7620
7862
|
function readTail(path, opts) {
|
|
7621
7863
|
let size;
|
|
7622
7864
|
try {
|
|
7623
|
-
size =
|
|
7865
|
+
size = statSync6(path).size;
|
|
7624
7866
|
} catch {
|
|
7625
7867
|
return null;
|
|
7626
7868
|
}
|
|
@@ -7655,7 +7897,7 @@ function latestRunLaunch(runLogsDir, runLogKeys) {
|
|
|
7655
7897
|
if (!dir) return null;
|
|
7656
7898
|
let files;
|
|
7657
7899
|
try {
|
|
7658
|
-
files =
|
|
7900
|
+
files = readdirSync7(dir);
|
|
7659
7901
|
} catch {
|
|
7660
7902
|
return null;
|
|
7661
7903
|
}
|
|
@@ -7666,8 +7908,8 @@ function latestRunLaunch(runLogsDir, runLogKeys) {
|
|
|
7666
7908
|
}
|
|
7667
7909
|
if (indexes.size === 0) return null;
|
|
7668
7910
|
const index = Math.max(...indexes);
|
|
7669
|
-
const out = [
|
|
7670
|
-
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;
|
|
7671
7913
|
return { index, total: indexes.size, out, err };
|
|
7672
7914
|
}
|
|
7673
7915
|
function runLogTail(runLogsDir, runLogKeys, opts) {
|
|
@@ -7937,25 +8179,25 @@ var SwarmClient = class _SwarmClient {
|
|
|
7937
8179
|
this.repoFullNames = registry.map((e) => e.repoFullName);
|
|
7938
8180
|
this.repoPathByFullName = new Map(registry.map((e) => [e.repoFullName, normalizeRepo(e.path)]));
|
|
7939
8181
|
this.host = opts.host ?? null;
|
|
7940
|
-
this.repoExists = opts.repoExists ??
|
|
8182
|
+
this.repoExists = opts.repoExists ?? existsSync8;
|
|
7941
8183
|
this.questionSyncMs = opts.questionSyncMs ?? 3e3;
|
|
7942
8184
|
this.executorId = opts.executorId ?? EXECUTOR.id;
|
|
7943
8185
|
this.outboxPath = opts.outboxPath;
|
|
7944
8186
|
this.mapPath = `${opts.outboxPath}.prodmap.json`;
|
|
7945
8187
|
this.stormPath = `${opts.outboxPath}.storm.jsonl`;
|
|
7946
|
-
|
|
8188
|
+
mkdirSync7(dirname2(this.outboxPath), { recursive: true });
|
|
7947
8189
|
this.recover();
|
|
7948
8190
|
}
|
|
7949
8191
|
// ── рестарт: поднять outbox (незаписанные операции) и карту runKey→prodId ─────
|
|
7950
8192
|
recover() {
|
|
7951
|
-
if (
|
|
8193
|
+
if (existsSync8(this.mapPath)) {
|
|
7952
8194
|
try {
|
|
7953
8195
|
const obj = JSON.parse(readFileSync7(this.mapPath, "utf8"));
|
|
7954
8196
|
for (const [k, v] of Object.entries(obj)) this.prodIdByKey.set(k, v);
|
|
7955
8197
|
} catch {
|
|
7956
8198
|
}
|
|
7957
8199
|
}
|
|
7958
|
-
if (
|
|
8200
|
+
if (existsSync8(this.outboxPath)) {
|
|
7959
8201
|
const txt = readFileSync7(this.outboxPath, "utf8");
|
|
7960
8202
|
for (const line of txt.split("\n")) {
|
|
7961
8203
|
const s = line.trim();
|
|
@@ -7976,7 +8218,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
7976
8218
|
// eventsLog ПЕРВЫМИ (до hydrate), в порядке файла (= хронологический); id
|
|
7977
8219
|
// переприсваиваем локально (id событий — только порядок, не корреляция с продом).
|
|
7978
8220
|
replayGlobalEvents() {
|
|
7979
|
-
if (!
|
|
8221
|
+
if (!existsSync8(this.stormPath)) return;
|
|
7980
8222
|
let txt;
|
|
7981
8223
|
try {
|
|
7982
8224
|
txt = readFileSync7(this.stormPath, "utf8");
|
|
@@ -8976,7 +9218,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
8976
9218
|
* транзиентным сбоем ОС, который этот PR должен переживать, а не превращать в мор.
|
|
8977
9219
|
*/
|
|
8978
9220
|
reconcileRuntime(opts) {
|
|
8979
|
-
const wtExists = opts.worktreeExists ??
|
|
9221
|
+
const wtExists = opts.worktreeExists ?? existsSync8;
|
|
8980
9222
|
const pidByWorktree = /* @__PURE__ */ new Map();
|
|
8981
9223
|
try {
|
|
8982
9224
|
for (const p of opts.listProcesses()) if (p.worktree) pidByWorktree.set(p.worktree, p.pid);
|
|
@@ -9596,7 +9838,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
9596
9838
|
*
|
|
9597
9839
|
* Прод недоступен / ответ без поручений → пустые списки (демон работает дальше).
|
|
9598
9840
|
*/
|
|
9599
|
-
async heartbeat(daemonVersion, pause, capacity, resources, storm, worktreesDir, signIn, tick, executors) {
|
|
9841
|
+
async heartbeat(daemonVersion, pause, capacity, resources, storm, worktreesDir, signIn, tick, executors, providers) {
|
|
9600
9842
|
try {
|
|
9601
9843
|
const args = this.repoFullNames.length ? { repoFullNames: this.repoFullNames } : {};
|
|
9602
9844
|
if (daemonVersion) args.daemonVersion = daemonVersion;
|
|
@@ -9627,6 +9869,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
9627
9869
|
args.tick = { seq: Math.max(0, Math.trunc(tick.seq)), ageMs: Math.max(0, Math.trunc(tick.ageMs)), intervalMs: Math.trunc(tick.intervalMs) };
|
|
9628
9870
|
}
|
|
9629
9871
|
if (executors) args.executorsAvailable = executors;
|
|
9872
|
+
if (providers) args.providersAvailable = providers;
|
|
9630
9873
|
const res = await this.call("swarm_heartbeat", args);
|
|
9631
9874
|
if (res?.isError) return EMPTY_HEARTBEAT_REPLY;
|
|
9632
9875
|
this.heartbeatOkAt = this.now();
|
|
@@ -9917,6 +10160,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
9917
10160
|
local.return_reason = toReturnReason(pr.returnReason) ?? local.return_reason;
|
|
9918
10161
|
local.review_phase = pr.reviewPhase ?? local.review_phase;
|
|
9919
10162
|
local.repo = this.resolveRepo(pr.repo ?? null);
|
|
10163
|
+
if (typeof pr.repoless === "boolean") local.repoless = pr.repoless;
|
|
9920
10164
|
local.host_id = pr.hostId ?? null;
|
|
9921
10165
|
local.host_name = pr.hostName ?? null;
|
|
9922
10166
|
local.host_pinned = pr.hostPinned === true;
|
|
@@ -10213,13 +10457,13 @@ var SwarmClient = class _SwarmClient {
|
|
|
10213
10457
|
}
|
|
10214
10458
|
persistPending() {
|
|
10215
10459
|
try {
|
|
10216
|
-
|
|
10460
|
+
writeFileSync7(this.outboxPath, this.pending.map((e) => JSON.stringify(e)).join("\n") + (this.pending.length ? "\n" : ""));
|
|
10217
10461
|
} catch {
|
|
10218
10462
|
}
|
|
10219
10463
|
}
|
|
10220
10464
|
persistMap() {
|
|
10221
10465
|
try {
|
|
10222
|
-
|
|
10466
|
+
writeFileSync7(this.mapPath, JSON.stringify(Object.fromEntries(this.prodIdByKey)));
|
|
10223
10467
|
} catch {
|
|
10224
10468
|
}
|
|
10225
10469
|
}
|
|
@@ -10290,20 +10534,20 @@ function tickPulse(health, now, intervalMs) {
|
|
|
10290
10534
|
}
|
|
10291
10535
|
|
|
10292
10536
|
// src/logRotate.ts
|
|
10293
|
-
import { copyFileSync as
|
|
10537
|
+
import { copyFileSync as copyFileSync4, renameSync as renameSync5, statSync as statSync7, fstatSync, truncateSync, unlinkSync as unlinkSync3, existsSync as existsSync9 } from "fs";
|
|
10294
10538
|
var realIo = {
|
|
10295
10539
|
size: (path) => {
|
|
10296
10540
|
try {
|
|
10297
|
-
return
|
|
10541
|
+
return statSync7(path).size;
|
|
10298
10542
|
} catch {
|
|
10299
10543
|
return null;
|
|
10300
10544
|
}
|
|
10301
10545
|
},
|
|
10302
|
-
copy:
|
|
10546
|
+
copy: copyFileSync4,
|
|
10303
10547
|
rename: renameSync5,
|
|
10304
10548
|
truncate: (path) => truncateSync(path, 0),
|
|
10305
10549
|
unlink: unlinkSync3,
|
|
10306
|
-
exists:
|
|
10550
|
+
exists: existsSync9
|
|
10307
10551
|
};
|
|
10308
10552
|
var realOwnerIo = {
|
|
10309
10553
|
statFd: (fd) => {
|
|
@@ -10316,7 +10560,7 @@ var realOwnerIo = {
|
|
|
10316
10560
|
},
|
|
10317
10561
|
statPath: (path) => {
|
|
10318
10562
|
try {
|
|
10319
|
-
const s =
|
|
10563
|
+
const s = statSync7(path);
|
|
10320
10564
|
return { dev: s.dev, ino: s.ino };
|
|
10321
10565
|
} catch {
|
|
10322
10566
|
return null;
|
|
@@ -10450,13 +10694,13 @@ async function buildRepoRegistry(paths) {
|
|
|
10450
10694
|
}
|
|
10451
10695
|
|
|
10452
10696
|
// src/repoMemory.ts
|
|
10453
|
-
import { readFileSync as readFileSync10, writeFileSync as
|
|
10454
|
-
import { join as
|
|
10697
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync9 } from "fs";
|
|
10698
|
+
import { join as join12 } from "path";
|
|
10455
10699
|
var FILE = "repos.json";
|
|
10456
10700
|
function loadRememberedRepos(home) {
|
|
10457
10701
|
let raw;
|
|
10458
10702
|
try {
|
|
10459
|
-
raw = readFileSync10(
|
|
10703
|
+
raw = readFileSync10(join12(home, FILE), "utf8");
|
|
10460
10704
|
} catch {
|
|
10461
10705
|
return [];
|
|
10462
10706
|
}
|
|
@@ -10471,7 +10715,7 @@ function loadRememberedRepos(home) {
|
|
|
10471
10715
|
function rememberRepos(home, paths, now = () => /* @__PURE__ */ new Date()) {
|
|
10472
10716
|
const clean = paths.filter((p) => p.trim().length > 0);
|
|
10473
10717
|
if (clean.length === 0) return;
|
|
10474
|
-
|
|
10718
|
+
writeFileSync9(join12(home, FILE), `${JSON.stringify({ paths: clean, at: now().toISOString() }, null, 2)}
|
|
10475
10719
|
`);
|
|
10476
10720
|
}
|
|
10477
10721
|
function pickRepoPaths(args) {
|
|
@@ -10486,12 +10730,12 @@ init_src();
|
|
|
10486
10730
|
init_config();
|
|
10487
10731
|
init_linkFailure();
|
|
10488
10732
|
import { homedir as homedir5 } from "os";
|
|
10489
|
-
import { readFileSync as readFileSync12, renameSync as renameSync6, writeFileSync as
|
|
10490
|
-
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";
|
|
10491
10735
|
|
|
10492
10736
|
// src/repoScan.ts
|
|
10493
|
-
import { readdirSync as
|
|
10494
|
-
import { join as
|
|
10737
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync11, statSync as statSync8 } from "fs";
|
|
10738
|
+
import { join as join13 } from "path";
|
|
10495
10739
|
var SKIP = /* @__PURE__ */ new Set([
|
|
10496
10740
|
"node_modules",
|
|
10497
10741
|
"vendor",
|
|
@@ -10521,7 +10765,7 @@ function parseOriginFromGitConfig(text) {
|
|
|
10521
10765
|
}
|
|
10522
10766
|
function originOf(dir) {
|
|
10523
10767
|
try {
|
|
10524
|
-
return parseOriginFromGitConfig(readFileSync11(
|
|
10768
|
+
return parseOriginFromGitConfig(readFileSync11(join13(dir, ".git", "config"), "utf8"));
|
|
10525
10769
|
} catch {
|
|
10526
10770
|
return null;
|
|
10527
10771
|
}
|
|
@@ -10550,15 +10794,15 @@ function walk(dir, depth, maxDepth, found) {
|
|
|
10550
10794
|
}
|
|
10551
10795
|
let entries;
|
|
10552
10796
|
try {
|
|
10553
|
-
entries =
|
|
10797
|
+
entries = readdirSync8(dir);
|
|
10554
10798
|
} catch {
|
|
10555
10799
|
return;
|
|
10556
10800
|
}
|
|
10557
10801
|
for (const name of entries) {
|
|
10558
10802
|
if (name.startsWith(".") || SKIP.has(name)) continue;
|
|
10559
|
-
const child =
|
|
10803
|
+
const child = join13(dir, name);
|
|
10560
10804
|
try {
|
|
10561
|
-
if (!
|
|
10805
|
+
if (!statSync8(child).isDirectory()) continue;
|
|
10562
10806
|
} catch {
|
|
10563
10807
|
continue;
|
|
10564
10808
|
}
|
|
@@ -10578,7 +10822,7 @@ function defaultScanRoots(home, knownPaths = []) {
|
|
|
10578
10822
|
if (parent && parent !== p) add(parent);
|
|
10579
10823
|
}
|
|
10580
10824
|
for (const name of ["projects", "code", "src", "dev", "work", "repos", "git", "Projects", "Code", "Developer", "Documents/GitHub", "go/src"]) {
|
|
10581
|
-
add(
|
|
10825
|
+
add(join13(home, name));
|
|
10582
10826
|
}
|
|
10583
10827
|
return out;
|
|
10584
10828
|
}
|
|
@@ -10592,7 +10836,7 @@ function resolveScanRoots(raw, home = homedir5(), knownPaths = []) {
|
|
|
10592
10836
|
for (const part of v.split(",")) {
|
|
10593
10837
|
const p = part.trim();
|
|
10594
10838
|
if (!p) continue;
|
|
10595
|
-
const abs = p === "~" ? home : p.startsWith("~/") ?
|
|
10839
|
+
const abs = p === "~" ? home : p.startsWith("~/") ? join14(home, p.slice(2)) : isAbsolute(p) ? p : resolve2(home, p);
|
|
10596
10840
|
if (!out.includes(abs)) out.push(abs);
|
|
10597
10841
|
}
|
|
10598
10842
|
return out;
|
|
@@ -10821,7 +11065,7 @@ function loadRepoMapCache(path) {
|
|
|
10821
11065
|
function writeRepoMapCache(path, entries, scannedAt = stamp()) {
|
|
10822
11066
|
try {
|
|
10823
11067
|
const tmp = `${path}.tmp`;
|
|
10824
|
-
|
|
11068
|
+
writeFileSync10(tmp, JSON.stringify({ at: stamp(), scannedAt, entries }, null, 2));
|
|
10825
11069
|
renameSync6(tmp, path);
|
|
10826
11070
|
} catch {
|
|
10827
11071
|
}
|
|
@@ -10829,17 +11073,17 @@ function writeRepoMapCache(path, entries, scannedAt = stamp()) {
|
|
|
10829
11073
|
|
|
10830
11074
|
// src/hostIdentity.ts
|
|
10831
11075
|
import { hostname } from "os";
|
|
10832
|
-
import { existsSync as
|
|
10833
|
-
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";
|
|
10834
11078
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
10835
11079
|
function hostIdentityPath(home) {
|
|
10836
|
-
return
|
|
11080
|
+
return join15(home, "host.json");
|
|
10837
11081
|
}
|
|
10838
11082
|
function loadHostIdentity(deps) {
|
|
10839
|
-
const exists = deps.exists ??
|
|
11083
|
+
const exists = deps.exists ?? existsSync10;
|
|
10840
11084
|
const readFile2 = deps.readFile ?? ((p) => readFileSync13(p, "utf8"));
|
|
10841
11085
|
const writeFile4 = deps.writeFile ?? ((p, data) => {
|
|
10842
|
-
|
|
11086
|
+
writeFileSync11(`${p}.tmp`, data);
|
|
10843
11087
|
renameSync7(`${p}.tmp`, p);
|
|
10844
11088
|
});
|
|
10845
11089
|
const host = deps.hostname ?? hostname;
|
|
@@ -10932,8 +11176,8 @@ function pickResumeCandidate(pausedForRelief) {
|
|
|
10932
11176
|
}
|
|
10933
11177
|
|
|
10934
11178
|
// src/reliefLoop.ts
|
|
10935
|
-
import { existsSync as
|
|
10936
|
-
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";
|
|
10937
11181
|
var numEnv3 = (name, def) => {
|
|
10938
11182
|
const v = Number(process.env[name]);
|
|
10939
11183
|
return Number.isFinite(v) && v > 0 ? v : def;
|
|
@@ -10968,10 +11212,10 @@ function reliefLoopTripped(entry, cfg = DEFAULT_RELIEF_LOOP_CONFIG) {
|
|
|
10968
11212
|
return !!entry && entry.pauses >= cfg.limit;
|
|
10969
11213
|
}
|
|
10970
11214
|
function reliefLoopStatePath(home) {
|
|
10971
|
-
return
|
|
11215
|
+
return join16(home, "relief-loop.json");
|
|
10972
11216
|
}
|
|
10973
11217
|
function loadReliefLoopState(home, now = Date.now(), io = {}, cfg = DEFAULT_RELIEF_LOOP_CONFIG) {
|
|
10974
|
-
const exists = io.exists ??
|
|
11218
|
+
const exists = io.exists ?? existsSync11;
|
|
10975
11219
|
const readFile2 = io.readFile ?? ((p) => readFileSync14(p, "utf8"));
|
|
10976
11220
|
const path = reliefLoopStatePath(home);
|
|
10977
11221
|
if (!exists(path)) return {};
|
|
@@ -10994,7 +11238,7 @@ function loadReliefLoopState(home, now = Date.now(), io = {}, cfg = DEFAULT_RELI
|
|
|
10994
11238
|
function saveReliefLoopState(home, state, io = {}) {
|
|
10995
11239
|
const path = reliefLoopStatePath(home);
|
|
10996
11240
|
const writeFile4 = io.writeFile ?? ((p, data) => {
|
|
10997
|
-
|
|
11241
|
+
writeFileSync12(`${p}.tmp`, data);
|
|
10998
11242
|
renameSync8(`${p}.tmp`, p);
|
|
10999
11243
|
});
|
|
11000
11244
|
writeFile4(path, JSON.stringify(state, null, 2));
|
|
@@ -11156,15 +11400,15 @@ function buildReliefCostCandidates(cost, t, sustainMs, build) {
|
|
|
11156
11400
|
|
|
11157
11401
|
// src/launcher.ts
|
|
11158
11402
|
import { spawn as spawn2 } from "child_process";
|
|
11159
|
-
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";
|
|
11160
11404
|
import { createRequire } from "module";
|
|
11161
11405
|
import { homedir as homedir6 } from "os";
|
|
11162
|
-
import { dirname as dirname3, join as
|
|
11406
|
+
import { dirname as dirname3, join as join18 } from "path";
|
|
11163
11407
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
11164
11408
|
|
|
11165
11409
|
// src/droneHome.ts
|
|
11166
|
-
import { lstatSync, mkdirSync as
|
|
11167
|
-
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";
|
|
11168
11412
|
var DRONE_HOME_DENY_DEFAULT = [".taskless-swarm", ".bash_history", ".zsh_history"];
|
|
11169
11413
|
function droneHomeDeny(env = process.env) {
|
|
11170
11414
|
const extra = (env.SWARM_DRONE_HOME_DENY || "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
@@ -11182,34 +11426,34 @@ function buildDroneHome(opts) {
|
|
|
11182
11426
|
const { realHome, droneHome } = opts;
|
|
11183
11427
|
const deny = opts.deny ?? droneHomeDeny();
|
|
11184
11428
|
const platform = opts.platform ?? process.platform;
|
|
11185
|
-
|
|
11186
|
-
const wanted = new Set(mirroredEntries(
|
|
11429
|
+
mkdirSync8(droneHome, { recursive: true, mode: 448 });
|
|
11430
|
+
const wanted = new Set(mirroredEntries(readdirSync9(realHome), deny, platform));
|
|
11187
11431
|
const rel = relative(realHome, droneHome);
|
|
11188
11432
|
if (rel && !rel.startsWith("..") && !rel.includes(sep)) wanted.delete(rel);
|
|
11189
|
-
for (const existing of
|
|
11433
|
+
for (const existing of readdirSync9(droneHome)) {
|
|
11190
11434
|
if (wanted.has(existing)) continue;
|
|
11191
|
-
const p =
|
|
11435
|
+
const p = join17(droneHome, existing);
|
|
11192
11436
|
try {
|
|
11193
11437
|
if (lstatSync(p).isSymbolicLink()) rmSync(p);
|
|
11194
11438
|
} catch {
|
|
11195
11439
|
}
|
|
11196
11440
|
}
|
|
11197
11441
|
for (const name of wanted) {
|
|
11198
|
-
const link2 =
|
|
11442
|
+
const link2 = join17(droneHome, name);
|
|
11199
11443
|
try {
|
|
11200
11444
|
lstatSync(link2);
|
|
11201
11445
|
continue;
|
|
11202
11446
|
} catch {
|
|
11203
11447
|
}
|
|
11204
|
-
const target =
|
|
11448
|
+
const target = join17(realHome, name);
|
|
11205
11449
|
let isDir;
|
|
11206
11450
|
try {
|
|
11207
|
-
isDir =
|
|
11451
|
+
isDir = statSync9(target).isDirectory();
|
|
11208
11452
|
} catch {
|
|
11209
11453
|
continue;
|
|
11210
11454
|
}
|
|
11211
11455
|
try {
|
|
11212
|
-
|
|
11456
|
+
symlinkSync3(target, link2, isDir ? "junction" : "file");
|
|
11213
11457
|
} catch (e) {
|
|
11214
11458
|
if (e.code !== "EEXIST") throw e;
|
|
11215
11459
|
}
|
|
@@ -11222,7 +11466,7 @@ var REAL_PATH_ENV_PINS = [
|
|
|
11222
11466
|
{ env: "YARN_GLOBAL_FOLDER", segments: [".yarn", "berry"] }
|
|
11223
11467
|
];
|
|
11224
11468
|
function realPathEnvPins(realHome) {
|
|
11225
|
-
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)]));
|
|
11226
11470
|
}
|
|
11227
11471
|
function dronePrivatePaths(realHome, swarmHome) {
|
|
11228
11472
|
return [
|
|
@@ -11305,7 +11549,7 @@ function droneEnv(worktree, base3 = process.env, isolation, droneCap = null) {
|
|
|
11305
11549
|
const env = { ...base3 };
|
|
11306
11550
|
const isolate = base3.SWARM_TURBO_ISOLATE !== "0";
|
|
11307
11551
|
if (isolate && !base3.TURBO_CACHE_DIR) {
|
|
11308
|
-
env.TURBO_CACHE_DIR =
|
|
11552
|
+
env.TURBO_CACHE_DIR = join18(worktree, ".turbo", "cache");
|
|
11309
11553
|
}
|
|
11310
11554
|
Object.assign(env, droneTestEnv(droneCap, base3));
|
|
11311
11555
|
for (const key of DAEMON_STATE_ENV) delete env[key];
|
|
@@ -11336,21 +11580,21 @@ var DAEMON_STATE_ENV = [
|
|
|
11336
11580
|
...PROVIDER_TOKEN_ENV
|
|
11337
11581
|
];
|
|
11338
11582
|
function bundledRoleDir(kind) {
|
|
11339
|
-
return
|
|
11583
|
+
return join18(dirname3(fileURLToPath2(import.meta.url)), "..", "roles", kind);
|
|
11340
11584
|
}
|
|
11341
11585
|
function roleDir(worktree, kind) {
|
|
11342
|
-
return
|
|
11586
|
+
return join18(worktree, ".claude", "roles", kind);
|
|
11343
11587
|
}
|
|
11344
11588
|
function roleDirs(worktree, kind) {
|
|
11345
|
-
return [bundledRoleDir(kind), roleDir(worktree, kind)].filter((dir) =>
|
|
11589
|
+
return [bundledRoleDir(kind), roleDir(worktree, kind)].filter((dir) => existsSync12(dir));
|
|
11346
11590
|
}
|
|
11347
11591
|
function nextRunLogPath(runLogsDir, runLogKeys) {
|
|
11348
11592
|
const dir = runLogDirForWrite(runLogsDir, runLogKeys);
|
|
11349
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)");
|
|
11350
|
-
|
|
11594
|
+
mkdirSync9(dir, { recursive: true });
|
|
11351
11595
|
let files = [];
|
|
11352
11596
|
try {
|
|
11353
|
-
files =
|
|
11597
|
+
files = readdirSync10(dir);
|
|
11354
11598
|
} catch {
|
|
11355
11599
|
}
|
|
11356
11600
|
let next = 0;
|
|
@@ -11358,7 +11602,7 @@ function nextRunLogPath(runLogsDir, runLogKeys) {
|
|
|
11358
11602
|
const m = /^(\d+)\.json/.exec(f);
|
|
11359
11603
|
if (m) next = Math.max(next, Number(m[1]) + 1);
|
|
11360
11604
|
}
|
|
11361
|
-
return
|
|
11605
|
+
return join18(dir, `${next}.json`);
|
|
11362
11606
|
}
|
|
11363
11607
|
function openNextRunLog(runLogsDir, runLogKeys) {
|
|
11364
11608
|
for (let attempt = 0; attempt < 50; attempt++) {
|
|
@@ -11425,6 +11669,10 @@ function makeLauncher(cfg) {
|
|
|
11425
11669
|
SWARM_RUN_KIND: run.kind,
|
|
11426
11670
|
SWARM_RUN_NAME: run.name,
|
|
11427
11671
|
...run.workspace_id ? { SWARM_WORKSPACE_ID: run.workspace_id } : {},
|
|
11672
|
+
// TASWM-598: repoless-прогон той же спавн-фиксацией — гейт done() («сдача отчётом,
|
|
11673
|
+
// не PR») обязан срабатывать и по данным СПАВНА, а не только по строке прогона от
|
|
11674
|
+
// демона (тот же класс граблей, что у SWARM_REVIEWS_RUN_ID в TASWM-375).
|
|
11675
|
+
...run.repoless ? { SWARM_RUN_REPOLESS: "1" } : {},
|
|
11428
11676
|
...run.reviews_run_id != null ? { SWARM_REVIEWS_RUN_ID: String(run.reviews_run_id) } : {},
|
|
11429
11677
|
// TASWM-344: та же роль, что у SWARM_REVIEWS_RUN_ID выше, для верификатора — без неё
|
|
11430
11678
|
// его done() в client-режиме пошёл бы веткой обычной сдачи PR, и вердикт пропал бы.
|
|
@@ -11446,9 +11694,9 @@ function makeLauncher(cfg) {
|
|
|
11446
11694
|
}
|
|
11447
11695
|
const realHome = cfg.droneIsolation?.realHome ?? homedir6();
|
|
11448
11696
|
const home = cfg.droneIsolation ? buildDroneHome({ realHome, droneHome: cfg.droneIsolation.home }) : void 0;
|
|
11449
|
-
if (cfg.droneIsolation && process.env.TASKLESS_TOKEN && !
|
|
11697
|
+
if (cfg.droneIsolation && process.env.TASKLESS_TOKEN && !existsSync12(join18(cfg.droneIsolation.swarmHome, "token"))) {
|
|
11450
11698
|
console.error(
|
|
11451
|
-
`[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.`
|
|
11452
11700
|
);
|
|
11453
11701
|
}
|
|
11454
11702
|
const executor = cfg.executor ?? executorForRun(run, cfg.swarmModels?.() ?? null);
|
|
@@ -11510,8 +11758,8 @@ function makeLauncher(cfg) {
|
|
|
11510
11758
|
init_procCleanup();
|
|
11511
11759
|
|
|
11512
11760
|
// src/cost.ts
|
|
11513
|
-
import { readFileSync as readFileSync15, readdirSync as
|
|
11514
|
-
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";
|
|
11515
11763
|
init_executors();
|
|
11516
11764
|
init_swarmModels();
|
|
11517
11765
|
var UNPROCESSED_LOG_RE = /^\d+\.json$/;
|
|
@@ -11519,7 +11767,7 @@ var SEGMENT_LOG_RE = /^(\d+)\.json(\.done)?$/;
|
|
|
11519
11767
|
var RESCUE_OPEN_WINDOW_MAX_MS = 12 * 60 * 60 * 1e3;
|
|
11520
11768
|
function unprocessedLogFiles(dir) {
|
|
11521
11769
|
try {
|
|
11522
|
-
return
|
|
11770
|
+
return readdirSync11(dir).filter((f) => UNPROCESSED_LOG_RE.test(f));
|
|
11523
11771
|
} catch {
|
|
11524
11772
|
return [];
|
|
11525
11773
|
}
|
|
@@ -11528,7 +11776,7 @@ function segmentStarts(dir) {
|
|
|
11528
11776
|
const starts = /* @__PURE__ */ new Map();
|
|
11529
11777
|
let entries;
|
|
11530
11778
|
try {
|
|
11531
|
-
entries =
|
|
11779
|
+
entries = readdirSync11(dir);
|
|
11532
11780
|
} catch {
|
|
11533
11781
|
return starts;
|
|
11534
11782
|
}
|
|
@@ -11536,7 +11784,7 @@ function segmentStarts(dir) {
|
|
|
11536
11784
|
const m = SEGMENT_LOG_RE.exec(f);
|
|
11537
11785
|
if (!m) continue;
|
|
11538
11786
|
try {
|
|
11539
|
-
const st =
|
|
11787
|
+
const st = statSync10(join19(dir, f));
|
|
11540
11788
|
starts.set(Number(m[1]), st.birthtimeMs > 0 ? st.birthtimeMs : st.ctimeMs);
|
|
11541
11789
|
} catch {
|
|
11542
11790
|
}
|
|
@@ -11589,7 +11837,7 @@ function accountRunCost(deps, run) {
|
|
|
11589
11837
|
let unmeasured = 0;
|
|
11590
11838
|
const processed = [];
|
|
11591
11839
|
for (const f of files) {
|
|
11592
|
-
const full =
|
|
11840
|
+
const full = join19(dir, f);
|
|
11593
11841
|
let raw = null;
|
|
11594
11842
|
try {
|
|
11595
11843
|
raw = readFileSync15(full, "utf8");
|
|
@@ -11646,8 +11894,8 @@ function makeCostSweeper(deps) {
|
|
|
11646
11894
|
}
|
|
11647
11895
|
|
|
11648
11896
|
// src/runOutcome.ts
|
|
11649
|
-
import { readdirSync as
|
|
11650
|
-
import { join as
|
|
11897
|
+
import { readdirSync as readdirSync12, readFileSync as readFileSync16 } from "fs";
|
|
11898
|
+
import { join as join20 } from "path";
|
|
11651
11899
|
init_executors();
|
|
11652
11900
|
function endedItself(outcome) {
|
|
11653
11901
|
return outcome === "graceful" || outcome === "budget" || outcome === "aborted";
|
|
@@ -11661,7 +11909,7 @@ function readLatestResultRaw(runLogsDir, runLogKeys) {
|
|
|
11661
11909
|
if (!dir) return null;
|
|
11662
11910
|
let files;
|
|
11663
11911
|
try {
|
|
11664
|
-
files =
|
|
11912
|
+
files = readdirSync12(dir);
|
|
11665
11913
|
} catch {
|
|
11666
11914
|
return null;
|
|
11667
11915
|
}
|
|
@@ -11674,7 +11922,7 @@ function readLatestResultRaw(runLogsDir, runLogKeys) {
|
|
|
11674
11922
|
}
|
|
11675
11923
|
if (!latest) return null;
|
|
11676
11924
|
try {
|
|
11677
|
-
return readFileSync16(
|
|
11925
|
+
return readFileSync16(join20(dir, latest.name), "utf8");
|
|
11678
11926
|
} catch {
|
|
11679
11927
|
return null;
|
|
11680
11928
|
}
|
|
@@ -11706,9 +11954,11 @@ init_claudeCode();
|
|
|
11706
11954
|
init_swarmModels();
|
|
11707
11955
|
|
|
11708
11956
|
// src/executors/detect.ts
|
|
11957
|
+
init_src();
|
|
11958
|
+
init_swarmModels();
|
|
11709
11959
|
init_executors();
|
|
11710
11960
|
import { accessSync, constants } from "fs";
|
|
11711
|
-
import { delimiter, join as
|
|
11961
|
+
import { delimiter, join as join21 } from "path";
|
|
11712
11962
|
function binRunnable(bin, env) {
|
|
11713
11963
|
if (!bin) return false;
|
|
11714
11964
|
if (bin.includes("/") || bin.includes("\\")) {
|
|
@@ -11724,7 +11974,7 @@ function binRunnable(bin, env) {
|
|
|
11724
11974
|
if (!dir) continue;
|
|
11725
11975
|
for (const ext of exts) {
|
|
11726
11976
|
try {
|
|
11727
|
-
accessSync(
|
|
11977
|
+
accessSync(join21(dir, bin + ext), constants.X_OK);
|
|
11728
11978
|
return true;
|
|
11729
11979
|
} catch {
|
|
11730
11980
|
}
|
|
@@ -11755,26 +12005,36 @@ function cachedInstalledExecutorIds(now = Date.now(), ttlMs = 3e5, env = process
|
|
|
11755
12005
|
}
|
|
11756
12006
|
return cachedIds;
|
|
11757
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
|
+
}
|
|
11758
12018
|
|
|
11759
12019
|
// src/orchestrator.ts
|
|
11760
12020
|
init_src();
|
|
11761
12021
|
init_git();
|
|
11762
12022
|
|
|
11763
12023
|
// src/deps.ts
|
|
11764
|
-
import { existsSync as
|
|
11765
|
-
import { join as
|
|
12024
|
+
import { existsSync as existsSync15, readdirSync as readdirSync14, readFileSync as readFileSync18 } from "fs";
|
|
12025
|
+
import { join as join25 } from "path";
|
|
11766
12026
|
import { execa } from "execa";
|
|
11767
12027
|
|
|
11768
12028
|
// src/prepareLock.ts
|
|
11769
12029
|
import { createHash } from "crypto";
|
|
11770
|
-
import { closeSync as closeSync4, openSync as openSync4, rmSync as rmSync2, statSync as
|
|
11771
|
-
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";
|
|
11772
12032
|
import { tmpdir } from "os";
|
|
11773
12033
|
var WAIT_TIMEOUT_MS = 5 * 6e4;
|
|
11774
12034
|
var POLL_MS = 300;
|
|
11775
12035
|
var STALE_MS = 20 * 6e4;
|
|
11776
12036
|
function machineLockPath(key, dir = tmpdir()) {
|
|
11777
|
-
return
|
|
12037
|
+
return join23(dir, `swarm-prepare-${createHash("sha1").update(key).digest("hex").slice(0, 16)}.lock`);
|
|
11778
12038
|
}
|
|
11779
12039
|
function defaultTryCreate(path, content) {
|
|
11780
12040
|
try {
|
|
@@ -11791,7 +12051,7 @@ function defaultTryCreate(path, content) {
|
|
|
11791
12051
|
}
|
|
11792
12052
|
function defaultAgeMs(path) {
|
|
11793
12053
|
try {
|
|
11794
|
-
return Date.now() -
|
|
12054
|
+
return Date.now() - statSync12(path).mtimeMs;
|
|
11795
12055
|
} catch {
|
|
11796
12056
|
return null;
|
|
11797
12057
|
}
|
|
@@ -11835,8 +12095,8 @@ init_config();
|
|
|
11835
12095
|
init_config();
|
|
11836
12096
|
import { createHash as createHash2 } from "crypto";
|
|
11837
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";
|
|
11838
|
-
import { existsSync as
|
|
11839
|
-
import { join as
|
|
12098
|
+
import { existsSync as existsSync14, readFileSync as readFileSync17 } from "fs";
|
|
12099
|
+
import { join as join24 } from "path";
|
|
11840
12100
|
function fingerprint(parts) {
|
|
11841
12101
|
const h = createHash2("sha256");
|
|
11842
12102
|
for (const p of parts) {
|
|
@@ -11850,8 +12110,8 @@ async function cloneTree(src, dst) {
|
|
|
11850
12110
|
const entries = await readdir(src, { withFileTypes: true });
|
|
11851
12111
|
await Promise.all(
|
|
11852
12112
|
entries.map(async (e) => {
|
|
11853
|
-
const from =
|
|
11854
|
-
const to =
|
|
12113
|
+
const from = join24(src, e.name);
|
|
12114
|
+
const to = join24(dst, e.name);
|
|
11855
12115
|
if (e.isDirectory()) return cloneTree(from, to);
|
|
11856
12116
|
if (e.isSymbolicLink()) {
|
|
11857
12117
|
return symlink(await readlink(from), to).catch(() => cp(from, to, { recursive: true, verbatimSymlinks: true }));
|
|
@@ -11864,11 +12124,11 @@ function cacheRoot(io) {
|
|
|
11864
12124
|
return io.root ?? ENV_CACHE_DIR;
|
|
11865
12125
|
}
|
|
11866
12126
|
function snapshotDir(io, key) {
|
|
11867
|
-
return
|
|
12127
|
+
return join24(cacheRoot(io), key);
|
|
11868
12128
|
}
|
|
11869
12129
|
function readManifest(dir) {
|
|
11870
12130
|
try {
|
|
11871
|
-
const parsed = JSON.parse(readFileSync17(
|
|
12131
|
+
const parsed = JSON.parse(readFileSync17(join24(dir, "manifest.json"), "utf8"));
|
|
11872
12132
|
if (!parsed || typeof parsed !== "object") return null;
|
|
11873
12133
|
const m = parsed;
|
|
11874
12134
|
if (typeof m.key !== "string" || !Array.isArray(m.dirs)) return null;
|
|
@@ -11880,11 +12140,11 @@ function readManifest(dir) {
|
|
|
11880
12140
|
}
|
|
11881
12141
|
}
|
|
11882
12142
|
function hasEnvSnapshot(key, io = {}) {
|
|
11883
|
-
const exists = io.exists ??
|
|
11884
|
-
return exists(
|
|
12143
|
+
const exists = io.exists ?? existsSync14;
|
|
12144
|
+
return exists(join24(snapshotDir(io, key), "manifest.json"));
|
|
11885
12145
|
}
|
|
11886
12146
|
async function restoreEnvSnapshot(worktree, key, io = {}) {
|
|
11887
|
-
const exists = io.exists ??
|
|
12147
|
+
const exists = io.exists ?? existsSync14;
|
|
11888
12148
|
const clone = io.clone ?? cloneTree;
|
|
11889
12149
|
const dir = snapshotDir(io, key);
|
|
11890
12150
|
const manifest = readManifest(dir);
|
|
@@ -11893,13 +12153,13 @@ async function restoreEnvSnapshot(worktree, key, io = {}) {
|
|
|
11893
12153
|
try {
|
|
11894
12154
|
for (let i = 0; i < manifest.dirs.length; i++) {
|
|
11895
12155
|
const rel = manifest.dirs[i] ?? "";
|
|
11896
|
-
const target =
|
|
12156
|
+
const target = join24(worktree, rel);
|
|
11897
12157
|
if (exists(target)) continue;
|
|
11898
|
-
await clone(
|
|
12158
|
+
await clone(join24(dir, "trees", String(i)), target);
|
|
11899
12159
|
made.push(rel);
|
|
11900
12160
|
}
|
|
11901
12161
|
} catch {
|
|
11902
|
-
for (const rel of made) await rm2(
|
|
12162
|
+
for (const rel of made) await rm2(join24(worktree, rel), { recursive: true, force: true }).catch(() => {
|
|
11903
12163
|
});
|
|
11904
12164
|
return null;
|
|
11905
12165
|
}
|
|
@@ -11912,19 +12172,19 @@ async function touch(dir) {
|
|
|
11912
12172
|
});
|
|
11913
12173
|
}
|
|
11914
12174
|
async function saveEnvSnapshot(worktree, key, dirs, io = {}) {
|
|
11915
|
-
const exists = io.exists ??
|
|
12175
|
+
const exists = io.exists ?? existsSync14;
|
|
11916
12176
|
const clone = io.clone ?? cloneTree;
|
|
11917
12177
|
if (hasEnvSnapshot(key, io)) return true;
|
|
11918
|
-
const present = dirs.filter((rel) => exists(
|
|
12178
|
+
const present = dirs.filter((rel) => exists(join24(worktree, rel)));
|
|
11919
12179
|
if (!present.length) return false;
|
|
11920
12180
|
const root = cacheRoot(io);
|
|
11921
|
-
const tmp =
|
|
12181
|
+
const tmp = join24(root, `.tmp-${key}-${process.pid}`);
|
|
11922
12182
|
try {
|
|
11923
12183
|
await rm2(tmp, { recursive: true, force: true });
|
|
11924
|
-
await mkdir2(
|
|
11925
|
-
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)));
|
|
11926
12186
|
const manifest = { key, dirs: present, createdAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
11927
|
-
await writeFile2(
|
|
12187
|
+
await writeFile2(join24(tmp, "manifest.json"), JSON.stringify(manifest, null, 2));
|
|
11928
12188
|
await rename2(tmp, snapshotDir(io, key));
|
|
11929
12189
|
return true;
|
|
11930
12190
|
} catch {
|
|
@@ -11944,13 +12204,13 @@ async function pruneEnvSnapshots(io = {}) {
|
|
|
11944
12204
|
}
|
|
11945
12205
|
const withTime = [];
|
|
11946
12206
|
for (const name of names) {
|
|
11947
|
-
const s = await stat(
|
|
12207
|
+
const s = await stat(join24(root, name)).catch(() => null);
|
|
11948
12208
|
if (s) withTime.push({ name, mtime: s.mtimeMs });
|
|
11949
12209
|
}
|
|
11950
12210
|
withTime.sort((a, b) => b.mtime - a.mtime);
|
|
11951
12211
|
let removed = 0;
|
|
11952
12212
|
for (const { name } of withTime.slice(Math.max(0, keep))) {
|
|
11953
|
-
await rm2(
|
|
12213
|
+
await rm2(join24(root, name), { recursive: true, force: true }).catch(() => {
|
|
11954
12214
|
});
|
|
11955
12215
|
removed++;
|
|
11956
12216
|
}
|
|
@@ -11966,9 +12226,9 @@ async function sweepEnvCacheTemp(io = {}) {
|
|
|
11966
12226
|
}
|
|
11967
12227
|
let removed = 0;
|
|
11968
12228
|
for (const name of names) {
|
|
11969
|
-
const s = await lstat(
|
|
12229
|
+
const s = await lstat(join24(root, name)).catch(() => null);
|
|
11970
12230
|
if (!s || Date.now() - s.mtimeMs < 60 * 6e4) continue;
|
|
11971
|
-
await rm2(
|
|
12231
|
+
await rm2(join24(root, name), { recursive: true, force: true }).catch(() => {
|
|
11972
12232
|
});
|
|
11973
12233
|
removed++;
|
|
11974
12234
|
}
|
|
@@ -12002,14 +12262,14 @@ function safeReadText(p) {
|
|
|
12002
12262
|
}
|
|
12003
12263
|
function safeListDirs(p) {
|
|
12004
12264
|
try {
|
|
12005
|
-
return
|
|
12265
|
+
return readdirSync14(p, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
12006
12266
|
} catch {
|
|
12007
12267
|
return [];
|
|
12008
12268
|
}
|
|
12009
12269
|
}
|
|
12010
12270
|
function safeListFiles(p) {
|
|
12011
12271
|
try {
|
|
12012
|
-
return
|
|
12272
|
+
return readdirSync14(p, { withFileTypes: true }).filter((e) => e.isFile()).map((e) => e.name);
|
|
12013
12273
|
} catch {
|
|
12014
12274
|
return [];
|
|
12015
12275
|
}
|
|
@@ -12035,21 +12295,21 @@ function overridePlan(override) {
|
|
|
12035
12295
|
};
|
|
12036
12296
|
}
|
|
12037
12297
|
function detectPackageManager(worktree, io = {}) {
|
|
12038
|
-
const exists = io.exists ??
|
|
12298
|
+
const exists = io.exists ?? existsSync15;
|
|
12039
12299
|
const readText = io.readText ?? safeReadText;
|
|
12040
|
-
const hasPkgJson = exists(
|
|
12300
|
+
const hasPkgJson = exists(join25(worktree, "package.json"));
|
|
12041
12301
|
if (!hasPkgJson) {
|
|
12042
|
-
if (exists(
|
|
12302
|
+
if (exists(join25(worktree, "deno.json")) || exists(join25(worktree, "deno.jsonc")) || exists(join25(worktree, "deno.lock"))) return "deno";
|
|
12043
12303
|
return null;
|
|
12044
12304
|
}
|
|
12045
|
-
const pkg = readJson(readText,
|
|
12305
|
+
const pkg = readJson(readText, join25(worktree, "package.json"));
|
|
12046
12306
|
const declared = typeof pkg?.packageManager === "string" ? pkg.packageManager.split("@")[0] : void 0;
|
|
12047
12307
|
if (declared === "pnpm" || declared === "bun" || declared === "npm" || declared === "yarn") return declared;
|
|
12048
|
-
if (exists(
|
|
12049
|
-
if (exists(
|
|
12050
|
-
if (exists(
|
|
12051
|
-
if (exists(
|
|
12052
|
-
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";
|
|
12053
12313
|
return "npm";
|
|
12054
12314
|
}
|
|
12055
12315
|
function jsInstallCommand(pm) {
|
|
@@ -12105,7 +12365,7 @@ var ECOSYSTEM_MARKERS = [
|
|
|
12105
12365
|
// конфигурация — дело сборки, не подготовки
|
|
12106
12366
|
];
|
|
12107
12367
|
function detectPlan(worktree, io) {
|
|
12108
|
-
const exists = io.exists ??
|
|
12368
|
+
const exists = io.exists ?? existsSync15;
|
|
12109
12369
|
const listFiles = io.listFiles ?? safeListFiles;
|
|
12110
12370
|
const pm = detectPackageManager(worktree, io);
|
|
12111
12371
|
if (pm) {
|
|
@@ -12113,7 +12373,7 @@ function detectPlan(worktree, io) {
|
|
|
12113
12373
|
// node_modules на месте — установку пропускаем (быстрый путь переиспользованного worktree).
|
|
12114
12374
|
// У deno каталога может не быть вовсе (кэш в DENO_DIR) — тогда `deno install` отработает
|
|
12115
12375
|
// заново, но он дешёвый: тянет из того же общего кэша.
|
|
12116
|
-
{ label: `${pm} install`, run: jsInstallCommand(pm), skipIfExists:
|
|
12376
|
+
{ label: `${pm} install`, run: jsInstallCommand(pm), skipIfExists: join25(worktree, "node_modules"), source: "detect" }
|
|
12117
12377
|
];
|
|
12118
12378
|
for (const target of workspaceBuildTargets(worktree, io)) {
|
|
12119
12379
|
commands.push({ label: `\u0441\u0431\u043E\u0440\u043A\u0430 ${target.name}`, run: jsRunScript(pm, "build"), cwd: target.dir, source: "detect" });
|
|
@@ -12122,12 +12382,12 @@ function detectPlan(worktree, io) {
|
|
|
12122
12382
|
return { source: "detect", ecosystem: `node/${pm}`, commands };
|
|
12123
12383
|
}
|
|
12124
12384
|
for (const marker of ECOSYSTEM_MARKERS) {
|
|
12125
|
-
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));
|
|
12126
12386
|
if (!hit) continue;
|
|
12127
12387
|
let ecosystem = marker.ecosystem;
|
|
12128
12388
|
let command = marker.command;
|
|
12129
12389
|
for (const refine of marker.refine ?? []) {
|
|
12130
|
-
if (!exists(
|
|
12390
|
+
if (!exists(join25(worktree, refine.file))) continue;
|
|
12131
12391
|
ecosystem = refine.ecosystem;
|
|
12132
12392
|
command = refine.command;
|
|
12133
12393
|
break;
|
|
@@ -12184,12 +12444,12 @@ var CI_INSTALL_PATTERNS = [
|
|
|
12184
12444
|
function ciWorkflowPlan(worktree, io) {
|
|
12185
12445
|
const readText = io.readText ?? safeReadText;
|
|
12186
12446
|
const listFiles = io.listFiles ?? safeListFiles;
|
|
12187
|
-
const dir =
|
|
12447
|
+
const dir = join25(worktree, ".github", "workflows");
|
|
12188
12448
|
const files = listFiles(dir).filter((n) => n.endsWith(".yml") || n.endsWith(".yaml"));
|
|
12189
12449
|
const seen = /* @__PURE__ */ new Set();
|
|
12190
12450
|
const commands = [];
|
|
12191
12451
|
for (const name of files.sort()) {
|
|
12192
|
-
const yaml = readText(
|
|
12452
|
+
const yaml = readText(join25(dir, name));
|
|
12193
12453
|
if (yaml === null) continue;
|
|
12194
12454
|
for (const raw of workflowRunLines(yaml)) {
|
|
12195
12455
|
const line = raw.replace(/\s+/g, " ").trim();
|
|
@@ -12204,7 +12464,7 @@ function ciWorkflowPlan(worktree, io) {
|
|
|
12204
12464
|
return commands.length ? { source: "ci-workflow", ecosystem: "ci-\u043A\u043E\u043D\u0444\u0438\u0433", commands } : null;
|
|
12205
12465
|
}
|
|
12206
12466
|
function workspaceGlobs(worktree, readText) {
|
|
12207
|
-
const yaml = readText(
|
|
12467
|
+
const yaml = readText(join25(worktree, "pnpm-workspace.yaml"));
|
|
12208
12468
|
if (yaml !== null) {
|
|
12209
12469
|
const globs = [];
|
|
12210
12470
|
let inPackages = false;
|
|
@@ -12224,7 +12484,7 @@ function workspaceGlobs(worktree, readText) {
|
|
|
12224
12484
|
}
|
|
12225
12485
|
if (globs.length) return globs;
|
|
12226
12486
|
}
|
|
12227
|
-
const pkg = readJson(readText,
|
|
12487
|
+
const pkg = readJson(readText, join25(worktree, "package.json"));
|
|
12228
12488
|
const ws = pkg?.workspaces;
|
|
12229
12489
|
const list = Array.isArray(ws) ? ws : Array.isArray(ws?.packages) ? ws.packages : [];
|
|
12230
12490
|
return list.filter((g) => typeof g === "string");
|
|
@@ -12235,14 +12495,14 @@ function workspaceDirs(worktree, globs, io) {
|
|
|
12235
12495
|
if (glob.startsWith("!")) continue;
|
|
12236
12496
|
const star = glob.indexOf("*");
|
|
12237
12497
|
if (star === -1) {
|
|
12238
|
-
const dir =
|
|
12239
|
-
if (io.exists(
|
|
12498
|
+
const dir = join25(worktree, glob);
|
|
12499
|
+
if (io.exists(join25(dir, "package.json"))) dirs.add(dir);
|
|
12240
12500
|
continue;
|
|
12241
12501
|
}
|
|
12242
|
-
const base3 =
|
|
12502
|
+
const base3 = join25(worktree, glob.slice(0, star).replace(/\/$/, ""));
|
|
12243
12503
|
for (const name of io.listDirs(base3)) {
|
|
12244
|
-
const dir =
|
|
12245
|
-
if (io.exists(
|
|
12504
|
+
const dir = join25(base3, name);
|
|
12505
|
+
if (io.exists(join25(dir, "package.json"))) dirs.add(dir);
|
|
12246
12506
|
}
|
|
12247
12507
|
}
|
|
12248
12508
|
return [...dirs];
|
|
@@ -12263,18 +12523,18 @@ function entryPaths(pkg) {
|
|
|
12263
12523
|
return out;
|
|
12264
12524
|
}
|
|
12265
12525
|
function workspaceBuildTargets(worktree, io = {}) {
|
|
12266
|
-
const exists = io.exists ??
|
|
12526
|
+
const exists = io.exists ?? existsSync15;
|
|
12267
12527
|
const readText = io.readText ?? safeReadText;
|
|
12268
12528
|
const listDirs = io.listDirs ?? safeListDirs;
|
|
12269
12529
|
const globs = workspaceGlobs(worktree, readText);
|
|
12270
12530
|
if (!globs.length) return [];
|
|
12271
12531
|
const pkgs = [];
|
|
12272
12532
|
for (const dir of workspaceDirs(worktree, globs, { exists, listDirs })) {
|
|
12273
|
-
const pkg = readJson(readText,
|
|
12533
|
+
const pkg = readJson(readText, join25(dir, "package.json"));
|
|
12274
12534
|
if (!pkg || typeof pkg.name !== "string") continue;
|
|
12275
12535
|
const scripts = pkg.scripts ?? {};
|
|
12276
12536
|
const entries = entryPaths(pkg);
|
|
12277
|
-
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)));
|
|
12278
12538
|
const deps = Object.keys({ ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} });
|
|
12279
12539
|
pkgs.push({ name: pkg.name, dir, deps, needsBuild });
|
|
12280
12540
|
}
|
|
@@ -12302,7 +12562,7 @@ function devDatabaseUrl(worktree, io = {}) {
|
|
|
12302
12562
|
const fromEnv = (io.env ?? process.env).DATABASE_URL;
|
|
12303
12563
|
if (fromEnv && fromEnv.trim()) return fromEnv.trim();
|
|
12304
12564
|
for (const file of [".env", ".env.example"]) {
|
|
12305
|
-
const raw = readText(
|
|
12565
|
+
const raw = readText(join25(worktree, file));
|
|
12306
12566
|
if (raw === null) continue;
|
|
12307
12567
|
const m = /^\s*(?:export\s+)?DATABASE_URL\s*=\s*(.*)$/m.exec(raw);
|
|
12308
12568
|
const value = (m?.[1] ?? "").trim().replace(/^['"]|['"]$/g, "");
|
|
@@ -12318,11 +12578,11 @@ function isLocalDatabase(url) {
|
|
|
12318
12578
|
}
|
|
12319
12579
|
}
|
|
12320
12580
|
function prismaPackages(worktree, io) {
|
|
12321
|
-
const exists = io.exists ??
|
|
12581
|
+
const exists = io.exists ?? existsSync15;
|
|
12322
12582
|
const readText = io.readText ?? safeReadText;
|
|
12323
12583
|
const listDirs = io.listDirs ?? safeListDirs;
|
|
12324
12584
|
const dirs = [worktree, ...workspaceDirs(worktree, workspaceGlobs(worktree, readText), { exists, listDirs })];
|
|
12325
|
-
return dirs.filter((dir) => exists(
|
|
12585
|
+
return dirs.filter((dir) => exists(join25(dir, "prisma", "schema.prisma")) && listDirs(join25(dir, "prisma", "migrations")).length > 0);
|
|
12326
12586
|
}
|
|
12327
12587
|
function jsExecBin(pm, command) {
|
|
12328
12588
|
switch (pm) {
|
|
@@ -12352,25 +12612,25 @@ function migrateCommands(worktree, pm, io) {
|
|
|
12352
12612
|
var ENV_DEFINING_FILES = ["pnpm-lock.yaml", "package-lock.json", "yarn.lock", "bun.lock", "bun.lockb", "deno.lock", "pnpm-workspace.yaml"];
|
|
12353
12613
|
function envCachePlan(worktree, io = {}) {
|
|
12354
12614
|
if (!ENV_CACHE_ENABLED) return null;
|
|
12355
|
-
const exists = io.exists ??
|
|
12615
|
+
const exists = io.exists ?? existsSync15;
|
|
12356
12616
|
const readText = io.readText ?? safeReadText;
|
|
12357
12617
|
const listDirs = io.listDirs ?? safeListDirs;
|
|
12358
12618
|
const pm = detectPackageManager(worktree, io);
|
|
12359
12619
|
if (!pm) return null;
|
|
12360
12620
|
const parts = [`pm:${pm}`];
|
|
12361
12621
|
for (const name of ENV_DEFINING_FILES) {
|
|
12362
|
-
const raw = readText(
|
|
12622
|
+
const raw = readText(join25(worktree, name));
|
|
12363
12623
|
if (raw !== null) parts.push(`${name}
|
|
12364
12624
|
${raw}`);
|
|
12365
12625
|
}
|
|
12366
12626
|
const pkgDirs = workspaceDirs(worktree, workspaceGlobs(worktree, readText), { exists, listDirs });
|
|
12367
12627
|
const rels = pkgDirs.map((dir) => dir.slice(worktree.length + 1)).sort();
|
|
12368
12628
|
for (const rel of ["", ...rels]) {
|
|
12369
|
-
const raw = readText(
|
|
12629
|
+
const raw = readText(join25(worktree, rel, "package.json"));
|
|
12370
12630
|
if (raw !== null) parts.push(`${rel}/package.json
|
|
12371
12631
|
${raw}`);
|
|
12372
12632
|
}
|
|
12373
|
-
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"))] };
|
|
12374
12634
|
}
|
|
12375
12635
|
function planPrepare(worktree, io = {}) {
|
|
12376
12636
|
const plan = overridePlan(io.override) ?? detectPlan(worktree, io) ?? ciWorkflowPlan(worktree, io);
|
|
@@ -12378,7 +12638,7 @@ function planPrepare(worktree, io = {}) {
|
|
|
12378
12638
|
return { ...plan, commands: plan.commands.slice(0, MAX_PLAN_COMMANDS) };
|
|
12379
12639
|
}
|
|
12380
12640
|
async function ensureWorktreeDeps(worktree, io = {}) {
|
|
12381
|
-
const exists = io.exists ??
|
|
12641
|
+
const exists = io.exists ?? existsSync15;
|
|
12382
12642
|
const exec = io.exec ?? ((cmd) => runCommand(cmd, worktree));
|
|
12383
12643
|
const approve = io.approve ?? (() => true);
|
|
12384
12644
|
const cachePlan = envCachePlan(worktree, io);
|
|
@@ -12395,7 +12655,7 @@ async function ensureWorktreeDeps(worktree, io = {}) {
|
|
|
12395
12655
|
restored: [],
|
|
12396
12656
|
cached: false
|
|
12397
12657
|
};
|
|
12398
|
-
if (cachePlan && !exists(
|
|
12658
|
+
if (cachePlan && !exists(join25(worktree, "node_modules"))) {
|
|
12399
12659
|
report.restored = await restoreEnvSnapshot(worktree, cachePlan.key, cacheIO) ?? [];
|
|
12400
12660
|
}
|
|
12401
12661
|
const plan = planPrepare(worktree, io);
|
|
@@ -12482,6 +12742,11 @@ function depsPromptNotice(report) {
|
|
|
12482
12742
|
|
|
12483
12743
|
// src/orchestrator.ts
|
|
12484
12744
|
init_config();
|
|
12745
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync10, rmSync as rmSync3 } from "fs";
|
|
12746
|
+
import { join as join26, dirname as dirname4 } from "path";
|
|
12747
|
+
function repolessRunDir(worktreesDir, taskSlug) {
|
|
12748
|
+
return join26(dirname4(worktreesDir), "runs", taskSlug);
|
|
12749
|
+
}
|
|
12485
12750
|
var WORKTREE_HELD_STATUSES = /* @__PURE__ */ new Set(["running", "blocked", "review", "paused", "storm_dead"]);
|
|
12486
12751
|
function worktreePathHeldLive(db, path, exceptRunId) {
|
|
12487
12752
|
return db.listRuns().some((r) => r.id !== exceptRunId && r.worktree_path === path && WORKTREE_HELD_STATUSES.has(r.status));
|
|
@@ -12523,6 +12788,24 @@ function healTaskSlug(db, run, task) {
|
|
|
12523
12788
|
return db.updateRun(run.id, { task_slug: slug }) ?? run;
|
|
12524
12789
|
}
|
|
12525
12790
|
async function spawnDrone(deps, run) {
|
|
12791
|
+
if (run.repoless) {
|
|
12792
|
+
const workdir = repolessRunDir(deps.worktreesDir, run.task_slug);
|
|
12793
|
+
if (existsSync16(workdir)) {
|
|
12794
|
+
rmSync3(workdir, { recursive: true, force: true });
|
|
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)`);
|
|
12796
|
+
}
|
|
12797
|
+
mkdirSync10(workdir, { recursive: true });
|
|
12798
|
+
if (run.area && deps.db.runningAreas("").includes(run.area)) throw new AreaBusyError(run.area);
|
|
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)`);
|
|
12800
|
+
const built2 = await deps.buildPrompt(run, workdir);
|
|
12801
|
+
const pid2 = deps.launch({ worktree: workdir, run, prompt: built2 });
|
|
12802
|
+
deps.db.addEvent(run.id, "step", `\u0434\u0440\u043E\u043D \u0437\u0430\u043F\u0443\u0449\u0435\u043D \u0432 ${workdir} (pid ${pid2})`);
|
|
12803
|
+
return deps.db.updateRun(run.id, {
|
|
12804
|
+
status: "running",
|
|
12805
|
+
worktree_path: workdir,
|
|
12806
|
+
pid: pid2
|
|
12807
|
+
});
|
|
12808
|
+
}
|
|
12526
12809
|
const repo = normalizeRepo(run.repo || deps.repo || "");
|
|
12527
12810
|
if (!repo) throw new Error(`\u0443 \u043F\u0440\u043E\u0433\u043E\u043D\u0430 #${run.id} (${run.task_slug}) \u043D\u0435\u0442 repo \u0438 \u043D\u0435\u0442 \u0434\u0435\u0444\u043E\u043B\u0442\u0430 SWARM_REPO`);
|
|
12528
12811
|
const conflict = deps.conflicts ? await deps.conflicts(run, repo) : { kind: "unknown" };
|
|
@@ -12726,7 +13009,7 @@ function parkReasonUnretriable(reason) {
|
|
|
12726
13009
|
// package.json
|
|
12727
13010
|
var package_default = {
|
|
12728
13011
|
name: "@taskless-app/swarm",
|
|
12729
|
-
version: "0.6.
|
|
13012
|
+
version: "0.6.63",
|
|
12730
13013
|
type: "module",
|
|
12731
13014
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
12732
13015
|
keywords: [
|
|
@@ -12777,7 +13060,7 @@ var package_default = {
|
|
|
12777
13060
|
execa: "^10.0.0",
|
|
12778
13061
|
zod: "3.25.76"
|
|
12779
13062
|
},
|
|
12780
|
-
gitHead: "
|
|
13063
|
+
gitHead: "8d438b6288da036308528cff1160a157b4b64abd"
|
|
12781
13064
|
};
|
|
12782
13065
|
|
|
12783
13066
|
// src/version.ts
|
|
@@ -13565,8 +13848,8 @@ import { z } from "zod";
|
|
|
13565
13848
|
init_git();
|
|
13566
13849
|
|
|
13567
13850
|
// src/diff.ts
|
|
13568
|
-
import { statSync as
|
|
13569
|
-
import { join as
|
|
13851
|
+
import { statSync as statSync13 } from "fs";
|
|
13852
|
+
import { join as join31 } from "path";
|
|
13570
13853
|
import { $ as $4 } from "execa";
|
|
13571
13854
|
var MAX_FILES = 200;
|
|
13572
13855
|
var MAX_LINES_PER_FILE = 1500;
|
|
@@ -13709,7 +13992,7 @@ async function resolveBase(wt, baseBranch) {
|
|
|
13709
13992
|
}
|
|
13710
13993
|
function mtime(path) {
|
|
13711
13994
|
try {
|
|
13712
|
-
return
|
|
13995
|
+
return statSync13(path).mtimeMs;
|
|
13713
13996
|
} catch {
|
|
13714
13997
|
return 0;
|
|
13715
13998
|
}
|
|
@@ -13734,7 +14017,7 @@ async function collectRunDiff(worktree, opts = {}) {
|
|
|
13734
14017
|
files.push(pf);
|
|
13735
14018
|
}
|
|
13736
14019
|
}
|
|
13737
|
-
files.sort((a, b) => mtime(
|
|
14020
|
+
files.sort((a, b) => mtime(join31(worktree, b.path)) - mtime(join31(worktree, a.path)));
|
|
13738
14021
|
const truncatedFiles = files.length > MAX_FILES;
|
|
13739
14022
|
if (truncatedFiles) files = files.slice(0, MAX_FILES);
|
|
13740
14023
|
const added = files.reduce((s, f) => s + f.added, 0);
|
|
@@ -14486,6 +14769,45 @@ ${(summary ?? "").trim()}${shots.warning}`,
|
|
|
14486
14769
|
\u26A0\uFE0F \u0412\u0435\u0440\u0434\u0438\u043A\u0442-\u043A\u043E\u043C\u043C\u0435\u043D\u0442 \u0432 \u0437\u0430\u0434\u0430\u0447\u0443 \u041D\u0415 \u0443\u0435\u0445\u0430\u043B (${commentWarning}) \u2014 \u0432\u0435\u0440\u0434\u0438\u043A\u0442 \u0435\u0441\u0442\u044C \u0442\u043E\u043B\u044C\u043A\u043E \u043D\u0430 \u043F\u0440\u043E\u0433\u043E\u043D\u0435. \u041F\u0440\u043E\u0434\u0443\u0431\u043B\u0438\u0440\u0443\u0439 \u0435\u0433\u043E \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u043E\u043C \u0432 PR: \`gh pr comment ${trustedPrUrl} --body "${verdictText} \u2026"\`.` : "";
|
|
14487
14770
|
return { content: [{ type: "text", text: `\u0432\u0435\u0440\u0434\u0438\u043A\u0442 \u0432\u0435\u0440\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u0437\u0430\u043F\u0438\u0441\u0430\u043D (${verdictText})${shotsNote(shots)}${commentNote}` }] };
|
|
14488
14771
|
}
|
|
14772
|
+
if (run?.repoless || opts.repoless) {
|
|
14773
|
+
const report = (summary ?? "").trim();
|
|
14774
|
+
if (!report) {
|
|
14775
|
+
return {
|
|
14776
|
+
content: [
|
|
14777
|
+
{
|
|
14778
|
+
type: "text",
|
|
14779
|
+
text: "done() repoless-\u043F\u0440\u043E\u0433\u043E\u043D\u0430 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 summary \u2014 \u043E\u043D \u0443\u0445\u043E\u0434\u0438\u0442 \u041E\u0422\u0427\u0401\u0422\u041E\u041C \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u043E\u043C \u0432 \u0437\u0430\u0434\u0430\u0447\u0443: \u0447\u0442\u043E \u0441\u0434\u0435\u043B\u0430\u043D\u043E, \u0447\u0435\u043C \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u043E (\u043F\u043E \u043A\u0440\u0438\u0442\u0435\u0440\u0438\u044F\u043C \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438), \u043A\u0430\u043A\u0438\u0435 \u0440\u0435\u0448\u0435\u043D\u0438\u044F \u043F\u0440\u0438\u043D\u044F\u043B \u0438 \u0447\u0442\u043E \u043E\u0441\u0442\u0430\u043B\u043E\u0441\u044C \u0437\u0430 \u0441\u043A\u043E\u0431\u043A\u0430\u043C\u0438. PR \u0443 \u044D\u0442\u043E\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u043D\u0435\u0442 \u2014 \u043E\u0442\u0447\u0451\u0442 \u0438 \u0435\u0441\u0442\u044C \u0441\u0434\u0430\u0447\u0430."
|
|
14780
|
+
}
|
|
14781
|
+
],
|
|
14782
|
+
isError: true
|
|
14783
|
+
};
|
|
14784
|
+
}
|
|
14785
|
+
const shots = await uploadShots();
|
|
14786
|
+
const slug = run && reportSlug(run.task_slug) || opts.expectedTaskSlug;
|
|
14787
|
+
if (slug && opts.taskless) {
|
|
14788
|
+
try {
|
|
14789
|
+
await opts.taskless.addComment(
|
|
14790
|
+
slug,
|
|
14791
|
+
`\u041E\u0442\u0447\u0451\u0442 (\u0437\u0430\u0434\u0430\u0447\u0430 \u0431\u0435\u0437 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F \u2014 \u0440\u0430\u0431\u043E\u0442\u044B \u0432 git \u043D\u0435\u0442):
|
|
14792
|
+
|
|
14793
|
+
${report}${shots.warning}`,
|
|
14794
|
+
{
|
|
14795
|
+
swarmKind: "report",
|
|
14796
|
+
// TASWM-265: имени взять неоткуда при тонкой строке — честная заглушка.
|
|
14797
|
+
swarmDroneName: run?.name ?? "(\u0438\u043C\u044F \u043D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u043E)"
|
|
14798
|
+
},
|
|
14799
|
+
shots.attachments
|
|
14800
|
+
);
|
|
14801
|
+
} catch (e) {
|
|
14802
|
+
await store.addEvent(null, "step", `\u043E\u0442\u0447\u0451\u0442 \u0432 \u0437\u0430\u0434\u0430\u0447\u0443 ${slug} \u043D\u0435 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D: ${e instanceof Error ? e.message : String(e)}`);
|
|
14803
|
+
}
|
|
14804
|
+
} else {
|
|
14805
|
+
await store.addEvent(null, "step", `\u043E\u0442\u0447\u0451\u0442 \u0434\u0440\u043E\u043D\u0430 (Taskless \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D${slug ? "" : ", \u0441\u043B\u0430\u0433 \u043D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043D"}): ${report}`);
|
|
14806
|
+
}
|
|
14807
|
+
await store.updateRun(null, { status: "done" });
|
|
14808
|
+
await store.addEvent(null, "done", "repoless-\u0441\u0434\u0430\u0447\u0430: \u043E\u0442\u0447\u0451\u0442 \u0432 \u0437\u0430\u0434\u0430\u0447\u0435, \u043F\u0440\u0438\u0451\u043C\u043A\u0430 \u0437\u0430 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u043E\u043C (\u0431\u0435\u0437 PR/CI/mergeGate)");
|
|
14809
|
+
return { content: [{ type: "text", text: `\u043F\u0440\u0438\u043D\u044F\u0442\u043E: \u043E\u0442\u0447\u0451\u0442 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D \u0432 \u0437\u0430\u0434\u0430\u0447\u0443${shotsNote(shots)}, \u043F\u0440\u043E\u0433\u043E\u043D \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043D. \u041F\u0440\u0438\u0451\u043C\u043A\u0443 \u0434\u0435\u043B\u0430\u0435\u0442 \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u043F\u043E \u043A\u0440\u0438\u0442\u0435\u0440\u0438\u044F\u043C \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438.` }] };
|
|
14810
|
+
}
|
|
14489
14811
|
if (isGithubPrUrl(pr_url)) {
|
|
14490
14812
|
const report = (summary ?? "").trim();
|
|
14491
14813
|
if (!report) {
|
|
@@ -14717,13 +15039,15 @@ async function runDroneServer(runId) {
|
|
|
14717
15039
|
const expectedKind = toRunKind(process.env.SWARM_RUN_KIND);
|
|
14718
15040
|
const spawnReviewsRunId = Number(process.env.SWARM_REVIEWS_RUN_ID);
|
|
14719
15041
|
const spawnVerifiesRunId = Number(process.env.SWARM_VERIFIES_RUN_ID);
|
|
15042
|
+
const spawnRepoless = process.env.SWARM_RUN_REPOLESS === "1";
|
|
14720
15043
|
const common = {
|
|
14721
15044
|
taskless,
|
|
14722
15045
|
runKind: expectedKind,
|
|
14723
15046
|
prHeadBranch,
|
|
14724
15047
|
...expectedTaskSlug ? { expectedTaskSlug } : {},
|
|
14725
15048
|
...Number.isInteger(spawnReviewsRunId) && spawnReviewsRunId > 0 ? { reviewsRunId: spawnReviewsRunId } : {},
|
|
14726
|
-
...Number.isInteger(spawnVerifiesRunId) && spawnVerifiesRunId > 0 ? { verifiesRunId: spawnVerifiesRunId } : {}
|
|
15049
|
+
...Number.isInteger(spawnVerifiesRunId) && spawnVerifiesRunId > 0 ? { verifiesRunId: spawnVerifiesRunId } : {},
|
|
15050
|
+
...spawnRepoless ? { repoless: true } : {}
|
|
14727
15051
|
};
|
|
14728
15052
|
const channelUrl = process.env.SWARM_DRONE_CHANNEL_URL;
|
|
14729
15053
|
const channelToken = process.env.SWARM_DRONE_CHANNEL_TOKEN;
|
|
@@ -15693,9 +16017,9 @@ function mergeQueueCandidates(runs, repo, repoFallback) {
|
|
|
15693
16017
|
const byPr = /* @__PURE__ */ new Map();
|
|
15694
16018
|
for (const r of runs) {
|
|
15695
16019
|
if (effectiveRepoOf(r.repo, repoFallback) !== repo || !isMergeCandidate(r)) continue;
|
|
15696
|
-
const
|
|
15697
|
-
const seen = byPr.get(
|
|
15698
|
-
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);
|
|
15699
16023
|
}
|
|
15700
16024
|
return [...byPr.values()];
|
|
15701
16025
|
}
|
|
@@ -15708,10 +16032,10 @@ function makeMergeQueueResolver(deps) {
|
|
|
15708
16032
|
};
|
|
15709
16033
|
return async (run) => {
|
|
15710
16034
|
if (!deps.baseSync || !run.pr_url) return null;
|
|
15711
|
-
const
|
|
15712
|
-
if (
|
|
16035
|
+
const num2 = prNumberOf(run.pr_url);
|
|
16036
|
+
if (num2 == null) return null;
|
|
15713
16037
|
const candidates = mergeQueueCandidates(deps.listRuns(), effectiveRepoOf(run.repo, deps.repoFallback), deps.repoFallback);
|
|
15714
|
-
const mine = candidates.find((c) => prNumberOf(c.pr_url) ===
|
|
16038
|
+
const mine = candidates.find((c) => prNumberOf(c.pr_url) === num2);
|
|
15715
16039
|
if (!mine) return null;
|
|
15716
16040
|
const ready = [];
|
|
15717
16041
|
const urlOf = /* @__PURE__ */ new Map();
|
|
@@ -15827,10 +16151,10 @@ function makeMergeIntentResolver(deps) {
|
|
|
15827
16151
|
};
|
|
15828
16152
|
return async (run) => {
|
|
15829
16153
|
if (!deps.baseSync || !run.pr_url || !hasMergeIntent(run)) return null;
|
|
15830
|
-
const
|
|
15831
|
-
if (
|
|
16154
|
+
const num2 = prNumberOf(run.pr_url);
|
|
16155
|
+
if (num2 == null) return null;
|
|
15832
16156
|
const marked = mergeQueueCandidates(deps.listRuns(), effectiveRepoOf(run.repo, deps.repoFallback), deps.repoFallback).filter(hasMergeIntent);
|
|
15833
|
-
const mine = marked.find((c) => prNumberOf(c.pr_url) ===
|
|
16157
|
+
const mine = marked.find((c) => prNumberOf(c.pr_url) === num2);
|
|
15834
16158
|
if (!mine) return null;
|
|
15835
16159
|
const queue = orderMergeQueue(marked.map(entryOf));
|
|
15836
16160
|
const entry = entryOf(mine);
|
|
@@ -15987,22 +16311,22 @@ async function prodClearMergeIntent(runId, deps = {}) {
|
|
|
15987
16311
|
}
|
|
15988
16312
|
|
|
15989
16313
|
// src/envGate.ts
|
|
15990
|
-
import { existsSync as
|
|
15991
|
-
import { join as
|
|
16314
|
+
import { existsSync as existsSync19 } from "fs";
|
|
16315
|
+
import { join as join33 } from "path";
|
|
15992
16316
|
import { createConnection } from "net";
|
|
15993
16317
|
import { execa as execa2 } from "execa";
|
|
15994
16318
|
|
|
15995
16319
|
// src/platform.ts
|
|
15996
|
-
import { existsSync as
|
|
15997
|
-
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";
|
|
15998
16322
|
function resolveCommandPath(name, env = process.env, platform = process.platform) {
|
|
15999
|
-
if (name.includes("/") || name.includes("\\")) return
|
|
16323
|
+
if (name.includes("/") || name.includes("\\")) return existsSync18(name) ? name : null;
|
|
16000
16324
|
const dirs = (env.PATH ?? env.Path ?? "").split(delimiter2).filter(Boolean);
|
|
16001
16325
|
const exts = platform === "win32" ? (env.PATHEXT ?? ".EXE;.CMD;.BAT").split(";").filter(Boolean) : [""];
|
|
16002
16326
|
for (const dir of dirs) {
|
|
16003
16327
|
for (const ext of exts) {
|
|
16004
|
-
const candidate =
|
|
16005
|
-
if (
|
|
16328
|
+
const candidate = join32(dir, name + ext);
|
|
16329
|
+
if (existsSync18(candidate)) return candidate;
|
|
16006
16330
|
}
|
|
16007
16331
|
}
|
|
16008
16332
|
return null;
|
|
@@ -16085,8 +16409,8 @@ var COMPOSE_MARKERS = [
|
|
|
16085
16409
|
"compose.yaml"
|
|
16086
16410
|
];
|
|
16087
16411
|
function detectRequirements(repo, io = {}) {
|
|
16088
|
-
const exists = io.exists ??
|
|
16089
|
-
const marker = COMPOSE_MARKERS.find((f) => exists(
|
|
16412
|
+
const exists = io.exists ?? existsSync19;
|
|
16413
|
+
const marker = COMPOSE_MARKERS.find((f) => exists(join33(repo, f)));
|
|
16090
16414
|
return marker ? [{ kind: "docker", raw: `docker (\u0434\u0435\u0442\u0435\u043A\u0442: ${marker})` }] : [];
|
|
16091
16415
|
}
|
|
16092
16416
|
function resolveRequirements(repo, declared, io = {}) {
|
|
@@ -17841,10 +18165,10 @@ function closeWebServer(server) {
|
|
|
17841
18165
|
|
|
17842
18166
|
// src/hostCommands.ts
|
|
17843
18167
|
init_src();
|
|
17844
|
-
import { readFileSync as readFileSync23, renameSync as renameSync10, writeFileSync as
|
|
17845
|
-
import { join as
|
|
18168
|
+
import { readFileSync as readFileSync23, renameSync as renameSync10, writeFileSync as writeFileSync16 } from "fs";
|
|
18169
|
+
import { join as join34 } from "path";
|
|
17846
18170
|
function hostCommandStatePath(home) {
|
|
17847
|
-
return
|
|
18171
|
+
return join34(home, "host-command.json");
|
|
17848
18172
|
}
|
|
17849
18173
|
function readState(path) {
|
|
17850
18174
|
try {
|
|
@@ -17855,7 +18179,7 @@ function readState(path) {
|
|
|
17855
18179
|
}
|
|
17856
18180
|
function writeState(path, state) {
|
|
17857
18181
|
try {
|
|
17858
|
-
|
|
18182
|
+
writeFileSync16(`${path}.tmp`, JSON.stringify(state));
|
|
17859
18183
|
renameSync10(`${path}.tmp`, path);
|
|
17860
18184
|
} catch {
|
|
17861
18185
|
}
|
|
@@ -18018,8 +18342,8 @@ async function doRestart(cmd, opts, note) {
|
|
|
18018
18342
|
|
|
18019
18343
|
// src/selfUpdate.ts
|
|
18020
18344
|
init_git();
|
|
18021
|
-
import { existsSync as
|
|
18022
|
-
import { join as
|
|
18345
|
+
import { existsSync as existsSync20 } from "fs";
|
|
18346
|
+
import { join as join35 } from "path";
|
|
18023
18347
|
import { $ as $5 } from "execa";
|
|
18024
18348
|
var DAEMON_PACKAGE = "@taskless-app/swarm";
|
|
18025
18349
|
var defaultRun = async (cmd, args, cwd) => {
|
|
@@ -18032,7 +18356,7 @@ function tail(text, max = 400) {
|
|
|
18032
18356
|
}
|
|
18033
18357
|
async function runSelfUpdate(io) {
|
|
18034
18358
|
const run = io.run ?? defaultRun;
|
|
18035
|
-
const exists = io.exists ??
|
|
18359
|
+
const exists = io.exists ?? existsSync20;
|
|
18036
18360
|
const repo = io.repo;
|
|
18037
18361
|
await io.onStep("fetch", "\u0442\u044F\u043D\u0443 \u0441\u0432\u0435\u0436\u0438\u0439 \u043A\u043E\u0434");
|
|
18038
18362
|
const fetched = await run("git", ["-C", repo, "fetch", "--quiet", "origin"], repo);
|
|
@@ -18061,7 +18385,7 @@ async function runSelfUpdate(io) {
|
|
|
18061
18385
|
};
|
|
18062
18386
|
}
|
|
18063
18387
|
await io.onStep("install", "\u0441\u0442\u0430\u0432\u043B\u044E \u0437\u0430\u0432\u0438\u0441\u0438\u043C\u043E\u0441\u0442\u0438");
|
|
18064
|
-
if (!exists(
|
|
18388
|
+
if (!exists(join35(repo, "pnpm-lock.yaml"))) {
|
|
18065
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" };
|
|
18066
18390
|
}
|
|
18067
18391
|
const installed2 = await run("pnpm", ["install", "--frozen-lockfile"], repo);
|
|
@@ -18226,18 +18550,18 @@ async function fetchExternalStorm(url, opts = {}) {
|
|
|
18226
18550
|
}
|
|
18227
18551
|
|
|
18228
18552
|
// src/anomalyState.ts
|
|
18229
|
-
import { existsSync as
|
|
18230
|
-
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";
|
|
18231
18555
|
var KEY_TTL_MS = 7 * 24 * 60 * 6e4;
|
|
18232
18556
|
var MAX_RESOLVED = 200;
|
|
18233
18557
|
function emptyState() {
|
|
18234
18558
|
return { since: {}, lastFiredAt: {}, fires: {}, resolved: [], stopQuiet: null };
|
|
18235
18559
|
}
|
|
18236
18560
|
function anomalyStatePath(home) {
|
|
18237
|
-
return
|
|
18561
|
+
return join36(home, "anomaly-state.json");
|
|
18238
18562
|
}
|
|
18239
18563
|
function loadAnomalyState(home, now = Date.now(), io = {}) {
|
|
18240
|
-
const exists = io.exists ??
|
|
18564
|
+
const exists = io.exists ?? existsSync21;
|
|
18241
18565
|
const readFile2 = io.readFile ?? ((p) => readFileSync24(p, "utf8"));
|
|
18242
18566
|
const path = anomalyStatePath(home);
|
|
18243
18567
|
if (!exists(path)) return emptyState();
|
|
@@ -18268,7 +18592,7 @@ function loadAnomalyState(home, now = Date.now(), io = {}) {
|
|
|
18268
18592
|
function saveAnomalyState(home, state, io = {}) {
|
|
18269
18593
|
const path = anomalyStatePath(home);
|
|
18270
18594
|
const writeFile4 = io.writeFile ?? ((p, data) => {
|
|
18271
|
-
|
|
18595
|
+
writeFileSync17(`${p}.tmp`, data);
|
|
18272
18596
|
renameSync11(`${p}.tmp`, p);
|
|
18273
18597
|
});
|
|
18274
18598
|
writeFile4(path, JSON.stringify(state, null, 2));
|
|
@@ -18795,8 +19119,16 @@ function worktreeFromCmd(args) {
|
|
|
18795
19119
|
const quoted = args.match(/--mcp-config\s+"([^"]+[/\\]\.swarm-mcp\.json)"/);
|
|
18796
19120
|
const bare = quoted ? null : args.match(/--mcp-config\s+(\S+[/\\]\.swarm-mcp\.json)/);
|
|
18797
19121
|
const path = quoted?.[1] ?? bare?.[1];
|
|
18798
|
-
if (
|
|
18799
|
-
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;
|
|
18800
19132
|
}
|
|
18801
19133
|
function listDroneProcesses() {
|
|
18802
19134
|
const rows = [];
|
|
@@ -19418,8 +19750,36 @@ function buildChangesFixPrompt(args) {
|
|
|
19418
19750
|
}
|
|
19419
19751
|
var HERO_CONTINUE_NUDGE = "\u0422\u0435\u0431\u044F \u0440\u0430\u0437\u0431\u0443\u0434\u0438\u043B\u0438, \u0413\u0435\u0440\u043E\u0439: \u0432 \u043E\u0442\u0440\u044F\u0434\u0435 \u0447\u0442\u043E-\u0442\u043E \u043F\u0440\u043E\u0438\u0437\u043E\u0448\u043B\u043E (\u0434\u0440\u043E\u043D \u0437\u0430\u0434\u0430\u043B \u0432\u043E\u043F\u0440\u043E\u0441, \u0441\u0434\u0430\u043B PR \u0438\u043B\u0438 \u0443\u043C\u0435\u0440) \u2014 \u043B\u0438\u0431\u043E \u0442\u0435\u0431\u044F \u043F\u043E\u0437\u0432\u0430\u043B \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440. \u0422\u044B headless, \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0430\u0435\u0448\u044C \u0422\u041E\u0422 \u0416\u0415 \u044D\u043F\u0438\u043A: \u0443\u0441\u0442\u0430\u0432 \u0438 \u0442\u0435\u043B\u043E \u044D\u043F\u0438\u043A\u0430 \u0443\u0436\u0435 \u0432 \u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442\u0435 \u043F\u0440\u043E\u0448\u043B\u043E\u0439 \u0441\u0435\u0441\u0441\u0438\u0438. \u0413\u043B\u044F\u043D\u044C \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435 \u043E\u0442\u0440\u044F\u0434\u0430 (squad_status) \u0438 \u0440\u0430\u0437\u0431\u0435\u0440\u0438\u0441\u044C, \u0447\u0442\u043E \u0438\u0437\u043C\u0435\u043D\u0438\u043B\u043E\u0441\u044C: \u0442\u0435\u0445\u043D\u0438\u0447\u0435\u0441\u043A\u0438\u0435 \u0432\u043E\u043F\u0440\u043E\u0441\u044B \u0434\u0440\u043E\u043D\u043E\u0432 \u0437\u0430\u043A\u0440\u044B\u0432\u0430\u0439 answer_drone; \u043F\u0440\u043E\u0434\u0443\u043A\u0442\u043E\u0432\u043E\u0435/\u0434\u0438\u0437\u0430\u0439\u043D/scope \u2014 \u044D\u0441\u043A\u0430\u043B\u0438\u0440\u0443\u0439 \u0447\u0435\u0440\u0435\u0437 ask. \u041A\u043E\u0434 \u043D\u0435 \u043F\u0438\u0448\u0438, PR \u043D\u0435 \u043C\u0435\u0440\u0436\u0438, done \u041D\u0415 \u0437\u043E\u0432\u0438. \u0420\u0430\u0437\u043E\u0431\u0440\u0430\u043B\u0441\u044F \u0441 \u0440\u044B\u0432\u043A\u043E\u043C \u2014 \u0441\u043D\u043E\u0432\u0430 \u0437\u043E\u0432\u0438 rest(summary) \u0438 \u0437\u0430\u043C\u0440\u0438. \u0412\u043E\u043F\u0440\u043E\u0441\u043E\u0432 \u0432 stdout \u043D\u0435 \u0437\u0430\u0434\u0430\u0432\u0430\u0439 \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u0447\u0435\u0440\u0435\u0437 ask.";
|
|
19420
19752
|
var HEADLESS_BLOCK = "\u26D4 HEADLESS-\u0420\u0415\u0416\u0418\u041C \u2014 \u0416\u0401\u0421\u0422\u041A\u041E. \u0418\u043D\u0442\u0435\u0440\u0430\u043A\u0442\u0438\u0432\u043D\u043E\u0433\u043E \u0447\u0430\u0442\u0430 \u041D\u0415\u0422: \u0442\u0432\u043E\u0439 stdout \u043D\u0438\u043A\u0442\u043E \u043D\u0435 \u0447\u0438\u0442\u0430\u0435\u0442 \u0438 \u043E\u0442\u0432\u0435\u0442\u0438\u0442\u044C \u043D\u0435 \u043C\u043E\u0436\u0435\u0442. \u041D\u0418\u041A\u041E\u0413\u0414\u0410 \u043D\u0435 \u0437\u0430\u0434\u0430\u0432\u0430\u0439 \u0432\u043E\u043F\u0440\u043E\u0441\u043E\u0432 \u0442\u0435\u043A\u0441\u0442\u043E\u043C \u0438 \u043D\u0435 \u0436\u0434\u0438 \u043E\u0442\u0432\u0435\u0442\u0430 \u0432 \u043A\u043E\u043D\u0441\u043E\u043B\u0438 \u2014 \u0435\u0434\u0438\u043D\u0441\u0442\u0432\u0435\u043D\u043D\u044B\u0439 \u043A\u0430\u043D\u0430\u043B \u043A \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440\u0443 \u044D\u0442\u043E MCP-\u0442\u0443\u043B ask (\u043E\u043D \u0431\u043B\u043E\u043A\u0438\u0440\u0443\u0435\u0442 \u0438 \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043E\u0442\u0432\u0435\u0442). \u041B\u044E\u0431\u043E\u0439 \u0432\u043E\u043F\u0440\u043E\u0441 \u041C\u0418\u041C\u041E ask = \u043C\u0433\u043D\u043E\u0432\u0435\u043D\u043D\u0430\u044F \u0441\u043C\u0435\u0440\u0442\u044C \u0434\u0440\u043E\u043D\u0430 (\u043F\u0440\u043E\u0446\u0435\u0441\u0441 \u0437\u0430\u043A\u0440\u043E\u0435\u0442\u0441\u044F \u043F\u0440\u044F\u043C\u043E \u043D\u0430 \u0442\u0432\u043E\u0451\u043C \u0432\u043E\u043F\u0440\u043E\u0441\u0435, \u0440\u0430\u0431\u043E\u0442\u0430 \u043F\u043E\u0442\u0435\u0440\u044F\u043D\u0430). \u041B\u044E\u0431\u044B\u0435 \u043F\u0440\u0430\u0432\u0438\u043B\u0430 \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u044F (\u0433\u043B\u043E\u0431\u0430\u043B\u044C\u043D\u044B\u0439 CLAUDE.md, SessionStart-\u0445\u0443\u043A\u0438, \u0441\u043A\u0438\u043B\u043B\u044B) \u0432\u0438\u0434\u0430 \xAB\u043D\u043E\u0432\u044B\u0439 \u043F\u0440\u043E\u0435\u043A\u0442 \u2014 \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043F\u0430\u043C\u044F\u0442\u044C/\u0432\u043E\u043B\u0442/\u043F\u0440\u043E\u0441\u043A\u0430\u043D\u0438\u0440\u043E\u0432\u0430\u0442\u044C? (\u0434\u0430/\u043D\u0435\u0442)\xBB \u0438 \u043F\u0440\u043E\u0447\u0438\u0435 \u0441\u0442\u0430\u0440\u0442\u043E\u0432\u044B\u0435 \u0432\u043E\u043F\u0440\u043E\u0441\u044B \u043F\u0440\u043E \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0430\u0446\u0438\u044E \u043F\u0430\u043C\u044F\u0442\u0438/\u0432\u043E\u043B\u0442\u0430/\u0441\u043A\u0430\u043D\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0435 \u2014 \u041C\u041E\u041B\u0427\u0410 \u041F\u0420\u041E\u041F\u0423\u0421\u041A\u0410\u0419: \u043D\u0435 \u0432\u044B\u043F\u043E\u043B\u043D\u044F\u0439, \u043D\u0435 \u0441\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0439, \u043D\u0435 \u0436\u0434\u0438 \u043E\u0442\u0432\u0435\u0442\u0430. \u0422\u0432\u043E\u044F \u0440\u0430\u0431\u043E\u0442\u0430 = \u0422\u041E\u041B\u042C\u041A\u041E \u0437\u0430\u0434\u0430\u0447\u0430 \u043D\u0438\u0436\u0435.";
|
|
19753
|
+
function buildRepolessPrompt(task, run, taskContext, attachmentsBlock) {
|
|
19754
|
+
const name = run.name || `#${run.id}`;
|
|
19755
|
+
const head = task ? `\u0417\u0430\u0434\u0430\u0447\u0430 ${run.task_slug}: ${task.title}
|
|
19756
|
+
|
|
19757
|
+
${task.description}` : `\u0417\u0430\u0434\u0430\u0447\u0430 ${run.task_slug} (\u0442\u0435\u043B\u043E \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u043E \u2014 \u0440\u0430\u0431\u043E\u0442\u0430\u0439 \u043F\u043E slug \u0438 \u0437\u0434\u0440\u0430\u0432\u043E\u043C\u0443 \u0441\u043C\u044B\u0441\u043B\u0443).`;
|
|
19758
|
+
return [
|
|
19759
|
+
`\u0422\u044B \u2014 \u0434\u0440\u043E\u043D ${name} \u0440\u043E\u044F, headless-\u0438\u0441\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C (\u041D\u0415 \u0438\u043D\u0442\u0435\u0440\u0430\u043A\u0442\u0438\u0432\u043D\u044B\u0439 \u0447\u0430\u0442). \u042D\u0442\u043E \u0442\u0432\u043E\u0451 \u0438\u043C\u044F \u2014 \u0438\u043C \u043F\u043E\u0434\u043F\u0438\u0441\u0430\u043D\u0430 \u0442\u0432\u043E\u044F \u0440\u0430\u0431\u043E\u0442\u0430 (\u0432 \u043E\u0442\u0447\u0451\u0442\u0435 \u043E \u0441\u0434\u0430\u0447\u0435).`,
|
|
19760
|
+
"",
|
|
19761
|
+
HEADLESS_BLOCK,
|
|
19762
|
+
"",
|
|
19763
|
+
head,
|
|
19764
|
+
...taskContext ? ["", taskContext] : [],
|
|
19765
|
+
...attachmentsBlock ? ["", attachmentsBlock] : [],
|
|
19766
|
+
"",
|
|
19767
|
+
`\u0422\u044B \u2014 REPOLESS-\u0434\u0440\u043E\u043D: \u0443 \u044D\u0442\u043E\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u041D\u0415\u0422 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F \u0438 \u043A\u043E\u0434-\u043A\u043E\u043D\u0432\u0435\u0439\u0435\u0440\u0430. \u0420\u0430\u0431\u043E\u0442\u0430\u0435\u0448\u044C \u0432 \u0441\u043A\u0440\u0430\u0442\u0447-\u043A\u0430\u0442\u0430\u043B\u043E\u0433\u0435 (\u0442\u0432\u043E\u0439 cwd) \u2014 \u044D\u0442\u043E \u0440\u0430\u0431\u043E\u0447\u0430\u044F \u043F\u0430\u043F\u043A\u0430, \u0430 \u043D\u0435 git-worktree: \u041D\u0415 \u043A\u043E\u043C\u043C\u0438\u0442\u044C, \u041D\u0415 \u043F\u0443\u0448\u044C, \u041D\u0415 \u043E\u0442\u043A\u0440\u044B\u0432\u0430\u0439 PR (git \u0437\u0434\u0435\u0441\u044C \u043D\u0435\u0442 \u0432\u043E\u0432\u0441\u0435). \u0410\u0440\u0442\u0435\u0444\u0430\u043A\u0442\u044B \u0440\u0430\u0431\u043E\u0442\u044B (\u0444\u0430\u0439\u043B\u044B, \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A\u0438, \u0442\u0430\u0431\u043B\u0438\u0446\u044B) \u0441\u043E\u0437\u0434\u0430\u0432\u0430\u0439 \u0432 cwd \u2014 \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0443\u0432\u0438\u0434\u0438\u0442 \u0438\u0445 \u043F\u0440\u0438 \u0440\u0430\u0437\u0431\u043E\u0440\u0435 \u0441\u0434\u0430\u0447\u0438.`,
|
|
19768
|
+
"\u0418\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u044B overmind (MCP): report_step(text) \u2014 \u043B\u043E\u0433\u0438\u0440\u0443\u0439 \u0445\u043E\u0434 \u0440\u0430\u0431\u043E\u0442\u044B; read_task() \u2014 \u0441\u0432\u0435\u0436\u0438\u0439 \u0441\u043D\u0430\u043F\u0448\u043E\u0442 \u0437\u0430\u0434\u0430\u0447\u0438 (\u043E\u043F\u0438\u0441\u0430\u043D\u0438\u0435+\u043A\u0440\u0438\u0442\u0435\u0440\u0438\u0438 \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438+\u043A\u043E\u043C\u043C\u0435\u043D\u0442\u044B+\u0434\u043E\u043A\u0438) \u0431\u0435\u0437 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u043E\u0432, \u0435\u0441\u043B\u0438 \u0442\u0440\u0435\u0431\u043E\u0432\u0430\u043D\u0438\u044F \u043C\u043E\u0433\u043B\u0438 \u0434\u043E\u043F\u0438\u0441\u0430\u0442\u044C \u043F\u043E\u0441\u043B\u0435 \u0441\u0442\u0430\u0440\u0442\u0430; ask(question, options?) \u2014 \u0435\u0441\u043B\u0438 \u0443\u043F\u0451\u0440\u0441\u044F \u0432 \u0420\u0415\u0428\u0415\u041D\u0418\u0415, \u0441\u043F\u0440\u043E\u0441\u0438 \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440\u0430 (\u0434\u0430\u0439 2\u20134 \u0432\u0430\u0440\u0438\u0430\u043D\u0442\u0430 \u0432 options, \u0435\u0441\u043B\u0438 \u0440\u0430\u0437\u0432\u0438\u043B\u043A\u0430 \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u043D\u0430\u044F) \u0438 \u0434\u043E\u0436\u0434\u0438\u0441\u044C \u043E\u0442\u0432\u0435\u0442\u0430 (\u041D\u0415 \u0443\u0433\u0430\u0434\u044B\u0432\u0430\u0439); report_acceptance_check(id, state, evidence) \u2014 \u0437\u0430\u043A\u0440\u043E\u0439 \u041A\u0410\u0416\u0414\u042B\u0419 \u043F\u0443\u043D\u043A\u0442 \u043A\u0440\u0438\u0442\u0435\u0440\u0438\u0435\u0432 \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438 \u0437\u0430\u0434\u0430\u0447\u0438 (id \u0438\u0437 \u0431\u043B\u043E\u043A\u0430 \xAB\u041A\u0440\u0438\u0442\u0435\u0440\u0438\u0438 \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438\xBB, state = passed|failed|pending \u043F\u043E \u0444\u0430\u043A\u0442\u0443, evidence \u2014 \u0447\u0442\u043E \u043D\u0430\u0431\u043B\u044E\u0434\u0430\u043B/\u0447\u0435\u043C \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u043B); \u043F\u0440\u043E\u0439\u0434\u0438\u0441\u044C \u043F\u043E \u043D\u0438\u043C \u041F\u0415\u0420\u0415\u0414 done(); return_task(reason, missing, readings, assumed, questions) \u2014 \u0432\u0435\u0440\u043D\u0443\u0442\u044C \u0421\u042B\u0420\u0423\u042E \u0437\u0430\u0434\u0430\u0447\u0443 \u0430\u0432\u0442\u043E\u0440\u0443; note(text) \u2014 \u0437\u0430\u043C\u0435\u0442\u043A\u0430 \xAB\u0437\u0430\u043C\u0435\u0447\u0435\u043D\u043E \u043F\u043E \u043F\u0443\u0442\u0438\xBB \u0411\u0415\u0417 \u0431\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u043A\u0438; report_weight(note) \u2014 \u0440\u0430\u0431\u043E\u0442\u0430 \u0442\u044F\u0436\u0435\u043B\u0435\u0435 \u043E\u0436\u0438\u0434\u0430\u043D\u0438\u0439, \u0441\u043A\u0430\u0436\u0438 \u041F\u041E \u0425\u041E\u0414\u0423.",
|
|
19769
|
+
"\u0421\u042B\u0420\u0423\u042E \u0417\u0410\u0414\u0410\u0427\u0423 \u041D\u0415 \u0412\u042B\u0414\u0423\u041C\u042B\u0412\u0410\u0419 \u2014 \u0412\u0415\u0420\u041D\u0418 \u0410\u0412\u0422\u041E\u0420\u0423 (return_task): \u043D\u0435\u043F\u043E\u043D\u044F\u0442\u043D\u043E, \u0447\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C (unclear_goal), \u043D\u0435\u0447\u0435\u043C \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442 (no_acceptance), \u043F\u043E\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430 \u043F\u0440\u043E\u0442\u0438\u0432\u043E\u0440\u0435\u0447\u0438\u0442 \u0441\u0430\u043C\u0430 \u0441\u0435\u0431\u0435 (contradiction), \u043D\u0435 \u0437\u0430\u043A\u0440\u044B\u0442\u044C \u0437\u0430 \u043E\u0434\u0438\u043D \u043F\u0440\u043E\u0433\u043E\u043D (too_big). \u0422\u043E\u043B\u043A\u043E\u0432\u0430\u043D\u0438\u0439 \u0434\u0432\u0430 \u0438 \u043E\u0431\u0430 \u043E\u0441\u043C\u044B\u0441\u043B\u0435\u043D\u043D\u044B \u2014 \u0432\u044B\u0431\u0435\u0440\u0438 \u043E\u0447\u0435\u0432\u0438\u0434\u043D\u043E\u0435, \u0441\u0434\u0435\u043B\u0430\u0439 \u0438 \u043D\u0430\u0437\u043E\u0432\u0438 \u0440\u0430\u0437\u0432\u0438\u043B\u043A\u0443 \u0432 \u043E\u0442\u0447\u0451\u0442\u0435.",
|
|
19770
|
+
"",
|
|
19771
|
+
"\u041F\u0420\u041E\u0422\u041E\u041A\u041E\u041B \u0421\u0414\u0410\u0427\u0418 (\u0431\u0435\u0437 PR \u2014 \u043E\u0442\u0447\u0451\u0442 \u0438 \u0435\u0441\u0442\u044C \u0441\u0434\u0430\u0447\u0430):",
|
|
19772
|
+
"0. \u041F\u0435\u0440\u0435\u0437\u0432\u043E\u043D\u0438 read_task() \u2014 \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440 \u043C\u043E\u0433 \u0434\u043E\u043F\u0438\u0441\u0430\u0442\u044C \u0442\u0440\u0435\u0431\u043E\u0432\u0430\u043D\u0438\u0435 \u041F\u041E\u0421\u041B\u0415 \u0442\u0432\u043E\u0435\u0433\u043E \u0441\u0442\u0430\u0440\u0442\u0430.",
|
|
19773
|
+
`1. \u041F\u0440\u043E\u0439\u0434\u0438 \u041A\u0410\u0416\u0414\u042B\u0419 \u043F\u0443\u043D\u043A\u0442 \u043A\u0440\u0438\u0442\u0435\u0440\u0438\u0435\u0432 \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438 \u0438 \u0437\u0430\u043A\u0440\u043E\u0439 \u0435\u0433\u043E report_acceptance_check(id, state, evidence) \u2014 evidence \u043E\u0431\u044F\u0437\u0430\u043D \u0431\u044B\u0442\u044C \u043D\u0430\u0431\u043B\u044E\u0434\u0430\u0435\u043C\u044B\u043C (\u0447\u0442\u043E \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u043B, \u0447\u0435\u043C \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u043B), \u0430 \u043D\u0435 \xAB\u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043E\u043A\xBB.`,
|
|
19774
|
+
`2. \u0410\u0440\u0442\u0435\u0444\u0430\u043A\u0442\u044B \u0441\u043B\u043E\u0436\u0438 \u0432 cwd: \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044C \u0438\u043C\u0435\u043D\u043D\u043E \u044D\u0442\u043E\u0442 \u043A\u0430\u0442\u0430\u043B\u043E\u0433.`,
|
|
19775
|
+
`3. \u0412\u044B\u0437\u043E\u0432\u0438 done(pr_url, summary): pr_url \u2014 \u0441\u0441\u044B\u043B\u043A\u0430 \u043D\u0430 \u0437\u0430\u0434\u0430\u0447\u0443${task?.url ? ` (${task.url})` : " \u0438\u0437 read_task()"}, summary \u2014 \u041E\u0422\u0427\u0401\u0422: \u0447\u0442\u043E \u0441\u0434\u0435\u043B\u0430\u043D\u043E, \u0447\u0435\u043C \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u043E \u043F\u043E \u043A\u0430\u0436\u0434\u043E\u043C\u0443 \u043A\u0440\u0438\u0442\u0435\u0440\u0438\u044E, \u043A\u0430\u043A\u0438\u0435 \u0440\u0435\u0448\u0435\u043D\u0438\u044F \u043F\u0440\u0438\u043D\u044F\u043B, \u0447\u0442\u043E \u043E\u0441\u0442\u0430\u043B\u043E\u0441\u044C \u0437\u0430 \u0441\u043A\u043E\u0431\u043A\u0430\u043C\u0438. summary \u0443\u0445\u043E\u0434\u0438\u0442 \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u043E\u043C \u0432 \u0437\u0430\u0434\u0430\u0447\u0443 \u2014 \u0435\u0433\u043E \u0447\u0438\u0442\u0430\u0435\u0442 \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0438 \u043F\u043E \u043D\u0435\u043C\u0443 \u043F\u0440\u0438\u043D\u0438\u043C\u0430\u0435\u0442 \u0440\u0430\u0431\u043E\u0442\u0443. \u0421\u043A\u0440\u0438\u043D\u044B \u0430\u0440\u0442\u0435\u0444\u0430\u043A\u0442\u043E\u0432 (\u0435\u0441\u043B\u0438 \u0443\u043C\u0435\u0441\u0442\u043D\u044B) \u043F\u0435\u0440\u0435\u0434\u0430\u0439 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u043E\u043C screenshots.`,
|
|
19776
|
+
"",
|
|
19777
|
+
"\u{1F4B8} \u0421\u0435\u0441\u0441\u0438\u044F \u043E\u0433\u0440\u0430\u043D\u0438\u0447\u0435\u043D\u0430 \u041F\u041E\u0422\u041E\u041B\u041A\u041E\u041C \u0422\u0420\u0410\u0422: \u0443\u043F\u0440\u0451\u0448\u044C\u0441\u044F \u2014 \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u044F\u0442 \u043F\u043E\u0441\u0440\u0435\u0434\u0438 \u0440\u0430\u0431\u043E\u0442\u044B. \u0427\u0438\u0442\u0430\u0439 \u0442\u043E, \u0447\u0442\u043E \u043D\u0443\u0436\u043D\u043E \u0437\u0430\u0434\u0430\u0447\u0435, \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u043D\u043D\u043E\u0435 \u043D\u0435 \u043F\u0435\u0440\u0435\u0447\u0438\u0442\u044B\u0432\u0430\u0439; \u043F\u0440\u043E\u043C\u0435\u0436\u0443\u0442\u043E\u0447\u043D\u044B\u0439 \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442 \u0441\u043E\u0445\u0440\u0430\u043D\u044F\u0439 \u0444\u0430\u0439\u043B\u0430\u043C\u0438 \u0432 cwd \u043F\u043E \u0445\u043E\u0434\u0443 \u2014 \u0442\u043E\u0433\u0434\u0430 \u043E\u0431\u0440\u044B\u0432 \u043D\u0435 \u043F\u043E\u0442\u0435\u0440\u044F\u0435\u0442 \u0440\u0430\u0431\u043E\u0442\u0443."
|
|
19778
|
+
].join("\n");
|
|
19779
|
+
}
|
|
19421
19780
|
function buildPrompt(task, run, verifyMode = SWARM_VERIFY, taskContext, attachmentsBlock, zoneMemoryBlock) {
|
|
19422
19781
|
const name = run.name || `#${run.id}`;
|
|
19782
|
+
if (run.repoless) return buildRepolessPrompt(task, run, taskContext, attachmentsBlock);
|
|
19423
19783
|
const head = task ? `\u0417\u0430\u0434\u0430\u0447\u0430 ${run.task_slug}: ${task.title}
|
|
19424
19784
|
|
|
19425
19785
|
${task.description}` : `\u0417\u0430\u0434\u0430\u0447\u0430 ${run.task_slug} (\u0442\u0435\u043B\u043E \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u043E \u2014 \u0440\u0430\u0431\u043E\u0442\u0430\u0439 \u043F\u043E slug \u0438 \u0437\u0434\u0440\u0430\u0432\u043E\u043C\u0443 \u0441\u043C\u044B\u0441\u043B\u0443).`;
|
|
@@ -19513,7 +19873,7 @@ ${task.description}` : `\u0417\u0430\u0434\u0430\u0447\u0430 ${run.task_slug} (\
|
|
|
19513
19873
|
}
|
|
19514
19874
|
return parts.join("\n");
|
|
19515
19875
|
}
|
|
19516
|
-
var HERO_CHARTER_PATH =
|
|
19876
|
+
var HERO_CHARTER_PATH = join37(dirname6(THIS_FILE), "..", "docs", "HERO.md");
|
|
19517
19877
|
function buildHeroPrompt(task, run, taskContext, attachmentsBlock) {
|
|
19518
19878
|
const name = run.name || `#${run.id}`;
|
|
19519
19879
|
const charter = readFileSync25(HERO_CHARTER_PATH, "utf8");
|
|
@@ -19573,7 +19933,7 @@ function ciTrustLine(prUrl, verifyMode) {
|
|
|
19573
19933
|
}
|
|
19574
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}`;
|
|
19575
19935
|
}
|
|
19576
|
-
var REVIEW_SKILL_PATH =
|
|
19936
|
+
var REVIEW_SKILL_PATH = join37(bundledRoleDir("drone"), "skills", "taskless-review", "SKILL.md");
|
|
19577
19937
|
function reviewDefectClasses(skillPath = REVIEW_SKILL_PATH) {
|
|
19578
19938
|
const text = readFileSync25(skillPath, "utf8");
|
|
19579
19939
|
const m = /^## Классы дефектов\n([\s\S]*?)(?=^## |(?![\s\S]))/m.exec(text);
|
|
@@ -19839,7 +20199,7 @@ async function wakeRun(deps, runId, opts = {}) {
|
|
|
19839
20199
|
if (run.status === "review" && run.pr_url && !needsFixIteration(run) && !stoppedForHuman) {
|
|
19840
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` };
|
|
19841
20201
|
}
|
|
19842
|
-
const worktreeExists = deps.worktreeExists ??
|
|
20202
|
+
const worktreeExists = deps.worktreeExists ?? existsSync22;
|
|
19843
20203
|
const hasTranscript = deps.hasTranscript ?? executorHasSession;
|
|
19844
20204
|
const wt = run.worktree_path;
|
|
19845
20205
|
const canContinue = !!wt && worktreeExists(wt) && hasTranscript(run);
|
|
@@ -19964,9 +20324,9 @@ function repoHasCi(deps, run) {
|
|
|
19964
20324
|
function repoHasCiWorkflows(worktreePath, repo) {
|
|
19965
20325
|
for (const base3 of [worktreePath, repo]) {
|
|
19966
20326
|
if (!base3) continue;
|
|
19967
|
-
const dir =
|
|
20327
|
+
const dir = join37(base3, ".github", "workflows");
|
|
19968
20328
|
try {
|
|
19969
|
-
if (
|
|
20329
|
+
if (readdirSync15(dir).some((f) => f.endsWith(".yml") || f.endsWith(".yaml"))) return true;
|
|
19970
20330
|
} catch {
|
|
19971
20331
|
}
|
|
19972
20332
|
}
|
|
@@ -20165,7 +20525,7 @@ async function wakeReviewerOnCiReady(deps, run, over) {
|
|
|
20165
20525
|
return true;
|
|
20166
20526
|
}
|
|
20167
20527
|
function worktreeAndTranscriptAlive(deps, run) {
|
|
20168
|
-
const exists = deps.worktreeExists ??
|
|
20528
|
+
const exists = deps.worktreeExists ?? existsSync22;
|
|
20169
20529
|
const transcript = deps.hasTranscript ?? executorHasSession;
|
|
20170
20530
|
const wt = run.worktree_path;
|
|
20171
20531
|
return !!wt && exists(wt) && transcript(run);
|
|
@@ -20265,7 +20625,7 @@ async function wakeAuthorOnChanges(deps, snapshot, now, droneCap) {
|
|
|
20265
20625
|
}
|
|
20266
20626
|
const wt = run.worktree_path;
|
|
20267
20627
|
const wtPath = wt || (deps.worktreesDir ? droneWorktreePath(deps.worktreesDir, normalizeRepo(run.repo || deps.repoFallback || ""), run.task_slug) : null);
|
|
20268
|
-
const worktreeReady = !!wtPath && (deps.worktreeExists ??
|
|
20628
|
+
const worktreeReady = !!wtPath && (deps.worktreeExists ?? existsSync22)(wtPath);
|
|
20269
20629
|
if (!worktreeReady && !await freshChangesWakeAllowed(deps, run, prUrl, now)) return false;
|
|
20270
20630
|
try {
|
|
20271
20631
|
await deps.respawn(run, "fix");
|
|
@@ -20348,7 +20708,7 @@ async function zoneConflictFor(db, models, activeFiles, run, repo, repoFallback)
|
|
|
20348
20708
|
activeFiles.prune(holders.map((r) => r.id));
|
|
20349
20709
|
const fileExists = (p) => {
|
|
20350
20710
|
try {
|
|
20351
|
-
return
|
|
20711
|
+
return statSync14(join37(repo, p), { throwIfNoEntry: false })?.isFile() ?? false;
|
|
20352
20712
|
} catch {
|
|
20353
20713
|
return false;
|
|
20354
20714
|
}
|
|
@@ -20584,6 +20944,8 @@ async function trySpawnQueuedRun(deps, run) {
|
|
|
20584
20944
|
if (!await projectQuotaGateAllows(deps, run)) return "skipped";
|
|
20585
20945
|
const prodOverride = await prodOverrideReason(deps, run, ["queued"]);
|
|
20586
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);
|
|
20587
20949
|
if (deps.db.takeRun && !await deps.db.takeRun(run.id)) {
|
|
20588
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)");
|
|
20589
20951
|
}
|
|
@@ -20740,7 +21102,7 @@ async function liftReturners(deps, returners, now, droneCap) {
|
|
|
20740
21102
|
deps.returners?.delete(run.id);
|
|
20741
21103
|
continue;
|
|
20742
21104
|
}
|
|
20743
|
-
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);
|
|
20744
21106
|
}
|
|
20745
21107
|
if (lifted) deps.returners?.delete(run.id);
|
|
20746
21108
|
}
|
|
@@ -20759,7 +21121,7 @@ async function resumeWatchdogParked(deps, droneCap) {
|
|
|
20759
21121
|
}
|
|
20760
21122
|
if (!candidate) return;
|
|
20761
21123
|
if (candidate.pid != null && deps.isAlive(candidate.pid)) return;
|
|
20762
|
-
const worktreeExists = deps.worktreeExists ??
|
|
21124
|
+
const worktreeExists = deps.worktreeExists ?? existsSync22;
|
|
20763
21125
|
const hasTranscript = deps.hasTranscript ?? executorHasSession;
|
|
20764
21126
|
const wt = candidate.worktree_path;
|
|
20765
21127
|
const canContinue = !!wt && worktreeExists(wt) && hasTranscript(candidate);
|
|
@@ -21546,7 +21908,7 @@ function buildEscalationCandidates(db) {
|
|
|
21546
21908
|
}
|
|
21547
21909
|
async function tickOnce(deps) {
|
|
21548
21910
|
const now = deps.now ? deps.now() : Date.now();
|
|
21549
|
-
const worktreeExists = deps.worktreeExists ??
|
|
21911
|
+
const worktreeExists = deps.worktreeExists ?? existsSync22;
|
|
21550
21912
|
const hasTranscript = deps.hasTranscript ?? executorHasSession;
|
|
21551
21913
|
deps.sampleHost?.();
|
|
21552
21914
|
if (deps.rehydrate) {
|
|
@@ -22447,7 +22809,7 @@ async function resolveConflict(deps, reviewRun) {
|
|
|
22447
22809
|
model: reviewRun.model,
|
|
22448
22810
|
review_model: reviewRun.review_model
|
|
22449
22811
|
});
|
|
22450
|
-
const wt =
|
|
22812
|
+
const wt = join37(deps.worktreesDir, basename6(repo), `${reviewRun.task_slug}-resolve-${resolver.id}`);
|
|
22451
22813
|
try {
|
|
22452
22814
|
await deps.git.prepareDetachedWorktree(repo, branch, wt);
|
|
22453
22815
|
await deps.git.setWorktreeIdentity(wt, resolver.name);
|
|
@@ -22527,7 +22889,7 @@ async function spawnReviewer(deps, reviewRun, files) {
|
|
|
22527
22889
|
// (своей у ревьюера нет, TASWM-204), и коммент с вердиктом должен уехать именно туда.
|
|
22528
22890
|
workspace_id: reviewRun.workspace_id
|
|
22529
22891
|
});
|
|
22530
|
-
const wt =
|
|
22892
|
+
const wt = join37(deps.worktreesDir, basename6(repo), `${reviewRun.task_slug}-review-${reviewer.id}`);
|
|
22531
22893
|
try {
|
|
22532
22894
|
await deps.git.prepareDetachedWorktree(repo, branch, wt);
|
|
22533
22895
|
await deps.git.setWorktreeIdentity(wt, reviewer.name);
|
|
@@ -22608,7 +22970,7 @@ async function spawnVerifier(deps, verifiedRun, files) {
|
|
|
22608
22970
|
// штамп цикла: фикс-итерацию проверяет свежий верификатор
|
|
22609
22971
|
workspace_id: verifiedRun.workspace_id
|
|
22610
22972
|
});
|
|
22611
|
-
const wt =
|
|
22973
|
+
const wt = join37(deps.worktreesDir, basename6(repo), `${verifiedRun.task_slug}-verify-${verifier.id}`);
|
|
22612
22974
|
try {
|
|
22613
22975
|
await deps.git.prepareDetachedWorktree(repo, branch, wt);
|
|
22614
22976
|
await deps.git.setWorktreeIdentity(wt, verifier.name);
|
|
@@ -22656,7 +23018,7 @@ async function respawnRun(deps, run, mode, nudge) {
|
|
|
22656
23018
|
]);
|
|
22657
23019
|
const base3 = effectiveBaseBranch(run.base_branch, projectBase);
|
|
22658
23020
|
const runToSpawn = base3 && run.base_branch !== base3 ? deps.db.updateRun(run.id, { base_branch: base3 }) ?? run : run;
|
|
22659
|
-
if (!
|
|
23021
|
+
if (!existsSync22(wt)) {
|
|
22660
23022
|
const branch = runToSpawn.branch || runToSpawn.task_slug;
|
|
22661
23023
|
const source = await addWorktree(repo, wt, branch, {
|
|
22662
23024
|
...base3 ? { base: await remoteBaseRef(repo, base3) } : {},
|
|
@@ -22697,7 +23059,7 @@ function worktreePathPatch(run, wt) {
|
|
|
22697
23059
|
return run.worktree_path === wt ? {} : { worktree_path: wt };
|
|
22698
23060
|
}
|
|
22699
23061
|
async function syncCrashedOnStartup(deps) {
|
|
22700
|
-
const worktreeExists = deps.worktreeExists ??
|
|
23062
|
+
const worktreeExists = deps.worktreeExists ?? existsSync22;
|
|
22701
23063
|
let orphaned = 0;
|
|
22702
23064
|
let merged = 0;
|
|
22703
23065
|
let requeued = 0;
|
|
@@ -22851,10 +23213,10 @@ async function migrateWorktreesAtStartup() {
|
|
|
22851
23213
|
legacyDir: WORKTREES_LEGACY_DIR,
|
|
22852
23214
|
targetDir: WORKTREES_DIR,
|
|
22853
23215
|
envOverride: process.env.SWARM_WORKTREES || "",
|
|
22854
|
-
exists: (d) =>
|
|
23216
|
+
exists: (d) => existsSync22(d),
|
|
22855
23217
|
isNonEmptyDir: (d) => {
|
|
22856
23218
|
try {
|
|
22857
|
-
return
|
|
23219
|
+
return readdirSync15(d).length > 0;
|
|
22858
23220
|
} catch {
|
|
22859
23221
|
return false;
|
|
22860
23222
|
}
|
|
@@ -22866,7 +23228,7 @@ async function migrateWorktreesAtStartup() {
|
|
|
22866
23228
|
});
|
|
22867
23229
|
} catch (e) {
|
|
22868
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);
|
|
22869
|
-
return
|
|
23231
|
+
return existsSync22(WORKTREES_DIR) ? WORKTREES_DIR : WORKTREES_LEGACY_DIR;
|
|
22870
23232
|
}
|
|
22871
23233
|
}
|
|
22872
23234
|
async function reportWorkspaceAccess(tl, db) {
|
|
@@ -23050,7 +23412,8 @@ async function runDaemon(opts) {
|
|
|
23050
23412
|
// настенным временем. Не «демон запущен», а «цикл прокрутился».
|
|
23051
23413
|
tickPulse(tickHealth, Date.now(), tickIntervalMs),
|
|
23052
23414
|
// TASWM-592: установленные агенты машины — справочник для парка машин.
|
|
23053
|
-
cachedInstalledExecutorIds()
|
|
23415
|
+
cachedInstalledExecutorIds(),
|
|
23416
|
+
availableProviders(cachedInstalledExecutorIds())
|
|
23054
23417
|
);
|
|
23055
23418
|
if (reply.maxDrones !== void 0) operatorMaxDrones = reply.maxDrones;
|
|
23056
23419
|
if (reply.commands.length) onHostCommands(reply.commands);
|
|
@@ -23491,6 +23854,7 @@ async function runDaemon(opts) {
|
|
|
23491
23854
|
// TASWM-364: swarmModels — ТОТ ЖЕ снимок, что уехал в launcher: цена токенов считается
|
|
23492
23855
|
// по модели, на которой прогон реально работал. TASWM-592: исполнитель НЕ пинится —
|
|
23493
23856
|
// аккаунтант сам резолвит его по прогону (итог писал харнесс ЭТОГО прогона).
|
|
23857
|
+
providerGap: (run) => providerUnavailableReason(resolveRunModelRef(run, lastSwarmModels).providerId, availableProviders(cachedInstalledExecutorIds())),
|
|
23494
23858
|
accountCost: makeCostAccountant({ runLogsDir: RUN_LOGS_DIR, db, swarmModels: () => lastSwarmModels, modelRefFor: (run) => runModelRefPin.get(run.id) ?? null }),
|
|
23495
23859
|
// TASWM-413: тот же аккаунтант, но поводом служит завершённый ЗАПУСК, а не смерть
|
|
23496
23860
|
// прогона в running — иначе сданный через done() прогон не получает цену никогда.
|
|
@@ -23556,7 +23920,7 @@ async function runDaemon(opts) {
|
|
|
23556
23920
|
isDirty: (p) => worktreeDirty(p),
|
|
23557
23921
|
releaseWorktree: (repo, p) => releaseWorktree(repo || opts.repo, p),
|
|
23558
23922
|
pruneWorktrees: (repo) => pruneWorktrees(repo || opts.repo),
|
|
23559
|
-
worktreeExists:
|
|
23923
|
+
worktreeExists: existsSync22,
|
|
23560
23924
|
liveWorktrees: () => new Set(listDroneProcesses().map((p) => p.worktree)),
|
|
23561
23925
|
narrate: narrator.narrate
|
|
23562
23926
|
});
|
|
@@ -23691,7 +24055,7 @@ async function runDaemon(opts) {
|
|
|
23691
24055
|
mode,
|
|
23692
24056
|
nudge
|
|
23693
24057
|
),
|
|
23694
|
-
worktreeExists: (p) =>
|
|
24058
|
+
worktreeExists: (p) => existsSync22(p),
|
|
23695
24059
|
// TASWM-514: с этого момента считаем попытки спавна — счётчик живёт ровно одну жизнь
|
|
23696
24060
|
// процесса демона и рестарт не переживает (см. preStartAttempts).
|
|
23697
24061
|
startedAt: Date.now(),
|
|
@@ -23902,7 +24266,7 @@ async function runDaemon(opts) {
|
|
|
23902
24266
|
onStep
|
|
23903
24267
|
});
|
|
23904
24268
|
}
|
|
23905
|
-
const repo = await repoRoot(
|
|
24269
|
+
const repo = await repoRoot(dirname6(THIS_FILE)).catch(() => null);
|
|
23906
24270
|
if (!repo) {
|
|
23907
24271
|
return { ok: false, step: "fetch", message: "\u0431\u0435\u0433\u0443 \u0438\u0437 \u0438\u0441\u0445\u043E\u0434\u043D\u0438\u043A\u043E\u0432, \u043D\u043E git-\u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F \u043D\u0430\u0434 \u043D\u0438\u043C\u0438 \u043D\u0435\u0442 \u2014 \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E" };
|
|
23908
24272
|
}
|
|
@@ -24215,6 +24579,7 @@ export {
|
|
|
24215
24579
|
buildCiWakeNudge,
|
|
24216
24580
|
buildHeroPrompt,
|
|
24217
24581
|
buildPrompt,
|
|
24582
|
+
buildRepolessPrompt,
|
|
24218
24583
|
buildResolverPrompt,
|
|
24219
24584
|
buildReviewChecklist,
|
|
24220
24585
|
buildReviewerPrompt,
|