@taskless-app/swarm 0.6.63 → 0.6.65
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 +49 -29
- package/dist/overmind.js +1558 -1504
- 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
|
|
392
|
-
const by = (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: `${
|
|
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
|
-
//
|
|
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.
|
|
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:
|
|
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:
|
|
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
|
|
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))
|
|
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 (!
|
|
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.
|
|
3875
|
+
version: "0.6.65",
|
|
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: "
|
|
3926
|
+
gitHead: "254a8954d2f53f168b6cebc23b2daa0bc1562426"
|
|
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
|
|
4464
|
-
if (
|
|
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
|
|
11042
|
-
if (!
|
|
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" &&
|
|
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 ${
|
|
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 (
|
|
11053
|
-
return { action: "wait", code: "checks_pending", reason: `\u043D\u0430 PR \u043D\u043E\u0432\u044B\u0439 \u043A\u043E\u043C\u043C\u0438\u0442 ${shortSha(
|
|
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
|
|
11334
|
-
const recencyGated = !
|
|
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 =
|
|
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 =
|
|
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
|
|
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:
|
|
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
|
}
|