@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/cli.js CHANGED
@@ -607,10 +607,10 @@ function pick(rows) {
607
607
  return newest(rows.filter((r) => r.author)) ?? newest(rows);
608
608
  }
609
609
  function pickRunForPr(rows, ref, ctxRepo) {
610
- const num = prNumberOf(ref);
611
- if (num == null) return null;
610
+ const num2 = prNumberOf(ref);
611
+ if (num2 == null) return null;
612
612
  const target = repoKeyOf(ref) ?? repoKeyOf(ctxRepo);
613
- const hits = rows.filter((r) => r.prUrl && prNumberOf(r.prUrl) === num);
613
+ const hits = rows.filter((r) => r.prUrl && prNumberOf(r.prUrl) === num2);
614
614
  if (hits.length === 0) return null;
615
615
  if (target) {
616
616
  const mine = hits.filter((r) => keyOf(r) === target);
@@ -650,6 +650,9 @@ var init_returnReason = __esm({
650
650
  });
651
651
 
652
652
  // ../swarm-core/src/modelPolicy.ts
653
+ function isHarnessDefaultModel(model) {
654
+ return typeof model === "string" && model.trim().toLowerCase() === HARNESS_DEFAULT_MODEL;
655
+ }
653
656
  function findProvider(id) {
654
657
  const key = typeof id === "string" ? id.trim().toLowerCase() : "";
655
658
  return MODEL_PROVIDERS.find((p) => p.id === key) ?? null;
@@ -701,6 +704,17 @@ var init_modelPolicy = __esm({
701
704
  selectable: true,
702
705
  roles: { executor: "glm-5.3", review: "glm-5.3" }
703
706
  },
707
+ // Grok CLI. Каталог — живой `grok models` (16.10.2026), целиком и без выдуманных
708
+ // имён: grok-4.7 (дефолт CLI и исполнителя), grok-4.7-build-fast, grok-4.6, grok-4.5
709
+ // (проверка — младшая, та же идея, что sonnet против opus). Тарифа нет: цену пишет CLI.
710
+ {
711
+ id: "xai",
712
+ label: "xAI (Grok)",
713
+ executorId: "grok",
714
+ selectable: true,
715
+ roles: { executor: "grok-4.7", review: "grok-4.5" },
716
+ models: ["grok-4.7", "grok-4.7-build-fast", "grok-4.6", "grok-4.5"]
717
+ },
704
718
  // TASWM-565 · шаг 1 из четырёх: провайдер в реестре ЕСТЬ, выбрать его ещё нельзя.
705
719
  // Имён моделей здесь нет СОЗНАТЕЛЬНО: у владельца подписка, состав моделей в ней нам
706
720
  // неизвестен, а выдуманное имя хуже маркера «решает Codex».
@@ -1089,18 +1103,18 @@ var init_hosts = __esm({
1089
1103
  function parseHostResources(raw) {
1090
1104
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
1091
1105
  const v = raw;
1092
- const num = (x) => typeof x === "number" && Number.isFinite(x) ? x : null;
1093
- const memFreeGb = num(v.memFreeGb);
1094
- const memTotalGb = num(v.memTotalGb);
1106
+ const num2 = (x) => typeof x === "number" && Number.isFinite(x) ? x : null;
1107
+ const memFreeGb = num2(v.memFreeGb);
1108
+ const memTotalGb = num2(v.memTotalGb);
1095
1109
  if (memFreeGb == null || memTotalGb == null) return null;
1096
1110
  if (typeof v.measuredAt !== "string" || Number.isNaN(Date.parse(v.measuredAt))) return null;
1097
- const cpu = num(v.cpuBusyPct);
1111
+ const cpu = num2(v.cpuBusyPct);
1098
1112
  return {
1099
1113
  cpuBusyPct: cpu == null ? null : Math.min(100, Math.max(0, cpu)),
1100
1114
  memFreeGb,
1101
1115
  memTotalGb,
1102
- diskFreeGb: num(v.diskFreeGb),
1103
- diskTotalGb: num(v.diskTotalGb),
1116
+ diskFreeGb: num2(v.diskFreeGb),
1117
+ diskTotalGb: num2(v.diskTotalGb),
1104
1118
  measuredAt: v.measuredAt
1105
1119
  };
1106
1120
  }
@@ -1137,6 +1151,7 @@ var init_hostPool = __esm({
1137
1151
  "../swarm-core/src/hostPool.ts"() {
1138
1152
  "use strict";
1139
1153
  init_hosts();
1154
+ init_modelPolicy();
1140
1155
  HOST_REJECTION_TEXT = {
1141
1156
  offline: "\u043D\u0435 \u043D\u0430 \u0441\u0432\u044F\u0437\u0438",
1142
1157
  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}`,
@@ -2109,10 +2124,10 @@ function launchCostUsd(result, model) {
2109
2124
  return costFromUsage(result.usage, model);
2110
2125
  }
2111
2126
  function launchSpend(result) {
2112
- const num = (v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? v : 0;
2127
+ const num2 = (v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? v : 0;
2113
2128
  const sum = (u) => ({
2114
- tokensIn: num(u.input_tokens) + num(u.cache_creation_input_tokens) + num(u.cache_read_input_tokens),
2115
- tokensOut: num(u.output_tokens)
2129
+ tokensIn: num2(u.input_tokens) + num2(u.cache_creation_input_tokens) + num2(u.cache_read_input_tokens),
2130
+ tokensOut: num2(u.output_tokens)
2116
2131
  });
2117
2132
  const spend = sum(result.usage ?? {});
2118
2133
  if (spend.tokensIn === 0 && spend.tokensOut === 0 && result.modelUsage) {
@@ -2122,7 +2137,7 @@ function launchSpend(result) {
2122
2137
  spend.tokensOut += perModel.tokensOut;
2123
2138
  }
2124
2139
  }
2125
- return { ...spend, durationMs: num(result.duration_ms) };
2140
+ return { ...spend, durationMs: num2(result.duration_ms) };
2126
2141
  }
2127
2142
  function asTokenUsage(m) {
2128
2143
  return {
@@ -2214,9 +2229,9 @@ function transcriptSpendInWindow(worktree, fromMs, toMs, opts = {}) {
2214
2229
  unpriced += 1;
2215
2230
  unpricedModel ??= model;
2216
2231
  }
2217
- const num = (v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? v : 0;
2218
- tokensIn += num(usage2.input_tokens) + num(usage2.cache_creation_input_tokens) + num(usage2.cache_read_input_tokens);
2219
- tokensOut += num(usage2.output_tokens);
2232
+ const num2 = (v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? v : 0;
2233
+ tokensIn += num2(usage2.input_tokens) + num2(usage2.cache_creation_input_tokens) + num2(usage2.cache_read_input_tokens);
2234
+ tokensOut += num2(usage2.output_tokens);
2220
2235
  if (firstAt === null || at < firstAt) firstAt = at;
2221
2236
  if (lastAt === null || at > lastAt) lastAt = at;
2222
2237
  replies += 1;
@@ -2444,13 +2459,15 @@ var init_swarmHome = __esm({
2444
2459
  });
2445
2460
 
2446
2461
  // src/executors/codex.ts
2447
- import { existsSync as existsSync3, mkdirSync as mkdirSync3, readdirSync as readdirSync4, statSync as statSync3, symlinkSync } from "fs";
2462
+ import { copyFileSync as copyFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync3, readdirSync as readdirSync4, statSync as statSync3, symlinkSync } from "fs";
2448
2463
  import { join as join5 } from "path";
2449
2464
  function resolveCodexBin(env = process.env) {
2450
2465
  return (env.SWARM_CODEX_BIN ?? "").trim() || "codex";
2451
2466
  }
2452
2467
  function codexHomePath(worktree, swarmHome = SWARM_HOME) {
2453
- return join5(swarmHome, "executor-state", "codex", worktree.replace(/[/.]/g, "-"));
2468
+ const folded = worktree.replace(/[/.]/g, "-");
2469
+ const key = /[:\\]/.test(folded) ? worktree.replace(/[^A-Za-z0-9]+/g, "-").replace(/^-|-$/g, "") || "worktree" : folded;
2470
+ return join5(swarmHome, "executor-state", "codex", key);
2454
2471
  }
2455
2472
  function ensureCodexHome(worktree, realHome, env = process.env, swarmHome = SWARM_HOME) {
2456
2473
  const home = codexHomePath(worktree, swarmHome);
@@ -2463,6 +2480,10 @@ function ensureCodexHome(worktree, realHome, env = process.env, swarmHome = SWAR
2463
2480
  try {
2464
2481
  symlinkSync(target, link);
2465
2482
  } catch {
2483
+ try {
2484
+ copyFileSync2(target, link);
2485
+ } catch {
2486
+ }
2466
2487
  }
2467
2488
  }
2468
2489
  return home;
@@ -2613,6 +2634,206 @@ ${notice}` : spec.prompt;
2613
2634
  }
2614
2635
  });
2615
2636
 
2637
+ // src/executors/grok.ts
2638
+ import { copyFileSync as copyFileSync3, existsSync as existsSync4, mkdirSync as mkdirSync4, readdirSync as readdirSync5, statSync as statSync4, symlinkSync as symlinkSync2, writeFileSync as writeFileSync3 } from "fs";
2639
+ import { join as join6 } from "path";
2640
+ function resolveGrokBin(env = process.env) {
2641
+ return (env.SWARM_GROK_BIN ?? "").trim() || "grok";
2642
+ }
2643
+ function grokHomePath(worktree, swarmHome = SWARM_HOME) {
2644
+ const key = worktree.replace(/[^A-Za-z0-9]+/g, "-").replace(/^-|-$/g, "") || "worktree";
2645
+ return join6(swarmHome, "executor-state", "grok", key);
2646
+ }
2647
+ function grokSessionDir(worktree, swarmHome = SWARM_HOME) {
2648
+ return join6(grokHomePath(worktree, swarmHome), "sessions", encodeURIComponent(worktree));
2649
+ }
2650
+ function tomlBasic(value) {
2651
+ const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r");
2652
+ return `"${escaped}"`;
2653
+ }
2654
+ function grokMcpToml(spec) {
2655
+ const env = Object.entries(spec.mcp.env).map(([k, v]) => `${k} = ${tomlBasic(v)}`).join(", ");
2656
+ const args = spec.mcp.args.map((a) => tomlBasic(a)).join(", ");
2657
+ return [
2658
+ "[mcp_servers." + spec.mcp.name + "]",
2659
+ "command = " + tomlBasic(spec.mcp.command),
2660
+ "args = [" + args + "]",
2661
+ "env = { " + env + " }",
2662
+ ""
2663
+ ].join("\n");
2664
+ }
2665
+ function ensureGrokHome(worktree, realHome, env = process.env, swarmHome = SWARM_HOME) {
2666
+ const home = grokHomePath(worktree, swarmHome);
2667
+ mkdirSync4(home, { recursive: true });
2668
+ const real = (env.GROK_HOME ?? "").trim() || join6(realHome, ".grok");
2669
+ const target = join6(real, "auth.json");
2670
+ const link = join6(home, "auth.json");
2671
+ if (existsSync4(target) && !existsSync4(link)) {
2672
+ try {
2673
+ symlinkSync2(target, link);
2674
+ } catch {
2675
+ try {
2676
+ copyFileSync3(target, link);
2677
+ } catch {
2678
+ }
2679
+ }
2680
+ }
2681
+ return home;
2682
+ }
2683
+ function modelArgs(model) {
2684
+ if (!model || isHarnessDefaultModel(model)) return [];
2685
+ return ["--model", model];
2686
+ }
2687
+ function denyArgs(paths) {
2688
+ return paths.flatMap((p) => ["--deny", `Read(${p}) Edit(${p}) Write(${p})`]);
2689
+ }
2690
+ function newestSessionMtime(dir, depth = 3) {
2691
+ let entries;
2692
+ try {
2693
+ entries = readdirSync5(dir, { withFileTypes: true });
2694
+ } catch {
2695
+ return null;
2696
+ }
2697
+ let latest = null;
2698
+ for (const entry of entries) {
2699
+ const full = join6(dir, entry.name);
2700
+ try {
2701
+ if (entry.isDirectory()) {
2702
+ if (depth <= 0) continue;
2703
+ const nested = newestSessionMtime(full, depth - 1);
2704
+ if (nested != null && (latest == null || nested > latest)) latest = nested;
2705
+ } else if (entry.isFile()) {
2706
+ const mtime2 = statSync4(full).mtimeMs;
2707
+ if (latest == null || mtime2 > latest) latest = mtime2;
2708
+ }
2709
+ } catch {
2710
+ }
2711
+ }
2712
+ return latest;
2713
+ }
2714
+ function num(v) {
2715
+ return typeof v === "number" && Number.isFinite(v) ? v : 0;
2716
+ }
2717
+ function grokAbort(rec) {
2718
+ if (rec.type === "error") {
2719
+ const raw = typeof rec.message === "string" && rec.message ? rec.message : "error";
2720
+ const kind = /tool/i.test(raw) ? "tools" : /401|unauthorized|network|fetch|ECONN|api/i.test(raw) ? "link" : "other";
2721
+ return { kind, raw: raw.slice(0, 300) };
2722
+ }
2723
+ const stop = typeof rec.stopReason === "string" ? rec.stopReason : "";
2724
+ if (rec.is_error === true || stop === "error" || stop.startsWith("error_")) {
2725
+ const raw = stop || "is_error";
2726
+ return { kind: /tool/i.test(raw) ? "tools" : "other", raw };
2727
+ }
2728
+ return void 0;
2729
+ }
2730
+ function parseGrokResult(raw) {
2731
+ const trimmed = raw.trim();
2732
+ if (!trimmed) return null;
2733
+ let parsed;
2734
+ try {
2735
+ parsed = JSON.parse(trimmed);
2736
+ } catch {
2737
+ return null;
2738
+ }
2739
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return null;
2740
+ const rec = parsed;
2741
+ const hasShape = typeof rec.text === "string" || typeof rec.stopReason === "string" || typeof rec.sessionId === "string" || rec.type === "error";
2742
+ if (!hasShape) return null;
2743
+ const reported = typeof rec.total_cost_usd === "number" && Number.isFinite(rec.total_cost_usd);
2744
+ const usage2 = rec.usage;
2745
+ let tokensIn;
2746
+ let tokensOut;
2747
+ if (typeof usage2 === "object" && usage2 !== null) {
2748
+ const u = usage2;
2749
+ const hasAny = ["input_tokens", "output_tokens", "cache_read_input_tokens", "cache_creation_input_tokens"].some(
2750
+ (k) => typeof u[k] === "number"
2751
+ );
2752
+ if (hasAny) {
2753
+ tokensIn = num(u.input_tokens) + num(u.cache_read_input_tokens) + num(u.cache_creation_input_tokens);
2754
+ tokensOut = num(u.output_tokens);
2755
+ }
2756
+ }
2757
+ const aborted = grokAbort(rec);
2758
+ const result = {
2759
+ costUsd: reported ? rec.total_cost_usd : 0
2760
+ };
2761
+ 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)";
2762
+ if (tokensIn != null && tokensOut != null) {
2763
+ result.tokensIn = tokensIn;
2764
+ result.tokensOut = tokensOut;
2765
+ }
2766
+ if (aborted) result.aborted = aborted;
2767
+ return result;
2768
+ }
2769
+ var grokExecutor;
2770
+ var init_grok = __esm({
2771
+ "src/executors/grok.ts"() {
2772
+ "use strict";
2773
+ init_src();
2774
+ init_swarmHome();
2775
+ init_swarmFiles();
2776
+ init_codex();
2777
+ grokExecutor = {
2778
+ id: "grok",
2779
+ title: "Grok CLI (grok)",
2780
+ binEnv: "SWARM_GROK_BIN",
2781
+ install: {
2782
+ 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.",
2783
+ pkg: "grok",
2784
+ command: "curl -fsSL https://x.ai/cli/install.sh | bash",
2785
+ windowsCommand: "irm https://x.ai/cli/install.ps1 | iex"
2786
+ },
2787
+ resolveBin: (env) => resolveGrokBin(env ?? process.env),
2788
+ plan: (spec) => {
2789
+ const home = ensureGrokHome(spec.worktree, spec.realHome);
2790
+ writeFileSync3(join6(home, "config.toml"), grokMcpToml(spec));
2791
+ writeFileSync3(
2792
+ join6(spec.worktree, SWARM_MCP_CONFIG_FILE),
2793
+ JSON.stringify(
2794
+ { mcpServers: { [spec.mcp.name]: { command: spec.mcp.command, args: spec.mcp.args, env: spec.mcp.env } } },
2795
+ null,
2796
+ 2
2797
+ )
2798
+ );
2799
+ const notice = skillsNotice(spec.skillDirs);
2800
+ const prompt = notice ? `${spec.prompt}
2801
+
2802
+ ${notice}` : spec.prompt;
2803
+ const args = [
2804
+ // `--cwd` стоит первым: по нему реконсайл узнаёт worktree живого процесса.
2805
+ // Флаг настоящий. Выдуманный `--mcp-config` grok отверг бы и дрон не стартовал.
2806
+ "--cwd",
2807
+ spec.worktree,
2808
+ "--no-auto-update",
2809
+ "--output-format",
2810
+ "json",
2811
+ "--yolo",
2812
+ ...spec.continueSession ? ["--continue"] : [],
2813
+ ...modelArgs(spec.model),
2814
+ ...spec.effort ? ["--effort", spec.effort] : [],
2815
+ ...denyArgs(spec.denyPaths),
2816
+ "-p",
2817
+ prompt
2818
+ ];
2819
+ return { bin: resolveGrokBin(), args, env: { GROK_HOME: home } };
2820
+ },
2821
+ parseResult(raw) {
2822
+ return parseGrokResult(raw);
2823
+ },
2824
+ session: {
2825
+ exists: (worktree) => newestSessionMtime(grokSessionDir(worktree)) !== null,
2826
+ mtimeMs: (worktree) => newestSessionMtime(grokSessionDir(worktree))
2827
+ },
2828
+ probe: {
2829
+ args: ["-p", "ok", "--output-format", "json", "--yolo", "--max-turns", "1", "--no-auto-update"],
2830
+ limitPattern: /usage limit/i,
2831
+ authPattern: /not logged in|unauthorized|\b401\b|authentication required|auth required/i
2832
+ }
2833
+ };
2834
+ }
2835
+ });
2836
+
2616
2837
  // src/swarmModels.ts
2617
2838
  function pick2(v) {
2618
2839
  const s = typeof v === "string" ? v.trim() : "";
@@ -2628,10 +2849,22 @@ function forKind(kind, swarm, norm) {
2628
2849
  if (!swarm) return null;
2629
2850
  return isReviewKind(kind) ? norm(swarm.reviewer) ?? norm(swarm.drone) : norm(swarm.drone);
2630
2851
  }
2852
+ function providersFromEnv(env = process.env) {
2853
+ const raw = (env.SWARM_PROVIDERS ?? "").trim();
2854
+ if (!raw) return null;
2855
+ const known = new Set(MODEL_PROVIDERS.map((p) => p.id));
2856
+ const list = [...new Set(raw.split(/[\s,]+/).map((p) => p.trim().toLowerCase()).filter((p) => known.has(p)))];
2857
+ return list.length ? list : null;
2858
+ }
2631
2859
  function resolveRunModelRef(run, swarm, env = process.env) {
2632
- const configured = parseModelRef(
2633
- pick2(run.model) ?? forKind(run.kind, swarm, pick2) ?? pick2(env.SWARM_DRONE_MODEL)
2634
- );
2860
+ const pinned = parseModelRef(pick2(run.model));
2861
+ if (pinned) return pinned;
2862
+ const configured = parseModelRef(forKind(run.kind, swarm, pick2) ?? pick2(env.SWARM_DRONE_MODEL));
2863
+ const own = providersFromEnv(env);
2864
+ if (own) {
2865
+ if (configured && own.includes(configured.providerId)) return configured;
2866
+ return { providerId: own[0], model: defaultModelFor(modelRoleOf(run.kind), own[0]) };
2867
+ }
2635
2868
  if (configured) return configured;
2636
2869
  const providerId = pick2(env.SWARM_MODEL_PROVIDER) ?? DEFAULT_PROVIDER_ID;
2637
2870
  return { providerId, model: defaultModelFor(modelRoleOf(run.kind), providerId) };
@@ -2678,21 +2911,24 @@ var init_executors = __esm({
2678
2911
  init_src();
2679
2912
  init_claudeCode();
2680
2913
  init_codex();
2914
+ init_grok();
2681
2915
  init_swarmModels();
2682
2916
  init_types2();
2683
2917
  init_claudeCode();
2684
2918
  init_codex();
2919
+ init_grok();
2685
2920
  DEFAULT_EXECUTOR_ID = "claude-code";
2686
2921
  EXECUTORS = {
2687
2922
  [claudeCodeExecutor.id]: claudeCodeExecutor,
2688
- [codexExecutor.id]: codexExecutor
2923
+ [codexExecutor.id]: codexExecutor,
2924
+ [grokExecutor.id]: grokExecutor
2689
2925
  };
2690
2926
  }
2691
2927
  });
2692
2928
 
2693
2929
  // src/config.ts
2694
- import { basename, join as join6, resolve } from "path";
2695
- import { readFileSync as readFileSync3, realpathSync, renameSync, writeFileSync as writeFileSync3 } from "fs";
2930
+ import { basename, join as join7, resolve } from "path";
2931
+ import { readFileSync as readFileSync3, realpathSync, renameSync, writeFileSync as writeFileSync4 } from "fs";
2696
2932
  function normalizeRepo(repo) {
2697
2933
  const r = (repo ?? "").trim();
2698
2934
  if (!r) return "";
@@ -2706,10 +2942,10 @@ function effectiveRepoOf(repo, fallback) {
2706
2942
  return normalizeRepo(repo || fallback || "");
2707
2943
  }
2708
2944
  function droneWorktreePath(worktreesDir, repo, slug) {
2709
- return join6(droneWorktreeRoot(worktreesDir, repo), slug);
2945
+ return join7(droneWorktreeRoot(worktreesDir, repo), slug);
2710
2946
  }
2711
2947
  function droneWorktreeRoot(worktreesDir, repo) {
2712
- return join6(worktreesDir, basename(normalizeRepo(repo)));
2948
+ return join7(worktreesDir, basename(normalizeRepo(repo)));
2713
2949
  }
2714
2950
  function resolveEffectiveWorktreesDir(deps) {
2715
2951
  if (deps.envOverride) return deps.envOverride;
@@ -2736,7 +2972,7 @@ function mcpEndpoint(api, path = TASKLESS_MCP_PATH) {
2736
2972
  }
2737
2973
  function tokenFromFile() {
2738
2974
  try {
2739
- return readFileSync3(join6(SWARM_HOME, "token"), "utf8").trim();
2975
+ return readFileSync3(join7(SWARM_HOME, "token"), "utf8").trim();
2740
2976
  } catch {
2741
2977
  return "";
2742
2978
  }
@@ -2749,25 +2985,25 @@ var init_config = __esm({
2749
2985
  init_executors();
2750
2986
  init_swarmHome();
2751
2987
  init_swarmHome();
2752
- DB_PATH = process.env.SWARM_DB || join6(SWARM_HOME, "swarm.db");
2988
+ DB_PATH = process.env.SWARM_DB || join7(SWARM_HOME, "swarm.db");
2753
2989
  EXECUTOR = resolveExecutor(process.env.SWARM_EXECUTOR);
2754
- DRONE_HOME = process.env.SWARM_DRONE_HOME || join6(SWARM_HOME, "drone-home");
2990
+ DRONE_HOME = process.env.SWARM_DRONE_HOME || join7(SWARM_HOME, "drone-home");
2755
2991
  DRONE_HOME_ISOLATION = process.env.SWARM_DRONE_ISOLATE_HOME !== "0" && process.platform !== "win32";
2756
2992
  DRONE_ISOLATION = DRONE_HOME_ISOLATION ? { home: DRONE_HOME, swarmHome: SWARM_HOME } : void 0;
2757
- WORKTREES_NOINDEX_DIR = join6(SWARM_HOME, "worktrees.noindex");
2758
- WORKTREES_LEGACY_DIR = join6(SWARM_HOME, "worktrees");
2993
+ WORKTREES_NOINDEX_DIR = join7(SWARM_HOME, "worktrees.noindex");
2994
+ WORKTREES_LEGACY_DIR = join7(SWARM_HOME, "worktrees");
2759
2995
  WORKTREES_DIR = process.env.SWARM_WORKTREES || WORKTREES_NOINDEX_DIR;
2760
- RUN_LOGS_DIR = process.env.SWARM_RUN_LOGS || join6(SWARM_HOME, "run-logs");
2761
- DAEMON_LOG_PATH = process.env.SWARM_DAEMON_LOG || join6(SWARM_HOME, "overmind.log");
2996
+ RUN_LOGS_DIR = process.env.SWARM_RUN_LOGS || join7(SWARM_HOME, "run-logs");
2997
+ DAEMON_LOG_PATH = process.env.SWARM_DAEMON_LOG || join7(SWARM_HOME, "overmind.log");
2762
2998
  DAEMON_LOG_MAX_BYTES = envNum("SWARM_DAEMON_LOG_MAX_BYTES", 16 * 1024 * 1024);
2763
2999
  DAEMON_LOG_KEEP = envNum("SWARM_DAEMON_LOG_KEEP", 2);
2764
3000
  DAEMON_LOG_CHECK_MS = envNum("SWARM_DAEMON_LOG_CHECK_MS", 6e4);
2765
3001
  DIST_BUILD = true;
2766
3002
  SWARM_BACKEND = process.env.SWARM_BACKEND === "client" ? "client" : process.env.SWARM_BACKEND === "sqlite" ? "sqlite" : DIST_BUILD ? "client" : "sqlite";
2767
- SWARM_OUTBOX = process.env.SWARM_OUTBOX || join6(SWARM_HOME, "outbox.jsonl");
3003
+ SWARM_OUTBOX = process.env.SWARM_OUTBOX || join7(SWARM_HOME, "outbox.jsonl");
2768
3004
  SWARM_MAX_IN_FLIGHT = Math.trunc(envNum("SWARM_MAX_IN_FLIGHT", 3));
2769
3005
  SWARM_CLAIM_INTERVAL_MS = envNum("SWARM_CLAIM_INTERVAL_MS", 6e4);
2770
- ENV_CACHE_DIR = process.env.SWARM_ENV_CACHE_DIR || join6(SWARM_HOME, "env-cache");
3006
+ ENV_CACHE_DIR = process.env.SWARM_ENV_CACHE_DIR || join7(SWARM_HOME, "env-cache");
2771
3007
  ENV_CACHE_ENABLED = process.env.SWARM_ENV_CACHE !== "0";
2772
3008
  ENV_CACHE_KEEP = Math.trunc(envNum("SWARM_ENV_CACHE_KEEP", 4));
2773
3009
  SWARM_MAX_LOAD_FACTOR = envNum("SWARM_MAX_LOAD_FACTOR", 0.9);
@@ -2797,15 +3033,15 @@ var init_config = __esm({
2797
3033
  DRONE_CHANNEL_ENABLED = process.env.SWARM_DRONE_CHANNEL !== "0";
2798
3034
  DRONE_CHANNEL_PORT = Number(process.env.SWARM_DRONE_CHANNEL_PORT) || 7421;
2799
3035
  DRONE_CHANNEL_URL = process.env.SWARM_DRONE_CHANNEL_URL || `http://127.0.0.1:${DRONE_CHANNEL_PORT}`;
2800
- DRONE_CHANNEL_SECRET_PATH = process.env.SWARM_DRONE_CHANNEL_SECRET || join6(SWARM_HOME, "drone-channel.key");
3036
+ DRONE_CHANNEL_SECRET_PATH = process.env.SWARM_DRONE_CHANNEL_SECRET || join7(SWARM_HOME, "drone-channel.key");
2801
3037
  DRONE_CHANNEL_GRACE_MS = envNum("SWARM_DRONE_CHANNEL_GRACE_MS", 12e4);
2802
- HEARTBEAT_PATH = process.env.SWARM_HEARTBEAT || join6(SWARM_HOME, "overmind.heartbeat");
3038
+ HEARTBEAT_PATH = process.env.SWARM_HEARTBEAT || join7(SWARM_HOME, "overmind.heartbeat");
2803
3039
  HEARTBEAT_STALE_MS = Number(process.env.SWARM_HEARTBEAT_STALE_MS) || 3e4;
2804
3040
  SWARM_REPO = process.env.SWARM_REPO || "";
2805
3041
  SWARM_SCAN_DEPTH = Number(process.env.SWARM_SCAN_DEPTH) || 3;
2806
3042
  SWARM_REPO_PATHS = (process.env.SWARM_REPOS || SWARM_REPO).split(",").map((s) => s.trim()).filter(Boolean);
2807
3043
  SWARM_SCAN_ROOTS_RAW = process.env.SWARM_SCAN_ROOTS || "";
2808
- REPO_MAP_PATH = process.env.SWARM_REPO_MAP || join6(SWARM_HOME, "repo-map.json");
3044
+ REPO_MAP_PATH = process.env.SWARM_REPO_MAP || join7(SWARM_HOME, "repo-map.json");
2809
3045
  SWARM_REPO_MAP_MS = envNum("SWARM_REPO_MAP_MS", 15 * 6e4);
2810
3046
  SWARM_REPO_SCAN_TTL_MS = envNum("SWARM_REPO_SCAN_TTL_MS", 24 * 60 * 6e4);
2811
3047
  TASKLESS_API = process.env.TASKLESS_API || "https://taskless.ru";
@@ -2820,7 +3056,7 @@ var init_config = __esm({
2820
3056
  SWARM_AUTO_REVIEW = process.env.SWARM_AUTO_REVIEW !== "0";
2821
3057
  SWARM_AUTO_VERIFY = process.env.SWARM_AUTO_VERIFY !== "0";
2822
3058
  SWARM_MERGE_QUEUE = process.env.SWARM_MERGE_QUEUE !== "0";
2823
- REVIEW_CUTOFF_PATH = process.env.SWARM_REVIEW_CUTOFF || join6(SWARM_HOME, "review-cutoff.json");
3059
+ REVIEW_CUTOFF_PATH = process.env.SWARM_REVIEW_CUTOFF || join7(SWARM_HOME, "review-cutoff.json");
2824
3060
  SWARM_REVIEW_CAP = Math.trunc(envNum("SWARM_REVIEW_CAP", 1));
2825
3061
  SWARM_STORM_URL = process.env.SWARM_STORM_URL || "";
2826
3062
  WEB_PORT = Number(process.env.SWARM_WEB_PORT) || 7420;
@@ -3148,8 +3384,8 @@ var init_store = __esm({
3148
3384
  });
3149
3385
 
3150
3386
  // src/agentToken.ts
3151
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, unlinkSync } from "fs";
3152
- import { join as join7 } from "path";
3387
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, unlinkSync } from "fs";
3388
+ import { join as join8 } from "path";
3153
3389
  function loadAgentToken() {
3154
3390
  try {
3155
3391
  const s = JSON.parse(readFileSync5(STORE_PATH, "utf8"));
@@ -3159,7 +3395,7 @@ function loadAgentToken() {
3159
3395
  }
3160
3396
  }
3161
3397
  function saveAgentToken(s) {
3162
- writeFileSync4(STORE_PATH, JSON.stringify(s, null, 2), { mode: 384 });
3398
+ writeFileSync5(STORE_PATH, JSON.stringify(s, null, 2), { mode: 384 });
3163
3399
  }
3164
3400
  function clearAgentToken() {
3165
3401
  try {
@@ -3230,7 +3466,7 @@ var init_agentToken = __esm({
3230
3466
  "src/agentToken.ts"() {
3231
3467
  "use strict";
3232
3468
  init_config();
3233
- STORE_PATH = join7(SWARM_HOME, "agent.json");
3469
+ STORE_PATH = join8(SWARM_HOME, "agent.json");
3234
3470
  base = (api) => api.replace(/\/$/, "");
3235
3471
  TOKEN_PROBE_TIMEOUT_MS = 8e3;
3236
3472
  }
@@ -3616,7 +3852,7 @@ var init_package = __esm({
3616
3852
  "package.json"() {
3617
3853
  package_default = {
3618
3854
  name: "@taskless-app/swarm",
3619
- version: "0.6.61",
3855
+ version: "0.6.63",
3620
3856
  type: "module",
3621
3857
  description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
3622
3858
  keywords: [
@@ -3667,7 +3903,7 @@ var init_package = __esm({
3667
3903
  execa: "^10.0.0",
3668
3904
  zod: "3.25.76"
3669
3905
  },
3670
- gitHead: "97838ed30c3fef4cc868c38d8fd9373635a3b48c"
3906
+ gitHead: "8d438b6288da036308528cff1160a157b4b64abd"
3671
3907
  };
3672
3908
  }
3673
3909
  });
@@ -3833,7 +4069,7 @@ var init_netTimeout = __esm({
3833
4069
 
3834
4070
  // src/droneChannel.ts
3835
4071
  import { createHmac, randomBytes, timingSafeEqual } from "crypto";
3836
- import { chmodSync as chmodSync2, mkdirSync as mkdirSync7, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
4072
+ import { chmodSync as chmodSync2, mkdirSync as mkdirSync8, readFileSync as readFileSync9, writeFileSync as writeFileSync8 } from "fs";
3837
4073
  import { dirname as dirname3 } from "path";
3838
4074
  import { serve } from "@hono/node-server";
3839
4075
  function loadChannelSecret(path) {
@@ -3843,8 +4079,8 @@ function loadChannelSecret(path) {
3843
4079
  } catch {
3844
4080
  }
3845
4081
  const secret = randomBytes(32).toString("hex");
3846
- mkdirSync7(dirname3(path), { recursive: true });
3847
- writeFileSync7(path, secret, { mode: 384 });
4082
+ mkdirSync8(dirname3(path), { recursive: true });
4083
+ writeFileSync8(path, secret, { mode: 384 });
3848
4084
  try {
3849
4085
  chmodSync2(path, 384);
3850
4086
  } catch {
@@ -3921,8 +4157,8 @@ var init_authState = __esm({
3921
4157
 
3922
4158
  // src/oauth.ts
3923
4159
  import { createHash, randomBytes as randomBytes2 } from "crypto";
3924
- import { readFileSync as readFileSync10, writeFileSync as writeFileSync8, unlinkSync as unlinkSync3 } from "fs";
3925
- import { join as join12 } from "path";
4160
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync9, unlinkSync as unlinkSync3 } from "fs";
4161
+ import { join as join13 } from "path";
3926
4162
  function makePkce() {
3927
4163
  const verifier = randomBytes2(48).toString("base64url");
3928
4164
  const challenge = createHash("sha256").update(verifier).digest("base64url");
@@ -4012,7 +4248,7 @@ function loadStore() {
4012
4248
  }
4013
4249
  }
4014
4250
  function saveStore(s) {
4015
- writeFileSync8(STORE_PATH2, JSON.stringify(s, null, 2), { mode: 384 });
4251
+ writeFileSync9(STORE_PATH2, JSON.stringify(s, null, 2), { mode: 384 });
4016
4252
  }
4017
4253
  function clearStore() {
4018
4254
  try {
@@ -4031,7 +4267,7 @@ async function ensureClientId(api, redirectUri, fetchFn = fetch) {
4031
4267
  const existing = loadClientId();
4032
4268
  if (existing) return existing;
4033
4269
  const clientId = await registerClient({ api, redirectUri }, fetchFn);
4034
- writeFileSync8(CLIENT_PATH, JSON.stringify({ clientId }, null, 2), { mode: 384 });
4270
+ writeFileSync9(CLIENT_PATH, JSON.stringify({ clientId }, null, 2), { mode: 384 });
4035
4271
  return clientId;
4036
4272
  }
4037
4273
  async function ensureAccess(store, opts = {}) {
@@ -4057,16 +4293,16 @@ var init_oauth = __esm({
4057
4293
  AUTHORIZE = "/api/oauth/authorize";
4058
4294
  TOKEN = "/api/oauth/token";
4059
4295
  SCOPE = "openid profile email taskless:full";
4060
- STORE_PATH2 = join12(SWARM_HOME, "oauth.json");
4061
- CLIENT_PATH = join12(SWARM_HOME, "oauth-client.json");
4296
+ STORE_PATH2 = join13(SWARM_HOME, "oauth.json");
4297
+ CLIENT_PATH = join13(SWARM_HOME, "oauth-client.json");
4062
4298
  base2 = (api) => api.replace(/\/$/, "");
4063
4299
  }
4064
4300
  });
4065
4301
 
4066
4302
  // src/git.ts
4067
- import { existsSync as existsSync10, readdirSync as readdirSync9, realpathSync as realpathSync2, statSync as statSync9 } from "fs";
4303
+ import { existsSync as existsSync11, readdirSync as readdirSync10, realpathSync as realpathSync2, statSync as statSync10 } from "fs";
4068
4304
  import { appendFile, chmod, mkdir, readFile, rename, rm, writeFile } from "fs/promises";
4069
- import { isAbsolute, join as join15, resolve as resolve2, sep as sep2 } from "path";
4305
+ import { isAbsolute, join as join16, resolve as resolve2, sep as sep2 } from "path";
4070
4306
  import { $ as $5 } from "execa";
4071
4307
  function gitNet(repo, args, timeoutMs) {
4072
4308
  return withHardTimeout(
@@ -4080,14 +4316,14 @@ async function reclaimStaleWorktree(repo, worktree) {
4080
4316
  await detachWorktree(repo, worktree);
4081
4317
  }
4082
4318
  async function inspectWorktreePath(path) {
4083
- if (!existsSync10(path)) return "free";
4319
+ if (!existsSync11(path)) return "free";
4084
4320
  try {
4085
- if (readdirSync9(path).length === 0) return "free";
4321
+ if (readdirSync10(path).length === 0) return "free";
4086
4322
  } catch {
4087
4323
  return "orphan";
4088
4324
  }
4089
4325
  try {
4090
- if (statSync9(join15(path, ".git")).isDirectory()) return "main-checkout";
4326
+ if (statSync10(join16(path, ".git")).isDirectory()) return "main-checkout";
4091
4327
  } catch {
4092
4328
  }
4093
4329
  const top = await $5({ reject: false })`git -C ${path} rev-parse --show-toplevel`;
@@ -4126,7 +4362,7 @@ async function clearWorktreePath(repo, path, branch, opts = {}) {
4126
4362
  await detachWorktree(repo, path);
4127
4363
  opts.onStaleReclaim?.(path);
4128
4364
  }
4129
- if (!existsSync10(path)) return;
4365
+ if (!existsSync11(path)) return;
4130
4366
  await parkOrphanDir(repo, path, branch);
4131
4367
  }
4132
4368
  async function parkOrphanDir(repo, path, branch) {
@@ -4147,7 +4383,7 @@ async function parkOrphanDir(repo, path, branch) {
4147
4383
  }
4148
4384
  function isLinkedWorktree(dir) {
4149
4385
  try {
4150
- return statSync9(join15(dir, ".git")).isFile();
4386
+ return statSync10(join16(dir, ".git")).isFile();
4151
4387
  } catch {
4152
4388
  return false;
4153
4389
  }
@@ -4159,7 +4395,7 @@ async function detachWorktree(repo, worktree) {
4159
4395
  }
4160
4396
  }
4161
4397
  async function ensureWorktreeDirGone(worktree) {
4162
- if (!existsSync10(worktree)) return false;
4398
+ if (!existsSync11(worktree)) return false;
4163
4399
  if (!isLinkedWorktree(worktree)) {
4164
4400
  console.error(
4165
4401
  `[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.`
@@ -4174,7 +4410,7 @@ async function ensureWorktreeDirGone(worktree) {
4174
4410
  );
4175
4411
  return true;
4176
4412
  }
4177
- if (existsSync10(worktree)) {
4413
+ if (existsSync11(worktree)) {
4178
4414
  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.`);
4179
4415
  }
4180
4416
  return true;
@@ -4223,7 +4459,7 @@ async function checkoutWorktree(repo, path, branch, opts) {
4223
4459
  }
4224
4460
  const busyAt = await worktreeForBranch(repo, branch);
4225
4461
  if (busyAt) {
4226
- const exists = existsSync10(busyAt);
4462
+ const exists = existsSync11(busyAt);
4227
4463
  const live = exists && (opts.isWorktreeHeldLive ? await opts.isWorktreeHeldLive(busyAt) : true);
4228
4464
  if (live) throw new WorktreeBusyError(branch, busyAt);
4229
4465
  if (exists && await worktreeDirty(busyAt)) throw new WorktreeBusyError(branch, busyAt);
@@ -4254,8 +4490,8 @@ async function ensureGitExcluded(worktree, pattern) {
4254
4490
  try {
4255
4491
  const commonDir = await gitPath(worktree, "--git-common-dir");
4256
4492
  if (!commonDir) return false;
4257
- const infoDir = join15(commonDir, "info");
4258
- const excludeFile = join15(infoDir, "exclude");
4493
+ const infoDir = join16(commonDir, "info");
4494
+ const excludeFile = join16(infoDir, "exclude");
4259
4495
  let current = "";
4260
4496
  try {
4261
4497
  current = await readFile(excludeFile, "utf8");
@@ -4275,7 +4511,7 @@ async function gitPath(worktree, flag) {
4275
4511
  const out = await $5({ reject: false })`git -C ${worktree} rev-parse ${flag}`;
4276
4512
  const raw = out.stdout.trim();
4277
4513
  if (out.exitCode !== 0 || !raw) return null;
4278
- return isAbsolute(raw) ? raw : join15(worktree, raw);
4514
+ return isAbsolute(raw) ? raw : join16(worktree, raw);
4279
4515
  }
4280
4516
  async function ensureWorktreeHygiene(worktree) {
4281
4517
  for (const pattern of SWARM_EXCLUDE_PATTERNS) await ensureGitExcluded(worktree, pattern);
@@ -4285,12 +4521,12 @@ async function installGuardHooks(worktree) {
4285
4521
  try {
4286
4522
  const gitDir = await gitPath(worktree, "--git-dir");
4287
4523
  if (!gitDir) return false;
4288
- const hooksDir = join15(gitDir, "swarm-hooks");
4524
+ const hooksDir = join16(gitDir, "swarm-hooks");
4289
4525
  const prev = await previousHooksPath(worktree);
4290
4526
  await mkdir(hooksDir, { recursive: true });
4291
4527
  for (const hook of GUARD_HOOKS) {
4292
- await writeFile(join15(hooksDir, hook), guardHookScript(hook, prev ? `${posix(prev)}/${hook}` : null));
4293
- await chmod(join15(hooksDir, hook), 493);
4528
+ await writeFile(join16(hooksDir, hook), guardHookScript(hook, prev ? `${posix(prev)}/${hook}` : null));
4529
+ await chmod(join16(hooksDir, hook), 493);
4294
4530
  }
4295
4531
  await $5`git -C ${worktree} config extensions.worktreeConfig true`;
4296
4532
  await $5`git -C ${worktree} config --worktree core.hooksPath ${posix(hooksDir)}`;
@@ -4309,7 +4545,7 @@ async function previousHooksPath(worktree) {
4309
4545
  if (out.exitCode === 0 && value) return value;
4310
4546
  }
4311
4547
  const commonDir = await gitPath(worktree, "--git-common-dir");
4312
- return commonDir ? join15(commonDir, "hooks") : null;
4548
+ return commonDir ? join16(commonDir, "hooks") : null;
4313
4549
  }
4314
4550
  async function removeWorktree(repo, path) {
4315
4551
  const branch = (await $5({ reject: false })`git -C ${path} symbolic-ref --quiet --short HEAD`).stdout.trim();
@@ -4372,7 +4608,7 @@ var init_git = __esm({
4372
4608
 
4373
4609
  // src/attachments.ts
4374
4610
  import { mkdir as mkdir2, rm as rm2, writeFile as writeFile2 } from "fs/promises";
4375
- import { join as join16 } from "path";
4611
+ import { join as join17 } from "path";
4376
4612
  var ATTACHMENTS_DIR, ATTACH_MAX_TOTAL_BYTES, ATTACH_MAX_FILE_BYTES, IMAGE_EXT, DOC_EXT, TEXT_EXT, KNOWN_EXT;
4377
4613
  var init_attachments = __esm({
4378
4614
  "src/attachments.ts"() {
@@ -4391,7 +4627,7 @@ var init_attachments = __esm({
4391
4627
 
4392
4628
  // src/shotUpload.ts
4393
4629
  import { readFile as fsReadFile } from "fs/promises";
4394
- import { basename as basename5, isAbsolute as isAbsolute2, join as join17 } from "path";
4630
+ import { basename as basename5, isAbsolute as isAbsolute2, join as join18 } from "path";
4395
4631
  var SHOT_MAX_FILE_BYTES;
4396
4632
  var init_shotUpload = __esm({
4397
4633
  "src/shotUpload.ts"() {
@@ -4401,8 +4637,8 @@ var init_shotUpload = __esm({
4401
4637
  });
4402
4638
 
4403
4639
  // src/workspace.ts
4404
- import { readFileSync as readFileSync11, writeFileSync as writeFileSync9, unlinkSync as unlinkSync4 } from "fs";
4405
- import { join as join18 } from "path";
4640
+ import { readFileSync as readFileSync11, writeFileSync as writeFileSync10, unlinkSync as unlinkSync4 } from "fs";
4641
+ import { join as join19 } from "path";
4406
4642
  function loadWorkspace() {
4407
4643
  try {
4408
4644
  const w = JSON.parse(readFileSync11(WORKSPACE_PATH, "utf8"));
@@ -4412,7 +4648,7 @@ function loadWorkspace() {
4412
4648
  }
4413
4649
  }
4414
4650
  function saveWorkspace(w) {
4415
- writeFileSync9(WORKSPACE_PATH, JSON.stringify(w, null, 2), { mode: 384 });
4651
+ writeFileSync10(WORKSPACE_PATH, JSON.stringify(w, null, 2), { mode: 384 });
4416
4652
  }
4417
4653
  function clearWorkspace() {
4418
4654
  try {
@@ -4428,7 +4664,7 @@ var init_workspace = __esm({
4428
4664
  "src/workspace.ts"() {
4429
4665
  "use strict";
4430
4666
  init_config();
4431
- WORKSPACE_PATH = join18(SWARM_HOME, "workspace.json");
4667
+ WORKSPACE_PATH = join19(SWARM_HOME, "workspace.json");
4432
4668
  }
4433
4669
  });
4434
4670
 
@@ -4846,13 +5082,13 @@ var init_daemonLink = __esm({
4846
5082
  });
4847
5083
 
4848
5084
  // src/pauseState.ts
4849
- import { existsSync as existsSync11, readFileSync as readFileSync12, renameSync as renameSync5, unlinkSync as unlinkSync5, writeFileSync as writeFileSync10 } from "fs";
4850
- import { join as join19 } from "path";
5085
+ import { existsSync as existsSync12, readFileSync as readFileSync12, renameSync as renameSync5, unlinkSync as unlinkSync5, writeFileSync as writeFileSync11 } from "fs";
5086
+ import { join as join20 } from "path";
4851
5087
  function pauseStatePath(home) {
4852
- return join19(home, "pause.json");
5088
+ return join20(home, "pause.json");
4853
5089
  }
4854
5090
  function loadPauseState(home, io = {}) {
4855
- const exists = io.exists ?? existsSync11;
5091
+ const exists = io.exists ?? existsSync12;
4856
5092
  const readFile2 = io.readFile ?? ((p) => readFileSync12(p, "utf8"));
4857
5093
  const path = pauseStatePath(home);
4858
5094
  if (!exists(path)) return ACTIVE;
@@ -4872,12 +5108,12 @@ function loadPauseState(home, io = {}) {
4872
5108
  function savePauseState(home, state, io = {}) {
4873
5109
  const path = pauseStatePath(home);
4874
5110
  if (!state.paused) {
4875
- const remove = io.remove ?? ((p) => existsSync11(p) && unlinkSync5(p));
5111
+ const remove = io.remove ?? ((p) => existsSync12(p) && unlinkSync5(p));
4876
5112
  remove(path);
4877
5113
  return;
4878
5114
  }
4879
5115
  const writeFile3 = io.writeFile ?? ((p, data) => {
4880
- writeFileSync10(`${p}.tmp`, data);
5116
+ writeFileSync11(`${p}.tmp`, data);
4881
5117
  renameSync5(`${p}.tmp`, p);
4882
5118
  });
4883
5119
  writeFile3(path, JSON.stringify(state, null, 2));
@@ -4914,7 +5150,7 @@ var init_pauseState = __esm({
4914
5150
  });
4915
5151
 
4916
5152
  // src/heartbeat.ts
4917
- import { readFileSync as readFileSync13, renameSync as renameSync6, writeFileSync as writeFileSync11 } from "fs";
5153
+ import { readFileSync as readFileSync13, renameSync as renameSync6, writeFileSync as writeFileSync12 } from "fs";
4918
5154
  function readHeartbeat(path) {
4919
5155
  try {
4920
5156
  const ms = Number(readFileSync13(path, "utf8").trim());
@@ -4936,7 +5172,7 @@ __export(db_exports, {
4936
5172
  });
4937
5173
  import { createRequire as createRequire2 } from "module";
4938
5174
  import { randomUUID as randomUUID3 } from "crypto";
4939
- import { existsSync as existsSync12 } from "fs";
5175
+ import { existsSync as existsSync13 } from "fs";
4940
5176
  import { resolve as resolve3 } from "path";
4941
5177
  function rowToQuestion(row) {
4942
5178
  return {
@@ -5018,6 +5254,8 @@ function rowToRun(row) {
5018
5254
  // базовая ветка PR (TASWM-285); null → дефолтная
5019
5255
  workspace_id: row.workspace_id ?? null,
5020
5256
  // воркспейс задачи прогона (TASWM-288); null → глобальный пин
5257
+ // TASWM-597: repoless-прогон (офлайн-проект, без worktree/PR). null/0 → код-конвейер.
5258
+ repoless: row.repoless === 1,
5021
5259
  created_at: row.created_at,
5022
5260
  updated_at: row.updated_at
5023
5261
  };
@@ -5089,6 +5327,7 @@ CREATE TABLE IF NOT EXISTS runs (
5089
5327
  priority INTEGER NOT NULL DEFAULT 0,
5090
5328
  base_branch TEXT,
5091
5329
  workspace_id TEXT,
5330
+ repoless INTEGER,
5092
5331
  created_at TEXT NOT NULL DEFAULT (datetime('now')),
5093
5332
  updated_at TEXT NOT NULL DEFAULT (datetime('now'))
5094
5333
  );
@@ -5186,6 +5425,8 @@ CREATE TABLE IF NOT EXISTS imports (
5186
5425
  "ALTER TABLE runs ADD COLUMN base_branch TEXT",
5187
5426
  // Воркспейс задачи прогона (TASWM-288): им пинятся задачные MCP-вызовы прогона.
5188
5427
  "ALTER TABLE runs ADD COLUMN workspace_id TEXT",
5428
+ // TASWM-597: repoless-прогон — задача офлайн-проекта, спавн без worktree/ветки/PR.
5429
+ "ALTER TABLE runs ADD COLUMN repoless INTEGER",
5189
5430
  // Чем обошёлся прогон, кроме денег (TASWM-353): токены вход/выход и время работы.
5190
5431
  "ALTER TABLE runs ADD COLUMN tokens_in INTEGER NOT NULL DEFAULT 0",
5191
5432
  "ALTER TABLE runs ADD COLUMN tokens_out INTEGER NOT NULL DEFAULT 0",
@@ -5362,6 +5603,7 @@ CREATE TABLE IF NOT EXISTS imports (
5362
5603
  const arr = v;
5363
5604
  return arr && arr.length ? JSON.stringify(arr) : null;
5364
5605
  }
5606
+ if (f === "repoless") return v === true ? 1 : v === false ? 0 : null;
5365
5607
  if (f === "area" && typeof v === "string") return normalizeZoneLabel(v) || null;
5366
5608
  return v;
5367
5609
  });
@@ -5594,7 +5836,7 @@ CREATE TABLE IF NOT EXISTS imports (
5594
5836
  const repoN = normalizeRepo(repo);
5595
5837
  const already = this.db.prepare("SELECT run_count FROM imports WHERE source = ?").get(abs);
5596
5838
  if (already) return { imported: false, runs: already.run_count };
5597
- if (!existsSync12(abs)) throw new Error(`import-db: \u0444\u0430\u0439\u043B\u0430 \u043D\u0435\u0442: ${abs}`);
5839
+ if (!existsSync13(abs)) throw new Error(`import-db: \u0444\u0430\u0439\u043B\u0430 \u043D\u0435\u0442: ${abs}`);
5598
5840
  const src = new this.databaseCtor(abs);
5599
5841
  try {
5600
5842
  const runs = src.prepare("SELECT * FROM runs ORDER BY id").all();
@@ -5922,8 +6164,8 @@ CREATE TABLE IF NOT EXISTS imports (
5922
6164
  });
5923
6165
 
5924
6166
  // src/repoScan.ts
5925
- import { readdirSync as readdirSync10, readFileSync as readFileSync14, statSync as statSync10 } from "fs";
5926
- import { join as join20 } from "path";
6167
+ import { readdirSync as readdirSync11, readFileSync as readFileSync14, statSync as statSync11 } from "fs";
6168
+ import { join as join21 } from "path";
5927
6169
  var init_repoScan = __esm({
5928
6170
  "src/repoScan.ts"() {
5929
6171
  "use strict";
@@ -5933,8 +6175,8 @@ var init_repoScan = __esm({
5933
6175
 
5934
6176
  // src/repoDiscovery.ts
5935
6177
  import { homedir as homedir6 } from "os";
5936
- import { readFileSync as readFileSync15, renameSync as renameSync7, writeFileSync as writeFileSync12 } from "fs";
5937
- import { isAbsolute as isAbsolute3, join as join21, resolve as resolve4 } from "path";
6178
+ import { readFileSync as readFileSync15, renameSync as renameSync7, writeFileSync as writeFileSync13 } from "fs";
6179
+ import { isAbsolute as isAbsolute3, join as join22, resolve as resolve4 } from "path";
5938
6180
  function repoMapLines(rows) {
5939
6181
  if (!rows?.length) return [];
5940
6182
  const missing = rows.filter((r) => !r.path).length;
@@ -6325,10 +6567,10 @@ __export(statusCli_exports, {
6325
6567
  probeLink: () => probeLink,
6326
6568
  runStatusCli: () => runStatusCli
6327
6569
  });
6328
- import { existsSync as existsSync13, readFileSync as readFileSync16 } from "fs";
6570
+ import { existsSync as existsSync14, readFileSync as readFileSync16 } from "fs";
6329
6571
  function outboxPending(path) {
6330
6572
  try {
6331
- if (!existsSync13(path)) return 0;
6573
+ if (!existsSync14(path)) return 0;
6332
6574
  return readFileSync16(path, "utf8").split("\n").filter((l) => l.trim()).length;
6333
6575
  } catch {
6334
6576
  return null;
@@ -6536,8 +6778,8 @@ var init_prodMergeGate = __esm({
6536
6778
  });
6537
6779
 
6538
6780
  // src/platform.ts
6539
- import { existsSync as existsSync14, readFileSync as readFileSync17 } from "fs";
6540
- import { delimiter, join as join22 } from "path";
6781
+ import { existsSync as existsSync15, readFileSync as readFileSync17 } from "fs";
6782
+ import { delimiter, join as join23 } from "path";
6541
6783
  function safeReadText(path) {
6542
6784
  try {
6543
6785
  return readFileSync17(path, "utf8");
@@ -6546,13 +6788,13 @@ function safeReadText(path) {
6546
6788
  }
6547
6789
  }
6548
6790
  function resolveCommandPath(name, env = process.env, platform = process.platform) {
6549
- if (name.includes("/") || name.includes("\\")) return existsSync14(name) ? name : null;
6791
+ if (name.includes("/") || name.includes("\\")) return existsSync15(name) ? name : null;
6550
6792
  const dirs = (env.PATH ?? env.Path ?? "").split(delimiter).filter(Boolean);
6551
6793
  const exts = platform === "win32" ? (env.PATHEXT ?? ".EXE;.CMD;.BAT").split(";").filter(Boolean) : [""];
6552
6794
  for (const dir of dirs) {
6553
6795
  for (const ext of exts) {
6554
- const candidate = join22(dir, name + ext);
6555
- if (existsSync14(candidate)) return candidate;
6796
+ const candidate = join23(dir, name + ext);
6797
+ if (existsSync15(candidate)) return candidate;
6556
6798
  }
6557
6799
  }
6558
6800
  return null;
@@ -6655,13 +6897,13 @@ var init_platform = __esm({
6655
6897
  });
6656
6898
 
6657
6899
  // src/envGate.ts
6658
- import { existsSync as existsSync15 } from "fs";
6659
- import { join as join23 } from "path";
6900
+ import { existsSync as existsSync16 } from "fs";
6901
+ import { join as join24 } from "path";
6660
6902
  import { createConnection } from "net";
6661
6903
  import { execa as execa3 } from "execa";
6662
6904
  function detectRequirements(repo, io = {}) {
6663
- const exists = io.exists ?? existsSync15;
6664
- const marker = COMPOSE_MARKERS.find((f) => exists(join23(repo, f)));
6905
+ const exists = io.exists ?? existsSync16;
6906
+ const marker = COMPOSE_MARKERS.find((f) => exists(join24(repo, f)));
6665
6907
  return marker ? [{ kind: "docker", raw: `docker (\u0434\u0435\u0442\u0435\u043A\u0442: ${marker})` }] : [];
6666
6908
  }
6667
6909
  async function dockerAlive() {
@@ -6693,7 +6935,7 @@ var init_envGate = __esm({
6693
6935
  });
6694
6936
 
6695
6937
  // src/doctor.ts
6696
- import { isAbsolute as isAbsolute4, join as join24 } from "path";
6938
+ import { isAbsolute as isAbsolute4, join as join25 } from "path";
6697
6939
  function ok(id, title, detail) {
6698
6940
  return { id, title, status: "ok", detail, remedies: [], critical: false };
6699
6941
  }
@@ -6718,12 +6960,14 @@ function checkExecutor(io, executor = resolveExecutor()) {
6718
6960
  const bin = executor.resolveBin();
6719
6961
  const where = /[/\\]/.test(bin) ? `\u043D\u0430\u0439\u0434\u0435\u043D: ${bin}` : "\u043D\u0430\u0439\u0434\u0435\u043D \u0432 PATH";
6720
6962
  if (io.hasCommand(bin)) return ok("claude", executor.title, where);
6963
+ const custom = executor.install.command == null ? null : io.platform.kind === "windows" && executor.install.windowsCommand ? executor.install.windowsCommand : executor.install.command;
6721
6964
  const remedies = [
6722
6965
  {
6723
6966
  what: executor.install.what,
6724
- command: globalInstallCommand(io.globalPm === "sources" ? "npm" : io.globalPm, executor.install.pkg),
6967
+ command: custom ?? globalInstallCommand(io.globalPm === "sources" ? "npm" : io.globalPm, executor.install.pkg),
6725
6968
  sudo: false,
6726
- auto: true
6969
+ // Свой инсталлер (не npm-пакет) человек ставит сам: автозапуск скрипта с сайта — нет.
6970
+ auto: custom == null
6727
6971
  }
6728
6972
  ];
6729
6973
  const detail = io.platform.kind === "windows" ? `\u0432 PATH \u043D\u0435\u0442 \`${bin}\`. \u041D\u0430 Windows spawn \u0438\u0449\u0435\u0442 \u0444\u0430\u0439\u043B \u043F\u043E PATHEXT \u2014 bash-\u043E\u0431\u0451\u0440\u0442\u043A\u0430 \u0431\u0435\u0437 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F \u0435\u043C\u0443 \u043D\u0435 \u0432\u0438\u0434\u043D\u0430; \u043D\u0435\u0441\u0442\u0430\u043D\u0434\u0430\u0440\u0442\u043D\u0430\u044F \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430 \u0437\u0430\u0434\u0430\u0451\u0442\u0441\u044F ${executor.binEnv}` : `\u0432 PATH \u043D\u0435\u0442 \`${bin}\` \u2014 \u0434\u0440\u043E\u043D\u0443 \u043D\u0435\u0447\u0435\u043C \u043F\u0438\u0441\u0430\u0442\u044C \u043A\u043E\u0434`;
@@ -6900,7 +7144,7 @@ function checkRepos(io, snap) {
6900
7144
  critical: true
6901
7145
  };
6902
7146
  }
6903
- if (env && !io.exists(join24(env, ".git"))) {
7147
+ if (env && !io.exists(join25(env, ".git"))) {
6904
7148
  return {
6905
7149
  id: "repos",
6906
7150
  title,
@@ -6910,7 +7154,7 @@ function checkRepos(io, snap) {
6910
7154
  critical: true
6911
7155
  };
6912
7156
  }
6913
- const broken = snap.paths.filter((p) => !io.exists(join24(p, ".git")));
7157
+ const broken = snap.paths.filter((p) => !io.exists(join25(p, ".git")));
6914
7158
  if (broken.length) {
6915
7159
  return {
6916
7160
  id: "repos",
@@ -7100,12 +7344,12 @@ var init_doctor = __esm({
7100
7344
  });
7101
7345
 
7102
7346
  // src/repoMemory.ts
7103
- import { readFileSync as readFileSync18, writeFileSync as writeFileSync13 } from "fs";
7104
- import { join as join25 } from "path";
7347
+ import { readFileSync as readFileSync18, writeFileSync as writeFileSync14 } from "fs";
7348
+ import { join as join26 } from "path";
7105
7349
  function loadRememberedRepos(home) {
7106
7350
  let raw;
7107
7351
  try {
7108
- raw = readFileSync18(join25(home, FILE), "utf8");
7352
+ raw = readFileSync18(join26(home, FILE), "utf8");
7109
7353
  } catch {
7110
7354
  return [];
7111
7355
  }
@@ -7141,7 +7385,7 @@ __export(installCli_exports, {
7141
7385
  runInstallHookCli: () => runInstallHookCli,
7142
7386
  shortenError: () => shortenError
7143
7387
  });
7144
- import { existsSync as existsSync16 } from "fs";
7388
+ import { existsSync as existsSync17 } from "fs";
7145
7389
  function classifyChromiumError(message) {
7146
7390
  if (/playwright-core не установлен|Cannot find (module|package)/i.test(message)) return "no-module";
7147
7391
  if (/error while loading shared libraries|cannot open shared object file|missing dependencies|\blib[\w.+-]*\.so[.\d]*\b/i.test(message)) return "no-libs";
@@ -7196,7 +7440,7 @@ function defaultDoctorIO(packageVersion) {
7196
7440
  packageVersion,
7197
7441
  entry,
7198
7442
  hasCommand: (name) => hasCommandInPath(name),
7199
- exists: existsSync16,
7443
+ exists: existsSync17,
7200
7444
  run: (command) => runQuiet(command),
7201
7445
  latestVersion: () => latestMemo ??= fetchLatestVersion(),
7202
7446
  probeChromium: () => probeChromium(),
@@ -7424,8 +7668,8 @@ var init_updateCli = __esm({
7424
7668
 
7425
7669
  // src/cli.ts
7426
7670
  init_cliIo();
7427
- import { basename as basename6, dirname as dirname5, join as join26 } from "path";
7428
- import { existsSync as existsSync17, readFileSync as readFileSync19, writeFileSync as writeFileSync14, mkdirSync as mkdirSync10, readdirSync as readdirSync11, statSync as statSync11, openSync as openSync4, readSync as readSync2, closeSync as closeSync4 } from "fs";
7671
+ import { basename as basename6, dirname as dirname5, join as join27 } from "path";
7672
+ import { existsSync as existsSync18, readFileSync as readFileSync19, writeFileSync as writeFileSync15, mkdirSync as mkdirSync11, readdirSync as readdirSync12, statSync as statSync12, openSync as openSync4, readSync as readSync2, closeSync as closeSync4 } from "fs";
7429
7673
  import { setTimeout as sleep2 } from "timers/promises";
7430
7674
 
7431
7675
  // src/swarmClient.ts
@@ -7433,7 +7677,7 @@ init_config();
7433
7677
  init_resources();
7434
7678
  init_names2();
7435
7679
  init_storm();
7436
- import { appendFileSync, existsSync as existsSync6, mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
7680
+ import { appendFileSync, existsSync as existsSync7, mkdirSync as mkdirSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "fs";
7437
7681
  import { dirname as dirname2 } from "path";
7438
7682
  import { randomUUID } from "crypto";
7439
7683
 
@@ -7466,24 +7710,24 @@ init_store();
7466
7710
  init_toolFailure();
7467
7711
 
7468
7712
  // src/logTail.ts
7469
- import { closeSync, existsSync as existsSync5, openSync, readSync, readdirSync as readdirSync6, statSync as statSync5 } from "fs";
7470
- import { join as join9 } from "path";
7713
+ import { closeSync, existsSync as existsSync6, openSync, readSync, readdirSync as readdirSync7, statSync as statSync6 } from "fs";
7714
+ import { join as join10 } from "path";
7471
7715
 
7472
7716
  // src/runLogDir.ts
7473
- import { existsSync as existsSync4, mkdirSync as mkdirSync5, readdirSync as readdirSync5, renameSync as renameSync2, statSync as statSync4 } from "fs";
7474
- import { join as join8 } from "path";
7717
+ import { existsSync as existsSync5, mkdirSync as mkdirSync6, readdirSync as readdirSync6, renameSync as renameSync2, statSync as statSync5 } from "fs";
7718
+ import { join as join9 } from "path";
7475
7719
  function runLogDirName(runLogKey) {
7476
7720
  const safe = runLogKey.replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^[-_]+|[-_]+$/g, "");
7477
7721
  if (!safe) throw new Error(`\u043A\u043B\u044E\u0447 \u043F\u0440\u043E\u0433\u043E\u043D\u0430 \u043D\u0435 \u0433\u043E\u0434\u0438\u0442\u0441\u044F \u0432 \u0438\u043C\u044F \u043A\u0430\u0442\u0430\u043B\u043E\u0433\u0430 run-log'\u043E\u0432: ${JSON.stringify(runLogKey)}`);
7478
7722
  return /^\d+$/.test(safe) ? `k-${safe}` : safe;
7479
7723
  }
7480
7724
  function runLogDirPath(runLogsDir, runLogKey) {
7481
- return join8(runLogsDir, runLogDirName(runLogKey));
7725
+ return join9(runLogsDir, runLogDirName(runLogKey));
7482
7726
  }
7483
7727
  function findRunLogDir(runLogsDir, keys) {
7484
7728
  for (const key of keys) {
7485
7729
  const dir = runLogDirPath(runLogsDir, key);
7486
- if (existsSync4(dir)) return dir;
7730
+ if (existsSync5(dir)) return dir;
7487
7731
  }
7488
7732
  return null;
7489
7733
  }
@@ -7689,25 +7933,25 @@ var SwarmClient = class _SwarmClient {
7689
7933
  this.repoFullNames = registry.map((e) => e.repoFullName);
7690
7934
  this.repoPathByFullName = new Map(registry.map((e) => [e.repoFullName, normalizeRepo(e.path)]));
7691
7935
  this.host = opts.host ?? null;
7692
- this.repoExists = opts.repoExists ?? existsSync6;
7936
+ this.repoExists = opts.repoExists ?? existsSync7;
7693
7937
  this.questionSyncMs = opts.questionSyncMs ?? 3e3;
7694
7938
  this.executorId = opts.executorId ?? EXECUTOR.id;
7695
7939
  this.outboxPath = opts.outboxPath;
7696
7940
  this.mapPath = `${opts.outboxPath}.prodmap.json`;
7697
7941
  this.stormPath = `${opts.outboxPath}.storm.jsonl`;
7698
- mkdirSync6(dirname2(this.outboxPath), { recursive: true });
7942
+ mkdirSync7(dirname2(this.outboxPath), { recursive: true });
7699
7943
  this.recover();
7700
7944
  }
7701
7945
  // ── рестарт: поднять outbox (незаписанные операции) и карту runKey→prodId ─────
7702
7946
  recover() {
7703
- if (existsSync6(this.mapPath)) {
7947
+ if (existsSync7(this.mapPath)) {
7704
7948
  try {
7705
7949
  const obj = JSON.parse(readFileSync6(this.mapPath, "utf8"));
7706
7950
  for (const [k, v] of Object.entries(obj)) this.prodIdByKey.set(k, v);
7707
7951
  } catch {
7708
7952
  }
7709
7953
  }
7710
- if (existsSync6(this.outboxPath)) {
7954
+ if (existsSync7(this.outboxPath)) {
7711
7955
  const txt = readFileSync6(this.outboxPath, "utf8");
7712
7956
  for (const line of txt.split("\n")) {
7713
7957
  const s = line.trim();
@@ -7728,7 +7972,7 @@ var SwarmClient = class _SwarmClient {
7728
7972
  // eventsLog ПЕРВЫМИ (до hydrate), в порядке файла (= хронологический); id
7729
7973
  // переприсваиваем локально (id событий — только порядок, не корреляция с продом).
7730
7974
  replayGlobalEvents() {
7731
- if (!existsSync6(this.stormPath)) return;
7975
+ if (!existsSync7(this.stormPath)) return;
7732
7976
  let txt;
7733
7977
  try {
7734
7978
  txt = readFileSync6(this.stormPath, "utf8");
@@ -8728,7 +8972,7 @@ var SwarmClient = class _SwarmClient {
8728
8972
  * транзиентным сбоем ОС, который этот PR должен переживать, а не превращать в мор.
8729
8973
  */
8730
8974
  reconcileRuntime(opts) {
8731
- const wtExists = opts.worktreeExists ?? existsSync6;
8975
+ const wtExists = opts.worktreeExists ?? existsSync7;
8732
8976
  const pidByWorktree = /* @__PURE__ */ new Map();
8733
8977
  try {
8734
8978
  for (const p of opts.listProcesses()) if (p.worktree) pidByWorktree.set(p.worktree, p.pid);
@@ -9348,7 +9592,7 @@ var SwarmClient = class _SwarmClient {
9348
9592
  *
9349
9593
  * Прод недоступен / ответ без поручений → пустые списки (демон работает дальше).
9350
9594
  */
9351
- async heartbeat(daemonVersion, pause, capacity, resources, storm, worktreesDir, signIn, tick, executors) {
9595
+ async heartbeat(daemonVersion, pause, capacity, resources, storm, worktreesDir, signIn, tick, executors, providers) {
9352
9596
  try {
9353
9597
  const args = this.repoFullNames.length ? { repoFullNames: this.repoFullNames } : {};
9354
9598
  if (daemonVersion) args.daemonVersion = daemonVersion;
@@ -9379,6 +9623,7 @@ var SwarmClient = class _SwarmClient {
9379
9623
  args.tick = { seq: Math.max(0, Math.trunc(tick.seq)), ageMs: Math.max(0, Math.trunc(tick.ageMs)), intervalMs: Math.trunc(tick.intervalMs) };
9380
9624
  }
9381
9625
  if (executors) args.executorsAvailable = executors;
9626
+ if (providers) args.providersAvailable = providers;
9382
9627
  const res = await this.call("swarm_heartbeat", args);
9383
9628
  if (res?.isError) return EMPTY_HEARTBEAT_REPLY;
9384
9629
  this.heartbeatOkAt = this.now();
@@ -9669,6 +9914,7 @@ var SwarmClient = class _SwarmClient {
9669
9914
  local.return_reason = toReturnReason(pr.returnReason) ?? local.return_reason;
9670
9915
  local.review_phase = pr.reviewPhase ?? local.review_phase;
9671
9916
  local.repo = this.resolveRepo(pr.repo ?? null);
9917
+ if (typeof pr.repoless === "boolean") local.repoless = pr.repoless;
9672
9918
  local.host_id = pr.hostId ?? null;
9673
9919
  local.host_name = pr.hostName ?? null;
9674
9920
  local.host_pinned = pr.hostPinned === true;
@@ -9965,13 +10211,13 @@ var SwarmClient = class _SwarmClient {
9965
10211
  }
9966
10212
  persistPending() {
9967
10213
  try {
9968
- writeFileSync5(this.outboxPath, this.pending.map((e) => JSON.stringify(e)).join("\n") + (this.pending.length ? "\n" : ""));
10214
+ writeFileSync6(this.outboxPath, this.pending.map((e) => JSON.stringify(e)).join("\n") + (this.pending.length ? "\n" : ""));
9969
10215
  } catch {
9970
10216
  }
9971
10217
  }
9972
10218
  persistMap() {
9973
10219
  try {
9974
- writeFileSync5(this.mapPath, JSON.stringify(Object.fromEntries(this.prodIdByKey)));
10220
+ writeFileSync6(this.mapPath, JSON.stringify(Object.fromEntries(this.prodIdByKey)));
9975
10221
  } catch {
9976
10222
  }
9977
10223
  }
@@ -10171,20 +10417,20 @@ function tailFile(path, lines) {
10171
10417
  }
10172
10418
 
10173
10419
  // src/logRotate.ts
10174
- import { copyFileSync as copyFileSync2, renameSync as renameSync3, statSync as statSync6, fstatSync, truncateSync, unlinkSync as unlinkSync2, existsSync as existsSync7 } from "fs";
10420
+ import { copyFileSync as copyFileSync4, renameSync as renameSync3, statSync as statSync7, fstatSync, truncateSync, unlinkSync as unlinkSync2, existsSync as existsSync8 } from "fs";
10175
10421
  var realIo = {
10176
10422
  size: (path) => {
10177
10423
  try {
10178
- return statSync6(path).size;
10424
+ return statSync7(path).size;
10179
10425
  } catch {
10180
10426
  return null;
10181
10427
  }
10182
10428
  },
10183
- copy: copyFileSync2,
10429
+ copy: copyFileSync4,
10184
10430
  rename: renameSync3,
10185
10431
  truncate: (path) => truncateSync(path, 0),
10186
10432
  unlink: unlinkSync2,
10187
- exists: existsSync7
10433
+ exists: existsSync8
10188
10434
  };
10189
10435
  var STRAY_GENERATIONS = 8;
10190
10436
  function rotateDaemonLog(path, opts, io = realIo) {
@@ -10212,17 +10458,17 @@ init_repoRegistry();
10212
10458
 
10213
10459
  // src/hostIdentity.ts
10214
10460
  import { hostname } from "os";
10215
- import { existsSync as existsSync8, readFileSync as readFileSync8, renameSync as renameSync4, writeFileSync as writeFileSync6 } from "fs";
10216
- import { join as join10 } from "path";
10461
+ import { existsSync as existsSync9, readFileSync as readFileSync8, renameSync as renameSync4, writeFileSync as writeFileSync7 } from "fs";
10462
+ import { join as join11 } from "path";
10217
10463
  import { randomUUID as randomUUID2 } from "crypto";
10218
10464
  function hostIdentityPath(home) {
10219
- return join10(home, "host.json");
10465
+ return join11(home, "host.json");
10220
10466
  }
10221
10467
  function loadHostIdentity(deps) {
10222
- const exists = deps.exists ?? existsSync8;
10468
+ const exists = deps.exists ?? existsSync9;
10223
10469
  const readFile2 = deps.readFile ?? ((p) => readFileSync8(p, "utf8"));
10224
10470
  const writeFile3 = deps.writeFile ?? ((p, data) => {
10225
- writeFileSync6(`${p}.tmp`, data);
10471
+ writeFileSync7(`${p}.tmp`, data);
10226
10472
  renameSync4(`${p}.tmp`, p);
10227
10473
  });
10228
10474
  const host = deps.hostname ?? hostname;
@@ -10337,8 +10583,8 @@ import { basename as basename4 } from "path";
10337
10583
  import { serve as serve2 } from "@hono/node-server";
10338
10584
 
10339
10585
  // src/diff.ts
10340
- import { statSync as statSync7 } from "fs";
10341
- import { join as join11 } from "path";
10586
+ import { statSync as statSync8 } from "fs";
10587
+ import { join as join12 } from "path";
10342
10588
  import { $ as $3 } from "execa";
10343
10589
  var MAX_FILES = 200;
10344
10590
  var MAX_LINES_PER_FILE = 1500;
@@ -10481,7 +10727,7 @@ async function resolveBase(wt, baseBranch) {
10481
10727
  }
10482
10728
  function mtime(path) {
10483
10729
  try {
10484
- return statSync7(path).mtimeMs;
10730
+ return statSync8(path).mtimeMs;
10485
10731
  } catch {
10486
10732
  return 0;
10487
10733
  }
@@ -10506,7 +10752,7 @@ async function collectRunDiff(worktree, opts = {}) {
10506
10752
  files.push(pf);
10507
10753
  }
10508
10754
  }
10509
- files.sort((a, b) => mtime(join11(worktree, b.path)) - mtime(join11(worktree, a.path)));
10755
+ files.sort((a, b) => mtime(join12(worktree, b.path)) - mtime(join12(worktree, a.path)));
10510
10756
  const truncatedFiles = files.length > MAX_FILES;
10511
10757
  if (truncatedFiles) files = files.slice(0, MAX_FILES);
10512
10758
  const added = files.reduce((s, f) => s + f.added, 0);
@@ -10676,9 +10922,9 @@ function mergeQueueCandidates(runs, repo, repoFallback) {
10676
10922
  const byPr = /* @__PURE__ */ new Map();
10677
10923
  for (const r of runs) {
10678
10924
  if (effectiveRepoOf(r.repo, repoFallback) !== repo || !isMergeCandidate(r)) continue;
10679
- const num = prNumberOf(r.pr_url);
10680
- const seen = byPr.get(num);
10681
- if (!seen || r.id > seen.id) byPr.set(num, r);
10925
+ const num2 = prNumberOf(r.pr_url);
10926
+ const seen = byPr.get(num2);
10927
+ if (!seen || r.id > seen.id) byPr.set(num2, r);
10682
10928
  }
10683
10929
  return [...byPr.values()];
10684
10930
  }
@@ -10691,10 +10937,10 @@ function makeMergeQueueResolver(deps) {
10691
10937
  };
10692
10938
  return async (run) => {
10693
10939
  if (!deps.baseSync || !run.pr_url) return null;
10694
- const num = prNumberOf(run.pr_url);
10695
- if (num == null) return null;
10940
+ const num2 = prNumberOf(run.pr_url);
10941
+ if (num2 == null) return null;
10696
10942
  const candidates = mergeQueueCandidates(deps.listRuns(), effectiveRepoOf(run.repo, deps.repoFallback), deps.repoFallback);
10697
- const mine = candidates.find((c) => prNumberOf(c.pr_url) === num);
10943
+ const mine = candidates.find((c) => prNumberOf(c.pr_url) === num2);
10698
10944
  if (!mine) return null;
10699
10945
  const ready = [];
10700
10946
  const urlOf = /* @__PURE__ */ new Map();
@@ -10810,10 +11056,10 @@ function makeMergeIntentResolver(deps) {
10810
11056
  };
10811
11057
  return async (run) => {
10812
11058
  if (!deps.baseSync || !run.pr_url || !hasMergeIntent(run)) return null;
10813
- const num = prNumberOf(run.pr_url);
10814
- if (num == null) return null;
11059
+ const num2 = prNumberOf(run.pr_url);
11060
+ if (num2 == null) return null;
10815
11061
  const marked = mergeQueueCandidates(deps.listRuns(), effectiveRepoOf(run.repo, deps.repoFallback), deps.repoFallback).filter(hasMergeIntent);
10816
- const mine = marked.find((c) => prNumberOf(c.pr_url) === num);
11062
+ const mine = marked.find((c) => prNumberOf(c.pr_url) === num2);
10817
11063
  if (!mine) return null;
10818
11064
  const queue = orderMergeQueue(marked.map(entryOf));
10819
11065
  const entry = entryOf(mine);
@@ -12530,15 +12776,15 @@ import { cancelRun, respawnRun, runDaemon, wakeRun, OVERMIND_ENTRY, listDronePro
12530
12776
 
12531
12777
  // src/launcher.ts
12532
12778
  import { spawn as spawn2 } from "child_process";
12533
- import { closeSync as closeSync3, existsSync as existsSync9, mkdirSync as mkdirSync9, openSync as openSync3, readdirSync as readdirSync8 } from "fs";
12779
+ import { closeSync as closeSync3, existsSync as existsSync10, mkdirSync as mkdirSync10, openSync as openSync3, readdirSync as readdirSync9 } from "fs";
12534
12780
  import { createRequire } from "module";
12535
12781
  import { homedir as homedir5 } from "os";
12536
- import { dirname as dirname4, join as join14 } from "path";
12782
+ import { dirname as dirname4, join as join15 } from "path";
12537
12783
  import { fileURLToPath as fileURLToPath2 } from "url";
12538
12784
 
12539
12785
  // src/droneHome.ts
12540
- import { lstatSync, mkdirSync as mkdirSync8, readdirSync as readdirSync7, rmSync, statSync as statSync8, symlinkSync as symlinkSync2 } from "fs";
12541
- import { join as join13, relative, sep } from "path";
12786
+ import { lstatSync, mkdirSync as mkdirSync9, readdirSync as readdirSync8, rmSync, statSync as statSync9, symlinkSync as symlinkSync3 } from "fs";
12787
+ import { join as join14, relative, sep } from "path";
12542
12788
  var DRONE_HOME_DENY_DEFAULT = [".taskless-swarm", ".bash_history", ".zsh_history"];
12543
12789
  function droneHomeDeny(env = process.env) {
12544
12790
  const extra = (env.SWARM_DRONE_HOME_DENY || "").split(",").map((s) => s.trim()).filter(Boolean);
@@ -12556,34 +12802,34 @@ function buildDroneHome(opts) {
12556
12802
  const { realHome, droneHome } = opts;
12557
12803
  const deny = opts.deny ?? droneHomeDeny();
12558
12804
  const platform = opts.platform ?? process.platform;
12559
- mkdirSync8(droneHome, { recursive: true, mode: 448 });
12560
- const wanted = new Set(mirroredEntries(readdirSync7(realHome), deny, platform));
12805
+ mkdirSync9(droneHome, { recursive: true, mode: 448 });
12806
+ const wanted = new Set(mirroredEntries(readdirSync8(realHome), deny, platform));
12561
12807
  const rel = relative(realHome, droneHome);
12562
12808
  if (rel && !rel.startsWith("..") && !rel.includes(sep)) wanted.delete(rel);
12563
- for (const existing of readdirSync7(droneHome)) {
12809
+ for (const existing of readdirSync8(droneHome)) {
12564
12810
  if (wanted.has(existing)) continue;
12565
- const p = join13(droneHome, existing);
12811
+ const p = join14(droneHome, existing);
12566
12812
  try {
12567
12813
  if (lstatSync(p).isSymbolicLink()) rmSync(p);
12568
12814
  } catch {
12569
12815
  }
12570
12816
  }
12571
12817
  for (const name of wanted) {
12572
- const link = join13(droneHome, name);
12818
+ const link = join14(droneHome, name);
12573
12819
  try {
12574
12820
  lstatSync(link);
12575
12821
  continue;
12576
12822
  } catch {
12577
12823
  }
12578
- const target = join13(realHome, name);
12824
+ const target = join14(realHome, name);
12579
12825
  let isDir;
12580
12826
  try {
12581
- isDir = statSync8(target).isDirectory();
12827
+ isDir = statSync9(target).isDirectory();
12582
12828
  } catch {
12583
12829
  continue;
12584
12830
  }
12585
12831
  try {
12586
- symlinkSync2(target, link, isDir ? "junction" : "file");
12832
+ symlinkSync3(target, link, isDir ? "junction" : "file");
12587
12833
  } catch (e) {
12588
12834
  if (e.code !== "EEXIST") throw e;
12589
12835
  }
@@ -12596,7 +12842,7 @@ var REAL_PATH_ENV_PINS = [
12596
12842
  { env: "YARN_GLOBAL_FOLDER", segments: [".yarn", "berry"] }
12597
12843
  ];
12598
12844
  function realPathEnvPins(realHome) {
12599
- return Object.fromEntries(REAL_PATH_ENV_PINS.map(({ env, segments }) => [env, join13(realHome, ...segments)]));
12845
+ return Object.fromEntries(REAL_PATH_ENV_PINS.map(({ env, segments }) => [env, join14(realHome, ...segments)]));
12600
12846
  }
12601
12847
  function dronePrivatePaths(realHome, swarmHome) {
12602
12848
  return [
@@ -12679,7 +12925,7 @@ function droneEnv(worktree, base3 = process.env, isolation, droneCap = null) {
12679
12925
  const env = { ...base3 };
12680
12926
  const isolate = base3.SWARM_TURBO_ISOLATE !== "0";
12681
12927
  if (isolate && !base3.TURBO_CACHE_DIR) {
12682
- env.TURBO_CACHE_DIR = join14(worktree, ".turbo", "cache");
12928
+ env.TURBO_CACHE_DIR = join15(worktree, ".turbo", "cache");
12683
12929
  }
12684
12930
  Object.assign(env, droneTestEnv(droneCap, base3));
12685
12931
  for (const key of DAEMON_STATE_ENV) delete env[key];
@@ -12710,21 +12956,21 @@ var DAEMON_STATE_ENV = [
12710
12956
  ...PROVIDER_TOKEN_ENV
12711
12957
  ];
12712
12958
  function bundledRoleDir(kind) {
12713
- return join14(dirname4(fileURLToPath2(import.meta.url)), "..", "roles", kind);
12959
+ return join15(dirname4(fileURLToPath2(import.meta.url)), "..", "roles", kind);
12714
12960
  }
12715
12961
  function roleDir(worktree, kind) {
12716
- return join14(worktree, ".claude", "roles", kind);
12962
+ return join15(worktree, ".claude", "roles", kind);
12717
12963
  }
12718
12964
  function roleDirs(worktree, kind) {
12719
- return [bundledRoleDir(kind), roleDir(worktree, kind)].filter((dir) => existsSync9(dir));
12965
+ return [bundledRoleDir(kind), roleDir(worktree, kind)].filter((dir) => existsSync10(dir));
12720
12966
  }
12721
12967
  function nextRunLogPath(runLogsDir, runLogKeys) {
12722
12968
  const dir = runLogDirForWrite(runLogsDir, runLogKeys);
12723
12969
  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)");
12724
- mkdirSync9(dir, { recursive: true });
12970
+ mkdirSync10(dir, { recursive: true });
12725
12971
  let files = [];
12726
12972
  try {
12727
- files = readdirSync8(dir);
12973
+ files = readdirSync9(dir);
12728
12974
  } catch {
12729
12975
  }
12730
12976
  let next = 0;
@@ -12732,7 +12978,7 @@ function nextRunLogPath(runLogsDir, runLogKeys) {
12732
12978
  const m = /^(\d+)\.json/.exec(f);
12733
12979
  if (m) next = Math.max(next, Number(m[1]) + 1);
12734
12980
  }
12735
- return join14(dir, `${next}.json`);
12981
+ return join15(dir, `${next}.json`);
12736
12982
  }
12737
12983
  function openNextRunLog(runLogsDir, runLogKeys) {
12738
12984
  for (let attempt = 0; attempt < 50; attempt++) {
@@ -12799,6 +13045,10 @@ function makeLauncher(cfg) {
12799
13045
  SWARM_RUN_KIND: run.kind,
12800
13046
  SWARM_RUN_NAME: run.name,
12801
13047
  ...run.workspace_id ? { SWARM_WORKSPACE_ID: run.workspace_id } : {},
13048
+ // TASWM-598: repoless-прогон той же спавн-фиксацией — гейт done() («сдача отчётом,
13049
+ // не PR») обязан срабатывать и по данным СПАВНА, а не только по строке прогона от
13050
+ // демона (тот же класс граблей, что у SWARM_REVIEWS_RUN_ID в TASWM-375).
13051
+ ...run.repoless ? { SWARM_RUN_REPOLESS: "1" } : {},
12802
13052
  ...run.reviews_run_id != null ? { SWARM_REVIEWS_RUN_ID: String(run.reviews_run_id) } : {},
12803
13053
  // TASWM-344: та же роль, что у SWARM_REVIEWS_RUN_ID выше, для верификатора — без неё
12804
13054
  // его done() в client-режиме пошёл бы веткой обычной сдачи PR, и вердикт пропал бы.
@@ -12820,9 +13070,9 @@ function makeLauncher(cfg) {
12820
13070
  }
12821
13071
  const realHome = cfg.droneIsolation?.realHome ?? homedir5();
12822
13072
  const home = cfg.droneIsolation ? buildDroneHome({ realHome, droneHome: cfg.droneIsolation.home }) : void 0;
12823
- if (cfg.droneIsolation && process.env.TASKLESS_TOKEN && !existsSync9(join14(cfg.droneIsolation.swarmHome, "token"))) {
13073
+ if (cfg.droneIsolation && process.env.TASKLESS_TOKEN && !existsSync10(join15(cfg.droneIsolation.swarmHome, "token"))) {
12824
13074
  console.error(
12825
- `[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 ${join14(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.`
13075
+ `[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 ${join15(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.`
12826
13076
  );
12827
13077
  }
12828
13078
  const executor = cfg.executor ?? executorForRun(run, cfg.swarmModels?.() ?? null);
@@ -13721,7 +13971,7 @@ async function runDaemonLogs(argv) {
13721
13971
  console.error(`\u043B\u043E\u0433 \u041F\u0420\u041E\u0413\u041E\u041D\u0410 \u2014 \u044D\u0442\u043E \xABswarm log ${stray}\xBB (\u0431\u0435\u0437 s). \xABswarm logs\xBB \u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442 \u043B\u043E\u0433 \u0434\u0435\u043C\u043E\u043D\u0430; \u0447\u0438\u0441\u043B\u043E \u0441\u0442\u0440\u043E\u043A \u2014 \xABswarm logs -n 200\xBB.`);
13722
13972
  return 1;
13723
13973
  }
13724
- if (!existsSync17(DAEMON_LOG_PATH)) {
13974
+ if (!existsSync18(DAEMON_LOG_PATH)) {
13725
13975
  console.error(`\u043B\u043E\u0433\u0430 \u0434\u0435\u043C\u043E\u043D\u0430 \u043D\u0435\u0442: ${DAEMON_LOG_PATH}`);
13726
13976
  console.error("\u043E\u043D \u043F\u0438\u0448\u0435\u0442\u0441\u044F \u043F\u0440\u0438 \u0444\u043E\u043D\u043E\u0432\u043E\u043C \u0437\u0430\u043F\u0443\u0441\u043A\u0435 (swarm start). \u0414\u0435\u043C\u043E\u043D \u043F\u043E\u0434\u043D\u044F\u0442 \u0432 \u0442\u0435\u0440\u043C\u0438\u043D\u0430\u043B\u0435 (--foreground) \u2014 \u0432\u044B\u0432\u043E\u0434 \u0438\u0434\u0451\u0442 \u0442\u0443\u0434\u0430.");
13727
13977
  return 1;
@@ -13729,12 +13979,12 @@ async function runDaemonLogs(argv) {
13729
13979
  const head = tailFile(DAEMON_LOG_PATH, lines);
13730
13980
  if (head) console.log(head);
13731
13981
  if (!follow) return 0;
13732
- let pos = statSync11(DAEMON_LOG_PATH).size;
13982
+ let pos = statSync12(DAEMON_LOG_PATH).size;
13733
13983
  for (; ; ) {
13734
13984
  await sleep2(500);
13735
13985
  let size;
13736
13986
  try {
13737
- size = statSync11(DAEMON_LOG_PATH).size;
13987
+ size = statSync12(DAEMON_LOG_PATH).size;
13738
13988
  } catch {
13739
13989
  continue;
13740
13990
  }
@@ -14003,10 +14253,10 @@ function effectiveWorktreesDir() {
14003
14253
  legacyDir: WORKTREES_LEGACY_DIR,
14004
14254
  targetDir: WORKTREES_DIR,
14005
14255
  envOverride: process.env.SWARM_WORKTREES || "",
14006
- exists: (d) => existsSync17(d),
14256
+ exists: (d) => existsSync18(d),
14007
14257
  isNonEmptyDir: (d) => {
14008
14258
  try {
14009
- return readdirSync11(d).length > 0;
14259
+ return readdirSync12(d).length > 0;
14010
14260
  } catch {
14011
14261
  return false;
14012
14262
  }
@@ -14062,15 +14312,15 @@ async function scoutRepo(repo) {
14062
14312
  await $6({ reject: false })`git -C ${worktree} reset --hard ${baseRef}`;
14063
14313
  }
14064
14314
  await setWorktreeIdentity(worktree, name);
14065
- const abs = (rel) => join26(worktree, rel);
14315
+ const abs = (rel) => join27(worktree, rel);
14066
14316
  const code = await runRepoScout({
14067
14317
  repoFullName,
14068
14318
  repoPath: worktree,
14069
14319
  name,
14070
- readFile: (rel) => existsSync17(abs(rel)) ? readFileSync19(abs(rel), "utf8") : null,
14320
+ readFile: (rel) => existsSync18(abs(rel)) ? readFileSync19(abs(rel), "utf8") : null,
14071
14321
  writeFile: (rel, text) => {
14072
- mkdirSync10(dirname5(abs(rel)), { recursive: true });
14073
- writeFileSync14(abs(rel), text);
14322
+ mkdirSync11(dirname5(abs(rel)), { recursive: true });
14323
+ writeFileSync15(abs(rel), text);
14074
14324
  },
14075
14325
  runScout: (prompt) => new Promise((resolve5) => {
14076
14326
  const child = spawn3(bin, [...ISOLATION_FLAGS, "--dangerously-skip-permissions", "-p", prompt], {