@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.
Files changed (3) hide show
  1. package/dist/cli.js +432 -182
  2. package/dist/overmind.js +673 -308
  3. 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 num = prNumberOf(ref);
596
- if (num == null) return null;
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) === num);
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 num = (x) => typeof x === "number" && Number.isFinite(x) ? x : null;
1187
- const memFreeGb = num(v.memFreeGb);
1188
- const memTotalGb = num(v.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 = num(v.cpuBusyPct);
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: num(v.diskFreeGb),
1197
- diskTotalGb: num(v.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 num = (v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? v : 0;
2348
+ const num2 = (v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? v : 0;
2334
2349
  const sum = (u) => ({
2335
- tokensIn: num(u.input_tokens) + num(u.cache_creation_input_tokens) + num(u.cache_read_input_tokens),
2336
- tokensOut: num(u.output_tokens)
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: num(result.duration_ms) };
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 num = (v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? v : 0;
2439
- tokensIn += num(usage.input_tokens) + num(usage.cache_creation_input_tokens) + num(usage.cache_read_input_tokens);
2440
- tokensOut += num(usage.output_tokens);
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
- return join6(swarmHome, "executor-state", "codex", worktree.replace(/[/.]/g, "-"));
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 configured = parseModelRef(
2854
- pick2(run.model) ?? forKind(run.kind, swarm, pick2) ?? pick2(env.SWARM_DRONE_MODEL)
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 join7, resolve } from "path";
3017
- import { readFileSync as readFileSync4, realpathSync, renameSync as renameSync2, writeFileSync as writeFileSync4 } from "fs";
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 join7(droneWorktreeRoot(worktreesDir, repo), slug);
3267
+ return join8(droneWorktreeRoot(worktreesDir, repo), slug);
3032
3268
  }
3033
3269
  function droneWorktreeRoot(worktreesDir, repo) {
3034
- return join7(worktreesDir, basename(normalizeRepo(repo)));
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(join7(SWARM_HOME, "token"), "utf8").trim();
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
- writeFileSync4(tmp, JSON.stringify({ at }));
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 || join7(SWARM_HOME, "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 || join7(SWARM_HOME, "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 = join7(SWARM_HOME, "worktrees.noindex");
3116
- WORKTREES_LEGACY_DIR = join7(SWARM_HOME, "worktrees");
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 || join7(SWARM_HOME, "run-logs");
3119
- DAEMON_LOG_PATH = process.env.SWARM_DAEMON_LOG || join7(SWARM_HOME, "overmind.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 || join7(SWARM_HOME, "outbox.jsonl");
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 || join7(SWARM_HOME, "env-cache");
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 || join7(SWARM_HOME, "drone-channel.key");
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 || join7(SWARM_HOME, "overmind.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 || join7(SWARM_HOME, "repo-map.json");
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 || join7(SWARM_HOME, "review-cutoff.json");
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 writeFileSync5, unlinkSync as unlinkSync2 } from "fs";
3706
- import { join as join8 } from "path";
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 = join8(SWARM_HOME, "agent.json");
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 writeFileSync7 } from "fs";
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
- writeFileSync7(tmp, String(now));
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 existsSync12, readdirSync as readdirSync12, realpathSync as realpathSync2, statSync as statSync10 } from "fs";
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 join21, resolve as resolve3, sep as sep2 } from "path";
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 (!existsSync12(path)) return "free";
4630
+ if (!existsSync13(path)) return "free";
4395
4631
  try {
4396
- if (readdirSync12(path).length === 0) return "free";
4632
+ if (readdirSync13(path).length === 0) return "free";
4397
4633
  } catch {
4398
4634
  return "orphan";
4399
4635
  }
4400
4636
  try {
4401
- if (statSync10(join21(path, ".git")).isDirectory()) return "main-checkout";
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 (!existsSync12(path)) return;
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 statSync10(join21(dir, ".git")).isFile();
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 (!existsSync12(worktree)) return false;
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 (existsSync12(worktree)) {
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 = existsSync12(busyAt);
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 = join21(commonDir, "info");
4574
- const excludeFile = join21(infoDir, "exclude");
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 : join21(worktree, 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 = join21(gitDir, "swarm-hooks");
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(join21(hooksDir, hook), guardHookScript(hook, prev ? `${posix(prev)}/${hook}` : null));
4609
- await chmod(join21(hooksDir, hook), 493);
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 ? join21(commonDir, "hooks") : null;
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 readdirSync12(dir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => join21(dir, d.name));
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 mkdirSync9, readFileSync as readFileSync19, writeFileSync as writeFileSync12 } from "fs";
4791
- import { dirname as dirname4 } from "path";
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
- mkdirSync9(dirname4(path), { recursive: true });
4801
- writeFileSync12(path, secret, { mode: 384 });
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 num = (v) => typeof v === "number" && Number.isFinite(v) ? v : null;
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 = num(p.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 = num(p.id);
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 join25 } from "path";
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 num = String(index).padStart(2, "0");
5495
+ const num2 = String(index).padStart(2, "0");
5260
5496
  const slug = slugifyCaption(caption) || "attachment";
5261
- return `${num}-${slug}.${ext}`;
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 = join25(opts.worktree, ATTACHMENTS_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(join25(dir, name), file.bytes);
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 join26 } from "path";
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 : join26(opts.worktree, 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 writeFileSync13, unlinkSync as unlinkSync4 } from "fs";
5589
- import { join as join27 } from "path";
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
- writeFileSync13(STORE_PATH2, JSON.stringify(s, null, 2), { mode: 384 });
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
- writeFileSync13(CLIENT_PATH, JSON.stringify({ clientId }, null, 2), { mode: 384 });
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 = join27(SWARM_HOME, "oauth.json");
5725
- CLIENT_PATH = join27(SWARM_HOME, "oauth-client.json");
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 writeFileSync14, unlinkSync as unlinkSync5 } from "fs";
5772
- import { join as join28 } from "path";
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 = join28(SWARM_HOME, "workspace.json");
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 existsSync15 } from "fs";
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 (!existsSync15(abs)) throw new Error(`import-db: \u0444\u0430\u0439\u043B\u0430 \u043D\u0435\u0442: ${abs}`);
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 existsSync20, readFileSync as readFileSync25, readdirSync as readdirSync14, renameSync as renameSync12, statSync as statSync13 } from "fs";
7421
- import { basename as basename6, dirname as dirname5, join as join35 } from "path";
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 existsSync7, mkdirSync as mkdirSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
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 existsSync6, openSync, readSync, readdirSync as readdirSync6, statSync as statSync5 } from "fs";
7560
- import { join as join10 } from "path";
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 existsSync5, mkdirSync as mkdirSync5, readdirSync as readdirSync5, renameSync as renameSync3, statSync as statSync4 } from "fs";
7564
- import { join as join9 } from "path";
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 join9(runLogsDir, runLogDirName(runLogKey));
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 (existsSync5(dir)) return dir;
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 = join9(runLogsDir, LEGACY_RUN_LOGS_SUBDIR);
7829
+ const legacyDir = join10(runLogsDir, LEGACY_RUN_LOGS_SUBDIR);
7588
7830
  let entries;
7589
7831
  try {
7590
- entries = readdirSync5(runLogsDir);
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 = join9(runLogsDir, name);
7840
+ const from = join10(runLogsDir, name);
7599
7841
  try {
7600
- if (!statSync4(from).isDirectory()) continue;
7601
- mkdirSync5(legacyDir, { recursive: true });
7602
- let to = join9(legacyDir, name);
7603
- for (let n = 2; existsSync5(to) && n < 100; n++) to = join9(legacyDir, `${name}-${n}`);
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 = statSync5(path).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 = readdirSync6(dir);
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 = [join10(dir, `${index}.json`), join10(dir, `${index}.json.done`)].find((p) => existsSync6(p)) ?? null;
7670
- const err = existsSync6(join10(dir, `${index}.err.log`)) ? join10(dir, `${index}.err.log`) : null;
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 ?? existsSync7;
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
- mkdirSync6(dirname2(this.outboxPath), { recursive: true });
8188
+ mkdirSync7(dirname2(this.outboxPath), { recursive: true });
7947
8189
  this.recover();
7948
8190
  }
7949
8191
  // ── рестарт: поднять outbox (незаписанные операции) и карту runKey→prodId ─────
7950
8192
  recover() {
7951
- if (existsSync7(this.mapPath)) {
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 (existsSync7(this.outboxPath)) {
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 (!existsSync7(this.stormPath)) return;
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 ?? existsSync7;
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
- writeFileSync6(this.outboxPath, this.pending.map((e) => JSON.stringify(e)).join("\n") + (this.pending.length ? "\n" : ""));
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
- writeFileSync6(this.mapPath, JSON.stringify(Object.fromEntries(this.prodIdByKey)));
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 copyFileSync2, renameSync as renameSync5, statSync as statSync6, fstatSync, truncateSync, unlinkSync as unlinkSync3, existsSync as existsSync8 } from "fs";
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 statSync6(path).size;
10541
+ return statSync7(path).size;
10298
10542
  } catch {
10299
10543
  return null;
10300
10544
  }
10301
10545
  },
10302
- copy: copyFileSync2,
10546
+ copy: copyFileSync4,
10303
10547
  rename: renameSync5,
10304
10548
  truncate: (path) => truncateSync(path, 0),
10305
10549
  unlink: unlinkSync3,
10306
- exists: existsSync8
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 = statSync6(path);
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 writeFileSync8 } from "fs";
10454
- import { join as join11 } from "path";
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(join11(home, FILE), "utf8");
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
- writeFileSync8(join11(home, FILE), `${JSON.stringify({ paths: clean, at: now().toISOString() }, null, 2)}
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 writeFileSync9 } from "fs";
10490
- import { isAbsolute, join as join13, resolve as resolve2 } from "path";
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 readdirSync7, readFileSync as readFileSync11, statSync as statSync7 } from "fs";
10494
- import { join as join12 } from "path";
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(join12(dir, ".git", "config"), "utf8"));
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 = readdirSync7(dir);
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 = join12(dir, name);
10803
+ const child = join13(dir, name);
10560
10804
  try {
10561
- if (!statSync7(child).isDirectory()) continue;
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(join12(home, name));
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("~/") ? join13(home, p.slice(2)) : isAbsolute(p) ? p : resolve2(home, p);
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
- writeFileSync9(tmp, JSON.stringify({ at: stamp(), scannedAt, entries }, null, 2));
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 existsSync9, readFileSync as readFileSync13, renameSync as renameSync7, writeFileSync as writeFileSync10 } from "fs";
10833
- import { join as join14 } from "path";
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 join14(home, "host.json");
11080
+ return join15(home, "host.json");
10837
11081
  }
10838
11082
  function loadHostIdentity(deps) {
10839
- const exists = deps.exists ?? existsSync9;
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
- writeFileSync10(`${p}.tmp`, data);
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 existsSync10, readFileSync as readFileSync14, renameSync as renameSync8, writeFileSync as writeFileSync11 } from "fs";
10936
- import { join as join15 } from "path";
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 join15(home, "relief-loop.json");
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 ?? existsSync10;
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
- writeFileSync11(`${p}.tmp`, data);
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 existsSync11, mkdirSync as mkdirSync8, openSync as openSync3, readdirSync as readdirSync9 } from "fs";
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 join17 } from "path";
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 mkdirSync7, readdirSync as readdirSync8, rmSync, statSync as statSync8, symlinkSync as symlinkSync2 } from "fs";
11167
- import { join as join16, relative, sep } from "path";
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
- mkdirSync7(droneHome, { recursive: true, mode: 448 });
11186
- const wanted = new Set(mirroredEntries(readdirSync8(realHome), deny, platform));
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 readdirSync8(droneHome)) {
11433
+ for (const existing of readdirSync9(droneHome)) {
11190
11434
  if (wanted.has(existing)) continue;
11191
- const p = join16(droneHome, existing);
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 = join16(droneHome, name);
11442
+ const link2 = join17(droneHome, name);
11199
11443
  try {
11200
11444
  lstatSync(link2);
11201
11445
  continue;
11202
11446
  } catch {
11203
11447
  }
11204
- const target = join16(realHome, name);
11448
+ const target = join17(realHome, name);
11205
11449
  let isDir;
11206
11450
  try {
11207
- isDir = statSync8(target).isDirectory();
11451
+ isDir = statSync9(target).isDirectory();
11208
11452
  } catch {
11209
11453
  continue;
11210
11454
  }
11211
11455
  try {
11212
- symlinkSync2(target, link2, isDir ? "junction" : "file");
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, join16(realHome, ...segments)]));
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 = join17(worktree, ".turbo", "cache");
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 join17(dirname3(fileURLToPath2(import.meta.url)), "..", "roles", kind);
11583
+ return join18(dirname3(fileURLToPath2(import.meta.url)), "..", "roles", kind);
11340
11584
  }
11341
11585
  function roleDir(worktree, kind) {
11342
- return join17(worktree, ".claude", "roles", kind);
11586
+ return join18(worktree, ".claude", "roles", kind);
11343
11587
  }
11344
11588
  function roleDirs(worktree, kind) {
11345
- return [bundledRoleDir(kind), roleDir(worktree, kind)].filter((dir) => existsSync11(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
- mkdirSync8(dir, { recursive: true });
11594
+ mkdirSync9(dir, { recursive: true });
11351
11595
  let files = [];
11352
11596
  try {
11353
- files = readdirSync9(dir);
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 join17(dir, `${next}.json`);
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 && !existsSync11(join17(cfg.droneIsolation.swarmHome, "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 ${join17(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.`
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 readdirSync10, renameSync as renameSync9, statSync as statSync9 } from "fs";
11514
- import { join as join18 } from "path";
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 readdirSync10(dir).filter((f) => UNPROCESSED_LOG_RE.test(f));
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 = readdirSync10(dir);
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 = statSync9(join18(dir, f));
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 = join18(dir, f);
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 readdirSync11, readFileSync as readFileSync16 } from "fs";
11650
- import { join as join19 } from "path";
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 = readdirSync11(dir);
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(join19(dir, latest.name), "utf8");
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 join20 } from "path";
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(join20(dir, bin + ext), constants.X_OK);
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 existsSync14, readdirSync as readdirSync13, readFileSync as readFileSync18 } from "fs";
11765
- import { join as join24 } from "path";
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 statSync11, writeSync } from "fs";
11771
- import { join as join22 } from "path";
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 join22(dir, `swarm-prepare-${createHash("sha1").update(key).digest("hex").slice(0, 16)}.lock`);
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() - statSync11(path).mtimeMs;
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 existsSync13, readFileSync as readFileSync17 } from "fs";
11839
- import { join as join23 } from "path";
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 = join23(src, e.name);
11854
- const to = join23(dst, e.name);
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 join23(cacheRoot(io), key);
12127
+ return join24(cacheRoot(io), key);
11868
12128
  }
11869
12129
  function readManifest(dir) {
11870
12130
  try {
11871
- const parsed = JSON.parse(readFileSync17(join23(dir, "manifest.json"), "utf8"));
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 ?? existsSync13;
11884
- return exists(join23(snapshotDir(io, key), "manifest.json"));
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 ?? existsSync13;
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 = join23(worktree, rel);
12156
+ const target = join24(worktree, rel);
11897
12157
  if (exists(target)) continue;
11898
- await clone(join23(dir, "trees", String(i)), target);
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(join23(worktree, rel), { recursive: true, force: true }).catch(() => {
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 ?? existsSync13;
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(join23(worktree, rel)));
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 = join23(root, `.tmp-${key}-${process.pid}`);
12181
+ const tmp = join24(root, `.tmp-${key}-${process.pid}`);
11922
12182
  try {
11923
12183
  await rm2(tmp, { recursive: true, force: true });
11924
- await mkdir2(join23(tmp, "trees"), { recursive: true });
11925
- for (let i = 0; i < present.length; i++) await clone(join23(worktree, present[i] ?? ""), join23(tmp, "trees", String(i)));
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(join23(tmp, "manifest.json"), JSON.stringify(manifest, null, 2));
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(join23(root, name)).catch(() => null);
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(join23(root, name), { recursive: true, force: true }).catch(() => {
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(join23(root, name)).catch(() => null);
12229
+ const s = await lstat(join24(root, name)).catch(() => null);
11970
12230
  if (!s || Date.now() - s.mtimeMs < 60 * 6e4) continue;
11971
- await rm2(join23(root, name), { recursive: true, force: true }).catch(() => {
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 readdirSync13(p, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
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 readdirSync13(p, { withFileTypes: true }).filter((e) => e.isFile()).map((e) => e.name);
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 ?? existsSync14;
12298
+ const exists = io.exists ?? existsSync15;
12039
12299
  const readText = io.readText ?? safeReadText;
12040
- const hasPkgJson = exists(join24(worktree, "package.json"));
12300
+ const hasPkgJson = exists(join25(worktree, "package.json"));
12041
12301
  if (!hasPkgJson) {
12042
- if (exists(join24(worktree, "deno.json")) || exists(join24(worktree, "deno.jsonc")) || exists(join24(worktree, "deno.lock"))) return "deno";
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, join24(worktree, "package.json"));
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(join24(worktree, "bun.lock")) || exists(join24(worktree, "bun.lockb"))) return "bun";
12049
- if (exists(join24(worktree, "pnpm-lock.yaml"))) return "pnpm";
12050
- if (exists(join24(worktree, "yarn.lock"))) return "yarn";
12051
- if (exists(join24(worktree, "package-lock.json"))) return "npm";
12052
- if (exists(join24(worktree, "deno.lock"))) return "deno";
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 ?? existsSync14;
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: join24(worktree, "node_modules"), source: "detect" }
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(join24(worktree, f))) || marker.ext !== void 0 && listFiles(worktree).some((n) => n.endsWith(marker.ext));
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(join24(worktree, refine.file))) continue;
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 = join24(worktree, ".github", "workflows");
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(join24(dir, name));
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(join24(worktree, "pnpm-workspace.yaml"));
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, join24(worktree, "package.json"));
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 = join24(worktree, glob);
12239
- if (io.exists(join24(dir, "package.json"))) dirs.add(dir);
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 = join24(worktree, glob.slice(0, star).replace(/\/$/, ""));
12502
+ const base3 = join25(worktree, glob.slice(0, star).replace(/\/$/, ""));
12243
12503
  for (const name of io.listDirs(base3)) {
12244
- const dir = join24(base3, name);
12245
- if (io.exists(join24(dir, "package.json"))) dirs.add(dir);
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 ?? existsSync14;
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, join24(dir, "package.json"));
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(join24(dir, e)));
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(join24(worktree, file));
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 ?? existsSync14;
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(join24(dir, "prisma", "schema.prisma")) && listDirs(join24(dir, "prisma", "migrations")).length > 0);
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 ?? existsSync14;
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(join24(worktree, name));
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(join24(worktree, rel, "package.json"));
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) => join24(rel, "node_modules"))] };
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 ?? existsSync14;
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(join24(worktree, "node_modules"))) {
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.61",
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: "97838ed30c3fef4cc868c38d8fd9373635a3b48c"
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 statSync12 } from "fs";
13569
- import { join as join29 } from "path";
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 statSync12(path).mtimeMs;
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(join29(worktree, b.path)) - mtime(join29(worktree, a.path)));
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 num = prNumberOf(r.pr_url);
15697
- const seen = byPr.get(num);
15698
- if (!seen || r.id > seen.id) byPr.set(num, r);
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 num = prNumberOf(run.pr_url);
15712
- if (num == null) return null;
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) === num);
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 num = prNumberOf(run.pr_url);
15831
- if (num == null) return null;
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) === num);
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 existsSync17 } from "fs";
15991
- import { join as join31 } from "path";
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 existsSync16, readFileSync as readFileSync22 } from "fs";
15997
- import { delimiter as delimiter2, join as join30 } from "path";
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 existsSync16(name) ? name : null;
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 = join30(dir, name + ext);
16005
- if (existsSync16(candidate)) return candidate;
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 ?? existsSync17;
16089
- const marker = COMPOSE_MARKERS.find((f) => exists(join31(repo, f)));
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 writeFileSync15 } from "fs";
17845
- import { join as join32 } from "path";
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 join32(home, "host-command.json");
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
- writeFileSync15(`${path}.tmp`, JSON.stringify(state));
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 existsSync18 } from "fs";
18022
- import { join as join33 } from "path";
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 ?? existsSync18;
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(join33(repo, "pnpm-lock.yaml"))) {
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 existsSync19, readFileSync as readFileSync24, renameSync as renameSync11, writeFileSync as writeFileSync16 } from "fs";
18230
- import { join as join34 } from "path";
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 join34(home, "anomaly-state.json");
18561
+ return join36(home, "anomaly-state.json");
18238
18562
  }
18239
18563
  function loadAnomalyState(home, now = Date.now(), io = {}) {
18240
- const exists = io.exists ?? existsSync19;
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
- writeFileSync16(`${p}.tmp`, data);
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 (!path) return null;
18799
- return path.replace(/[/\\]\.swarm-mcp\.json$/, "");
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 = join35(dirname5(THIS_FILE), "..", "docs", "HERO.md");
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 = join35(bundledRoleDir("drone"), "skills", "taskless-review", "SKILL.md");
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 ?? existsSync20;
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 = join35(base3, ".github", "workflows");
20327
+ const dir = join37(base3, ".github", "workflows");
19968
20328
  try {
19969
- if (readdirSync14(dir).some((f) => f.endsWith(".yml") || f.endsWith(".yaml"))) return true;
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 ?? existsSync20;
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 ?? existsSync20)(wtPath);
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 statSync13(join35(repo, p), { throwIfNoEntry: false })?.isFile() ?? false;
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 ?? existsSync20, deps.hasTranscript ?? executorHasSession, droneCap);
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 ?? existsSync20;
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 ?? existsSync20;
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 = join35(deps.worktreesDir, basename6(repo), `${reviewRun.task_slug}-resolve-${resolver.id}`);
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 = join35(deps.worktreesDir, basename6(repo), `${reviewRun.task_slug}-review-${reviewer.id}`);
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 = join35(deps.worktreesDir, basename6(repo), `${verifiedRun.task_slug}-verify-${verifier.id}`);
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 (!existsSync20(wt)) {
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 ?? existsSync20;
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) => existsSync20(d),
23216
+ exists: (d) => existsSync22(d),
22855
23217
  isNonEmptyDir: (d) => {
22856
23218
  try {
22857
- return readdirSync14(d).length > 0;
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 existsSync20(WORKTREES_DIR) ? WORKTREES_DIR : WORKTREES_LEGACY_DIR;
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: existsSync20,
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) => existsSync20(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(dirname5(THIS_FILE)).catch(() => null);
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,