@taskless-app/swarm 0.6.29 → 0.6.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -3239,7 +3239,7 @@ var init_package = __esm({
3239
3239
  "package.json"() {
3240
3240
  package_default = {
3241
3241
  name: "@taskless-app/swarm",
3242
- version: "0.6.29",
3242
+ version: "0.6.31",
3243
3243
  type: "module",
3244
3244
  description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
3245
3245
  keywords: [
@@ -3290,7 +3290,7 @@ var init_package = __esm({
3290
3290
  execa: "^10.0.0",
3291
3291
  zod: "3.25.76"
3292
3292
  },
3293
- gitHead: "d8072f68198b68b4252687b01e7e82e2b4769346"
3293
+ gitHead: "82950eae7a6ad09be4193708257798c811bb6fae"
3294
3294
  };
3295
3295
  }
3296
3296
  });
@@ -7060,6 +7060,8 @@ var SwarmClient = class _SwarmClient {
7060
7060
  // уходить «TASWM-392», а не «cmsqqpphd011y2xtbckkut6bj» — иначе оператору всё равно
7061
7061
  // нечего искать. Резолв делает прод (см. resolveDepRefs), здесь только запоминаем.
7062
7062
  depSlug = /* @__PURE__ */ new Map();
7063
+ // TASWM-526: публичный — гейт спавна судит по нему СВЕЖЕСТЬ вердикта слепоты (эпизоду
7064
+ // больше TTL → переспросить прежде, чем ронять прогон терминально; см. overmind).
7063
7065
  static DEPS_TTL_MS = 6e4;
7064
7066
  // TASWM-486: ссылки, по которым прод НЕ ОТВЕТИЛ (отверг вызов или не дозвонились) —
7065
7067
  // с какого времени, сколько попыток и чем именно отказал. Отказ ≠ ответ: вердикта в
@@ -7669,10 +7671,19 @@ var SwarmClient = class _SwarmClient {
7669
7671
  * до ручного `wake_run`. Теперь отказ помнится отдельно (`depsUnanswered`): переспрос идёт
7670
7672
  * по короткому нарастающему backoff, а сам факт «прод молчит» становится видимым —
7671
7673
  * причина отказа спавна называет его вслух, и на затянувшуюся слепоту звенит аномалия.
7674
+ *
7675
+ * TASWM-526: `force` — спросить МИМО каденции. Нужен ровно одному месту: гейту спавна,
7676
+ * когда он собирается применить ТЕРМИНАЛЬНЫЙ исход по старому вердикту слепоты. Штатная
7677
+ * пауза для исчерпанного бюджета — целый TTL, и всё это время свежезаведённый прогон
7678
+ * умирал бы по ответу, который прод дал минуту назад и с тех пор мог передумать (api
7679
+ * починили и выкатили). Решение «падать или нет» обязано опираться на СВЕЖИЙ ответ, а не
7680
+ * на кеш, — вот его и переспрашиваем. Монотонное `done` фильтруется и здесь: оно не
7681
+ * протухает по определению, спрашивать нечего.
7672
7682
  */
7673
- async refreshDeps(refs, nowMs = Date.now()) {
7683
+ async refreshDeps(refs, nowMs = Date.now(), opts = {}) {
7674
7684
  const ask = [...new Set(refs)].filter((ref) => {
7675
7685
  if (!ref || this.depsProd.get(ref)?.outcome === "done") return false;
7686
+ if (opts.force) return true;
7676
7687
  const asked = this.depsAskedAt.get(ref);
7677
7688
  if (asked === void 0) return true;
7678
7689
  return nowMs - asked >= this.depsRetryDelay(ref);
package/dist/overmind.js CHANGED
@@ -7035,6 +7035,8 @@ var SwarmClient = class _SwarmClient {
7035
7035
  // уходить «TASWM-392», а не «cmsqqpphd011y2xtbckkut6bj» — иначе оператору всё равно
7036
7036
  // нечего искать. Резолв делает прод (см. resolveDepRefs), здесь только запоминаем.
7037
7037
  depSlug = /* @__PURE__ */ new Map();
7038
+ // TASWM-526: публичный — гейт спавна судит по нему СВЕЖЕСТЬ вердикта слепоты (эпизоду
7039
+ // больше TTL → переспросить прежде, чем ронять прогон терминально; см. overmind).
7038
7040
  static DEPS_TTL_MS = 6e4;
7039
7041
  // TASWM-486: ссылки, по которым прод НЕ ОТВЕТИЛ (отверг вызов или не дозвонились) —
7040
7042
  // с какого времени, сколько попыток и чем именно отказал. Отказ ≠ ответ: вердикта в
@@ -7644,10 +7646,19 @@ var SwarmClient = class _SwarmClient {
7644
7646
  * до ручного `wake_run`. Теперь отказ помнится отдельно (`depsUnanswered`): переспрос идёт
7645
7647
  * по короткому нарастающему backoff, а сам факт «прод молчит» становится видимым —
7646
7648
  * причина отказа спавна называет его вслух, и на затянувшуюся слепоту звенит аномалия.
7649
+ *
7650
+ * TASWM-526: `force` — спросить МИМО каденции. Нужен ровно одному месту: гейту спавна,
7651
+ * когда он собирается применить ТЕРМИНАЛЬНЫЙ исход по старому вердикту слепоты. Штатная
7652
+ * пауза для исчерпанного бюджета — целый TTL, и всё это время свежезаведённый прогон
7653
+ * умирал бы по ответу, который прод дал минуту назад и с тех пор мог передумать (api
7654
+ * починили и выкатили). Решение «падать или нет» обязано опираться на СВЕЖИЙ ответ, а не
7655
+ * на кеш, — вот его и переспрашиваем. Монотонное `done` фильтруется и здесь: оно не
7656
+ * протухает по определению, спрашивать нечего.
7647
7657
  */
7648
- async refreshDeps(refs, nowMs = Date.now()) {
7658
+ async refreshDeps(refs, nowMs = Date.now(), opts = {}) {
7649
7659
  const ask = [...new Set(refs)].filter((ref) => {
7650
7660
  if (!ref || this.depsProd.get(ref)?.outcome === "done") return false;
7661
+ if (opts.force) return true;
7651
7662
  const asked = this.depsAskedAt.get(ref);
7652
7663
  if (asked === void 0) return true;
7653
7664
  return nowMs - asked >= this.depsRetryDelay(ref);
@@ -14226,7 +14237,7 @@ import { serve as serve2 } from "@hono/node-server";
14226
14237
  // package.json
14227
14238
  var package_default = {
14228
14239
  name: "@taskless-app/swarm",
14229
- version: "0.6.29",
14240
+ version: "0.6.31",
14230
14241
  type: "module",
14231
14242
  description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
14232
14243
  keywords: [
@@ -14277,7 +14288,7 @@ var package_default = {
14277
14288
  execa: "^10.0.0",
14278
14289
  zod: "3.25.76"
14279
14290
  },
14280
- gitHead: "d8072f68198b68b4252687b01e7e82e2b4769346"
14291
+ gitHead: "82950eae7a6ad09be4193708257798c811bb6fae"
14281
14292
  };
14282
14293
 
14283
14294
  // src/version.ts
@@ -16791,6 +16802,14 @@ function abortReason(abort) {
16791
16802
  return `${ABORT_TEXT[abort.kind]} (${abort.raw})`;
16792
16803
  }
16793
16804
  var ABORTED_CONTINUE_NUDGE = "\u0422\u0432\u043E\u044F \u043F\u0440\u043E\u0448\u043B\u0430\u044F \u0441\u0435\u0441\u0441\u0438\u044F \u041E\u0411\u041E\u0420\u0412\u0410\u041B\u0410\u0421\u042C \u043D\u0430 \u043F\u043E\u043B\u0443\u0441\u043B\u043E\u0432\u0435 (\u043D\u0435 \u0442\u044B \u0435\u0451 \u0437\u0430\u043A\u043E\u043D\u0447\u0438\u043B). \u0422\u044B headless-\u0434\u0440\u043E\u043D, \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0430\u0435\u0448\u044C \u0422\u0423 \u0416\u0415 \u0437\u0430\u0434\u0430\u0447\u0443. \u041F\u043E\u0441\u043C\u043E\u0442\u0440\u0438 `git status`/`git log`: \u0447\u0442\u043E \u0443\u0436\u0435 \u0441\u0434\u0435\u043B\u0430\u043D\u043E \u0438 \u0437\u0430\u043F\u0443\u0448\u0435\u043D\u043E \u2014 \u041D\u0415 \u043F\u0435\u0440\u0435\u0434\u0435\u043B\u044B\u0432\u0430\u0439. \u0412\u0410\u0416\u041D\u041E \u043F\u0440\u043E \u043E\u0431\u0440\u044B\u0432\u044B: \u0440\u0432\u0451\u0442\u0441\u044F \u0441\u0435\u0441\u0441\u0438\u044F \u043D\u0430 \u041E\u0422\u0412\u0415\u0422\u0415 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u0430, \u0447\u0435\u0439 \u0432\u044B\u0432\u043E\u0434 \u043E\u0433\u0440\u043E\u043C\u0435\u043D (\u043F\u043E\u043B\u043D\u044B\u0439 \u0441\u044C\u044E\u0442 \u0442\u0435\u0441\u0442\u043E\u0432, `git log` \u0431\u0435\u0437 \u043B\u0438\u043C\u0438\u0442\u0430, \u0434\u0430\u043C\u043F \u0444\u0430\u0439\u043B\u0430 \u0446\u0435\u043B\u0438\u043A\u043E\u043C). \u0413\u043D\u0430\u0442\u044C \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u043D\u0430\u0434\u043E \u043F\u043E-\u043F\u0440\u0435\u0436\u043D\u0435\u043C\u0443 \u043F\u043E\u043B\u043D\u043E\u0441\u0442\u044C\u044E \u2014 \u043D\u043E \u0432\u044B\u0432\u043E\u0434 \u043F\u0438\u0448\u0438 \u0432 \u0441\u0432\u043E\u0439 \u0444\u0430\u0439\u043B (`LOG=$(mktemp -t suite)`) \u0438 \u0431\u0435\u0440\u0438 \u0438\u0437 \u043D\u0435\u0433\u043E \u0445\u0432\u043E\u0441\u0442 \u0438 \u0438\u0442\u043E\u0433\u043E\u0432\u0443\u044E \u0441\u0442\u0440\u043E\u043A\u0443, \u0430 \u043D\u0435 \u043F\u0440\u043E\u0441\u0442\u044B\u043D\u044E. \u0414\u043E\u0432\u0435\u0434\u0438 \u0437\u0430\u0434\u0430\u0447\u0443 \u0434\u043E \u043A\u043E\u043D\u0446\u0430, \u043E\u0442\u043A\u0440\u043E\u0439 PR \u0438 \u041E\u0411\u042F\u0417\u0410\u0422\u0415\u041B\u042C\u041D\u041E \u0432\u044B\u0437\u043E\u0432\u0438 done(pr_url).";
16805
+ var SUBRUN_EXITED_TEXT = "\u0441\u0435\u0441\u0441\u0438\u044F \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043B\u0430\u0441\u044C \u0441\u0430\u043C\u0430, done() \u043D\u0435 \u0432\u044B\u0437\u0432\u0430\u043D \u2014 \u044D\u0442\u043E \u041D\u0415 \u0441\u043C\u0435\u0440\u0442\u044C (\u0438\u0442\u043E\u0433 \u0437\u0430\u043F\u0438\u0441\u0430\u043D, worktree \u0446\u0435\u043B)";
16806
+ function isSubrun(run) {
16807
+ return run.resolves_run_id != null || run.reviews_run_id != null || run.verifies_run_id != null;
16808
+ }
16809
+ function subrunWaitNudge(run) {
16810
+ const tail2 = run.resolves_run_id != null ? "\u0422\u044B \u0434\u0440\u043E\u043D-\u0420\u0415\u0417\u041E\u041B\u0412\u0415\u0420: \u0434\u043E\u0432\u0435\u0434\u0438 merge-\u043A\u043E\u043C\u043C\u0438\u0442, \u0437\u0430\u043F\u0443\u0448\u044C \u0432 \u0432\u0435\u0442\u043A\u0443 PR \u0438 \u0432\u044B\u0437\u043E\u0432\u0438 done(pr_url). \u041F\u0440\u043E\u0432\u0435\u0440\u044F\u0442\u044C \u0441\u043E\u0440\u0430\u0437\u043C\u0435\u0440\u043D\u043E \u043F\u0440\u0430\u0432\u043A\u0435 \u2014 \u0442\u0438\u043F\u044B/\u0442\u0435\u0441\u0442\u044B \u0417\u0410\u0422\u0420\u041E\u041D\u0423\u0422\u042B\u0425 \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442\u043E\u043C \u043F\u0430\u043A\u0435\u0442\u043E\u0432, \u0430 \u043D\u0435 \u0432\u0435\u0441\u044C \u043C\u043E\u043D\u043E\u0440\u0435\u043F\u043E-\u0441\u044C\u044E\u0442: \u043F\u043E\u043B\u043D\u044B\u0439 \u043F\u0440\u043E\u0433\u043E\u043D \u043D\u0430 PR \u0432\u0441\u0451 \u0440\u0430\u0432\u043D\u043E \u0441\u0434\u0435\u043B\u0430\u0435\u0442 CI." : run.verifies_run_id != null ? "\u0422\u044B \u0434\u0440\u043E\u043D-\u0412\u0415\u0420\u0418\u0424\u0418\u041A\u0410\u0422\u041E\u0420: \u0434\u043E\u0432\u0435\u0434\u0438 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0443 \u0438 \u0432\u044B\u043D\u0435\u0441\u0438 \u0432\u0435\u0440\u0434\u0438\u043A\u0442 (done \u0441 verdict, \u043B\u0438\u0431\u043E \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u043E\u043C \u0432 PR). \u041F\u0440\u043E\u0432\u0435\u0440\u044F\u0442\u044C \u0441\u043E\u0440\u0430\u0437\u043C\u0435\u0440\u043D\u043E \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0435\u043C\u043E\u043C\u0443 \u0434\u0438\u0444\u0444\u0443 \u2014 \u043D\u0435 \u0433\u043E\u043D\u044F\u0439 \u0432\u0435\u0441\u044C \u0441\u044C\u044E\u0442 \u043C\u043E\u043D\u043E\u0440\u0435\u043F\u044B \u0440\u0430\u0434\u0438 \u043E\u0434\u043D\u043E\u0433\u043E PR." : "\u0422\u044B \u0434\u0440\u043E\u043D-\u0420\u0415\u0412\u042C\u042E\u0415\u0420: \u0434\u043E\u0432\u0435\u0434\u0438 \u0447\u0435\u043A-\u043B\u0438\u0441\u0442 \u0438 \u0432\u044B\u043D\u0435\u0441\u0438 \u0432\u0435\u0440\u0434\u0438\u043A\u0442 (APPROVE / REQUEST CHANGES) \u2014 done() \u043B\u0438\u0431\u043E \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u043E\u043C \u0432 PR.";
16811
+ return `\u0422\u0432\u043E\u044F \u043F\u0440\u043E\u0448\u043B\u0430\u044F \u0441\u0435\u0441\u0441\u0438\u044F \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043B\u0430\u0441\u044C \u0421\u0410\u041C\u0410, \u043D\u043E \u0442\u044B \u043D\u0435 \u0432\u044B\u0437\u0432\u0430\u043B done() \u2014 \u0440\u043E\u0439 \u043F\u043E\u0434\u043D\u044F\u043B \u0422\u0423 \u0416\u0415 \u0441\u0435\u0441\u0441\u0438\u044E (--continue), \u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442 \u0446\u0435\u043B. \u0412\u0410\u0416\u041D\u041E: \u0435\u0441\u043B\u0438 \u0442\u044B \u043E\u0441\u0442\u0430\u0432\u0438\u043B \u0444\u043E\u043D\u043E\u0432\u0443\u044E \u0440\u0430\u0431\u043E\u0442\u0443 (\u0442\u0435\u0441\u0442\u044B/\u0441\u0431\u043E\u0440\u043A\u0443 \u0432 \u0444\u043E\u043D\u0435, Monitor, \xAB\u0436\u0434\u0443 \u0443\u0432\u0435\u0434\u043E\u043C\u043B\u0435\u043D\u0438\u044F\xBB) \u2014 \u0416\u0414\u0410\u0422\u042C \u0415\u0401 \u0422\u0423\u0422 \u041D\u0415\u041A\u041E\u041C\u0423: \u0441\u0435\u0441\u0441\u0438\u044F \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u0442\u0441\u044F, \u043A\u0430\u043A \u0442\u043E\u043B\u044C\u043A\u043E \u0442\u044B \u043F\u0435\u0440\u0435\u0441\u0442\u0430\u0451\u0448\u044C \u0437\u0432\u0430\u0442\u044C \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u044B, \u0438 \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 \u043D\u0435\u0439 \u0443\u043C\u0438\u0440\u0430\u0435\u0442 \u0444\u043E\u043D\u043E\u0432\u044B\u0439 \u043F\u0440\u043E\u0446\u0435\u0441\u0441. \u041D\u0438\u043A\u0430\u043A\u043E\u0433\u043E \u0443\u0432\u0435\u0434\u043E\u043C\u043B\u0435\u043D\u0438\u044F \u043D\u0435 \u043F\u0440\u0438\u0434\u0451\u0442. \u0414\u043E\u043B\u0433\u043E\u0435 \u0434\u0435\u0440\u0436\u0438 \u0411\u041B\u041E\u041A\u0418\u0420\u0423\u042E\u0429\u0418\u041C \u0432\u044B\u0437\u043E\u0432\u043E\u043C (\u0438\u043B\u0438 \u0434\u0440\u043E\u0431\u0438 \u043D\u0430 \u0447\u0430\u0441\u0442\u0438), \u0430 \u043E\u0431\u044A\u0451\u043C \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u0431\u0435\u0440\u0438 \u043F\u043E \u043E\u0431\u044A\u0451\u043C\u0443 \u0441\u0432\u043E\u0435\u0439 \u043F\u0440\u0430\u0432\u043A\u0438. ${tail2}`;
16812
+ }
16794
16813
  var EXITED_CONTINUE_NUDGE = "\u0422\u0432\u043E\u044F \u043F\u0440\u043E\u0448\u043B\u0430\u044F \u0441\u0435\u0441\u0441\u0438\u044F \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043B\u0430\u0441\u044C \u0421\u0410\u041C\u0410, \u043D\u043E \u0442\u044B \u0442\u0430\u043A \u0438 \u043D\u0435 \u0432\u044B\u0437\u0432\u0430\u043B done(pr_url) \u2014 \u0440\u043E\u0439 \u043D\u0435 \u0443\u0432\u0438\u0434\u0435\u043B \u0441\u0434\u0430\u0447\u0438. \u0422\u044B headless-\u0434\u0440\u043E\u043D, \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0430\u0435\u0448\u044C \u0422\u0423 \u0416\u0415 \u0437\u0430\u0434\u0430\u0447\u0443. \u041F\u043E\u0441\u043C\u043E\u0442\u0440\u0438 `git status`/`git log`: \u0447\u0442\u043E \u0443\u0436\u0435 \u0441\u0434\u0435\u043B\u0430\u043D\u043E \u0438 \u0437\u0430\u043F\u0443\u0448\u0435\u043D\u043E \u2014 \u041D\u0415 \u043F\u0435\u0440\u0435\u0434\u0435\u043B\u044B\u0432\u0430\u0439. \u0414\u043E\u0432\u0435\u0434\u0438 \u0437\u0430\u0434\u0430\u0447\u0443 \u0434\u043E \u043A\u043E\u043D\u0446\u0430, \u043E\u0442\u043A\u0440\u043E\u0439 PR (\u0435\u0441\u043B\u0438 \u0435\u0449\u0451 \u043D\u0435\u0442) \u0438 \u041E\u0411\u042F\u0417\u0410\u0422\u0415\u041B\u042C\u041D\u041E \u0432\u044B\u0437\u043E\u0432\u0438 done(pr_url) \u2014 \u0431\u0435\u0437 \u044D\u0442\u043E\u0433\u043E \u0440\u0430\u0431\u043E\u0442\u0430 \u043D\u0435 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F \u0441\u0434\u0430\u043D\u043D\u043E\u0439. \u0423\u0442\u043A\u043D\u0443\u043B\u0441\u044F \u0432 \u043B\u0438\u043C\u0438\u0442/\u043D\u0435 \u043C\u043E\u0436\u0435\u0448\u044C \u0437\u0430\u043A\u043E\u043D\u0447\u0438\u0442\u044C \u2014 \u043D\u0435 \u043C\u043E\u043B\u043E\u0442\u0438 \u0432\u0441\u043B\u0435\u043F\u0443\u044E, \u0437\u0430\u0434\u0430\u0439 \u0432\u043E\u043F\u0440\u043E\u0441 \u0447\u0435\u0440\u0435\u0437 MCP-\u0442\u0443\u043B ask. \u0412\u043E\u043F\u0440\u043E\u0441\u043E\u0432 \u0432 stdout \u043D\u0435 \u0437\u0430\u0434\u0430\u0432\u0430\u0439.";
16795
16814
  var STORM_DEAD_LIMIT = Number(process.env.SWARM_STORM_DEAD_LIMIT) || 3;
16796
16815
  var CONFLICT_RESOLVE_COOLDOWN_MS = Number(process.env.SWARM_CONFLICT_COOLDOWN_MS) || 3 * 60 * 1e3;
@@ -17522,11 +17541,11 @@ function buildResolverPrompt(reviewRun, resolver, conflicts, branch, mainRef) {
17522
17541
  "\u041F\u043E\u0440\u044F\u0434\u043E\u043A:",
17523
17542
  `1. \u0420\u0430\u0437\u0440\u0435\u0448\u0438 \u043C\u0430\u0440\u043A\u0435\u0440\u044B \u0432\u043E \u0432\u0441\u0435\u0445 \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442\u0443\u044E\u0449\u0438\u0445 \u0444\u0430\u0439\u043B\u0430\u0445 (${files}); \`git status\` \u043F\u043E\u043A\u0430\u0436\u0435\u0442, \u0435\u0441\u043B\u0438 \u043E\u0441\u0442\u0430\u043B\u043E\u0441\u044C.`,
17524
17543
  "2. `git add -A && git commit --no-edit` \u2014 \u0437\u0430\u0432\u0435\u0440\u0448\u0438 merge-\u043A\u043E\u043C\u043C\u0438\u0442 (\u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E \u043E\u0441\u0442\u0430\u0432\u044C).",
17525
- "3. \u041F\u0440\u043E\u0433\u043E\u043D\u0438 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u043F\u0440\u043E\u0435\u043A\u0442\u0430 \u043A\u0430\u043A \u0432 CI (\u0437\u0430\u0433\u043B\u044F\u043D\u0438 \u0432 .github/workflows \u0438 package.json \u0440\u0435\u043F\u043E \u2014 \u0442\u0435\u0441\u0442\u044B/\u0442\u0438\u043F\u044B/\u0441\u0431\u043E\u0440\u043A\u0430/\u043B\u0438\u043D\u0442) \u0438 \u0443\u0431\u0435\u0434\u0438\u0441\u044C, \u0447\u0442\u043E \u0437\u0435\u043B\u0435\u043D\u043E. \u041A\u0440\u0430\u0441\u043D\u043E\u0435 \u2014 \u043F\u043E\u0447\u0438\u043D\u0438 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u0438\u0435, \u043D\u0435 \u0441\u0430\u043C\u0443 \u0444\u0438\u0447\u0443.",
17544
+ "3. \u041F\u0440\u043E\u0432\u0435\u0440\u044C \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u0438\u0435 \u0421\u041E\u0420\u0410\u0417\u041C\u0415\u0420\u041D\u041E \u043F\u0440\u0430\u0432\u043A\u0435: \u0442\u0438\u043F\u044B \u0438 \u0442\u0435\u0441\u0442\u044B \u0417\u0410\u0422\u0420\u041E\u041D\u0423\u0422\u042B\u0425 \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442\u043E\u043C \u043F\u0430\u043A\u0435\u0442\u043E\u0432 (\u0434\u043B\u044F \u043F\u0440\u0430\u0432\u043A\u0438 \u0432 \u043F\u0430\u0440\u0443 \u0441\u0442\u0440\u043E\u043A \u044D\u0442\u043E \u0442\u0438\u043F\u0438\u0437\u0430\u0446\u0438\u044F \u043E\u0434\u043D\u043E\u0433\u043E \u043F\u0430\u043A\u0435\u0442\u0430, \u0430 \u043D\u0435 \u0441\u044C\u044E\u0442 \u043C\u043E\u043D\u043E\u0440\u0435\u043F\u044B). \u041F\u043E\u043B\u043D\u044B\u0439 \u043F\u0440\u043E\u0433\u043E\u043D \u043D\u0430 PR \u0432\u0441\u0451 \u0440\u0430\u0432\u043D\u043E \u0441\u0434\u0435\u043B\u0430\u0435\u0442 CI, \u0430 \u0442\u044B \u0441\u043B\u0438\u0432\u0430\u0435\u0448\u044C \u0447\u0443\u0436\u0438\u0435 \u0432\u0435\u0442\u043A\u0438, \u0430 \u043D\u0435 \u043F\u0438\u0448\u0435\u0448\u044C \u0444\u0438\u0447\u0443. \u041A\u0440\u0430\u0441\u043D\u043E\u0435 \u2014 \u043F\u043E\u0447\u0438\u043D\u0438 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u0438\u0435, \u043D\u0435 \u0441\u0430\u043C\u0443 \u0444\u0438\u0447\u0443.",
17526
17545
  `4. \`git push origin HEAD:refs/heads/${branch}\` \u2014 \u041E\u0411\u042B\u0427\u041D\u042B\u0419 push (\u044D\u0442\u043E fast-forward), \u043F\u043E\u043B\u043D\u044B\u0439 refspec (\u043D\u0435 \u0433\u043E\u043B\u043E\u0435 \`HEAD:${branch}\` \u2014 git \u043E\u0442\u043A\u0430\u0436\u0435\u0442\u0441\u044F \u0443\u0433\u0430\u0434\u044B\u0432\u0430\u0442\u044C, \u0435\u0441\u043B\u0438 \u0432\u0435\u0442\u043A\u0443 \u0442\u0435\u043C \u0432\u0440\u0435\u043C\u0435\u043D\u0435\u043C \u0443\u0434\u0430\u043B\u0438\u043B\u0438). \`--force\`/\`--force-with-lease\` \u041D\u0415 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439: \u0440\u0438\u0431\u0435\u0439\u0437/\u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0438\u0441\u044C \u0438\u0441\u0442\u043E\u0440\u0438\u0438 \u0442\u0443\u0442 \u0437\u0430\u043F\u0440\u0435\u0449\u0435\u043D\u044B \u0438 \u0433\u0435\u0439\u0442\u044F\u0442\u0441\u044F.`,
17527
17546
  `5. \u0412\u044B\u0437\u043E\u0432\u0438 done(${prUrl}) \u2014 \u0440\u043E\u0439 \u043F\u043E\u0434\u0445\u0432\u0430\u0442\u0438\u0442, \u0447\u0442\u043E \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442 \u0440\u0430\u0437\u0440\u0435\u0448\u0451\u043D \u0438 PR \u043E\u0431\u043D\u043E\u0432\u043B\u0451\u043D.`,
17528
17547
  "",
17529
- `\u0412 \u043A\u0430\u0436\u0434\u044B\u0439 \u043A\u043E\u043C\u043C\u0438\u0442 \u0434\u043E\u0431\u0430\u0432\u043B\u044F\u0439 \u0442\u0440\u0435\u0439\u043B\u0435\u0440-\u0441\u0442\u0440\u043E\u043A\u0443 \xABDrone: ${name} \xB7 resolver run #${resolver.id}\xBB. \u041A\u043E\u043C\u043C\u0438\u0442\u044C \u0438 \u043F\u0443\u0448\u044C \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442 \u2014 \u043D\u0435\u0437\u0430\u043F\u0443\u0448\u0435\u043D\u043D\u043E\u0435 \u0443\u043C\u0440\u0451\u0442 \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 \u0434\u0440\u043E\u043D\u043E\u043C. \u0414\u043E\u043B\u0433\u043E\u0435 (\u0442\u0435\u0441\u0442\u044B) \u0434\u0435\u0440\u0436\u0438 \u0431\u043B\u043E\u043A\u0438\u0440\u0443\u044E\u0449\u0438\u043C \u0432\u044B\u0437\u043E\u0432\u043E\u043C, \u043D\u0435 \u0432 \u0444\u043E\u043D\u0435.`
17548
+ `\u0412 \u043A\u0430\u0436\u0434\u044B\u0439 \u043A\u043E\u043C\u043C\u0438\u0442 \u0434\u043E\u0431\u0430\u0432\u043B\u044F\u0439 \u0442\u0440\u0435\u0439\u043B\u0435\u0440-\u0441\u0442\u0440\u043E\u043A\u0443 \xABDrone: ${name} \xB7 resolver run #${resolver.id}\xBB. \u041A\u043E\u043C\u043C\u0438\u0442\u044C \u0438 \u043F\u0443\u0448\u044C \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442 \u2014 \u043D\u0435\u0437\u0430\u043F\u0443\u0448\u0435\u043D\u043D\u043E\u0435 \u0443\u043C\u0440\u0451\u0442 \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 \u0434\u0440\u043E\u043D\u043E\u043C. \u0414\u043E\u043B\u0433\u043E\u0435 (\u0442\u0435\u0441\u0442\u044B) \u0434\u0435\u0440\u0436\u0438 \u0411\u041B\u041E\u041A\u0418\u0420\u0423\u042E\u0429\u0418\u041C \u0432\u044B\u0437\u043E\u0432\u043E\u043C, \u043D\u0435 \u0432 \u0444\u043E\u043D\u0435: \u0441\u0435\u0441\u0441\u0438\u044F \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u0442\u0441\u044F, \u043A\u0430\u043A \u0442\u043E\u043B\u044C\u043A\u043E \u0442\u044B \u043F\u0435\u0440\u0435\u0441\u0442\u0430\u0451\u0448\u044C \u0437\u0432\u0430\u0442\u044C \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u044B, \u0438 \u0444\u043E\u043D\u043E\u0432\u044B\u0439 \u043F\u0440\u043E\u0446\u0435\u0441\u0441 \u0443\u043C\u0438\u0440\u0430\u0435\u0442 \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 \u043D\u0435\u0439 \u2014 \u0436\u0434\u0430\u0442\u044C \u0435\u0433\u043E \u0443\u0432\u0435\u0434\u043E\u043C\u043B\u0435\u043D\u0438\u044F \u0442\u0443\u0442 \u043D\u0435\u043A\u043E\u043C\u0443 (TASWM-528).`
17530
17549
  ].join("\n");
17531
17550
  }
17532
17551
  function ciTrustLine(prUrl, verifyMode) {
@@ -18433,7 +18452,25 @@ async function trySpawnQueuedRun(deps, run) {
18433
18452
  if (unmet.length) {
18434
18453
  const lost = unmet.filter((d) => d.outcome === "unknown");
18435
18454
  const blind = deps.db.depsUnconfirmed?.(run.depends_on) ?? [];
18436
- const stuck = blind.find((d) => !d.retriable && d.attempts >= SwarmClient.DEPS_UNRETRIABLE_ATTEMPTS);
18455
+ let stuck = blind.find((d) => !d.retriable && d.attempts >= SwarmClient.DEPS_UNRETRIABLE_ATTEMPTS);
18456
+ if (stuck && Date.now() - stuck.since > SwarmClient.DEPS_TTL_MS && deps.db.refreshDeps) {
18457
+ const ref = stuck.ref;
18458
+ try {
18459
+ await deps.db.refreshDeps(run.depends_on, Date.now(), { force: true });
18460
+ } catch (e) {
18461
+ console.error("[overmind] \u043F\u0435\u0440\u0435\u0441\u043F\u0440\u043E\u0441 \u043F\u0440\u043E\u0442\u0443\u0445\u0448\u0435\u0433\u043E \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u0430 \u0441\u043B\u0435\u043F\u043E\u0442\u044B \u0441\u043E\u0440\u0432\u0430\u043B\u0441\u044F:", e);
18462
+ }
18463
+ stuck = (deps.db.depsUnconfirmed?.(run.depends_on) ?? []).find(
18464
+ (d) => d.ref === ref && !d.retriable && d.attempts >= SwarmClient.DEPS_UNRETRIABLE_ATTEMPTS
18465
+ );
18466
+ if (!stuck) {
18467
+ return deferSpawn(
18468
+ deps,
18469
+ run,
18470
+ `\u0432\u0435\u0440\u0434\u0438\u043A\u0442 \xAB\u043F\u0440\u043E\u0434 \u043E\u0442\u0432\u0435\u0440\u0433\u0430\u0435\u0442 swarm_deps_status\xBB \u0431\u044B\u043B \u0441\u0442\u0430\u0440\u0448\u0435 TTL (${Math.round(SwarmClient.DEPS_TTL_MS / 1e3)}\u0441) \u2014 \u043F\u0435\u0440\u0435\u0441\u043F\u0440\u043E\u0441\u0438\u043B \u043F\u0440\u043E\u0434, \u0442\u0435\u0440\u043C\u0438\u043D\u0430\u043B\u044C\u043D\u044B\u0439 \u0438\u0441\u0445\u043E\u0434 \u043F\u043E \u043F\u0440\u043E\u0442\u0443\u0445\u0448\u0435\u043C\u0443 \u043E\u0442\u0432\u0435\u0442\u0443 \u043D\u0435 \u043F\u0440\u0438\u043C\u0435\u043D\u044F\u044E (TASWM-526)`
18471
+ );
18472
+ }
18473
+ }
18437
18474
  if (stuck) {
18438
18475
  return await failBeforeStart(
18439
18476
  deps,
@@ -19450,7 +19487,8 @@ async function tickOnce(deps) {
19450
19487
  continue;
19451
19488
  }
19452
19489
  }
19453
- if (!alive && (outcome === "graceful" || outcome === "aborted") && run.status === "running" && run.resolves_run_id == null && run.reviews_run_id == null && run.verifies_run_id == null && run.kind !== "hero") {
19490
+ if (!alive && (outcome === "graceful" || outcome === "aborted") && run.status === "running" && !isSubrun(run) && // суб-дроны (резолвер/ревьюер/верификатор) — своими ветками ниже, TASWM-528
19491
+ run.kind !== "hero") {
19454
19492
  if (!wasAborted(outcome) && run.pr_url) {
19455
19493
  deps.db.updateRun(run.id, { status: "review", stop_reason: null });
19456
19494
  deps.db.addEvent(run.id, "step", `${SUBMITTED_EXIT_TEXT}: ${run.pr_url}`);
@@ -19494,7 +19532,8 @@ async function tickOnce(deps) {
19494
19532
  );
19495
19533
  continue;
19496
19534
  }
19497
- if (!alive && run.status === "running" && run.resolves_run_id == null && run.reviews_run_id == null && run.verifies_run_id == null && deps.respawn && run.respawns < RESPAWN_LIMIT) {
19535
+ if (!alive && run.status === "running" && !isSubrun(run) && // те же три роли одним предикатом — TASWM-528
19536
+ deps.respawn && run.respawns < RESPAWN_LIMIT) {
19498
19537
  const wt = run.worktree_path;
19499
19538
  const wtAlive = !!wt && worktreeExists(wt);
19500
19539
  const canContinue = wtAlive && hasTranscript(wt);
@@ -19547,24 +19586,46 @@ async function tickOnce(deps) {
19547
19586
  continue;
19548
19587
  }
19549
19588
  }
19589
+ if (!alive && outcome === "graceful" && run.status === "running" && isSubrun(run)) {
19590
+ const wt = run.worktree_path;
19591
+ const canContinue = !!wt && worktreeExists(wt) && hasTranscript(wt);
19592
+ if (deps.respawn && canContinue && run.respawns < RESPAWN_LIMIT) {
19593
+ const n = deps.db.incRespawn(run.id);
19594
+ deps.db.addEvent(run.id, "respawned", `\u0430\u0432\u0442\u043E-\u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0435\u043D\u0438\u0435 #${n}: ${SUBRUN_EXITED_TEXT} \u2014 --continue \u0441 \u043D\u0430\u043A\u0430\u0437\u043E\u043C \u043D\u0435 \u0436\u0434\u0430\u0442\u044C \u0444\u043E\u043D\u043E\u0432\u0443\u044E \u0440\u0430\u0431\u043E\u0442\u0443 \u0438 \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0442\u044C \u0441\u043E\u0440\u0430\u0437\u043C\u0435\u0440\u043D\u043E \u043F\u0440\u0430\u0432\u043A\u0435 (TASWM-528)`);
19595
+ narrate(deps, `${droneLabel(run)} \u0437\u0430\u043A\u043E\u043D\u0447\u0438\u043B \u0445\u043E\u0434, \u043D\u0435 \u043F\u043E\u0437\u0432\u0430\u0432 done() \u2014 \u043D\u0435 \u0445\u043E\u0440\u043E\u043D\u044E, \u043F\u043E\u0434\u043D\u0438\u043C\u0430\u044E --continue \u0442\u043E\u0439 \u0436\u0435 \u0441\u0435\u0441\u0441\u0438\u0438.`);
19596
+ try {
19597
+ await deps.respawn(run, "continue", subrunWaitNudge(run));
19598
+ continue;
19599
+ } catch (e) {
19600
+ deps.db.addEvent(run.id, "step", `${SUBRUN_EXITED_TEXT}, \u043D\u043E --continue \u0441\u043E\u0440\u0432\u0430\u043B\u0441\u044F: ${String(e)} \u2014 \u0437\u0430\u043A\u0440\u044B\u0432\u0430\u044E \u043F\u043E\u043F\u044B\u0442\u043A\u0443 \u043F\u043E \u043E\u0431\u0449\u0435\u0439 \u0432\u0435\u0442\u043A\u0435`);
19601
+ }
19602
+ } else {
19603
+ const why = !canContinue ? "worktree/\u0442\u0440\u0430\u043D\u0441\u043A\u0440\u0438\u043F\u0442 \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B" : !deps.respawn ? "\u0440\u0430\u0437\u0432\u043E\u0434\u043A\u0430 \u0430\u0432\u0442\u043E-\u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0435\u043D\u0438\u044F \u043D\u0435 \u0437\u0430\u0434\u0430\u043D\u0430" : `\u0438\u0441\u0447\u0435\u0440\u043F\u0430\u043D \u043B\u0438\u043C\u0438\u0442 \u0430\u0432\u0442\u043E-\u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0435\u043D\u0438\u0439 (${RESPAWN_LIMIT})`;
19604
+ deps.db.addEvent(run.id, "step", `${SUBRUN_EXITED_TEXT}, \u043D\u043E \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u044C \u043D\u0435\u0447\u0435\u043C: ${why} \u2014 \u0437\u0430\u043A\u0440\u044B\u0432\u0430\u044E \u043F\u043E\u043F\u044B\u0442\u043A\u0443 \u043F\u043E \u043E\u0431\u0449\u0435\u0439 \u0432\u0435\u0442\u043A\u0435 (TASWM-528)`);
19605
+ }
19606
+ }
19550
19607
  if (!alive && run.status === "running" && run.resolves_run_id != null) {
19551
19608
  const prUrl = await deliveredPrUrl(deps, run);
19552
19609
  if (run.worktree_path) await deps.removeWorktree(run.repo, run.worktree_path).catch(() => {
19553
19610
  });
19554
19611
  deps.db.updateRun(run.id, { status: "done" });
19612
+ const how = outcome === "graceful" ? "\u0440\u0435\u0437\u043E\u043B\u0432\u0435\u0440 \u0432\u044B\u0448\u0435\u043B \u0441\u0430\u043C, \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u044C \u0441\u0435\u0441\u0441\u0438\u044E \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C" : "\u0440\u0435\u0437\u043E\u043B\u0432\u0435\u0440 \u0443\u043C\u0435\u0440 \u0434\u043E done()";
19555
19613
  deps.db.addEvent(
19556
19614
  run.id,
19557
19615
  "done",
19558
- prUrl ? `\u0440\u0435\u0437\u043E\u043B\u0432\u0435\u0440 \u0443\u043C\u0435\u0440 \u0434\u043E done() \u2014 \u0440\u0430\u0431\u043E\u0442\u0430 \u043D\u0430 \u0432\u0435\u0442\u043A\u0435 PR (${prUrl}), \u043F\u043E\u043F\u044B\u0442\u043A\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u0430; \u0440\u0435\u043A\u043E\u043D\u0441\u0430\u0439\u043B \u0440\u043E\u0434\u0438\u0442\u0435\u043B\u044C\u0441\u043A\u043E\u0433\u043E PR \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442 merge/CI/\u043F\u043E\u0432\u0442\u043E\u0440 (TASWM-224)` : "\u0440\u0435\u0437\u043E\u043B\u0432\u0435\u0440 \u0443\u043C\u0435\u0440 \u0434\u043E done() \u2014 \u043F\u043E\u043F\u044B\u0442\u043A\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u0430; \u0440\u0435\u043A\u043E\u043D\u0441\u0430\u0439\u043B \u0440\u043E\u0434\u0438\u0442\u0435\u043B\u044C\u0441\u043A\u043E\u0433\u043E PR \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442 merge/CI/\u043F\u043E\u0432\u0442\u043E\u0440 (TASWM-224)"
19616
+ prUrl ? `${how} \u2014 \u0440\u0430\u0431\u043E\u0442\u0430 \u043D\u0430 \u0432\u0435\u0442\u043A\u0435 PR (${prUrl}), \u043F\u043E\u043F\u044B\u0442\u043A\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u0430; \u0440\u0435\u043A\u043E\u043D\u0441\u0430\u0439\u043B \u0440\u043E\u0434\u0438\u0442\u0435\u043B\u044C\u0441\u043A\u043E\u0433\u043E PR \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442 merge/CI/\u043F\u043E\u0432\u0442\u043E\u0440 (TASWM-224)` : `${how} \u2014 \u043F\u043E\u043F\u044B\u0442\u043A\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u0430; \u0440\u0435\u043A\u043E\u043D\u0441\u0430\u0439\u043B \u0440\u043E\u0434\u0438\u0442\u0435\u043B\u044C\u0441\u043A\u043E\u0433\u043E PR \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442 merge/CI/\u043F\u043E\u0432\u0442\u043E\u0440 (TASWM-224)`
19559
19617
  );
19560
19618
  narrate(deps, `${droneLabel(run)} (\u0440\u0435\u0437\u043E\u043B\u0432\u0435\u0440) \u0432\u044B\u0448\u0435\u043B \u0434\u043E done() \u2014 \u0437\u0430\u043A\u0440\u044B\u0432\u0430\u044E \u0431\u0435\u0437 \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440\u0441\u043A\u043E\u0433\u043E \u0430\u043B\u0451\u0440\u0442\u0430, \u0434\u0430\u043B\u044C\u0448\u0435 \u0440\u043E\u0434\u0438\u0442\u0435\u043B\u044C\u0441\u043A\u0438\u0439 PR.`);
19561
19619
  continue;
19562
19620
  }
19563
19621
  let reason = null;
19564
19622
  if (!alive) {
19565
- const crashNote = outcome === "crash" ? "\u0443\u0431\u0438\u0442 \u043D\u0430 \u043F\u043E\u043B\u043F\u0443\u0442\u0438 (\u043D\u0435\u0442 result-\u0444\u0430\u0439\u043B\u0430 \u2014 \u043E\u0431\u043E\u0440\u0432\u0430\u043B\u0441\u044F \u0434\u043E \u0437\u0430\u043F\u0438\u0441\u0438 \u0438\u0442\u043E\u0433\u0430: OOM/\u043F\u0430\u043D\u0438\u043A\u0430/kill)" : "pid \u043D\u0435 \u043E\u0442\u0432\u0435\u0447\u0430\u0435\u0442";
19566
- reason = run.respawns >= RESPAWN_LIMIT ? `\u0434\u0440\u043E\u043D \u0443\u043C\u0435\u0440 (${crashNote}): \u0438\u0441\u0447\u0435\u0440\u043F\u0430\u043D \u043B\u0438\u043C\u0438\u0442 \u0430\u0432\u0442\u043E-\u043E\u0436\u0438\u0432\u043B\u0435\u043D\u0438\u0439 (${RESPAWN_LIMIT})` : `\u0434\u0440\u043E\u043D \u0443\u043C\u0435\u0440: ${crashNote}`;
19567
- narrate(deps, `${droneLabel(run)} \u043D\u0435 \u043F\u0440\u0438\u0445\u043E\u0434\u0438\u0442 \u0432 \u0441\u0435\u0431\u044F \u2014 \u0441\u0434\u0430\u044E\u0441\u044C, \u0434\u0430\u043B\u044C\u0448\u0435 \u043D\u0443\u0436\u0435\u043D \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440.`);
19623
+ const how = outcome === "graceful" ? "\u0434\u0440\u043E\u043D \u0432\u044B\u0448\u0435\u043B \u0441\u0430\u043C (\u0441\u0435\u0441\u0441\u0438\u044F \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u0430 \u0448\u0442\u0430\u0442\u043D\u043E), \u043D\u043E done() \u043D\u0435 \u043F\u043E\u0437\u0432\u0430\u043B, \u0430 \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u044C \u0441\u0435\u0441\u0441\u0438\u044E \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C" : `\u0434\u0440\u043E\u043D \u0443\u043C\u0435\u0440: ${outcome === "crash" ? "\u0443\u0431\u0438\u0442 \u043D\u0430 \u043F\u043E\u043B\u043F\u0443\u0442\u0438 (\u043D\u0435\u0442 result-\u0444\u0430\u0439\u043B\u0430 \u2014 \u043E\u0431\u043E\u0440\u0432\u0430\u043B\u0441\u044F \u0434\u043E \u0437\u0430\u043F\u0438\u0441\u0438 \u0438\u0442\u043E\u0433\u0430: OOM/\u043F\u0430\u043D\u0438\u043A\u0430/kill)" : "pid \u043D\u0435 \u043E\u0442\u0432\u0435\u0447\u0430\u0435\u0442"}`;
19624
+ reason = run.respawns >= RESPAWN_LIMIT ? `${how} \u2014 \u0438\u0441\u0447\u0435\u0440\u043F\u0430\u043D \u043B\u0438\u043C\u0438\u0442 \u0430\u0432\u0442\u043E-\u043E\u0436\u0438\u0432\u043B\u0435\u043D\u0438\u0439 (${RESPAWN_LIMIT})` : how;
19625
+ narrate(
19626
+ deps,
19627
+ outcome === "graceful" ? `${droneLabel(run)} \u0437\u0430\u043A\u043E\u043D\u0447\u0438\u043B \u0445\u043E\u0434 \u0441\u0430\u043C, \u043D\u043E \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u044C \u0435\u0433\u043E \u0441\u0435\u0441\u0441\u0438\u044E \u043D\u0435\u0447\u0435\u043C \u2014 \u0434\u0430\u043B\u044C\u0448\u0435 \u043D\u0443\u0436\u0435\u043D \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440.` : `${droneLabel(run)} \u043D\u0435 \u043F\u0440\u0438\u0445\u043E\u0434\u0438\u0442 \u0432 \u0441\u0435\u0431\u044F \u2014 \u0441\u0434\u0430\u044E\u0441\u044C, \u0434\u0430\u043B\u044C\u0448\u0435 \u043D\u0443\u0436\u0435\u043D \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440.`
19628
+ );
19568
19629
  } else if (run.status === "running" && now - await livenessMs(deps, run, now, liveChildPpids) > STALL_MS) {
19569
19630
  reason = `\u0434\u0440\u043E\u043D \u0437\u0430\u0432\u0438\u0441: \u043C\u043E\u043B\u0447\u0438\u0442 > ${Math.round(STALL_MS / 6e4)} \u043C\u0438\u043D`;
19570
19631
  narrate(deps, `${droneLabel(run)} \u0437\u0430\u0442\u0438\u0445 \u0434\u043E\u043B\u044C\u0448\u0435 ${Math.round(STALL_MS / 6e4)} \u043C\u0438\u043D \u2014 \u043F\u043E\u043C\u0435\u0447\u0430\u044E \u0437\u0430\u0432\u0438\u0441\u0448\u0438\u043C, \u0433\u043B\u044F\u043D\u0443, \u0447\u0442\u043E \u0442\u0430\u043C.`);
@@ -21453,6 +21514,7 @@ export {
21453
21514
  STALL_MS,
21454
21515
  STORM_DEAD_LIMIT,
21455
21516
  SUBMITTED_EXIT_TEXT,
21517
+ SUBRUN_EXITED_TEXT,
21456
21518
  VERIFY_ESCALATION_MARK,
21457
21519
  VERIFY_SPAWN_LIMIT,
21458
21520
  WATCHDOG_PARK_REASON,
@@ -21468,6 +21530,7 @@ export {
21468
21530
  buildVerifierPrompt,
21469
21531
  cancelRun,
21470
21532
  hasLiveDescendant,
21533
+ isSubrun,
21471
21534
  lastChangesSummary,
21472
21535
  listDroneProcesses,
21473
21536
  livePpids,
@@ -21482,6 +21545,7 @@ export {
21482
21545
  runDaemon,
21483
21546
  spawnReviewer,
21484
21547
  spawnVerifier,
21548
+ subrunWaitNudge,
21485
21549
  syncCrashedOnStartup,
21486
21550
  tickOnce,
21487
21551
  verdictCommentMark,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taskless-app/swarm",
3
- "version": "0.6.29",
3
+ "version": "0.6.31",
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": [
@@ -39,7 +39,7 @@
39
39
  "execa": "^10.0.0",
40
40
  "zod": "3.25.76"
41
41
  },
42
- "gitHead": "d8072f68198b68b4252687b01e7e82e2b4769346",
42
+ "gitHead": "82950eae7a6ad09be4193708257798c811bb6fae",
43
43
  "scripts": {
44
44
  "overmind": "NODE_OPTIONS=\"${NODE_OPTIONS:-} --conditions=development\" tsx src/overmind.ts",
45
45
  "swarm": "NODE_OPTIONS=\"${NODE_OPTIONS:-} --conditions=development\" tsx src/cli.ts",