@taskless-app/swarm 0.6.0 → 0.6.1

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
@@ -152,6 +152,27 @@ swarm remove --yes # отключить машину от роя цел
152
152
  машин (её незавершённые прогоны освобождаются и уедут на другие машины) и стирает
153
153
  токены. Вернуть — `swarm login && swarm start`.
154
154
 
155
+ ## Перелогин — одна команда
156
+
157
+ Токен машины отзывается сам собой: вошли на второй машине, нажали «сбросить токен
158
+ роя», выключили рой тумблером. Демон при этом жив и тикает, но работу не берёт, а в
159
+ логе повторяет одну строку — «токен роя отозван … Почини одной командой: swarm login».
160
+
161
+ ```bash
162
+ swarm login # и всё: без stop, без start, без чтения логов
163
+ ```
164
+
165
+ Команда сама разруливает демона: увидела поднятого — **гасит его аккуратно** (как
166
+ `swarm stop --wait`: живые дроны доигрывают, новую работу рой в это время не берёт),
167
+ поднимает страницу входа и **поднимает демона обратно** — уже с новым токеном.
168
+ Перезапуск обязателен: токен читается один раз при старте процесса, иначе демон
169
+ продолжил бы стучаться старым.
170
+
171
+ Ждать нечего — `swarm stop --force` в другом терминале оборвёт дронов и вход пойдёт
172
+ сразу. Демон был погашен до команды — обратно она его не поднимает: было выключено,
173
+ выключенным и останется. Вход не удался или вкладку закрыли — демон возвращается в то
174
+ состояние, в котором был.
175
+
155
176
  ## Кем исполнять дрона
156
177
 
157
178
  Рою всё равно, какой агент внутри: всё, что знает про конкретный харнесс (как
package/dist/cli.js CHANGED
@@ -613,15 +613,19 @@ var init_hostPool = __esm({
613
613
  });
614
614
 
615
615
  // ../swarm-core/src/hostCommands.ts
616
- var HOST_COMMAND_STATUSES, TERMINAL, HOST_COMMAND_OPEN_STATUSES, HOST_COMMAND_TTL_MS, HOST_COMMAND_KEEPALIVE_MS, RUN_SCOPED_COMMAND_KINDS, RUN_SCOPED;
616
+ var SWARM_PACKAGE_NAME, MANUAL_UPDATE_COMMAND, HOST_COMMAND_STATUSES, TERMINAL, HOST_COMMAND_OPEN_STATUSES, HOST_COMMAND_TTL_MS, HOST_COMMAND_KEEPALIVE_MS, HOST_COMMAND_ACK_GRACE_MS, HOST_COMMAND_MUTE_REASON, RUN_SCOPED_COMMAND_KINDS, RUN_SCOPED;
617
617
  var init_hostCommands = __esm({
618
618
  "../swarm-core/src/hostCommands.ts"() {
619
619
  "use strict";
620
+ SWARM_PACKAGE_NAME = "@taskless-app/swarm";
621
+ MANUAL_UPDATE_COMMAND = `npm i -g ${SWARM_PACKAGE_NAME}@latest`;
620
622
  HOST_COMMAND_STATUSES = ["pending", "delivered", "running", "done", "failed", "rejected", "expired"];
621
623
  TERMINAL = /* @__PURE__ */ new Set(["done", "failed", "rejected", "expired"]);
622
624
  HOST_COMMAND_OPEN_STATUSES = HOST_COMMAND_STATUSES.filter((s) => !TERMINAL.has(s));
623
625
  HOST_COMMAND_TTL_MS = 30 * 6e4;
624
626
  HOST_COMMAND_KEEPALIVE_MS = 10 * 6e4;
627
+ HOST_COMMAND_ACK_GRACE_MS = 5 * 6e4;
628
+ HOST_COMMAND_MUTE_REASON = `\u043C\u0430\u0448\u0438\u043D\u0430 \u043D\u0435 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u043B\u0430 \u0438\u0441\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u0435 \u2014 \u0432\u0435\u0440\u043E\u044F\u0442\u043D\u043E, \u0434\u0435\u043C\u043E\u043D \u0441\u0442\u0430\u0440\u0435\u0435 \u043A\u043E\u043C\u0430\u043D\u0434\u044B. \u041E\u0431\u043D\u043E\u0432\u0438 \u0432\u0440\u0443\u0447\u043D\u0443\u044E: ${MANUAL_UPDATE_COMMAND}`;
625
629
  RUN_SCOPED_COMMAND_KINDS = ["stop_run", "wake_run"];
626
630
  RUN_SCOPED = new Set(RUN_SCOPED_COMMAND_KINDS);
627
631
  }
@@ -1833,7 +1837,7 @@ var init_package = __esm({
1833
1837
  "package.json"() {
1834
1838
  package_default = {
1835
1839
  name: "@taskless-app/swarm",
1836
- version: "0.6.0",
1840
+ version: "0.6.1",
1837
1841
  type: "module",
1838
1842
  description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
1839
1843
  keywords: [
@@ -1882,7 +1886,8 @@ var init_package = __esm({
1882
1886
  "@modelcontextprotocol/sdk": "^1.29.0",
1883
1887
  execa: "^10.0.0",
1884
1888
  zod: "3.25.76"
1885
- }
1889
+ },
1890
+ gitHead: "415ad928e18430894ae24ac2e4267073f5c6da14"
1886
1891
  };
1887
1892
  }
1888
1893
  });
@@ -1993,6 +1998,14 @@ async function probeAgentToken(args, fetchFn = fetch) {
1993
1998
  return "unreachable";
1994
1999
  }
1995
2000
  }
2001
+ function isRevokedTokenError(e) {
2002
+ if (e && typeof e === "object" && e.code === 401) return true;
2003
+ const text = e instanceof Error ? e.message : typeof e === "string" ? e : "";
2004
+ return /invalid_token|(?:http|status|code)[ =:]*401\b|\(401\)|401 unauthorized/i.test(text);
2005
+ }
2006
+ function revokedTokenLine() {
2007
+ return "[taskless] \u0442\u043E\u043A\u0435\u043D \u0440\u043E\u044F \u043E\u0442\u043E\u0437\u0432\u0430\u043D (401 invalid_token) \u2014 \u0440\u043E\u0439 \u043D\u0435 \u0431\u0435\u0440\u0451\u0442 \u0440\u0430\u0431\u043E\u0442\u0443. \u041F\u043E\u0447\u0438\u043D\u0438 \u043E\u0434\u043D\u043E\u0439 \u043A\u043E\u043C\u0430\u043D\u0434\u043E\u0439: swarm login";
2008
+ }
1996
2009
  var STORE_PATH2, base2;
1997
2010
  var init_agentToken = __esm({
1998
2011
  "src/agentToken.ts"() {
@@ -3216,8 +3229,9 @@ var SWARM_PACKAGE, LATEST_TIMEOUT_MS;
3216
3229
  var init_release = __esm({
3217
3230
  "src/release.ts"() {
3218
3231
  "use strict";
3232
+ init_src();
3219
3233
  init_claudeBin();
3220
- SWARM_PACKAGE = "@taskless-app/swarm";
3234
+ SWARM_PACKAGE = SWARM_PACKAGE_NAME;
3221
3235
  LATEST_TIMEOUT_MS = 4e3;
3222
3236
  }
3223
3237
  });
@@ -8908,7 +8922,9 @@ async function connectSwarmMcp(cfg) {
8908
8922
  try {
8909
8923
  await client.connect(transport);
8910
8924
  } catch (e) {
8911
- console.warn(`Swarm MCP: \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0438\u0442\u044C\u0441\u044F \u043D\u0435 \u0432\u044B\u0448\u043B\u043E (${e instanceof Error ? e.message : e}) \u2192 \u0431\u0443\u0444\u0435\u0440 \u0432 outbox.`);
8925
+ console.warn(
8926
+ isRevokedTokenError(e) ? `${revokedTokenLine()} (\u043F\u043E\u043A\u0430 \u0442\u043E\u043A\u0435\u043D\u0430 \u043D\u0435\u0442 \u2014 \u0441\u043E\u0431\u044B\u0442\u0438\u044F \u043A\u043E\u043F\u044F\u0442\u0441\u044F \u0432 outbox)` : `Swarm MCP: \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0438\u0442\u044C\u0441\u044F \u043D\u0435 \u0432\u044B\u0448\u043B\u043E (${e instanceof Error ? e.message : e}) \u2192 \u0431\u0443\u0444\u0435\u0440 \u0432 outbox.`
8927
+ );
8912
8928
  return null;
8913
8929
  }
8914
8930
  return async (name, args) => await client.callTool({ name, arguments: swarmToolArgs(name, args, workspace) });
@@ -8984,6 +9000,7 @@ function resilientSwarmMcp(opts = {}) {
8984
9000
 
8985
9001
  // src/login.ts
8986
9002
  import { execa as execa2 } from "execa";
9003
+ import { createServer } from "net";
8987
9004
  async function waitForLogin(d) {
8988
9005
  const deadline = d.now() + d.timeoutMs;
8989
9006
  for (; ; ) {
@@ -8993,6 +9010,53 @@ async function waitForLogin(d) {
8993
9010
  await d.sleep(d.pollMs);
8994
9011
  }
8995
9012
  }
9013
+ async function withDaemonStopped(d, body) {
9014
+ const st = await d.status();
9015
+ if (!st) {
9016
+ if (!await d.portFree()) {
9017
+ d.err(
9018
+ `\u0432\u0445\u043E\u0434 \u041D\u0415 \u0441\u043E\u0441\u0442\u043E\u044F\u043B\u0441\u044F: \u043F\u043E\u0440\u0442 ${d.port} \u0437\u0430\u043D\u044F\u0442, \u043D\u043E \u044D\u0442\u043E \u043D\u0435 \u0434\u0435\u043C\u043E\u043D \u0440\u043E\u044F (\u0435\u0433\u043E \u043C\u043E\u0440\u0434\u0430 \u043D\u0435 \u043E\u0442\u0432\u0435\u0447\u0430\u0435\u0442). \u0421\u0442\u0440\u0430\u043D\u0438\u0446\u0430 \u0432\u0445\u043E\u0434\u0430 \u043E\u0431\u044F\u0437\u0430\u043D\u0430 \u043F\u043E\u0434\u043D\u044F\u0442\u044C\u0441\u044F \u0438\u043C\u0435\u043D\u043D\u043E \u043D\u0430 \u043D\u0451\u043C \u2014 \u043E\u043D \u0437\u0430\u0448\u0438\u0442 \u0432 redirect_uri. \u041E\u0441\u0432\u043E\u0431\u043E\u0434\u0438 \u043F\u043E\u0440\u0442 \u0438 \u043F\u043E\u0432\u0442\u043E\u0440\u0438: swarm login`
9019
+ );
9020
+ return 1;
9021
+ }
9022
+ const code2 = await body();
9023
+ if (code2 === 0) d.out("\u0434\u0435\u043C\u043E\u043D \u043D\u0430 \u044D\u0442\u043E\u0439 \u043C\u0430\u0448\u0438\u043D\u0435 \u043D\u0435 \u043F\u043E\u0434\u043D\u044F\u0442 \u2014 \u0440\u043E\u0439 \u0436\u0434\u0451\u0442 \u0437\u0430\u043F\u0443\u0441\u043A\u0430: swarm start");
9024
+ return code2;
9025
+ }
9026
+ d.out(
9027
+ st.live.length ? `\u0434\u0435\u043C\u043E\u043D \u0440\u043E\u044F \u043F\u043E\u0434\u043D\u044F\u0442, \u0436\u0438\u0432\u044B\u0445 \u0441\u0435\u0441\u0441\u0438\u0439: ${st.live.length}. \u0413\u0430\u0448\u0443 \u0435\u0433\u043E \u0441\u0430\u043C \u2014 \u0432\u0445\u043E\u0434 \u043F\u043E\u0434\u043D\u0438\u043C\u0430\u0435\u0442 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0443 \u043D\u0430 \u0442\u043E\u043C \u0436\u0435 \u043F\u043E\u0440\u0442\u0443 ${d.port}.` : `\u0434\u0435\u043C\u043E\u043D \u0440\u043E\u044F \u043F\u043E\u0434\u043D\u044F\u0442 \u2014 \u0433\u0430\u0448\u0443 \u0435\u0433\u043E \u0441\u0430\u043C: \u0432\u0445\u043E\u0434 \u043F\u043E\u0434\u043D\u0438\u043C\u0430\u0435\u0442 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0443 \u043D\u0430 \u0442\u043E\u043C \u0436\u0435 \u043F\u043E\u0440\u0442\u0443 ${d.port}.`
9028
+ );
9029
+ if (await d.stop() !== "stopped") {
9030
+ d.err(`\u0432\u0445\u043E\u0434 \u041D\u0415 \u0441\u043E\u0441\u0442\u043E\u044F\u043B\u0441\u044F: \u0434\u0435\u043C\u043E\u043D \u043D\u0435 \u043F\u043E\u0433\u0430\u0448\u0435\u043D (\u0441\u043C. \u0432\u044B\u0448\u0435), \u043F\u043E\u0440\u0442 ${d.port} \u0437\u0430\u043D\u044F\u0442 \u0438\u043C. \u0420\u043E\u0439 \u043E\u0441\u0442\u0430\u043B\u0441\u044F \u043A\u0430\u043A \u0431\u044B\u043B.`);
9031
+ return 1;
9032
+ }
9033
+ if (!await d.portFree()) {
9034
+ d.err(`\u0432\u0445\u043E\u0434 \u041D\u0415 \u0441\u043E\u0441\u0442\u043E\u044F\u043B\u0441\u044F: \u0434\u0435\u043C\u043E\u043D \u043F\u043E\u0433\u0430\u0448\u0435\u043D, \u043D\u043E \u043F\u043E\u0440\u0442 ${d.port} \u0432\u0441\u0451 \u0440\u0430\u0432\u043D\u043E \u0437\u0430\u043D\u044F\u0442 \u043A\u0435\u043C-\u0442\u043E \u0435\u0449\u0451. \u041F\u043E\u0434\u043D\u0438\u043C\u0430\u044E \u0440\u043E\u0439 \u043E\u0431\u0440\u0430\u0442\u043D\u043E.`);
9035
+ await restoreDaemon(d, false);
9036
+ return 1;
9037
+ }
9038
+ let code = 1;
9039
+ try {
9040
+ code = await body();
9041
+ return code;
9042
+ } finally {
9043
+ await restoreDaemon(d, code === 0);
9044
+ }
9045
+ }
9046
+ async function restoreDaemon(d, loginOk) {
9047
+ d.out(
9048
+ loginOk ? "\u0432\u0445\u043E\u0434 \u0432\u044B\u043F\u043E\u043B\u043D\u0435\u043D \u2014 \u043F\u043E\u0434\u043D\u0438\u043C\u0430\u044E \u0434\u0435\u043C\u043E\u043D\u0430 \u043E\u0431\u0440\u0430\u0442\u043D\u043E, \u0443\u0436\u0435 \u0441 \u043D\u043E\u0432\u044B\u043C \u0442\u043E\u043A\u0435\u043D\u043E\u043C\u2026" : "\u0432\u0445\u043E\u0434 \u043D\u0435 \u0441\u043E\u0441\u0442\u043E\u044F\u043B\u0441\u044F \u2014 \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u044E \u0434\u0435\u043C\u043E\u043D\u0430 \u0432 \u043F\u0440\u0435\u0436\u043D\u0435\u0435 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435\u2026"
9049
+ );
9050
+ if (await d.start()) return;
9051
+ d.err("\u0434\u0435\u043C\u043E\u043D \u043E\u0431\u0440\u0430\u0442\u043D\u043E \u041D\u0415 \u043F\u043E\u0434\u043D\u044F\u043B\u0441\u044F (\u043F\u0440\u0438\u0447\u0438\u043D\u0430 \u0432\u044B\u0448\u0435) \u2014 \u0440\u043E\u0439 \u0441\u0442\u043E\u0438\u0442. \u041F\u043E\u0434\u043D\u0438\u043C\u0438 \u0432\u0440\u0443\u0447\u043D\u0443\u044E: swarm start");
9052
+ }
9053
+ function isPortFree(port, host = "127.0.0.1") {
9054
+ return new Promise((resolve4) => {
9055
+ const probe = createServer();
9056
+ probe.once("error", () => resolve4(false));
9057
+ probe.listen(port, host, () => probe.close(() => resolve4(true)));
9058
+ });
9059
+ }
8996
9060
  async function chooseWorkspace(d) {
8997
9061
  if (d.list.length === 0) {
8998
9062
  d.out("\u043D\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0445 \u0432\u043E\u0440\u043A\u0441\u043F\u0435\u0439\u0441\u043E\u0432 (list_workspaces \u043F\u0443\u0441\u0442)");
@@ -9264,6 +9328,59 @@ function takeWorkspace(argv) {
9264
9328
  return { workspace, rest: [...argv.slice(0, i), ...argv.slice(i + 2)] };
9265
9329
  }
9266
9330
  async function runLogin(db2, opts) {
9331
+ return withDaemonStopped(
9332
+ {
9333
+ status: async () => {
9334
+ const st = await daemonStatus2();
9335
+ return st ? { live: st.live } : null;
9336
+ },
9337
+ stop: stopDaemonForLogin,
9338
+ portFree: () => isPortFree(WEB_PORT),
9339
+ // Аргументы не передаём намеренно: пути к репозиториям демон помнит с прошлого
9340
+ // запуска (TASWM-335), а `swarm login` их и не знает — он про вход, не про репо.
9341
+ // А вот ОКРУЖЕНИЕ поднятого обратно демона — наше: если `swarm login` зовут из
9342
+ // шелла без SWARM_BACKEND, рой вернётся в sqlite-режиме, то есть слепым к
9343
+ // воркспейсу. В опубликованном пакете дефолт уже client (SWARM_DIST_BUILD) —
9344
+ // предупреждение достаётся монорепе, где это реальная разница.
9345
+ start: async () => {
9346
+ if (SWARM_BACKEND !== "client") {
9347
+ console.warn("SWARM_BACKEND=client \u043D\u0435 \u0437\u0430\u0434\u0430\u043D \u2014 \u043F\u043E\u0434\u043D\u0438\u043C\u0430\u044E \u0434\u0435\u043C\u043E\u043D\u0430 \u043E\u0431\u0440\u0430\u0442\u043D\u043E \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.");
9348
+ }
9349
+ return await runStartDetached([]) === 0;
9350
+ },
9351
+ out: (s) => console.log(s),
9352
+ err: (s) => console.error(s),
9353
+ port: WEB_PORT
9354
+ },
9355
+ () => runLoginFlow(db2, opts)
9356
+ );
9357
+ }
9358
+ async function stopDaemonForLogin() {
9359
+ const res = await daemonStop({ force: false, wait: true });
9360
+ if (!res) {
9361
+ const beat = readHeartbeat(HEARTBEAT_PATH);
9362
+ if (beat != null && Date.now() - beat < 6e4) {
9363
+ console.error(
9364
+ `\u0434\u0435\u043C\u043E\u043D \u043F\u043E\u0434\u0430\u0451\u0442 \u043F\u0443\u043B\u044C\u0441 (${HEARTBEAT_PATH}), \u043D\u043E \u043C\u043E\u0440\u0434\u0430 127.0.0.1:${WEB_PORT} \u043D\u0435 \u043E\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u2014 \u0441\u0430\u043C \u0441\u0435\u0431\u044F \u043F\u043E\u0433\u0430\u0441\u0438\u0442\u044C \u043E\u043D \u043D\u0435 \u043C\u043E\u0436\u0435\u0442. \u041F\u043E\u0445\u043E\u0436\u0435, \u043F\u0440\u043E\u0446\u0435\u0441\u0441 \u0437\u0430\u0432\u0438\u0441: \u043D\u0430\u0439\u0434\u0438 \u0435\u0433\u043E (ps) \u0438 \u043F\u043E\u0433\u0430\u0441\u0438 \u0441\u0438\u0433\u043D\u0430\u043B\u043E\u043C \u0432\u0440\u0443\u0447\u043D\u0443\u044E, \u043F\u043E\u0442\u043E\u043C \u043F\u043E\u0432\u0442\u043E\u0440\u0438 swarm login.`
9365
+ );
9366
+ return "failed";
9367
+ }
9368
+ return "stopped";
9369
+ }
9370
+ if (res.waiting) {
9371
+ console.log(`\u0436\u0434\u0443 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u0438\u044F \u0436\u0438\u0432\u044B\u0445 \u0441\u0435\u0441\u0441\u0438\u0439 (${res.sessions.length}): ${await liveSessionNames(res.sessions)} \u2014 \u043D\u043E\u0432\u0443\u044E \u0440\u0430\u0431\u043E\u0442\u0443 \u0440\u043E\u0439 \u0443\u0436\u0435 \u043D\u0435 \u0431\u0435\u0440\u0451\u0442`);
9372
+ console.log("\u043E\u0431\u043E\u0440\u0432\u0430\u0442\u044C \u0438\u0445 \u0438 \u0432\u043E\u0439\u0442\u0438 \u043F\u0440\u044F\u043C\u043E \u0441\u0435\u0439\u0447\u0430\u0441: swarm stop --force \u0432 \u0434\u0440\u0443\u0433\u043E\u043C \u0442\u0435\u0440\u043C\u0438\u043D\u0430\u043B\u0435");
9373
+ } else {
9374
+ console.log("\u0436\u0438\u0432\u044B\u0445 \u0441\u0435\u0441\u0441\u0438\u0439 \u043D\u0435 \u0431\u044B\u043B\u043E \u2014 \u0434\u0435\u043C\u043E\u043D \u043F\u043E\u0433\u0430\u0448\u0435\u043D");
9375
+ }
9376
+ const down = res.waiting ? await waitDaemonDown({ timeoutMs: 6 * 60 * 6e4 }) : await waitDaemonDown({ timeoutMs: 3e4, pollMs: 500 });
9377
+ if (down) return "stopped";
9378
+ console.error(
9379
+ res.waiting ? "\u0436\u0434\u0443 \u0431\u043E\u043B\u044C\u0448\u0435 6 \u0447\u0430\u0441\u043E\u0432 \u2014 \u0434\u0435\u043C\u043E\u043D \u0432\u0441\u0451 \u0435\u0449\u0451 \u0433\u0430\u0441\u043D\u0435\u0442. \u0412\u0445\u043E\u0434 \u043D\u0435 \u043D\u0430\u0447\u0438\u043D\u0430\u044E: \u043F\u043E\u0440\u0442 \u0437\u0430\u043D\u044F\u0442 \u0438\u043C (swarm status \u043F\u043E\u043A\u0430\u0436\u0435\u0442, \u043A\u0442\u043E \u0435\u0449\u0451 \u0436\u0438\u0432)." : "\u0434\u0435\u043C\u043E\u043D \u043F\u0440\u0438\u043D\u044F\u043B \u043A\u043E\u043C\u0430\u043D\u0434\u0443, \u043D\u043E \u0437\u0430 30\u0441 \u043D\u0435 \u0432\u044B\u0448\u0435\u043B \u2014 \u0432\u0445\u043E\u0434 \u043D\u0435 \u043D\u0430\u0447\u0438\u043D\u0430\u044E (\u043F\u043E\u0440\u0442 \u0437\u0430\u043D\u044F\u0442 \u0438\u043C). \u041F\u0440\u043E\u0432\u0435\u0440\u044C: swarm status"
9380
+ );
9381
+ return "failed";
9382
+ }
9383
+ async function runLoginFlow(db2, opts) {
9267
9384
  const web = startWeb({ db: db2 });
9268
9385
  try {
9269
9386
  let agent = loadAgentToken();
@@ -9351,7 +9468,7 @@ async function runLogin(db2, opts) {
9351
9468
  console.log(
9352
9469
  others.length ? `\u0440\u043E\u0439 \u0431\u0435\u0440\u0451\u0442 \u0440\u0430\u0431\u043E\u0442\u0443 \u0418\u0417 \u0412\u0421\u0415\u0425 \u0442\u0432\u043E\u0438\u0445 \u0432\u043E\u0440\u043A\u0441\u043F\u0435\u0439\u0441\u043E\u0432 (\u0435\u0449\u0451 ${others.length}: ${others.map((w) => w.slug).join(", ")}) \u2014 \u0432\u043E\u0440\u043A\u0441\u043F\u0435\u0439\u0441 \u043F\u0440\u0438\u0435\u0437\u0436\u0430\u0435\u0442 \u0441 \u043A\u0430\u0436\u0434\u044B\u043C \u043F\u0440\u043E\u0433\u043E\u043D\u043E\u043C. \u0412\u044B\u0431\u0440\u0430\u043D\u043D\u044B\u0439 \u043D\u0443\u0436\u0435\u043D \u0442\u043E\u043B\u044C\u043A\u043E \u0434\u043B\u044F \u0432\u044B\u0437\u043E\u0432\u043E\u0432 \u043D\u0435 \u043F\u0440\u043E \u043F\u0440\u043E\u0433\u043E\u043D.` : "\u044D\u0442\u043E \u0435\u0434\u0438\u043D\u0441\u0442\u0432\u0435\u043D\u043D\u044B\u0439 \u0432\u043E\u0440\u043A\u0441\u043F\u0435\u0439\u0441 \u0442\u043E\u043A\u0435\u043D\u0430."
9353
9470
  );
9354
- console.log("\u0433\u043E\u0442\u043E\u0432\u043E. \u041F\u043E\u0434\u043D\u044F\u0442\u044C \u0434\u0435\u043C\u043E\u043D\u0430: swarm start --repo <\u043F\u0443\u0442\u044C \u043A \u0440\u0435\u043F\u043E>");
9471
+ console.log("\u0433\u043E\u0442\u043E\u0432\u043E \u2014 \u0432\u0445\u043E\u0434 \u0432\u044B\u043F\u043E\u043B\u043D\u0435\u043D.");
9355
9472
  return 0;
9356
9473
  } finally {
9357
9474
  web.server.close();
@@ -9627,7 +9744,9 @@ function usage() {
9627
9744
  swarm update \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C \u0440\u043E\u0439 \u0434\u043E \u043E\u043F\u0443\u0431\u043B\u0438\u043A\u043E\u0432\u0430\u043D\u043D\u043E\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 (\u0442\u0435\u043C \u0436\u0435 \u043C\u0435\u043D\u0435\u0434\u0436\u0435\u0440\u043E\u043C,
9628
9745
  \u043A\u0430\u043A\u0438\u043C \u043E\u043D \u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D)
9629
9746
  swarm login [--workspace <slug|id>] [--no-open]
9630
- \u0432\u043E\u0439\u0442\u0438 \u0432 Taskless \u0438 \u0432\u044B\u0431\u0440\u0430\u0442\u044C \u0432\u043E\u0440\u043A\u0441\u043F\u0435\u0439\u0441
9747
+ \u0432\u043E\u0439\u0442\u0438 \u0432 Taskless \u0438 \u0432\u044B\u0431\u0440\u0430\u0442\u044C \u0432\u043E\u0440\u043A\u0441\u043F\u0435\u0439\u0441. \u0414\u0435\u043C\u043E\u043D\u0430 \u0433\u0430\u0441\u0438\u0442 \u0438 \u043F\u043E\u0434\u043D\u0438\u043C\u0430\u0435\u0442
9748
+ \u0441\u0430\u043C\u0430 (\u0436\u0438\u0432\u044B\u0435 \u0441\u0435\u0441\u0441\u0438\u0438 \u0434\u043E\u0438\u0433\u0440\u044B\u0432\u0430\u044E\u0442) \u2014 \u043F\u0435\u0440\u0435\u043B\u043E\u0433\u0438\u043D \u044D\u0442\u043E \u043E\u0434\u043D\u0430 \u043A\u043E\u043C\u0430\u043D\u0434\u0430,
9749
+ \u0431\u0435\u0437 stop/start \u0440\u0443\u043A\u0430\u043C\u0438
9631
9750
  swarm start [--repo <path>] [--foreground]
9632
9751
  \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.
9633
9752
  \u0420\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0438 \u043D\u0430\u0445\u043E\u0434\u0438\u0442 \u0441\u0430\u043C \u2014 \u043A\u043B\u043E\u043D\u044B \u043F\u0440\u043E\u0435\u043A\u0442\u043E\u0432 Taskless \u043D\u0430 \u044D\u0442\u043E\u0439 \u043C\u0430\u0448\u0438\u043D\u0435;