@taskless-app/swarm 0.6.63 → 0.6.64

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/cli.js +49 -29
  2. package/dist/overmind.js +1558 -1504
  3. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -388,8 +388,8 @@ function computeBlocker(status, stopReason, lastStep, pr, ci, deps, openQ) {
388
388
  }
389
389
  }
390
390
  function pickHeadline(lanes) {
391
- const live = lanes.filter((l2) => l2.live && !l2.obsolete);
392
- const by = (pred) => live.find(pred);
391
+ const live2 = lanes.filter((l2) => l2.live && !l2.obsolete);
392
+ const by = (pred) => live2.find(pred);
393
393
  const fmt = (l2, extra) => `${l2.name} \xB7 ${l2.slug} \u2014 ${extra}`;
394
394
  let l = by((x) => x.status === "review" && x.ci?.tone === "fail");
395
395
  if (l) return { icon: "\u274C", text: fmt(l, "CI \u0443\u043F\u0430\u043B \u2014 \u0447\u0438\u043D\u0438\u0442\u044C"), tone: "fail" };
@@ -407,7 +407,7 @@ function pickHeadline(lanes) {
407
407
  l = by((x) => x.status === "review");
408
408
  if (l) return { icon: "\u23F3", text: fmt(l, "review \u2014 CI \u0438\u0434\u0451\u0442"), tone: "review" };
409
409
  l = by((x) => x.status === "running");
410
- if (l) return { icon: "\u25B6", text: `${live.filter((x) => x.status === "running").length} \u0434\u0440\u043E\u043D\u0430 \u0432 \u0440\u0430\u0431\u043E\u0442\u0435 \u2014 \u0431\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u043E\u043A \u043D\u0435\u0442`, tone: "run" };
410
+ if (l) return { icon: "\u25B6", text: `${live2.filter((x) => x.status === "running").length} \u0434\u0440\u043E\u043D\u0430 \u0432 \u0440\u0430\u0431\u043E\u0442\u0435 \u2014 \u0431\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u043E\u043A \u043D\u0435\u0442`, tone: "run" };
411
411
  return null;
412
412
  }
413
413
  function computeCounters(lanes) {
@@ -706,13 +706,15 @@ var init_modelPolicy = __esm({
706
706
  },
707
707
  // Grok CLI. Каталог — живой `grok models` (16.10.2026), целиком и без выдуманных
708
708
  // имён: grok-4.7 (дефолт CLI и исполнителя), grok-4.7-build-fast, grok-4.6, grok-4.5
709
- // (проверка — младшая, та же идея, что sonnet против opus). Тарифа нет: цену пишет CLI.
709
+ // TASWM-605: обе роли — на свежей модели (решение владельца: рой работает на свежих
710
+ // моделях). Это только фолбэк: демон берёт дефолт живого `grok models` (liveModels.ts).
711
+ // Тарифа нет: цену пишет CLI.
710
712
  {
711
713
  id: "xai",
712
714
  label: "xAI (Grok)",
713
715
  executorId: "grok",
714
716
  selectable: true,
715
- roles: { executor: "grok-4.7", review: "grok-4.5" },
717
+ roles: { executor: "grok-4.7", review: "grok-4.7" },
716
718
  models: ["grok-4.7", "grok-4.7-build-fast", "grok-4.6", "grok-4.5"]
717
719
  },
718
720
  // TASWM-565 · шаг 1 из четырёх: провайдер в реестре ЕСТЬ, выбрать его ещё нельзя.
@@ -2834,7 +2836,24 @@ ${notice}` : spec.prompt;
2834
2836
  }
2835
2837
  });
2836
2838
 
2839
+ // src/liveModels.ts
2840
+ import { execFile } from "child_process";
2841
+ function liveDefaultModel(providerId) {
2842
+ return live.get(providerId) ?? null;
2843
+ }
2844
+ var live;
2845
+ var init_liveModels = __esm({
2846
+ "src/liveModels.ts"() {
2847
+ "use strict";
2848
+ init_grok();
2849
+ live = /* @__PURE__ */ new Map();
2850
+ }
2851
+ });
2852
+
2837
2853
  // src/swarmModels.ts
2854
+ function roleDefault(role, providerId) {
2855
+ return liveDefaultModel(providerId) ?? defaultModelFor(role, providerId);
2856
+ }
2838
2857
  function pick2(v) {
2839
2858
  const s = typeof v === "string" ? v.trim() : "";
2840
2859
  return s.length > 0 ? s : null;
@@ -2863,11 +2882,11 @@ function resolveRunModelRef(run, swarm, env = process.env) {
2863
2882
  const own = providersFromEnv(env);
2864
2883
  if (own) {
2865
2884
  if (configured && own.includes(configured.providerId)) return configured;
2866
- return { providerId: own[0], model: defaultModelFor(modelRoleOf(run.kind), own[0]) };
2885
+ return { providerId: own[0], model: roleDefault(modelRoleOf(run.kind), own[0]) };
2867
2886
  }
2868
2887
  if (configured) return configured;
2869
2888
  const providerId = pick2(env.SWARM_MODEL_PROVIDER) ?? DEFAULT_PROVIDER_ID;
2870
- return { providerId, model: defaultModelFor(modelRoleOf(run.kind), providerId) };
2889
+ return { providerId, model: roleDefault(modelRoleOf(run.kind), providerId) };
2871
2890
  }
2872
2891
  function resolveRunEffort(run, swarm, env = process.env) {
2873
2892
  return toEffortLevel(run.effort) ?? forKind(run.kind, swarm, toEffortLevel) ?? toEffortLevel(env.SWARM_DRONE_EFFORT) ?? null;
@@ -2876,6 +2895,7 @@ var init_swarmModels = __esm({
2876
2895
  "src/swarmModels.ts"() {
2877
2896
  "use strict";
2878
2897
  init_src();
2898
+ init_liveModels();
2879
2899
  }
2880
2900
  });
2881
2901
 
@@ -3288,11 +3308,11 @@ var init_resources = __esm({
3288
3308
 
3289
3309
  // src/names.ts
3290
3310
  function pickName(rows) {
3291
- const live = /* @__PURE__ */ new Set();
3311
+ const live2 = /* @__PURE__ */ new Set();
3292
3312
  const lastUse = /* @__PURE__ */ new Map();
3293
3313
  for (const r of rows) {
3294
3314
  if (!r.name) continue;
3295
- if (NAME_LIVE.has(r.status)) live.add(r.name);
3315
+ if (NAME_LIVE.has(r.status)) live2.add(r.name);
3296
3316
  const b = baseName(r.name);
3297
3317
  lastUse.set(b, Math.max(lastUse.get(b) ?? 0, r.id));
3298
3318
  }
@@ -3302,7 +3322,7 @@ function pickName(rows) {
3302
3322
  for (let g = 1; ; g++) {
3303
3323
  for (const base3 of ordered) {
3304
3324
  const cand = genName(base3, g);
3305
- if (!live.has(cand)) return cand;
3325
+ if (!live2.has(cand)) return cand;
3306
3326
  }
3307
3327
  }
3308
3328
  }
@@ -3852,7 +3872,7 @@ var init_package = __esm({
3852
3872
  "package.json"() {
3853
3873
  package_default = {
3854
3874
  name: "@taskless-app/swarm",
3855
- version: "0.6.63",
3875
+ version: "0.6.64",
3856
3876
  type: "module",
3857
3877
  description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
3858
3878
  keywords: [
@@ -3903,7 +3923,7 @@ var init_package = __esm({
3903
3923
  execa: "^10.0.0",
3904
3924
  zod: "3.25.76"
3905
3925
  },
3906
- gitHead: "8d438b6288da036308528cff1160a157b4b64abd"
3926
+ gitHead: "7f27042a00bf1554798cce7b8a233ee6c5686a50"
3907
3927
  };
3908
3928
  }
3909
3929
  });
@@ -4460,8 +4480,8 @@ async function checkoutWorktree(repo, path, branch, opts) {
4460
4480
  const busyAt = await worktreeForBranch(repo, branch);
4461
4481
  if (busyAt) {
4462
4482
  const exists = existsSync11(busyAt);
4463
- const live = exists && (opts.isWorktreeHeldLive ? await opts.isWorktreeHeldLive(busyAt) : true);
4464
- if (live) throw new WorktreeBusyError(branch, busyAt);
4483
+ const live2 = exists && (opts.isWorktreeHeldLive ? await opts.isWorktreeHeldLive(busyAt) : true);
4484
+ if (live2) throw new WorktreeBusyError(branch, busyAt);
4465
4485
  if (exists && await worktreeDirty(busyAt)) throw new WorktreeBusyError(branch, busyAt);
4466
4486
  await reclaimStaleWorktree(repo, busyAt);
4467
4487
  opts.onStaleReclaim?.(busyAt);
@@ -11038,19 +11058,19 @@ function makeMergeIntentResolver(deps) {
11038
11058
  if (!sha) {
11039
11059
  return { action: "wait", code: "checks_unknown", reason: "gh \u043D\u0435 \u0441\u043A\u0430\u0437\u0430\u043B HEAD PR \u2014 \u043D\u0435 \u043F\u043E\u043D\u044F\u0442\u044C, \u043F\u0440\u043E \u043A\u0430\u043A\u043E\u0439 \u043A\u043E\u043C\u043C\u0438\u0442 \u044D\u0442\u043E\u0442 \u0432\u0435\u0440\u0434\u0438\u043A\u0442; \u0441\u043F\u0440\u043E\u0448\u0443 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u043C \u0442\u0438\u043A\u043E\u043C" };
11040
11060
  }
11041
- const live = deps.baseSync ? await deps.baseSync(prUrl).catch(() => null) : null;
11042
- if (!live || !live.headSha) {
11061
+ const live2 = deps.baseSync ? await deps.baseSync(prUrl).catch(() => null) : null;
11062
+ if (!live2 || !live2.headSha) {
11043
11063
  return { action: "wait", code: "base_unknown", reason: "\u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043F\u0435\u0440\u0435\u0441\u043F\u0440\u043E\u0441\u0438\u0442\u044C \u0436\u0438\u0432\u043E\u0439 HEAD PR \u2014 \u0441\u043F\u0440\u043E\u0448\u0443 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u043C \u0442\u0438\u043A\u043E\u043C" };
11044
11064
  }
11045
- if (verdict.action === "merge" && live.behindBy > 0) {
11065
+ if (verdict.action === "merge" && live2.behindBy > 0) {
11046
11066
  return {
11047
11067
  action: "refresh_base",
11048
11068
  code: "base_stale",
11049
- reason: `\u0431\u0430\u0437\u0430 \u0443\u0448\u043B\u0430 \u0432\u043F\u0435\u0440\u0451\u0434 \u043D\u0430 ${live.behindBy} \u043A\u043E\u043C\u043C\u0438\u0442(\u043E\u0432) \u043F\u043E\u0441\u043B\u0435 \u043F\u0440\u0435\u0434\u044B\u0434\u0443\u0449\u0435\u0433\u043E \u043C\u0435\u0440\u0436\u0430 \u2014 \u0441\u043D\u0430\u0447\u0430\u043B\u0430 \u0432\u043B\u0438\u0442\u044C main \u0438 \u0434\u043E\u0436\u0434\u0430\u0442\u044C\u0441\u044F CI \u043D\u0430 \u043E\u0431\u043D\u043E\u0432\u043B\u0451\u043D\u043D\u043E\u0439 \u0431\u0430\u0437\u0435`
11069
+ reason: `\u0431\u0430\u0437\u0430 \u0443\u0448\u043B\u0430 \u0432\u043F\u0435\u0440\u0451\u0434 \u043D\u0430 ${live2.behindBy} \u043A\u043E\u043C\u043C\u0438\u0442(\u043E\u0432) \u043F\u043E\u0441\u043B\u0435 \u043F\u0440\u0435\u0434\u044B\u0434\u0443\u0449\u0435\u0433\u043E \u043C\u0435\u0440\u0436\u0430 \u2014 \u0441\u043D\u0430\u0447\u0430\u043B\u0430 \u0432\u043B\u0438\u0442\u044C main \u0438 \u0434\u043E\u0436\u0434\u0430\u0442\u044C\u0441\u044F CI \u043D\u0430 \u043E\u0431\u043D\u043E\u0432\u043B\u0451\u043D\u043D\u043E\u0439 \u0431\u0430\u0437\u0435`
11050
11070
  };
11051
11071
  }
11052
- if (live.headSha !== sha) {
11053
- return { action: "wait", code: "checks_pending", reason: `\u043D\u0430 PR \u043D\u043E\u0432\u044B\u0439 \u043A\u043E\u043C\u043C\u0438\u0442 ${shortSha(live.headSha)} \u2014 \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u044E \u0437\u0430\u043D\u043E\u0432\u043E` };
11072
+ if (live2.headSha !== sha) {
11073
+ return { action: "wait", code: "checks_pending", reason: `\u043D\u0430 PR \u043D\u043E\u0432\u044B\u0439 \u043A\u043E\u043C\u043C\u0438\u0442 ${shortSha(live2.headSha)} \u2014 \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u044E \u0437\u0430\u043D\u043E\u0432\u043E` };
11054
11074
  }
11055
11075
  return verdict;
11056
11076
  };
@@ -11330,13 +11350,13 @@ function timelineState(db2, now = Date.now(), overmindLog = []) {
11330
11350
  const lanes = [];
11331
11351
  const reviewPRs = [];
11332
11352
  for (const r of runs) {
11333
- const live = !isTerminalStatus(r.status);
11334
- const recencyGated = !live || r.status === "stalled";
11353
+ const live2 = !isTerminalStatus(r.status);
11354
+ const recencyGated = !live2 || r.status === "stalled";
11335
11355
  if (recencyGated && sqliteMs(r.updated_at) < cutoff) continue;
11336
11356
  const events = db2.events(r.id).map((e) => ({ kind: e.kind, text: e.text ?? null, at: sqliteIso(e.at) }));
11337
11357
  const steps = events.filter((e) => e.kind === "step" && e.text).map((e) => ({ at: e.at, text: e.text }));
11338
11358
  const lastStep = steps.length ? steps[steps.length - 1].text : null;
11339
- const laneEnd = live ? nowIso : sqliteIso(r.updated_at);
11359
+ const laneEnd = live2 ? nowIso : sqliteIso(r.updated_at);
11340
11360
  const segments = buildSegments(sqliteIso(r.created_at), events, laneEnd);
11341
11361
  const deps = (r.depends_on ?? []).map((ref) => {
11342
11362
  const { slug, unresolved } = resolveDepRef(ref, { slugByCuid: EMPTY_CUID_MAP, knownSlugs });
@@ -11358,7 +11378,7 @@ function timelineState(db2, now = Date.now(), overmindLog = []) {
11358
11378
  ci = ciCache.get(r.pr_url)?.ci ?? null;
11359
11379
  }
11360
11380
  }
11361
- const obsoleteBy = live && doneNameBySlug.has(r.task_slug) ? doneNameBySlug.get(r.task_slug) : null;
11381
+ const obsoleteBy = live2 && doneNameBySlug.has(r.task_slug) ? doneNameBySlug.get(r.task_slug) : null;
11362
11382
  const obsolete = obsoleteBy != null;
11363
11383
  const blocker = obsolete ? { icon: "\u{1F9DF}", text: `\u0443\u0441\u0442\u0430\u0440\u0435\u043B \u2014 \u0437\u0430\u0434\u0430\u0447\u0443 \u0437\u0430\u043A\u0440\u044B\u043B ${obsoleteBy}`, tone: "queued" } : computeBlocker(r.status, r.stop_reason, lastStep, r.pr_url, ci, deps, openQ.get(r.id) ?? null);
11364
11384
  lanes.push({
@@ -11370,7 +11390,7 @@ function timelineState(db2, now = Date.now(), overmindLog = []) {
11370
11390
  area: r.area,
11371
11391
  start: sqliteIso(r.created_at),
11372
11392
  end: laneEnd,
11373
- live,
11393
+ live: live2,
11374
11394
  obsolete,
11375
11395
  obsoleteBy,
11376
11396
  segments,
@@ -12487,7 +12507,7 @@ function setPausedVia(deps, paused, source, reason) {
12487
12507
  function daemonStatus(deps) {
12488
12508
  const counts = {};
12489
12509
  for (const r of deps.db.listRuns()) counts[r.status] = (counts[r.status] ?? 0) + 1;
12490
- const live = deps.liveSessionIds?.() ?? [];
12510
+ const live2 = deps.liveSessionIds?.() ?? [];
12491
12511
  const ver = deps.daemonVersion?.() ?? null;
12492
12512
  const queuedReady = deps.db.listRuns("queued").filter((r) => deps.db.unmetDeps(r.depends_on).length === 0).length;
12493
12513
  return {
@@ -12504,9 +12524,9 @@ function daemonStatus(deps) {
12504
12524
  backend: SWARM_BACKEND,
12505
12525
  paused: deps.control?.paused ?? false,
12506
12526
  pause: deps.control?.state ?? null,
12507
- restart: deps.restart ? { phase: deps.restart.phase, intent: deps.restart.intent, sessions: live } : null,
12527
+ restart: deps.restart ? { phase: deps.restart.phase, intent: deps.restart.intent, sessions: live2 } : null,
12508
12528
  counts,
12509
- live,
12529
+ live: live2,
12510
12530
  version: PACKAGE_VERSION,
12511
12531
  repos: deps.repoMap?.() ?? [],
12512
12532
  // TASWM-324: «нас не пускают» — то же состояние процесса, что кричит рамкой в лог.
@@ -13064,7 +13084,7 @@ function makeLauncher(cfg) {
13064
13084
  console.error(`[launcher] \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u043F\u0438\u0441\u0430\u0442\u044C \u0443\u0441\u0438\u043B\u0438\u0435 \u043F\u0440\u043E\u0433\u043E\u043D\u0430 #${run.id}: ${String(e)}`);
13065
13085
  }
13066
13086
  try {
13067
- cfg.recordModelRef?.(run.id, modelRef);
13087
+ cfg.recordModelRef?.(run.id, modelRef, run);
13068
13088
  } catch (e) {
13069
13089
  console.error(`[launcher] \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u043F\u0438\u0441\u0430\u0442\u044C \u043C\u043E\u0434\u0435\u043B\u044C \u043F\u0440\u043E\u0433\u043E\u043D\u0430 #${run.id}: ${String(e)}`);
13070
13090
  }