@taskless-app/swarm 0.4.2 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -28,10 +28,20 @@ npx @taskless-app/swarm start --repo <путь к репо> # поднят
28
28
  ```bash
29
29
  npm i -g @taskless-app/swarm
30
30
  swarm login --workspace <slug>
31
- swarm start --repo <путь к репо> # держит процесс живым — разбирает очередь, спавнит/будит дронов
31
+ swarm start --repo <путь к репо> # поднять рой: уходит в фон, терминал остаётся вам
32
32
  swarm --help # список остальных команд (spawn/ls/questions/answer/…)
33
33
  ```
34
34
 
35
+ **Демон открепляется от терминала.** `swarm start` не занимает окно: процесс уходит
36
+ в фон, а весь вывод пишется в `~/.taskless-swarm/overmind.log` — тот самый файл, из
37
+ которого агент читает хвост лога удалённо. Посмотреть: `swarm logs -f`. Нужен вывод
38
+ прямо в терминале (отладка, systemd, docker, где фоном занимается супервизор) —
39
+ `swarm start --foreground` (он же `-f`, `--attach`).
40
+
41
+ Команда не отчитывается о запуске раньше времени: она ждёт, пока демон реально
42
+ поднимется, и только тогда говорит «поднят». Не поднялся — покажет хвост лога с
43
+ настоящей причиной (занятый порт, отсутствующий токен) и завершится с ошибкой.
44
+
35
45
  Полный гайд по настройке и запуску роя — на [taskless.ru](https://taskless.ru).
36
46
 
37
47
  ## Остановить, приостановить, отключить машину
@@ -138,14 +148,19 @@ swarm_daemon_log(hostId, lines) # хвост лога самого демона
138
148
  трекера лог не оседает, строка обмена умирает на чтении. Чужие логи недоступны —
139
149
  и запрос, и доставка скоупятся владельцем машины.
140
150
 
141
- Лог самого демона демон не заводит (пишет в stdout) — заведите его перенаправлением
142
- или укажите свой путь:
151
+ Лог самого демона заводится сам: фоновый `swarm start` пишет в
152
+ `~/.taskless-swarm/overmind.log` и ротирует его при старте (прошлый — `.1`). Свой
153
+ путь — `SWARM_DAEMON_LOG`. Смотреть на месте:
143
154
 
144
155
  ```bash
145
- swarm start --repo <путь> >> ~/.taskless-swarm/overmind.log 2>&1 # путь по умолчанию
146
- SWARM_DAEMON_LOG=/var/log/overmind.log swarm start --repo <путь> # свой путь
156
+ swarm logs # хвост лога демона (по умолчанию 200 строк)
157
+ swarm logs -n 50 -f # следить за новыми строками
158
+ swarm log <runId> # это ДРУГОЕ: лог конкретного прогона
147
159
  ```
148
160
 
161
+ Запустили с `--foreground` — вывод идёт в терминал, и файла не будет: тогда за него
162
+ отвечает тот, кто перенаправил (systemd, docker, `tee`).
163
+
149
164
  ## Правообладатель и лицензия
150
165
 
151
166
  © 2026 Ilya Smurov. Проприетарное коммерческое ПО — см. [LICENSE](./LICENSE).
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  // src/cli.ts
4
4
  import { basename as basename4 } from "path";
5
- import { existsSync as existsSync9, readdirSync as readdirSync6 } from "fs";
5
+ import { existsSync as existsSync9, readdirSync as readdirSync6, statSync as statSync7, openSync as openSync4, readSync as readSync2, closeSync as closeSync4 } from "fs";
6
6
  import { createInterface } from "readline/promises";
7
7
  import { setTimeout as sleep2 } from "timers/promises";
8
8
 
@@ -1464,7 +1464,19 @@ import { randomUUID } from "crypto";
1464
1464
 
1465
1465
  // src/resources.ts
1466
1466
  import os from "os";
1467
+
1468
+ // src/quietExec.ts
1467
1469
  import { execFileSync } from "child_process";
1470
+ function execQuiet(file, args = [], opts = {}) {
1471
+ return execFileSync(file, args, {
1472
+ encoding: "utf8",
1473
+ stdio: ["ignore", "pipe", "pipe"],
1474
+ ...opts.maxBuffer ? { maxBuffer: opts.maxBuffer } : {}
1475
+ });
1476
+ }
1477
+ var PROC_SNAPSHOT_MAX_BUFFER = 16 * 1024 * 1024;
1478
+
1479
+ // src/resources.ts
1468
1480
  import { readFileSync as readFileSync2, statfsSync } from "fs";
1469
1481
  function isTransientResourceError(e) {
1470
1482
  const code = e?.code;
@@ -1489,7 +1501,7 @@ function parseVmStatAvailableBytes(vmStatOut) {
1489
1501
  function availableMemBytes() {
1490
1502
  if (process.platform === "darwin") {
1491
1503
  try {
1492
- const bytes = parseVmStatAvailableBytes(execFileSync("vm_stat", { encoding: "utf8" }));
1504
+ const bytes = parseVmStatAvailableBytes(execQuiet("vm_stat"));
1493
1505
  if (bytes > 0) return bytes;
1494
1506
  } catch (e) {
1495
1507
  logTransientSpawnError("vm_stat", e);
@@ -1503,7 +1515,7 @@ function parseSysctlInt(out) {
1503
1515
  }
1504
1516
  function readSysctlPair(nameA, nameB) {
1505
1517
  try {
1506
- const lines = execFileSync("sysctl", ["-n", nameA, nameB], { encoding: "utf8" }).trim().split("\n");
1518
+ const lines = execQuiet("sysctl", ["-n", nameA, nameB]).trim().split("\n");
1507
1519
  return [parseSysctlInt(lines[0] ?? ""), parseSysctlInt(lines[1] ?? "")];
1508
1520
  } catch (e) {
1509
1521
  logTransientSpawnError(`sysctl ${nameA}/${nameB}`, e);
@@ -3285,11 +3297,86 @@ function parseDecision(v) {
3285
3297
  }
3286
3298
  }
3287
3299
 
3288
- // src/procCleanup.ts
3289
- import { execFileSync as execFileSync3 } from "child_process";
3300
+ // src/daemonLaunch.ts
3301
+ import { openSync as openSync2, closeSync as closeSync2, renameSync as renameSync2, statSync as statSync2, writeFileSync as writeFileSync3, readFileSync as readFileSync4 } from "fs";
3302
+ import { spawn } from "child_process";
3303
+ var FOREGROUND_FLAGS = /* @__PURE__ */ new Set(["--foreground", "-f", "--attach"]);
3304
+ function parseStartMode(argv) {
3305
+ const rest = argv.filter((a) => !FOREGROUND_FLAGS.has(a));
3306
+ return { foreground: rest.length !== argv.length, rest };
3307
+ }
3308
+ function childStartArgv(rest) {
3309
+ return ["start", ...rest.filter((a) => !FOREGROUND_FLAGS.has(a)), "--foreground"];
3310
+ }
3311
+ function rotateDaemonLog(path, maxBytes) {
3312
+ let size;
3313
+ try {
3314
+ size = statSync2(path).size;
3315
+ } catch {
3316
+ return "missing";
3317
+ }
3318
+ if (size <= maxBytes) return "kept";
3319
+ renameSync2(path, `${path}.1`);
3320
+ writeFileSync3(path, "");
3321
+ return "rotated";
3322
+ }
3323
+ function tailText(text, lines) {
3324
+ const rows = text.split("\n");
3325
+ if (rows[rows.length - 1] === "") rows.pop();
3326
+ return rows.slice(-lines).join("\n");
3327
+ }
3328
+ async function waitForReady(opts) {
3329
+ const now = opts.now ?? Date.now;
3330
+ const sleep3 = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
3331
+ const started = now();
3332
+ for (; ; ) {
3333
+ if (await opts.probe()) return "ready";
3334
+ if (!opts.alive()) return "died";
3335
+ if (now() - started >= opts.timeoutMs) return "timeout";
3336
+ await sleep3(opts.pollMs);
3337
+ }
3338
+ }
3339
+ function launchDetached(opts) {
3340
+ const fd = openSync2(opts.logPath, "a");
3341
+ try {
3342
+ const child = spawn(opts.execPath, [...opts.execArgv, opts.entry, ...opts.args], {
3343
+ detached: true,
3344
+ stdio: ["ignore", fd, fd],
3345
+ env: opts.env
3346
+ });
3347
+ child.unref();
3348
+ let exited = false;
3349
+ child.once("exit", () => {
3350
+ exited = true;
3351
+ });
3352
+ return {
3353
+ pid: child.pid ?? -1,
3354
+ // Не `child.killed` (он про посланный сигнал) и не exit-код: после unref событие
3355
+ // может не прийти вовсе — спрашиваем ядро сигналом 0, это и есть «процесс есть».
3356
+ alive: () => {
3357
+ if (exited) return false;
3358
+ if (!child.pid) return false;
3359
+ try {
3360
+ process.kill(child.pid, 0);
3361
+ return true;
3362
+ } catch {
3363
+ return false;
3364
+ }
3365
+ }
3366
+ };
3367
+ } finally {
3368
+ closeSync2(fd);
3369
+ }
3370
+ }
3371
+ function tailFile(path, lines) {
3372
+ try {
3373
+ return tailText(readFileSync4(path, "utf8"), lines);
3374
+ } catch {
3375
+ return "";
3376
+ }
3377
+ }
3290
3378
 
3291
3379
  // src/procList.ts
3292
- import { execFileSync as execFileSync2 } from "child_process";
3293
3380
  function parsePsRows(out) {
3294
3381
  const rows = [];
3295
3382
  for (const line of out.split("\n")) {
@@ -3325,7 +3412,7 @@ function parseWinProcRows(out) {
3325
3412
  }
3326
3413
  var WIN_PS_COMMAND = "Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,CommandLine | ConvertTo-Json -Depth 2 -Compress";
3327
3414
  function realExec(file, args) {
3328
- return execFileSync2(file, args, { encoding: "utf8", maxBuffer: 16 * 1024 * 1024 });
3415
+ return execQuiet(file, args, { maxBuffer: PROC_SNAPSHOT_MAX_BUFFER });
3329
3416
  }
3330
3417
  function listProcs(opts = {}) {
3331
3418
  const platform = opts.platform ?? process.platform;
@@ -3393,7 +3480,7 @@ function pidsWithCwdUnder(dir, opts = {}) {
3393
3480
  if ((opts.platform ?? process.platform) === "win32") return winProcsUnder(dir, opts.procs ?? listProcs);
3394
3481
  let out;
3395
3482
  try {
3396
- out = execFileSync3("lsof", ["-a", "-d", "cwd", "-F", "pn"], { encoding: "utf8", maxBuffer: 16 * 1024 * 1024 });
3483
+ out = execQuiet("lsof", ["-w", "-a", "-d", "cwd", "-F", "pn"], { maxBuffer: PROC_SNAPSHOT_MAX_BUFFER });
3397
3484
  } catch (e) {
3398
3485
  logTransientSpawnError("lsof", e);
3399
3486
  return [];
@@ -3476,7 +3563,7 @@ function containerBelongsToPrefix(name, prefix) {
3476
3563
  }
3477
3564
  function dockerContainerNames() {
3478
3565
  try {
3479
- return execFileSync3("docker", ["ps", "-a", "--format", "{{.Names}}"], { encoding: "utf8" }).split("\n").map((s) => s.trim()).filter(Boolean);
3566
+ return execQuiet("docker", ["ps", "-a", "--format", "{{.Names}}"]).split("\n").map((s) => s.trim()).filter(Boolean);
3480
3567
  } catch (e) {
3481
3568
  logTransientSpawnError("docker ps", e);
3482
3569
  return [];
@@ -3486,7 +3573,7 @@ function removeContainers(names) {
3486
3573
  const removed = [];
3487
3574
  for (const name of names) {
3488
3575
  try {
3489
- execFileSync3("docker", ["rm", "-f", name], { encoding: "utf8" });
3576
+ execQuiet("docker", ["rm", "-f", name]);
3490
3577
  removed.push(name);
3491
3578
  } catch (e) {
3492
3579
  console.warn(`[procCleanup] docker rm -f ${name} \u0441\u043E\u0440\u0432\u0430\u043B\u0441\u044F: ${String(e)}`);
@@ -3546,7 +3633,7 @@ async function buildRepoRegistry(paths) {
3546
3633
 
3547
3634
  // src/hostIdentity.ts
3548
3635
  import { hostname } from "os";
3549
- import { existsSync as existsSync4, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync as writeFileSync3 } from "fs";
3636
+ import { existsSync as existsSync4, readFileSync as readFileSync5, renameSync as renameSync3, writeFileSync as writeFileSync4 } from "fs";
3550
3637
  import { join as join3 } from "path";
3551
3638
  import { randomUUID as randomUUID2 } from "crypto";
3552
3639
  function hostIdentityPath(home) {
@@ -3554,10 +3641,10 @@ function hostIdentityPath(home) {
3554
3641
  }
3555
3642
  function loadHostIdentity(deps) {
3556
3643
  const exists = deps.exists ?? existsSync4;
3557
- const readFile2 = deps.readFile ?? ((p) => readFileSync4(p, "utf8"));
3644
+ const readFile2 = deps.readFile ?? ((p) => readFileSync5(p, "utf8"));
3558
3645
  const writeFile2 = deps.writeFile ?? ((p, data) => {
3559
- writeFileSync3(`${p}.tmp`, data);
3560
- renameSync2(`${p}.tmp`, p);
3646
+ writeFileSync4(`${p}.tmp`, data);
3647
+ renameSync3(`${p}.tmp`, p);
3561
3648
  });
3562
3649
  const host = deps.hostname ?? hostname;
3563
3650
  const newId = deps.newId ?? randomUUID2;
@@ -3665,7 +3752,7 @@ import { basename as basename2 } from "path";
3665
3752
  import { serve as serve2 } from "@hono/node-server";
3666
3753
 
3667
3754
  // src/diff.ts
3668
- import { statSync as statSync2 } from "fs";
3755
+ import { statSync as statSync3 } from "fs";
3669
3756
  import { join as join4 } from "path";
3670
3757
  import { $ as $2 } from "execa";
3671
3758
  var MAX_FILES = 200;
@@ -3809,7 +3896,7 @@ async function resolveBase(wt, baseBranch) {
3809
3896
  }
3810
3897
  function mtime(path) {
3811
3898
  try {
3812
- return statSync2(path).mtimeMs;
3899
+ return statSync3(path).mtimeMs;
3813
3900
  } catch {
3814
3901
  return 0;
3815
3902
  }
@@ -3853,7 +3940,7 @@ async function collectRunDiff(worktree, opts = {}) {
3853
3940
  // package.json
3854
3941
  var package_default = {
3855
3942
  name: "@taskless-app/swarm",
3856
- version: "0.4.2",
3943
+ version: "0.4.4",
3857
3944
  type: "module",
3858
3945
  description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
3859
3946
  keywords: [
@@ -3956,18 +4043,18 @@ async function ghChecks(pr, run = realChecksRunner) {
3956
4043
 
3957
4044
  // src/droneChannel.ts
3958
4045
  import { createHmac, randomBytes, timingSafeEqual } from "crypto";
3959
- import { chmodSync, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
4046
+ import { chmodSync, mkdirSync as mkdirSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
3960
4047
  import { dirname as dirname2 } from "path";
3961
4048
  import { serve } from "@hono/node-server";
3962
4049
  function loadChannelSecret(path) {
3963
4050
  try {
3964
- const s = readFileSync5(path, "utf8").trim();
4051
+ const s = readFileSync6(path, "utf8").trim();
3965
4052
  if (s.length >= 32) return s;
3966
4053
  } catch {
3967
4054
  }
3968
4055
  const secret = randomBytes(32).toString("hex");
3969
4056
  mkdirSync3(dirname2(path), { recursive: true });
3970
- writeFileSync4(path, secret, { mode: 384 });
4057
+ writeFileSync5(path, secret, { mode: 384 });
3971
4058
  try {
3972
4059
  chmodSync(path, 384);
3973
4060
  } catch {
@@ -4001,7 +4088,7 @@ var EVENT_KIND_SET = new Set(EVENT_KINDS);
4001
4088
 
4002
4089
  // src/oauth.ts
4003
4090
  import { createHash, randomBytes as randomBytes2 } from "crypto";
4004
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, unlinkSync } from "fs";
4091
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync6, unlinkSync } from "fs";
4005
4092
  import { join as join5 } from "path";
4006
4093
  var REGISTER = "/api/oauth/register";
4007
4094
  var AUTHORIZE = "/api/oauth/authorize";
@@ -4093,13 +4180,13 @@ function toStore(clientId, t, now) {
4093
4180
  }
4094
4181
  function loadStore() {
4095
4182
  try {
4096
- return JSON.parse(readFileSync6(STORE_PATH, "utf8"));
4183
+ return JSON.parse(readFileSync7(STORE_PATH, "utf8"));
4097
4184
  } catch {
4098
4185
  return null;
4099
4186
  }
4100
4187
  }
4101
4188
  function saveStore(s) {
4102
- writeFileSync5(STORE_PATH, JSON.stringify(s, null, 2), { mode: 384 });
4189
+ writeFileSync6(STORE_PATH, JSON.stringify(s, null, 2), { mode: 384 });
4103
4190
  }
4104
4191
  function clearStore() {
4105
4192
  try {
@@ -4109,7 +4196,7 @@ function clearStore() {
4109
4196
  }
4110
4197
  function loadClientId() {
4111
4198
  try {
4112
- return JSON.parse(readFileSync6(CLIENT_PATH, "utf8")).clientId;
4199
+ return JSON.parse(readFileSync7(CLIENT_PATH, "utf8")).clientId;
4113
4200
  } catch {
4114
4201
  return null;
4115
4202
  }
@@ -4118,7 +4205,7 @@ async function ensureClientId(api, redirectUri, fetchFn = fetch) {
4118
4205
  const existing = loadClientId();
4119
4206
  if (existing) return existing;
4120
4207
  const clientId = await registerClient({ api, redirectUri }, fetchFn);
4121
- writeFileSync5(CLIENT_PATH, JSON.stringify({ clientId }, null, 2), { mode: 384 });
4208
+ writeFileSync6(CLIENT_PATH, JSON.stringify({ clientId }, null, 2), { mode: 384 });
4122
4209
  return clientId;
4123
4210
  }
4124
4211
  async function ensureAccess(store, opts = {}) {
@@ -5697,8 +5784,8 @@ function startWeb(deps, port = WEB_PORT) {
5697
5784
  import { cancelRun, respawnRun, runDaemon, wakeRun, OVERMIND_ENTRY, listDroneProcesses } from "./overmind.js";
5698
5785
 
5699
5786
  // src/launcher.ts
5700
- import { spawn } from "child_process";
5701
- import { closeSync as closeSync2, existsSync as existsSync6, mkdirSync as mkdirSync5, openSync as openSync2, readdirSync as readdirSync4, statSync as statSync4, writeFileSync as writeFileSync6 } from "fs";
5787
+ import { spawn as spawn2 } from "child_process";
5788
+ import { closeSync as closeSync3, existsSync as existsSync6, mkdirSync as mkdirSync5, openSync as openSync3, readdirSync as readdirSync4, statSync as statSync5, writeFileSync as writeFileSync7 } from "fs";
5702
5789
  import { createRequire as createRequire2 } from "module";
5703
5790
  import { homedir as homedir2 } from "os";
5704
5791
  import { dirname as dirname3, join as join7 } from "path";
@@ -5777,7 +5864,7 @@ function resolveClaudeBin(opts = {}) {
5777
5864
  }
5778
5865
 
5779
5866
  // src/droneHome.ts
5780
- import { lstatSync, mkdirSync as mkdirSync4, readdirSync as readdirSync3, rmSync, statSync as statSync3, symlinkSync } from "fs";
5867
+ import { lstatSync, mkdirSync as mkdirSync4, readdirSync as readdirSync3, rmSync, statSync as statSync4, symlinkSync } from "fs";
5781
5868
  import { join as join6, relative, sep } from "path";
5782
5869
  var DRONE_HOME_DENY_DEFAULT = [".taskless-swarm", ".bash_history", ".zsh_history"];
5783
5870
  function droneHomeDeny(env = process.env) {
@@ -5818,7 +5905,7 @@ function buildDroneHome(opts) {
5818
5905
  const target = join6(realHome, name);
5819
5906
  let isDir;
5820
5907
  try {
5821
- isDir = statSync3(target).isDirectory();
5908
+ isDir = statSync4(target).isDirectory();
5822
5909
  } catch {
5823
5910
  continue;
5824
5911
  }
@@ -5984,14 +6071,14 @@ function openNextRunLog(runLogsDir, runId) {
5984
6071
  const path = nextRunLogPath(runLogsDir, runId);
5985
6072
  let out;
5986
6073
  try {
5987
- out = openSync2(path, "wx");
6074
+ out = openSync3(path, "wx");
5988
6075
  } catch (e) {
5989
6076
  if (e.code !== "EEXIST") throw e;
5990
6077
  continue;
5991
6078
  }
5992
6079
  let err = null;
5993
6080
  try {
5994
- err = openSync2(`${path.slice(0, -".json".length)}.err.log`, "w");
6081
+ err = openSync3(`${path.slice(0, -".json".length)}.err.log`, "w");
5995
6082
  } catch {
5996
6083
  err = null;
5997
6084
  }
@@ -6052,7 +6139,7 @@ function makeLauncher(cfg) {
6052
6139
  }
6053
6140
  };
6054
6141
  const cfgPath = join7(worktree, ".swarm-mcp.json");
6055
- writeFileSync6(cfgPath, JSON.stringify(mcpConfig, null, 2));
6142
+ writeFileSync7(cfgPath, JSON.stringify(mcpConfig, null, 2));
6056
6143
  const model = run.model ?? process.env.SWARM_DRONE_MODEL ?? void 0;
6057
6144
  const pluginDirs = roleDirs(worktree, run.kind);
6058
6145
  const realHome = cfg.droneIsolation?.realHome ?? homedir2();
@@ -6072,7 +6159,7 @@ function makeLauncher(cfg) {
6072
6159
  errFd = fds.err ?? void 0;
6073
6160
  stdio = ["ignore", outFd, errFd ?? "ignore"];
6074
6161
  }
6075
- const child = spawn(cfg.claudeBin ?? resolveClaudeBin(), claudeArgs(cfgPath, prompt, continueSession, model, pluginDirs, settings), {
6162
+ const child = spawn2(cfg.claudeBin ?? resolveClaudeBin(), claudeArgs(cfgPath, prompt, continueSession, model, pluginDirs, settings), {
6076
6163
  cwd: worktree,
6077
6164
  detached: true,
6078
6165
  stdio,
@@ -6082,8 +6169,8 @@ function makeLauncher(cfg) {
6082
6169
  // Остальной env демона наследуется, как раньше.
6083
6170
  env: droneEnv(worktree, process.env, home ? { droneHome: home, realHome } : void 0, cfg.droneCap?.() ?? null)
6084
6171
  });
6085
- if (outFd !== void 0) closeSync2(outFd);
6086
- if (errFd !== void 0) closeSync2(errFd);
6172
+ if (outFd !== void 0) closeSync3(outFd);
6173
+ if (errFd !== void 0) closeSync3(errFd);
6087
6174
  child.unref();
6088
6175
  if (child.pid == null) throw new Error("\u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C \u0434\u0440\u043E\u043D\u0430 (\u043D\u0435\u0442 pid)");
6089
6176
  return child.pid;
@@ -6091,13 +6178,13 @@ function makeLauncher(cfg) {
6091
6178
  }
6092
6179
 
6093
6180
  // src/git.ts
6094
- import { existsSync as existsSync7, readdirSync as readdirSync5, statSync as statSync5 } from "fs";
6181
+ import { existsSync as existsSync7, readdirSync as readdirSync5, statSync as statSync6 } from "fs";
6095
6182
  import { appendFile, mkdir, readFile, rm } from "fs/promises";
6096
6183
  import { isAbsolute, join as join8 } from "path";
6097
6184
  import { $ as $4 } from "execa";
6098
6185
  function isLinkedWorktree(dir) {
6099
6186
  try {
6100
- return statSync5(join8(dir, ".git")).isFile();
6187
+ return statSync6(join8(dir, ".git")).isFile();
6101
6188
  } catch {
6102
6189
  return false;
6103
6190
  }
@@ -6137,20 +6224,20 @@ async function removeWorktree(repo, path) {
6137
6224
  }
6138
6225
 
6139
6226
  // src/agentToken.ts
6140
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync7, unlinkSync as unlinkSync2 } from "fs";
6227
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync8, unlinkSync as unlinkSync2 } from "fs";
6141
6228
  import { join as join9 } from "path";
6142
6229
  var STORE_PATH2 = join9(SWARM_HOME, "agent.json");
6143
6230
  var base2 = (api) => api.replace(/\/$/, "");
6144
6231
  function loadAgentToken() {
6145
6232
  try {
6146
- const s = JSON.parse(readFileSync7(STORE_PATH2, "utf8"));
6233
+ const s = JSON.parse(readFileSync8(STORE_PATH2, "utf8"));
6147
6234
  return s.token ? s : null;
6148
6235
  } catch {
6149
6236
  return null;
6150
6237
  }
6151
6238
  }
6152
6239
  function saveAgentToken(s) {
6153
- writeFileSync7(STORE_PATH2, JSON.stringify(s, null, 2), { mode: 384 });
6240
+ writeFileSync8(STORE_PATH2, JSON.stringify(s, null, 2), { mode: 384 });
6154
6241
  }
6155
6242
  function clearAgentToken() {
6156
6243
  try {
@@ -6202,19 +6289,19 @@ import { basename as basename3, isAbsolute as isAbsolute2, join as join11 } from
6202
6289
  var SHOT_MAX_FILE_BYTES = 10 * 1024 * 1024;
6203
6290
 
6204
6291
  // src/workspace.ts
6205
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync8, unlinkSync as unlinkSync3 } from "fs";
6292
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync9, unlinkSync as unlinkSync3 } from "fs";
6206
6293
  import { join as join12 } from "path";
6207
6294
  var WORKSPACE_PATH = join12(SWARM_HOME, "workspace.json");
6208
6295
  function loadWorkspace() {
6209
6296
  try {
6210
- const w = JSON.parse(readFileSync8(WORKSPACE_PATH, "utf8"));
6297
+ const w = JSON.parse(readFileSync9(WORKSPACE_PATH, "utf8"));
6211
6298
  return w && typeof w.id === "string" && w.id ? w : null;
6212
6299
  } catch {
6213
6300
  return null;
6214
6301
  }
6215
6302
  }
6216
6303
  function saveWorkspace(w) {
6217
- writeFileSync8(WORKSPACE_PATH, JSON.stringify(w, null, 2), { mode: 384 });
6304
+ writeFileSync9(WORKSPACE_PATH, JSON.stringify(w, null, 2), { mode: 384 });
6218
6305
  }
6219
6306
  function clearWorkspace() {
6220
6307
  try {
@@ -6695,7 +6782,7 @@ async function daemonStatus2() {
6695
6782
  var NO_DAEMON_NOTE = `\u0434\u0435\u043C\u043E\u043D \u043D\u0435 \u043E\u0442\u0432\u0435\u0447\u0430\u0435\u0442 (\u043C\u043E\u0440\u0434\u0430 127.0.0.1:${WEB_PORT}) \u2014 \u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u044E \u041B\u041E\u041A\u0410\u041B\u042C\u041D\u042B\u0419 \u0441\u0442\u043E\u0440 \u044D\u0442\u043E\u0439 \u043C\u0430\u0448\u0438\u043D\u044B, \u043E\u043D \u043C\u043E\u0436\u0435\u0442 \u0440\u0430\u0441\u0445\u043E\u0434\u0438\u0442\u044C\u0441\u044F \u0441 \u0434\u0430\u0448\u0431\u043E\u0440\u0434\u043E\u043C. \u041F\u043E\u0434\u043D\u0438\u043C\u0438 \u0434\u0435\u043C\u043E\u043D\u0430: swarm start`;
6696
6783
 
6697
6784
  // src/pauseState.ts
6698
- import { existsSync as existsSync8, readFileSync as readFileSync9, renameSync as renameSync3, unlinkSync as unlinkSync4, writeFileSync as writeFileSync9 } from "fs";
6785
+ import { existsSync as existsSync8, readFileSync as readFileSync10, renameSync as renameSync4, unlinkSync as unlinkSync4, writeFileSync as writeFileSync10 } from "fs";
6699
6786
  import { join as join13 } from "path";
6700
6787
  function pauseStatePath(home) {
6701
6788
  return join13(home, "pause.json");
@@ -6703,7 +6790,7 @@ function pauseStatePath(home) {
6703
6790
  var ACTIVE = { paused: false, at: "", source: "cli" };
6704
6791
  function loadPauseState(home, io = {}) {
6705
6792
  const exists = io.exists ?? existsSync8;
6706
- const readFile2 = io.readFile ?? ((p) => readFileSync9(p, "utf8"));
6793
+ const readFile2 = io.readFile ?? ((p) => readFileSync10(p, "utf8"));
6707
6794
  const path = pauseStatePath(home);
6708
6795
  if (!exists(path)) return ACTIVE;
6709
6796
  try {
@@ -6727,8 +6814,8 @@ function savePauseState(home, state, io = {}) {
6727
6814
  return;
6728
6815
  }
6729
6816
  const writeFile2 = io.writeFile ?? ((p, data) => {
6730
- writeFileSync9(`${p}.tmp`, data);
6731
- renameSync3(`${p}.tmp`, p);
6817
+ writeFileSync10(`${p}.tmp`, data);
6818
+ renameSync4(`${p}.tmp`, p);
6732
6819
  });
6733
6820
  writeFile2(path, JSON.stringify(state, null, 2));
6734
6821
  }
@@ -6757,10 +6844,10 @@ function sinceText(at, now) {
6757
6844
  }
6758
6845
 
6759
6846
  // src/heartbeat.ts
6760
- import { readFileSync as readFileSync10, renameSync as renameSync4, writeFileSync as writeFileSync10 } from "fs";
6847
+ import { readFileSync as readFileSync11, renameSync as renameSync5, writeFileSync as writeFileSync11 } from "fs";
6761
6848
  function readHeartbeat(path) {
6762
6849
  try {
6763
- const ms = Number(readFileSync10(path, "utf8").trim());
6850
+ const ms = Number(readFileSync11(path, "utf8").trim());
6764
6851
  return Number.isFinite(ms) ? ms : null;
6765
6852
  } catch {
6766
6853
  return null;
@@ -6948,6 +7035,98 @@ async function waitDaemonDown(opts) {
6948
7035
  await sleep2(pollMs);
6949
7036
  }
6950
7037
  }
7038
+ var MAX_DAEMON_LOG_BYTES = 16 * 1024 * 1024;
7039
+ var START_READY_TIMEOUT_MS = 45e3;
7040
+ async function runStartDetached(args) {
7041
+ const already = await daemonStatus2();
7042
+ if (already) {
7043
+ console.log(`\u0434\u0435\u043C\u043E\u043D \u0443\u0436\u0435 \u043F\u043E\u0434\u043D\u044F\u0442 (v${already.version})${already.hostName ? `, \u043C\u0430\u0448\u0438\u043D\u0430 \xAB${already.hostName}\xBB` : ""} \u2014 \u0432\u0442\u043E\u0440\u043E\u0433\u043E \u043D\u0435 \u043D\u0443\u0436\u043D\u043E.`);
7044
+ console.log("\u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435: swarm status \xB7 \u043B\u043E\u0433: swarm logs -f \xB7 \u043F\u043E\u0433\u0430\u0441\u0438\u0442\u044C: swarm stop");
7045
+ return 0;
7046
+ }
7047
+ const rotated = rotateDaemonLog(DAEMON_LOG_PATH, MAX_DAEMON_LOG_BYTES);
7048
+ const entry = process.argv[1];
7049
+ if (!entry) {
7050
+ console.error("\u043D\u0435\u0447\u0435\u043C \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C \u0441\u0435\u0431\u044F \u0444\u043E\u043D\u043E\u043C (\u043F\u0443\u0441\u0442\u043E\u0439 argv[1]) \u2014 \u043F\u043E\u0434\u043D\u0438\u043C\u0438 \u0432 \u0442\u0435\u0440\u043C\u0438\u043D\u0430\u043B\u0435: swarm start --foreground");
7051
+ return 1;
7052
+ }
7053
+ let launch;
7054
+ try {
7055
+ launch = launchDetached({
7056
+ execPath: process.execPath,
7057
+ // execArgv тащим за собой намеренно: в монорепе CLI запускают через tsx-loader, и
7058
+ // без него ребёнок не прочитает .ts-исходник, с которого сам же и стартовал.
7059
+ execArgv: process.execArgv,
7060
+ entry,
7061
+ args: childStartArgv(args),
7062
+ logPath: DAEMON_LOG_PATH,
7063
+ env: process.env
7064
+ });
7065
+ } catch (e) {
7066
+ console.error(`\u043D\u0435 \u0441\u043C\u043E\u0433 \u043E\u0442\u0434\u0435\u043B\u0438\u0442\u044C \u0434\u0435\u043C\u043E\u043D\u0430 \u043E\u0442 \u0442\u0435\u0440\u043C\u0438\u043D\u0430\u043B\u0430: ${e instanceof Error ? e.message : e}`);
7067
+ console.error("\u043F\u043E\u0434\u043D\u0438\u043C\u0438 \u0432 \u0442\u0435\u0440\u043C\u0438\u043D\u0430\u043B\u0435: swarm start --foreground");
7068
+ return 1;
7069
+ }
7070
+ console.log(`\u043F\u043E\u0434\u043D\u0438\u043C\u0430\u044E \u0440\u043E\u0439 \u0444\u043E\u043D\u043E\u043C (pid ${launch.pid}), \u043B\u043E\u0433: ${DAEMON_LOG_PATH}${rotated === "rotated" ? " (\u043F\u0440\u043E\u0448\u043B\u044B\u0439 \u0443\u0435\u0445\u0430\u043B \u0432 .1)" : ""}`);
7071
+ const verdict = await waitForReady({
7072
+ probe: async () => await daemonStatus2() != null,
7073
+ alive: launch.alive,
7074
+ timeoutMs: START_READY_TIMEOUT_MS,
7075
+ pollMs: 500
7076
+ });
7077
+ if (verdict === "ready") {
7078
+ console.log("\u0440\u043E\u0439 \u043F\u043E\u0434\u043D\u044F\u0442, \u0442\u0435\u0440\u043C\u0438\u043D\u0430\u043B \u0441\u0432\u043E\u0431\u043E\u0434\u0435\u043D. \u0421\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435: swarm status \xB7 \u043B\u043E\u0433: swarm logs -f \xB7 \u043F\u043E\u0433\u0430\u0441\u0438\u0442\u044C: swarm stop");
7079
+ return 0;
7080
+ }
7081
+ console.error(
7082
+ verdict === "died" ? "\u0434\u0435\u043C\u043E\u043D \u041D\u0415 \u043F\u043E\u0434\u043D\u044F\u043B\u0441\u044F \u2014 \u043F\u0440\u043E\u0446\u0435\u0441\u0441 \u0432\u044B\u0448\u0435\u043B \u0441\u0440\u0430\u0437\u0443. \u041F\u0440\u0438\u0447\u0438\u043D\u0430 \u0432 \u0445\u0432\u043E\u0441\u0442\u0435 \u043B\u043E\u0433\u0430:" : `\u0434\u0435\u043C\u043E\u043D \u043D\u0435 \u043E\u0442\u043E\u0437\u0432\u0430\u043B\u0441\u044F \u0437\u0430 ${Math.round(START_READY_TIMEOUT_MS / 1e3)}\u0441 (\u043F\u0440\u043E\u0446\u0435\u0441\u0441 \u0435\u0449\u0451 \u0436\u0438\u0432, pid ${launch.pid}). \u0425\u0432\u043E\u0441\u0442 \u043B\u043E\u0433\u0430:`
7083
+ );
7084
+ console.error(tailFile(DAEMON_LOG_PATH, 20) || `(\u043B\u043E\u0433 \u043F\u0443\u0441\u0442: ${DAEMON_LOG_PATH})`);
7085
+ return 1;
7086
+ }
7087
+ async function runDaemonLogs(argv) {
7088
+ const follow = argv.includes("-f") || argv.includes("--follow");
7089
+ const nAt = argv.findIndex((a) => a === "-n" || a === "--lines");
7090
+ const lines = nAt >= 0 ? Number(argv[nAt + 1]) : 200;
7091
+ if (!Number.isFinite(lines) || lines <= 0) {
7092
+ console.error("\u043D\u0443\u0436\u043D\u043E \u0447\u0438\u0441\u043B\u043E \u0441\u0442\u0440\u043E\u043A: swarm logs -n 200");
7093
+ return 1;
7094
+ }
7095
+ const stray = argv.find((a, i) => /^\d+$/.test(a) && i !== nAt + 1);
7096
+ if (stray) {
7097
+ 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.`);
7098
+ return 1;
7099
+ }
7100
+ if (!existsSync9(DAEMON_LOG_PATH)) {
7101
+ console.error(`\u043B\u043E\u0433\u0430 \u0434\u0435\u043C\u043E\u043D\u0430 \u043D\u0435\u0442: ${DAEMON_LOG_PATH}`);
7102
+ 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.");
7103
+ return 1;
7104
+ }
7105
+ const head = tailFile(DAEMON_LOG_PATH, lines);
7106
+ if (head) console.log(head);
7107
+ if (!follow) return 0;
7108
+ let pos = statSync7(DAEMON_LOG_PATH).size;
7109
+ for (; ; ) {
7110
+ await sleep2(500);
7111
+ let size;
7112
+ try {
7113
+ size = statSync7(DAEMON_LOG_PATH).size;
7114
+ } catch {
7115
+ continue;
7116
+ }
7117
+ if (size < pos) pos = 0;
7118
+ if (size === pos) continue;
7119
+ const fd = openSync4(DAEMON_LOG_PATH, "r");
7120
+ try {
7121
+ const buf = Buffer.alloc(size - pos);
7122
+ const read = readSync2(fd, buf, 0, buf.length, pos);
7123
+ process.stdout.write(buf.subarray(0, read).toString("utf8"));
7124
+ pos += read;
7125
+ } finally {
7126
+ closeSync4(fd);
7127
+ }
7128
+ }
7129
+ }
6951
7130
  async function runStop(argv) {
6952
7131
  const force = argv.includes("--force");
6953
7132
  const wait = argv.includes("--wait");
@@ -7092,33 +7271,62 @@ function printRuns(runs, view) {
7092
7271
  }).forEach((l) => console.log(l));
7093
7272
  }
7094
7273
  function usage() {
7095
- console.log(`swarm \u2014 \u0440\u043E\u0439 \u0434\u0440\u043E\u043D\u043E\u0432 (v${PACKAGE_VERSION2})
7274
+ console.log(`swarm \u2014 \u0440\u043E\u0439 AI-\u0434\u0440\u043E\u043D\u043E\u0432 (v${PACKAGE_VERSION2})
7096
7275
 
7097
- swarm login [--workspace <slug|id>] [--no-open] \u0432\u0445\u043E\u0434 \u0432 \u043F\u0440\u043E\u0434 + \u0432\u044B\u0431\u043E\u0440 \u0432\u043E\u0440\u043A\u0441\u043F\u0435\u0439\u0441\u0430
7098
- swarm start [--repo <path>] \u043F\u043E\u0434\u043D\u044F\u0442\u044C \u0434\u0435\u043C\u043E\u043D\u0430: \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u0442 \u043E\u0447\u0435\u0440\u0435\u0434\u044C, \u0441\u043F\u0430\u0432\u043D\u0438\u0442/\u0431\u0443\u0434\u0438\u0442 \u0434\u0440\u043E\u043D\u043E\u0432
7276
+ \u041D\u0410\u0427\u0410\u0422\u042C
7277
+ swarm login [--workspace <slug|id>] [--no-open]
7278
+ \u0432\u043E\u0439\u0442\u0438 \u0432 Taskless \u0438 \u0432\u044B\u0431\u0440\u0430\u0442\u044C \u0432\u043E\u0440\u043A\u0441\u043F\u0435\u0439\u0441
7279
+ swarm start [--repo <path>] [--foreground]
7280
+ \u043F\u043E\u0434\u043D\u044F\u0442\u044C \u0440\u043E\u0439 \u043D\u0430 \u044D\u0442\u043E\u0439 \u043C\u0430\u0448\u0438\u043D\u0435: \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u0442 \u043E\u0447\u0435\u0440\u0435\u0434\u044C, \u0441\u043F\u0430\u0432\u043D\u0438\u0442 \u0438 \u0431\u0443\u0434\u0438\u0442 \u0434\u0440\u043E\u043D\u043E\u0432
7099
7281
  swarm status \u0436\u0438\u0432 \u043B\u0438 \u0434\u0435\u043C\u043E\u043D, \u043D\u0430 \u043F\u0430\u0443\u0437\u0435 \u043B\u0438 \u0440\u043E\u0439, \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0434\u0440\u043E\u043D\u043E\u0432 \u0432 \u0440\u0430\u0431\u043E\u0442\u0435
7100
- swarm pause [\u043F\u0440\u0438\u0447\u0438\u043D\u0430\u2026] \u043D\u0435 \u0431\u0440\u0430\u0442\u044C \u043D\u043E\u0432\u0443\u044E \u0440\u0430\u0431\u043E\u0442\u0443 (\u0436\u0438\u0432\u044B\u0435 \u0434\u0440\u043E\u043D\u044B \u0434\u043E\u0440\u0430\u0431\u043E\u0442\u0430\u044E\u0442); \u043F\u0435\u0440\u0435\u0436\u0438\u0432\u0430\u0435\u0442 \u0440\u0435\u0441\u0442\u0430\u0440\u0442 \u0434\u0435\u043C\u043E\u043D\u0430
7101
- swarm resume \u0441\u043D\u044F\u0442\u044C \u043F\u0430\u0443\u0437\u0443
7102
- swarm stop [--wait|--force] \u043F\u043E\u0433\u0430\u0441\u0438\u0442\u044C \u0434\u0435\u043C\u043E\u043D\u0430 \u043D\u0430 \u044D\u0442\u043E\u0439 \u043C\u0430\u0448\u0438\u043D\u0435: \u0431\u0435\u0437 \u0444\u043B\u0430\u0433\u043E\u0432 \u043F\u0440\u0438 \u0436\u0438\u0432\u044B\u0445 \u0434\u0440\u043E\u043D\u0430\u0445 \u041D\u0415 \u0433\u0430\u0441\u0438\u0442,
7103
- \u0430 \u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442, \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0438\u0445; --wait \u2014 \u0434\u043E\u0436\u0434\u0430\u0442\u044C\u0441\u044F \u0438\u0445 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u0438\u044F; --force \u2014 \u0441\u0435\u0439\u0447\u0430\u0441
7104
- swarm remove [--yes] [--wait|--force] \u043E\u0442\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u043C\u0430\u0448\u0438\u043D\u0443 \u043E\u0442 \u0440\u043E\u044F: \u043F\u043E\u0433\u0430\u0441\u0438\u0442\u044C \u0434\u0435\u043C\u043E\u043D\u0430, \u0443\u0431\u0440\u0430\u0442\u044C \u0435\u0451 \u0438\u0437 \u043F\u0430\u0440\u043A\u0430 \u0438 \u0441\u0442\u0435\u0440\u0435\u0442\u044C \u0442\u043E\u043A\u0435\u043D\u044B
7105
- swarm ls [status] \u0441\u043F\u0438\u0441\u043E\u043A \u043F\u0440\u043E\u0433\u043E\u043D\u043E\u0432 \u0416\u0418\u0412\u041E\u0413\u041E \u0414\u0415\u041C\u041E\u041D\u0410 \u2014 \u0440\u043E\u0432\u043D\u043E \u0442\u0435, \u0447\u0442\u043E \u0432 \u0434\u0430\u0448\u0431\u043E\u0440\u0434\u0435 (\u043E\u043F\u0446. \u0444\u0438\u043B\u044C\u0442\u0440 \u043F\u043E \u0441\u0442\u0430\u0442\u0443\u0441\u0443)
7106
- swarm spawn <slug> [area] [--repo <path>] [--after <s1,s2>] [--priority <n>] [--base <\u0432\u0435\u0442\u043A\u0430>] [--host <\u043C\u0430\u0448\u0438\u043D\u0430|any>] \u0432 \u043E\u0447\u0435\u0440\u0435\u0434\u044C (--after \u2192 \u0436\u0434\u0430\u0442\u044C done \u0437\u0430\u0432\u0438\u0441\u0438\u043C\u043E\u0441\u0442\u0435\u0439, --priority \u2192 \u0432\u044B\u0448\u0435 \u0431\u0435\u0440\u0451\u0442\u0441\u044F \u0440\u0430\u043D\u044C\u0448\u0435, --base \u2192 PR \u0432 \u044D\u0442\u0443 \u0432\u0435\u0442\u043A\u0443, \u0430 \u043D\u0435 \u0432 \u0434\u0435\u0444\u043E\u043B\u0442\u043D\u0443\u044E, --host \u2192 \u043C\u0430\u0448\u0438\u043D\u0430 \u043F\u0440\u043E\u0433\u043E\u043D\u0430: \u041F\u041E \u0423\u041C\u041E\u041B\u0427\u0410\u041D\u0418\u042E \u044D\u0442\u0430, \xABany\xBB \u2192 \u043B\u044E\u0431\u0430\u044F \u0441\u0432\u043E\u0431\u043E\u0434\u043D\u0430\u044F)
7107
- swarm hosts \u043C\u0430\u0448\u0438\u043D\u044B \u0440\u043E\u044F: \u0438\u043C\u044F, \u043F\u0443\u043B\u044C\u0441, \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0438, id (\u0438\u043C\u044F \u0434\u043B\u044F --host)
7108
- swarm spawn <slug> --hero [--name HYDRA] [--repo <path>] [--after <s1,s2>] [--priority <n>] \u0413\u0435\u0440\u043E\u0439-\u043B\u0435\u0439\u0442\u0435\u043D\u0430\u043D\u0442 \u044D\u043F\u0438\u043A\u0430
7109
- swarm wake <runId> \u0440\u0430\u0437\u0431\u0443\u0434\u0438\u0442\u044C \u043F\u0440\u043E\u0433\u043E\u043D (id \u0438\u0437 swarm ls) \u2014 \u0447\u0435\u0440\u0435\u0437 \u0436\u0438\u0432\u043E\u0433\u043E \u0434\u0435\u043C\u043E\u043D\u0430; \u043D\u0435\u0447\u0435\u0433\u043E \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0430\u0442\u044C \u2192 \u0441\u0442\u0430\u0440\u0442 \u0441 \u043D\u0443\u043B\u044F
7282
+
7283
+ \u0414\u0410\u0422\u042C \u0420\u041E\u042E \u0420\u0410\u0411\u041E\u0422\u0423
7284
+ swarm spawn <slug> [area] [\u0444\u043B\u0430\u0433\u0438 \u043D\u0438\u0436\u0435]
7285
+ \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0437\u0430\u0434\u0430\u0447\u0443 \u0432 \u043E\u0447\u0435\u0440\u0435\u0434\u044C
7286
+ swarm ls [\u0441\u0442\u0430\u0442\u0443\u0441] \u043F\u0440\u043E\u0433\u043E\u043D\u044B \u0436\u0438\u0432\u043E\u0433\u043E \u0434\u0435\u043C\u043E\u043D\u0430 \u2014 \u0440\u043E\u0432\u043D\u043E \u0442\u0435, \u0447\u0442\u043E \u0432 \u0434\u0430\u0448\u0431\u043E\u0440\u0434\u0435
7287
+ swarm wake <runId> \u0440\u0430\u0437\u0431\u0443\u0434\u0438\u0442\u044C \u043F\u0440\u043E\u0433\u043E\u043D (id \u0438\u0437 swarm ls); \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0430\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E \u2192 \u043D\u0430\u0447\u043D\u0451\u0442 \u0441 \u043D\u0443\u043B\u044F
7288
+ swarm cancel <slug> <\u043F\u0440\u0438\u0447\u0438\u043D\u0430\u2026>
7289
+ \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u0434\u0440\u043E\u043D\u0430: \u0441\u0442\u0430\u0442\u0443\u0441 \xAB\u043E\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\xBB \u0441 \u043F\u0440\u0438\u0447\u0438\u043D\u043E\u0439, \u0432 \u0438\u0441\u0442\u043E\u0440\u0438\u0438 \u043E\u0441\u0442\u0430\u043D\u0435\u0442\u0441\u044F
7110
7290
  swarm questions \u043E\u0442\u043A\u0440\u044B\u0442\u044B\u0435 \u0432\u043E\u043F\u0440\u043E\u0441\u044B \u0434\u0440\u043E\u043D\u043E\u0432
7111
- swarm answer <qid> <...> \u043E\u0442\u0432\u0435\u0442\u0438\u0442\u044C \u043D\u0430 \u0432\u043E\u043F\u0440\u043E\u0441 (\u0440\u0430\u0437\u0431\u0443\u0434\u0438\u0442 \u0434\u0440\u043E\u043D\u0430)
7112
- swarm cancel <slug> <\u043F\u0440\u0438\u0447\u0438\u043D\u0430\u2026> \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u0434\u0440\u043E\u043D\u0430 \u0447\u0435\u0440\u0435\u0437 \u0436\u0438\u0432\u043E\u0433\u043E \u0434\u0435\u043C\u043E\u043D\u0430 (\u0441\u0442\u0430\u0442\u0443\u0441 \xAB\u043E\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\xBB + \u043F\u0440\u0438\u0447\u0438\u043D\u0430; \u0432 \u0438\u0441\u0442\u043E\u0440\u0438\u0438 \u043E\u0441\u0442\u0430\u0451\u0442\u0441\u044F)
7113
- swarm import-db <path> --repo <path> \u0438\u043C\u043F\u043E\u0440\u0442 \u0438\u0441\u0442\u043E\u0440\u0438\u0438 \u0438\u0437 \u0434\u0440\u0443\u0433\u043E\u0439 \u0411\u0414 (\u0438\u0434\u0435\u043C\u043F\u043E\u0442\u0435\u043D\u0442\u043D\u043E)
7114
- swarm log <runId> \u043B\u043E\u0433 \u043F\u0440\u043E\u0433\u043E\u043D\u0430
7115
- swarm logout \u0437\u0430\u0431\u044B\u0442\u044C \u0442\u043E\u043A\u0435\u043D\u044B \u0438 \u0432\u044B\u0431\u043E\u0440 \u0432\u043E\u0440\u043A\u0441\u043F\u0435\u0439\u0441\u0430
7291
+ swarm answer <qid> <\u0442\u0435\u043A\u0441\u0442\u2026>
7292
+ \u043E\u0442\u0432\u0435\u0442\u0438\u0442\u044C \u043D\u0430 \u0432\u043E\u043F\u0440\u043E\u0441 \u0438 \u0440\u0430\u0437\u0431\u0443\u0434\u0438\u0442\u044C \u0434\u0440\u043E\u043D\u0430
7293
+
7294
+ \u0423\u041F\u0420\u0410\u0412\u041B\u042F\u0422\u042C \u041C\u0410\u0428\u0418\u041D\u041E\u0419
7295
+ swarm pause [\u043F\u0440\u0438\u0447\u0438\u043D\u0430\u2026] \u043D\u0435 \u0431\u0440\u0430\u0442\u044C \u043D\u043E\u0432\u0443\u044E \u0440\u0430\u0431\u043E\u0442\u0443; \u0436\u0438\u0432\u044B\u0435 \u0434\u0440\u043E\u043D\u044B \u0434\u043E\u0440\u0430\u0431\u043E\u0442\u0430\u044E\u0442. \u041F\u0435\u0440\u0435\u0436\u0438\u0432\u0430\u0435\u0442 \u0440\u0435\u0441\u0442\u0430\u0440\u0442
7296
+ swarm resume \u0441\u043D\u043E\u0432\u0430 \u0431\u0440\u0430\u0442\u044C \u0440\u0430\u0431\u043E\u0442\u0443
7297
+ swarm stop [--wait|--force]
7298
+ \u043F\u043E\u0433\u0430\u0441\u0438\u0442\u044C \u0434\u0435\u043C\u043E\u043D\u0430 \u043D\u0430 \u044D\u0442\u043E\u0439 \u043C\u0430\u0448\u0438\u043D\u0435
7299
+ swarm remove [--yes] [--wait|--force]
7300
+ \u043E\u0442\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u043C\u0430\u0448\u0438\u043D\u0443 \u043E\u0442 \u0440\u043E\u044F: \u043F\u043E\u0433\u0430\u0441\u0438\u0442\u044C, \u0443\u0431\u0440\u0430\u0442\u044C \u0438\u0437 \u043F\u0430\u0440\u043A\u0430, \u0441\u0442\u0435\u0440\u0435\u0442\u044C \u0442\u043E\u043A\u0435\u043D\u044B
7301
+ swarm hosts \u043C\u0430\u0448\u0438\u043D\u044B \u0440\u043E\u044F: \u0438\u043C\u044F, \u043F\u0443\u043B\u044C\u0441, \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0438, id (\u0438\u043C\u044F \u0433\u043E\u0434\u0438\u0442\u0441\u044F \u0434\u043B\u044F --host)
7302
+
7303
+ \u0421\u041C\u041E\u0422\u0420\u0415\u0422\u042C, \u0427\u0422\u041E \u041F\u0420\u041E\u0418\u0421\u0425\u041E\u0414\u0418\u0422
7304
+ swarm logs [-n 200] [-f] \u043B\u043E\u0433 \u0414\u0415\u041C\u041E\u041D\u0410 (~/.taskless-swarm/overmind.log)
7305
+ swarm log <runId> \u043B\u043E\u0433 \u043E\u0434\u043D\u043E\u0433\u043E \u041F\u0420\u041E\u0413\u041E\u041D\u0410 \u2014 \u043D\u0435 \u043F\u0443\u0442\u0430\u0442\u044C \u0441 \u043F\u0440\u0435\u0434\u044B\u0434\u0443\u0449\u0435\u0439
7306
+ swarm web \u0432\u0435\u0431-\u043C\u043E\u0440\u0434\u0430 \u0440\u043E\u044F \u043D\u0430 127.0.0.1:${WEB_PORT}
7307
+
7308
+ \u041F\u0420\u041E\u0427\u0415\u0415
7116
7309
  swarm whoami \u043A\u0442\u043E \u0432\u043E\u0448\u0451\u043B \u0438 \u0432 \u043A\u0430\u043A\u043E\u043C \u0432\u043E\u0440\u043A\u0441\u043F\u0435\u0439\u0441\u0435
7117
- swarm web \u0432\u0435\u0431-\u043C\u043E\u0440\u0434\u0430 (\u0432\u0445\u043E\u0434 + \u0441\u0442\u0430\u0442\u0443\u0441) \u043D\u0430 127.0.0.1
7310
+ swarm logout \u0437\u0430\u0431\u044B\u0442\u044C \u0442\u043E\u043A\u0435\u043D\u044B \u0438 \u0432\u044B\u0431\u043E\u0440 \u0432\u043E\u0440\u043A\u0441\u043F\u0435\u0439\u0441\u0430
7118
7311
  swarm shot <url> <out-prefix> [--timeout <ms>] [--storage-state <path>]
7119
- headless-\u0441\u043A\u0440\u0438\u043D desktop+mobile \u041E\u0414\u041D\u041E\u0419 \u043A\u043E\u043C\u0430\u043D\u0434\u043E\u0439 (TASWM-40):
7312
+ headless-\u0441\u043A\u0440\u0438\u043D\u044B desktop+mobile \u043E\u0434\u043D\u043E\u0439 \u043A\u043E\u043C\u0430\u043D\u0434\u043E\u0439:
7120
7313
  <out-prefix>-desktop.png, <out-prefix>-mobile.png
7314
+ swarm import-db <path> --repo <path>
7315
+ \u0438\u043C\u043F\u043E\u0440\u0442 \u0438\u0441\u0442\u043E\u0440\u0438\u0438 \u043F\u0440\u043E\u0433\u043E\u043D\u043E\u0432 \u0438\u0437 \u0434\u0440\u0443\u0433\u043E\u0439 \u0411\u0414 (\u0438\u0434\u0435\u043C\u043F\u043E\u0442\u0435\u043D\u0442\u043D\u043E)
7121
7316
  swarm --version \u0432\u0435\u0440\u0441\u0438\u044F \u043F\u0430\u043A\u0435\u0442\u0430
7317
+
7318
+ \u0424\u041B\u0410\u0413\u0418, \u041A\u041E\u0422\u041E\u0420\u042B\u0415 \u0421\u0422\u041E\u0418\u0422 \u0417\u041D\u0410\u0422\u042C
7319
+ start \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E \u0434\u0435\u043C\u043E\u043D \u041E\u0422\u041A\u0420\u0415\u041F\u041B\u042F\u0415\u0422\u0421\u042F: \u0443\u0445\u043E\u0434\u0438\u0442 \u0432 \u0444\u043E\u043D, \u043F\u0438\u0448\u0435\u0442 \u0432 ~/.taskless-swarm/overmind.log,
7320
+ \u0442\u0435\u0440\u043C\u0438\u043D\u0430\u043B \u0441\u0432\u043E\u0431\u043E\u0434\u0435\u043D. --foreground (\u043E\u043D \u0436\u0435 -f, --attach) \u0434\u0435\u0440\u0436\u0438\u0442 \u0435\u0433\u043E \u0432 \u0442\u0435\u0440\u043C\u0438\u043D\u0430\u043B\u0435 \u2014
7321
+ \u0434\u043B\u044F \u043E\u0442\u043B\u0430\u0434\u043A\u0438 \u0438 \u0442\u0430\u043C, \u0433\u0434\u0435 \u0444\u043E\u043D\u043E\u043C \u0437\u0430\u043D\u0438\u043C\u0430\u0435\u0442\u0441\u044F \u0441\u0443\u043F\u0435\u0440\u0432\u0438\u0437\u043E\u0440 (systemd, docker)
7322
+ spawn --repo <path> \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0439 \u043F\u0440\u043E\u0433\u043E\u043D\u0430, \u0435\u0441\u043B\u0438 \u043D\u0435 \u0434\u0435\u0444\u043E\u043B\u0442\u043D\u044B\u0439
7323
+ --after <s1,s2> \u0436\u0434\u0430\u0442\u044C, \u043F\u043E\u043A\u0430 \u043F\u0435\u0440\u0435\u0447\u0438\u0441\u043B\u0435\u043D\u043D\u044B\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u043D\u0435 \u0431\u0443\u0434\u0443\u0442 done
7324
+ --priority <n> \u0432\u044B\u0448\u0435 \u0447\u0438\u0441\u043B\u043E \u2014 \u0440\u0430\u043D\u044C\u0448\u0435 \u0432\u043E\u0437\u044C\u043C\u0443\u0442 \u0438\u0437 \u043E\u0447\u0435\u0440\u0435\u0434\u0438
7325
+ --base <\u0432\u0435\u0442\u043A\u0430> PR \u043D\u0435 \u0432 \u0434\u0435\u0444\u043E\u043B\u0442\u043D\u0443\u044E \u0432\u0435\u0442\u043A\u0443, \u0430 \u0432 \u044D\u0442\u0443
7326
+ --host <\u043C\u0430\u0448\u0438\u043D\u0430|any> \u043D\u0430 \u043A\u0430\u043A\u043E\u0439 \u043C\u0430\u0448\u0438\u043D\u0435 \u0440\u0430\u0431\u043E\u0442\u0430\u0442\u044C; \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E \u044D\u0442\u0430, \xABany\xBB \u2014 \u043B\u044E\u0431\u0430\u044F \u0441\u0432\u043E\u0431\u043E\u0434\u043D\u0430\u044F
7327
+ --hero [--name HYDRA] \u0413\u0435\u0440\u043E\u0439-\u043B\u0435\u0439\u0442\u0435\u043D\u0430\u043D\u0442 \u044D\u043F\u0438\u043A\u0430 \u0432\u043C\u0435\u0441\u0442\u043E \u043E\u0431\u044B\u0447\u043D\u043E\u0433\u043E \u0434\u0440\u043E\u043D\u0430
7328
+ stop \u0431\u0435\u0437 \u0444\u043B\u0430\u0433\u043E\u0432 \u043F\u0440\u0438 \u0436\u0438\u0432\u044B\u0445 \u0434\u0440\u043E\u043D\u0430\u0445 \u041D\u0415 \u0433\u0430\u0441\u0438\u0442, \u0430 \u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442, \u043A\u0442\u043E \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442: \u0438\u0445 \u043D\u0435\u0437\u0430\u043F\u0443\u0448\u0435\u043D\u043D\u043E\u0435
7329
+ \u0443\u043C\u0440\u0451\u0442 \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 \u043D\u0438\u043C\u0438. --wait \u2014 \u0434\u043E\u0436\u0434\u0430\u0442\u044C\u0441\u044F, \u043F\u043E\u043A\u0430 \u0434\u043E\u0440\u0430\u0431\u043E\u0442\u0430\u044E\u0442; --force \u2014 \u043E\u0431\u043E\u0440\u0432\u0430\u0442\u044C \u0441\u0435\u0439\u0447\u0430\u0441
7122
7330
  `);
7123
7331
  }
7124
7332
  var effectiveWorktreesDirMemo;
@@ -7208,14 +7416,18 @@ if (cmd === "import-db") {
7208
7416
  process.exit(0);
7209
7417
  }
7210
7418
  if (cmd === "start") {
7419
+ const { foreground, rest: startArgs } = parseStartMode(rawArgs);
7211
7420
  if (SWARM_BACKEND !== "client") {
7212
7421
  console.warn("SWARM_BACKEND=client \u043D\u0435 \u0437\u0430\u0434\u0430\u043D \u2014 \u0434\u0435\u043C\u043E\u043D \u043F\u043E\u0434\u043D\u0438\u043C\u0435\u0442\u0441\u044F \u0432 \u043B\u043E\u043A\u0430\u043B\u044C\u043D\u043E\u043C sqlite-\u0440\u0435\u0436\u0438\u043C\u0435, \u0411\u0415\u0417 \u0441\u0432\u044F\u0437\u0438 \u0441 \u0432\u043E\u0440\u043A\u0441\u043F\u0435\u0439\u0441\u043E\u043C Taskless (\u043D\u0435 \u0443\u0432\u0438\u0434\u0438\u0442 \u0437\u0430\u0434\u0430\u0447\u0438, \u043D\u0435 \u043F\u043E\u0448\u043B\u0451\u0442 \u043F\u0443\u043B\u044C\u0441).");
7213
7422
  }
7214
- const { repo: repoFlag } = takeRepo(rawArgs);
7423
+ const { repo: repoFlag } = takeRepo(startArgs);
7215
7424
  const repo = repoFlag ?? SWARM_REPO;
7216
7425
  if (!repo) {
7217
7426
  console.warn("SWARM_REPO \u043D\u0435 \u0437\u0430\u0434\u0430\u043D \u2014 \u043F\u0440\u043E\u0433\u043E\u043D\u044B \u0431\u0435\u0437 \u044F\u0432\u043D\u043E\u0433\u043E repo \u043D\u0435 \u0437\u0430\u043F\u0443\u0441\u0442\u044F\u0442\u0441\u044F (\u043D\u0443\u0436\u0435\u043D spawn --repo).");
7218
7427
  }
7428
+ if (!foreground) {
7429
+ process.exit(await runStartDetached(startArgs));
7430
+ }
7219
7431
  try {
7220
7432
  await runDaemon({ repo });
7221
7433
  } catch (e) {
@@ -7224,6 +7436,9 @@ if (cmd === "start") {
7224
7436
  }
7225
7437
  process.exit(0);
7226
7438
  }
7439
+ if (cmd === "logs") {
7440
+ process.exit(await runDaemonLogs(rawArgs));
7441
+ }
7227
7442
  if (cmd === "ls") {
7228
7443
  const snap = await daemonRuns(rawArgs[0]);
7229
7444
  if (snap) {
package/dist/overmind.js CHANGED
@@ -1910,9 +1910,25 @@ CREATE TABLE IF NOT EXISTS imports (
1910
1910
  }
1911
1911
  });
1912
1912
 
1913
+ // src/quietExec.ts
1914
+ import { execFileSync } from "child_process";
1915
+ function execQuiet(file, args = [], opts = {}) {
1916
+ return execFileSync(file, args, {
1917
+ encoding: "utf8",
1918
+ stdio: ["ignore", "pipe", "pipe"],
1919
+ ...opts.maxBuffer ? { maxBuffer: opts.maxBuffer } : {}
1920
+ });
1921
+ }
1922
+ var PROC_SNAPSHOT_MAX_BUFFER;
1923
+ var init_quietExec = __esm({
1924
+ "src/quietExec.ts"() {
1925
+ "use strict";
1926
+ PROC_SNAPSHOT_MAX_BUFFER = 16 * 1024 * 1024;
1927
+ }
1928
+ });
1929
+
1913
1930
  // src/resources.ts
1914
1931
  import os from "os";
1915
- import { execFileSync } from "child_process";
1916
1932
  import { readFileSync as readFileSync3, statfsSync } from "fs";
1917
1933
  function isTransientResourceError(e) {
1918
1934
  const code = e?.code;
@@ -1943,7 +1959,7 @@ function parseVmStatAvailableBytes(vmStatOut) {
1943
1959
  function availableMemBytes() {
1944
1960
  if (process.platform === "darwin") {
1945
1961
  try {
1946
- const bytes = parseVmStatAvailableBytes(execFileSync("vm_stat", { encoding: "utf8" }));
1962
+ const bytes = parseVmStatAvailableBytes(execQuiet("vm_stat"));
1947
1963
  if (bytes > 0) return bytes;
1948
1964
  } catch (e) {
1949
1965
  logTransientSpawnError("vm_stat", e);
@@ -1957,7 +1973,7 @@ function parseSysctlInt(out) {
1957
1973
  }
1958
1974
  function readSysctlPair(nameA, nameB) {
1959
1975
  try {
1960
- const lines = execFileSync("sysctl", ["-n", nameA, nameB], { encoding: "utf8" }).trim().split("\n");
1976
+ const lines = execQuiet("sysctl", ["-n", nameA, nameB]).trim().split("\n");
1961
1977
  return [parseSysctlInt(lines[0] ?? ""), parseSysctlInt(lines[1] ?? "")];
1962
1978
  } catch (e) {
1963
1979
  logTransientSpawnError(`sysctl ${nameA}/${nameB}`, e);
@@ -2099,6 +2115,7 @@ var prevCpuTicks, RESOURCES_CACHE_MS, readingCache;
2099
2115
  var init_resources = __esm({
2100
2116
  "src/resources.ts"() {
2101
2117
  "use strict";
2118
+ init_quietExec();
2102
2119
  init_config();
2103
2120
  prevCpuTicks = null;
2104
2121
  RESOURCES_CACHE_MS = 250;
@@ -2133,7 +2150,6 @@ var init_heartbeat = __esm({
2133
2150
  });
2134
2151
 
2135
2152
  // src/procList.ts
2136
- import { execFileSync as execFileSync2 } from "child_process";
2137
2153
  function parsePsRows(out) {
2138
2154
  const rows = [];
2139
2155
  for (const line of out.split("\n")) {
@@ -2168,7 +2184,7 @@ function parseWinProcRows(out) {
2168
2184
  return rows;
2169
2185
  }
2170
2186
  function realExec(file, args) {
2171
- return execFileSync2(file, args, { encoding: "utf8", maxBuffer: 16 * 1024 * 1024 });
2187
+ return execQuiet(file, args, { maxBuffer: PROC_SNAPSHOT_MAX_BUFFER });
2172
2188
  }
2173
2189
  function listProcs(opts = {}) {
2174
2190
  const platform = opts.platform ?? process.platform;
@@ -2226,13 +2242,13 @@ var WIN_PS_COMMAND;
2226
2242
  var init_procList = __esm({
2227
2243
  "src/procList.ts"() {
2228
2244
  "use strict";
2245
+ init_quietExec();
2229
2246
  init_resources();
2230
2247
  WIN_PS_COMMAND = "Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,CommandLine | ConvertTo-Json -Depth 2 -Compress";
2231
2248
  }
2232
2249
  });
2233
2250
 
2234
2251
  // src/procCleanup.ts
2235
- import { execFileSync as execFileSync3 } from "child_process";
2236
2252
  function sleep(ms) {
2237
2253
  return new Promise((resolve3) => setTimeout(resolve3, ms));
2238
2254
  }
@@ -2262,7 +2278,7 @@ function pidsWithCwdUnder(dir, opts = {}) {
2262
2278
  if ((opts.platform ?? process.platform) === "win32") return winProcsUnder(dir, opts.procs ?? listProcs);
2263
2279
  let out;
2264
2280
  try {
2265
- out = execFileSync3("lsof", ["-a", "-d", "cwd", "-F", "pn"], { encoding: "utf8", maxBuffer: 16 * 1024 * 1024 });
2281
+ out = execQuiet("lsof", ["-w", "-a", "-d", "cwd", "-F", "pn"], { maxBuffer: PROC_SNAPSHOT_MAX_BUFFER });
2266
2282
  } catch (e) {
2267
2283
  logTransientSpawnError("lsof", e);
2268
2284
  return [];
@@ -2373,7 +2389,7 @@ function findOrphanContainers(containerNames, runs) {
2373
2389
  }
2374
2390
  function dockerContainerNames() {
2375
2391
  try {
2376
- return execFileSync3("docker", ["ps", "-a", "--format", "{{.Names}}"], { encoding: "utf8" }).split("\n").map((s) => s.trim()).filter(Boolean);
2392
+ return execQuiet("docker", ["ps", "-a", "--format", "{{.Names}}"]).split("\n").map((s) => s.trim()).filter(Boolean);
2377
2393
  } catch (e) {
2378
2394
  logTransientSpawnError("docker ps", e);
2379
2395
  return [];
@@ -2383,7 +2399,7 @@ function removeContainers(names) {
2383
2399
  const removed = [];
2384
2400
  for (const name of names) {
2385
2401
  try {
2386
- execFileSync3("docker", ["rm", "-f", name], { encoding: "utf8" });
2402
+ execQuiet("docker", ["rm", "-f", name]);
2387
2403
  removed.push(name);
2388
2404
  } catch (e) {
2389
2405
  console.warn(`[procCleanup] docker rm -f ${name} \u0441\u043E\u0440\u0432\u0430\u043B\u0441\u044F: ${String(e)}`);
@@ -2445,6 +2461,7 @@ async function sweepOrphans(params) {
2445
2461
  var init_procCleanup = __esm({
2446
2462
  "src/procCleanup.ts"() {
2447
2463
  "use strict";
2464
+ init_quietExec();
2448
2465
  init_resources();
2449
2466
  init_procList();
2450
2467
  }
@@ -9035,7 +9052,7 @@ async function collectRunDiff(worktree, opts = {}) {
9035
9052
  // package.json
9036
9053
  var package_default = {
9037
9054
  name: "@taskless-app/swarm",
9038
- version: "0.4.2",
9055
+ version: "0.4.4",
9039
9056
  type: "module",
9040
9057
  description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
9041
9058
  keywords: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taskless-app/swarm",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "type": "module",
5
5
  "description": "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
6
6
  "keywords": [