@taskless-app/swarm 0.6.4 → 0.6.5
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 +34 -4
- package/dist/overmind.js +99 -11
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -1884,7 +1884,7 @@ var init_package = __esm({
|
|
|
1884
1884
|
"package.json"() {
|
|
1885
1885
|
package_default = {
|
|
1886
1886
|
name: "@taskless-app/swarm",
|
|
1887
|
-
version: "0.6.
|
|
1887
|
+
version: "0.6.5",
|
|
1888
1888
|
type: "module",
|
|
1889
1889
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
1890
1890
|
keywords: [
|
|
@@ -1934,7 +1934,7 @@ var init_package = __esm({
|
|
|
1934
1934
|
execa: "^10.0.0",
|
|
1935
1935
|
zod: "3.25.76"
|
|
1936
1936
|
},
|
|
1937
|
-
gitHead: "
|
|
1937
|
+
gitHead: "76ff5edd816a2b9dd7f10db62c8fde89eec7771f"
|
|
1938
1938
|
};
|
|
1939
1939
|
}
|
|
1940
1940
|
});
|
|
@@ -5291,6 +5291,19 @@ var SwarmClient = class _SwarmClient {
|
|
|
5291
5291
|
* → null: ридер (makeMaxDronesReader) берёт env-фолбэк.
|
|
5292
5292
|
*/
|
|
5293
5293
|
async ownerMaxDrones() {
|
|
5294
|
+
return (await this.ownerSwarmSettings())?.maxDrones ?? null;
|
|
5295
|
+
}
|
|
5296
|
+
/**
|
|
5297
|
+
* TASWM-364: настройки роя ЦЕЛИКОМ из того же who_am_i — живой кап дронов И модели, на
|
|
5298
|
+
* которых спавнятся дроны и ревьюеры (раздел «Рой» в настройках). Одним вызовом, а не
|
|
5299
|
+
* двумя: читатель у них один (ридер maxDrones раз в TTL), и второй сетевой поход за
|
|
5300
|
+
* соседним полем того же ответа был бы платой ни за что.
|
|
5301
|
+
*
|
|
5302
|
+
* Прод недоступен / ответ без валидного капа → null: вызывающий берёт env-фолбэки
|
|
5303
|
+
* (SWARM_MAX_IN_FLIGHT для капа, SWARM_DRONE_MODEL для модели). Модель без капа отдельно
|
|
5304
|
+
* не отдаём СОЗНАТЕЛЬНО — «ответ прода не разобрался» это одно событие, а не два.
|
|
5305
|
+
*/
|
|
5306
|
+
async ownerSwarmSettings() {
|
|
5294
5307
|
let res;
|
|
5295
5308
|
try {
|
|
5296
5309
|
res = await this.call("who_am_i", {});
|
|
@@ -5300,7 +5313,14 @@ var SwarmClient = class _SwarmClient {
|
|
|
5300
5313
|
if (res?.isError) return null;
|
|
5301
5314
|
const obj = jsonFromTextContent(res);
|
|
5302
5315
|
const n = obj?.maxDrones;
|
|
5303
|
-
|
|
5316
|
+
if (!(typeof n === "number" && Number.isFinite(n) && n > 0)) return null;
|
|
5317
|
+
const str = (v) => typeof v === "string" && v.trim() ? v.trim() : null;
|
|
5318
|
+
return {
|
|
5319
|
+
maxDrones: Math.trunc(n),
|
|
5320
|
+
// Старый прод (до TASWM-364) поля swarmSettings не отдаёт вовсе — обе модели null,
|
|
5321
|
+
// то есть прежнее поведение: env машины и дефолт харнесса.
|
|
5322
|
+
models: { drone: str(obj?.swarmSettings?.droneModel), reviewer: str(obj?.swarmSettings?.reviewerModel) }
|
|
5323
|
+
};
|
|
5304
5324
|
}
|
|
5305
5325
|
/**
|
|
5306
5326
|
* Live verifyMode проекта из Taskless (TASWM-171): читает swarm_repo_config по
|
|
@@ -8709,6 +8729,16 @@ function droneTestEnv(droneCap, base3 = process.env, host = hostForkSpec()) {
|
|
|
8709
8729
|
};
|
|
8710
8730
|
}
|
|
8711
8731
|
|
|
8732
|
+
// src/swarmModels.ts
|
|
8733
|
+
function resolveRunModel(run, swarm, env = process.env) {
|
|
8734
|
+
const pick = (v) => {
|
|
8735
|
+
const s = typeof v === "string" ? v.trim() : "";
|
|
8736
|
+
return s.length > 0 ? s : null;
|
|
8737
|
+
};
|
|
8738
|
+
const fromSwarm = run.kind === "reviewer" ? pick(swarm?.reviewer) ?? pick(swarm?.drone) : pick(swarm?.drone);
|
|
8739
|
+
return pick(run.model) ?? fromSwarm ?? pick(env.SWARM_DRONE_MODEL) ?? null;
|
|
8740
|
+
}
|
|
8741
|
+
|
|
8712
8742
|
// src/launcher.ts
|
|
8713
8743
|
init_executors();
|
|
8714
8744
|
var requireFromHere = createRequire(import.meta.url);
|
|
@@ -8846,7 +8876,7 @@ function makeLauncher(cfg) {
|
|
|
8846
8876
|
...run.hero_run_id != null ? { SWARM_HERO_RUN_ID: String(run.hero_run_id) } : {}
|
|
8847
8877
|
}
|
|
8848
8878
|
};
|
|
8849
|
-
const model = run
|
|
8879
|
+
const model = resolveRunModel(run, cfg.swarmModels?.() ?? null);
|
|
8850
8880
|
const realHome = cfg.droneIsolation?.realHome ?? homedir4();
|
|
8851
8881
|
const home = cfg.droneIsolation ? buildDroneHome({ realHome, droneHome: cfg.droneIsolation.home }) : void 0;
|
|
8852
8882
|
if (cfg.droneIsolation && process.env.TASKLESS_TOKEN && !existsSync7(join12(cfg.droneIsolation.swarmHome, "token"))) {
|
package/dist/overmind.js
CHANGED
|
@@ -4105,6 +4105,16 @@ function makeTasklessClient(call, workspaceId, taskUrlBase, fetchFile, fetchImpl
|
|
|
4105
4105
|
const text = res?.content?.find((c) => c.type === "text")?.text;
|
|
4106
4106
|
return typeof text === "string" && text.trim() ? text : null;
|
|
4107
4107
|
}
|
|
4108
|
+
async function reportAcceptanceCheck(input) {
|
|
4109
|
+
const res = await safeCall("report_acceptance_check", {
|
|
4110
|
+
id: input.id,
|
|
4111
|
+
state: input.state,
|
|
4112
|
+
...input.evidence ? { evidence: input.evidence } : {}
|
|
4113
|
+
});
|
|
4114
|
+
if (!res) return null;
|
|
4115
|
+
const text = res.content?.find((c) => c.type === "text")?.text;
|
|
4116
|
+
return typeof text === "string" && text.trim() ? text : null;
|
|
4117
|
+
}
|
|
4108
4118
|
async function resolveId(idOrSlug) {
|
|
4109
4119
|
const cached = idCache.get(idOrSlug);
|
|
4110
4120
|
if (cached) return cached;
|
|
@@ -4173,6 +4183,7 @@ function makeTasklessClient(call, workspaceId, taskUrlBase, fetchFile, fetchImpl
|
|
|
4173
4183
|
backlogStatusId,
|
|
4174
4184
|
getDocument,
|
|
4175
4185
|
getTaskContext,
|
|
4186
|
+
reportAcceptanceCheck,
|
|
4176
4187
|
createTask: async (input) => {
|
|
4177
4188
|
if (!input.projectId) {
|
|
4178
4189
|
throw new Error("createTask: projectId \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u0435\u043D \u2014 \u0430\u0432\u0442\u043E-\u0441\u043E\u0437\u0434\u0430\u043D\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u0440\u043E\u0435\u043C \u0431\u0435\u0437 \u043F\u0440\u043E\u0435\u043A\u0442\u0430 \u0437\u0430\u043F\u0440\u0435\u0449\u0435\u043D\u043E (TASWM-204)");
|
|
@@ -4421,7 +4432,7 @@ var init_taskless = __esm({
|
|
|
4421
4432
|
init_agentToken();
|
|
4422
4433
|
init_workspace();
|
|
4423
4434
|
SLUG_RE = /^[A-Za-z][A-Za-z0-9]*-\d+$/;
|
|
4424
|
-
WS_FREE_TOOLS = /* @__PURE__ */ new Set(["list_workspaces", "who_am_i", "finalize_upload"]);
|
|
4435
|
+
WS_FREE_TOOLS = /* @__PURE__ */ new Set(["list_workspaces", "who_am_i", "finalize_upload", "report_acceptance_check"]);
|
|
4425
4436
|
TaskBodyUnavailableError = class extends Error {
|
|
4426
4437
|
constructor(slug, workspaceId) {
|
|
4427
4438
|
super(
|
|
@@ -6686,6 +6697,19 @@ var SwarmClient = class _SwarmClient {
|
|
|
6686
6697
|
* → null: ридер (makeMaxDronesReader) берёт env-фолбэк.
|
|
6687
6698
|
*/
|
|
6688
6699
|
async ownerMaxDrones() {
|
|
6700
|
+
return (await this.ownerSwarmSettings())?.maxDrones ?? null;
|
|
6701
|
+
}
|
|
6702
|
+
/**
|
|
6703
|
+
* TASWM-364: настройки роя ЦЕЛИКОМ из того же who_am_i — живой кап дронов И модели, на
|
|
6704
|
+
* которых спавнятся дроны и ревьюеры (раздел «Рой» в настройках). Одним вызовом, а не
|
|
6705
|
+
* двумя: читатель у них один (ридер maxDrones раз в TTL), и второй сетевой поход за
|
|
6706
|
+
* соседним полем того же ответа был бы платой ни за что.
|
|
6707
|
+
*
|
|
6708
|
+
* Прод недоступен / ответ без валидного капа → null: вызывающий берёт env-фолбэки
|
|
6709
|
+
* (SWARM_MAX_IN_FLIGHT для капа, SWARM_DRONE_MODEL для модели). Модель без капа отдельно
|
|
6710
|
+
* не отдаём СОЗНАТЕЛЬНО — «ответ прода не разобрался» это одно событие, а не два.
|
|
6711
|
+
*/
|
|
6712
|
+
async ownerSwarmSettings() {
|
|
6689
6713
|
let res;
|
|
6690
6714
|
try {
|
|
6691
6715
|
res = await this.call("who_am_i", {});
|
|
@@ -6695,7 +6719,14 @@ var SwarmClient = class _SwarmClient {
|
|
|
6695
6719
|
if (res?.isError) return null;
|
|
6696
6720
|
const obj = jsonFromTextContent(res);
|
|
6697
6721
|
const n = obj?.maxDrones;
|
|
6698
|
-
|
|
6722
|
+
if (!(typeof n === "number" && Number.isFinite(n) && n > 0)) return null;
|
|
6723
|
+
const str2 = (v) => typeof v === "string" && v.trim() ? v.trim() : null;
|
|
6724
|
+
return {
|
|
6725
|
+
maxDrones: Math.trunc(n),
|
|
6726
|
+
// Старый прод (до TASWM-364) поля swarmSettings не отдаёт вовсе — обе модели null,
|
|
6727
|
+
// то есть прежнее поведение: env машины и дефолт харнесса.
|
|
6728
|
+
models: { drone: str2(obj?.swarmSettings?.droneModel), reviewer: str2(obj?.swarmSettings?.reviewerModel) }
|
|
6729
|
+
};
|
|
6699
6730
|
}
|
|
6700
6731
|
/**
|
|
6701
6732
|
* Live verifyMode проекта из Taskless (TASWM-171): читает swarm_repo_config по
|
|
@@ -8186,6 +8217,16 @@ function droneTestEnv(droneCap, base3 = process.env, host = hostForkSpec()) {
|
|
|
8186
8217
|
};
|
|
8187
8218
|
}
|
|
8188
8219
|
|
|
8220
|
+
// src/swarmModels.ts
|
|
8221
|
+
function resolveRunModel(run, swarm, env = process.env) {
|
|
8222
|
+
const pick2 = (v) => {
|
|
8223
|
+
const s = typeof v === "string" ? v.trim() : "";
|
|
8224
|
+
return s.length > 0 ? s : null;
|
|
8225
|
+
};
|
|
8226
|
+
const fromSwarm = run.kind === "reviewer" ? pick2(swarm?.reviewer) ?? pick2(swarm?.drone) : pick2(swarm?.drone);
|
|
8227
|
+
return pick2(run.model) ?? fromSwarm ?? pick2(env.SWARM_DRONE_MODEL) ?? null;
|
|
8228
|
+
}
|
|
8229
|
+
|
|
8189
8230
|
// src/launcher.ts
|
|
8190
8231
|
init_executors();
|
|
8191
8232
|
var requireFromHere = createRequire(import.meta.url);
|
|
@@ -8323,7 +8364,7 @@ function makeLauncher(cfg) {
|
|
|
8323
8364
|
...run.hero_run_id != null ? { SWARM_HERO_RUN_ID: String(run.hero_run_id) } : {}
|
|
8324
8365
|
}
|
|
8325
8366
|
};
|
|
8326
|
-
const model = run
|
|
8367
|
+
const model = resolveRunModel(run, cfg.swarmModels?.() ?? null);
|
|
8327
8368
|
const realHome = cfg.droneIsolation?.realHome ?? homedir4();
|
|
8328
8369
|
const home = cfg.droneIsolation ? buildDroneHome({ realHome, droneHome: cfg.droneIsolation.home }) : void 0;
|
|
8329
8370
|
if (cfg.droneIsolation && process.env.TASKLESS_TOKEN && !existsSync8(join12(cfg.droneIsolation.swarmHome, "token"))) {
|
|
@@ -8391,7 +8432,7 @@ function accountRunCost(deps, run) {
|
|
|
8391
8432
|
const dir = join13(deps.runLogsDir, String(run.id));
|
|
8392
8433
|
const files = unprocessedLogFiles(dir);
|
|
8393
8434
|
if (files.length === 0) return;
|
|
8394
|
-
const model = run
|
|
8435
|
+
const model = resolveRunModel(run, deps.swarmModels?.() ?? null);
|
|
8395
8436
|
const executor = deps.executor ?? resolveExecutor();
|
|
8396
8437
|
let added = 0;
|
|
8397
8438
|
let tokensIn = 0;
|
|
@@ -9495,6 +9536,41 @@ ${notFoundText}` : notFoundText }],
|
|
|
9495
9536
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
9496
9537
|
}
|
|
9497
9538
|
);
|
|
9539
|
+
server.tool(
|
|
9540
|
+
"report_acceptance_check",
|
|
9541
|
+
"\u0417\u0430\u043A\u0440\u044B\u0442\u044C \u043E\u0434\u0438\u043D \u043F\u0443\u043D\u043A\u0442 \u043A\u0440\u0438\u0442\u0435\u0440\u0438\u0435\u0432 \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438 \u0442\u0432\u043E\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0438: passed \u2014 \u043F\u0440\u043E\u0448\u043B\u0430, failed \u2014 \u0443\u043F\u0430\u043B\u0430, pending \u2014 \u0441\u043D\u043E\u0432\u0430 \u043D\u0435 \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u043B\u0430\u0441\u044C. id \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u0431\u0435\u0440\u0438 \u0438\u0437 \u0431\u043B\u043E\u043A\u0430 \xAB\u041A\u0440\u0438\u0442\u0435\u0440\u0438\u0438 \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438\xBB (\u0441\u0442\u0440\u043E\u043A\u0430 \xAB(id: \u2026)\xBB) \u0432 \u043F\u0440\u043E\u043C\u043F\u0442\u0435 \u0438\u043B\u0438 \u0432 read_task. evidence \u2014 \u0414\u041E\u041A\u0410\u0417\u0410\u0422\u0415\u041B\u042C\u0421\u0422\u0412\u041E: \u0441\u0442\u0440\u043E\u043A\u0430 \u0432\u044B\u0432\u043E\u0434\u0430 \u043A\u043E\u043C\u0430\u043D\u0434\u044B, \u0441\u0441\u044B\u043B\u043A\u0430 \u043D\u0430 PR/\u0441\u043A\u0440\u0438\u043D, \u0447\u0442\u043E \u0438\u043C\u0435\u043D\u043D\u043E \u043D\u0430\u0431\u043B\u044E\u0434\u0430\u043B. \u0421\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435 \u0441\u0442\u0430\u0432\u044C \u043F\u043E \u0424\u0410\u041A\u0422\u0423 \u043F\u0440\u043E\u0433\u043E\u043D\u0430, \u0430 \u043D\u0435 \u043F\u043E \u043E\u0436\u0438\u0434\u0430\u043D\u0438\u044E: \xAB\u0443\u043F\u0430\u043B\u0430\xBB \u0438 \xAB\u043D\u0435 \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u043B\u0430\u0441\u044C\xBB \u2014 \u0440\u0430\u0437\u043D\u043E\u0435. \u041F\u0440\u043E\u0439\u0434\u0438\u0441\u044C \u043F\u043E \u0432\u0441\u0435\u043C \u043F\u0443\u043D\u043A\u0442\u0430\u043C \u041F\u0415\u0420\u0415\u0414 done(): \u043D\u0435\u043F\u0440\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u043D\u044B\u0435 \u0433\u0430\u043B\u043E\u0447\u043A\u0438 \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u0442 \u0440\u0443\u043A\u0430\u043C\u0438 \u043F\u043E \u0442\u0432\u043E\u0435\u043C\u0443 \u043E\u0442\u0447\u0451\u0442\u0443 \u2014 \u0440\u043E\u0432\u043D\u043E \u0442\u0430 \u0440\u0430\u0431\u043E\u0442\u0430, \u043A\u043E\u0442\u043E\u0440\u0443\u044E \u043A\u0440\u0438\u0442\u0435\u0440\u0438\u0438 \u0441\u043D\u0438\u043C\u0430\u044E\u0442. \u0421\u0442\u0430\u0432\u0438\u0442\u044C \u0441\u0430\u043C\u0438 \u043A\u0440\u0438\u0442\u0435\u0440\u0438\u0438 \u043D\u0435\u0447\u0435\u043C: \u0438\u0445 \u0437\u0430\u0434\u0430\u0451\u0442 \u043F\u043E\u0441\u0442\u0430\u043D\u043E\u0432\u0449\u0438\u043A.",
|
|
9542
|
+
{
|
|
9543
|
+
id: z.string().describe("id \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u0438\u0437 \u0431\u043B\u043E\u043A\u0430 \xAB\u041A\u0440\u0438\u0442\u0435\u0440\u0438\u0438 \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438\xBB"),
|
|
9544
|
+
state: z.enum(["passed", "failed", "pending"]).describe("passed | failed | pending \u2014 \u043F\u043E \u0444\u0430\u043A\u0442\u0443 \u043F\u0440\u043E\u0433\u043E\u043D\u0430"),
|
|
9545
|
+
evidence: z.string().max(4e3).optional().describe("\u0447\u0435\u043C \u0434\u043E\u043A\u0430\u0437\u0430\u043D\u043E: \u0432\u044B\u0432\u043E\u0434 \u043A\u043E\u043C\u0430\u043D\u0434\u044B, \u0441\u0441\u044B\u043B\u043A\u0430 \u043D\u0430 PR/\u0441\u043A\u0440\u0438\u043D, \u043D\u0430\u0431\u043B\u044E\u0434\u0430\u0435\u043C\u043E\u0435 \u043F\u043E\u0432\u0435\u0434\u0435\u043D\u0438\u0435")
|
|
9546
|
+
},
|
|
9547
|
+
async ({ id, state, evidence }) => {
|
|
9548
|
+
if (!opts.taskless) {
|
|
9549
|
+
return {
|
|
9550
|
+
content: [
|
|
9551
|
+
{
|
|
9552
|
+
type: "text",
|
|
9553
|
+
text: "Taskless \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D (slug-only \u0440\u0435\u0436\u0438\u043C) \u2014 \u0433\u0430\u043B\u043E\u0447\u043A\u0443 \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u043D\u0435\u0447\u0435\u043C. \u041E\u0442\u0447\u0438\u0442\u0430\u0439\u0441\u044F \u043F\u043E \u043A\u0440\u0438\u0442\u0435\u0440\u0438\u044E \u0442\u0435\u043A\u0441\u0442\u043E\u043C \u0432 summary \u043F\u0440\u0438 done()."
|
|
9554
|
+
}
|
|
9555
|
+
],
|
|
9556
|
+
isError: true
|
|
9557
|
+
};
|
|
9558
|
+
}
|
|
9559
|
+
const text = await opts.taskless.reportAcceptanceCheck({ id, state, evidence });
|
|
9560
|
+
if (!text) {
|
|
9561
|
+
return {
|
|
9562
|
+
content: [
|
|
9563
|
+
{
|
|
9564
|
+
type: "text",
|
|
9565
|
+
text: `\u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 ${id} \u043D\u0435 \u043E\u0442\u043C\u0435\u0447\u0435\u043D\u0430 (\u0441\u043C. \u043B\u043E\u0433 \u0434\u0435\u043C\u043E\u043D\u0430): id \u043C\u043E\u0433 \u0431\u044B\u0442\u044C \u0447\u0443\u0436\u0438\u043C \u0438\u043B\u0438 \u0443\u0441\u0442\u0430\u0440\u0435\u0442\u044C \u2014 \u043F\u0435\u0440\u0435\u0447\u0438\u0442\u0430\u0439 \u043A\u0440\u0438\u0442\u0435\u0440\u0438\u0438 \u0447\u0435\u0440\u0435\u0437 read_task. \u041D\u0435 \u043C\u043E\u043B\u0447\u0438 \u043E\u0431 \u044D\u0442\u043E\u043C \u0432 summary \u043F\u0440\u0438 done().`
|
|
9566
|
+
}
|
|
9567
|
+
],
|
|
9568
|
+
isError: true
|
|
9569
|
+
};
|
|
9570
|
+
}
|
|
9571
|
+
return { content: [{ type: "text", text }] };
|
|
9572
|
+
}
|
|
9573
|
+
);
|
|
9498
9574
|
server.tool(
|
|
9499
9575
|
"ask",
|
|
9500
9576
|
"\u0417\u0430\u0434\u0430\u0442\u044C \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440\u0443 \u0431\u043B\u043E\u043A\u0438\u0440\u0443\u044E\u0449\u0438\u0439 \u0432\u043E\u043F\u0440\u043E\u0441 \u0438 \u0434\u043E\u0436\u0434\u0430\u0442\u044C\u0441\u044F \u043E\u0442\u0432\u0435\u0442\u0430. \u0415\u0441\u043B\u0438 \u0440\u0430\u0437\u0432\u0438\u043B\u043A\u0430 \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u043D\u0430\u044F \u2014 \u0434\u0430\u0439 options (2\u20134 \u0432\u0430\u0440\u0438\u0430\u043D\u0442\u0430, \u0441\u0442\u0430\u043D\u0443\u0442 \u043A\u043D\u043E\u043F\u043A\u0430\u043C\u0438); \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440 \u0432\u044B\u0431\u0435\u0440\u0435\u0442 \u0432\u0430\u0440\u0438\u0430\u043D\u0442 \u0438\u043B\u0438 \u043D\u0430\u043F\u0438\u0448\u0435\u0442 \u0441\u0432\u043E\u0451. \u041E\u043F\u0443\u0441\u0442\u0438 options \u0434\u043B\u044F \u043E\u0442\u043A\u0440\u044B\u0442\u043E\u0433\u043E \u0432\u043E\u043F\u0440\u043E\u0441\u0430. \u0412\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043E\u0442\u0432\u0435\u0442 \u0441\u0442\u0440\u043E\u043A\u043E\u0439. \u0417\u043E\u0432\u0438, \u043A\u043E\u0433\u0434\u0430 \u0443\u043F\u0451\u0440\u0441\u044F \u0432 \u0440\u0435\u0448\u0435\u043D\u0438\u0435 \u2014 \u043D\u0435 \u0443\u0433\u0430\u0434\u044B\u0432\u0430\u0439.",
|
|
@@ -11037,7 +11113,7 @@ async function changedPaths(worktree, opts = {}) {
|
|
|
11037
11113
|
// package.json
|
|
11038
11114
|
var package_default = {
|
|
11039
11115
|
name: "@taskless-app/swarm",
|
|
11040
|
-
version: "0.6.
|
|
11116
|
+
version: "0.6.5",
|
|
11041
11117
|
type: "module",
|
|
11042
11118
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
11043
11119
|
keywords: [
|
|
@@ -11087,7 +11163,7 @@ var package_default = {
|
|
|
11087
11163
|
execa: "^10.0.0",
|
|
11088
11164
|
zod: "3.25.76"
|
|
11089
11165
|
},
|
|
11090
|
-
gitHead: "
|
|
11166
|
+
gitHead: "76ff5edd816a2b9dd7f10db62c8fde89eec7771f"
|
|
11091
11167
|
};
|
|
11092
11168
|
|
|
11093
11169
|
// src/version.ts
|
|
@@ -13954,7 +14030,7 @@ ${task.description}` : `\u0417\u0430\u0434\u0430\u0447\u0430 ${run.task_slug} (\
|
|
|
13954
14030
|
// вторую ветку мимо PR. Пишем ту, что реально записана на прогоне; пусто (первый спавн —
|
|
13955
14031
|
// ветку заводит spawnDrone из слага) — прежняя формулировка.
|
|
13956
14032
|
`\u0422\u044B \u2014 \u0434\u0440\u043E\u043D \u0440\u043E\u044F. \u0420\u0430\u0431\u043E\u0442\u0430\u0435\u0448\u044C \u0432 \u044D\u0442\u043E\u043C git-worktree, \u0432\u0435\u0442\u043A\u0430 \`${run.branch || run.task_slug}\`${run.branch && run.branch !== run.task_slug ? " (\u043E\u043D\u0430 \u041D\u0415 \u0440\u0430\u0432\u043D\u0430 \u0441\u043B\u0430\u0433\u0443 \u0437\u0430\u0434\u0430\u0447\u0438 \u2014 \u044D\u0442\u043E \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0435\u043D\u0438\u0435 \u0443\u0436\u0435 \u043E\u0442\u043A\u0440\u044B\u0442\u043E\u0433\u043E PR, \u043F\u0443\u0448 \u0442\u043E\u043B\u044C\u043A\u043E \u0432 \u043D\u0435\u0451)" : " \u0441\u043E\u0437\u0434\u0430\u043D\u0430 \u043F\u043E slug \u0437\u0430\u0434\u0430\u0447\u0438"}.`,
|
|
13957
|
-
"\u0418\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u044B overmind (MCP): report_step(text) \u2014 \u043B\u043E\u0433\u0438\u0440\u0443\u0439 \u0445\u043E\u0434 \u0440\u0430\u0431\u043E\u0442\u044B; read_task() \u2014 \u0441\u0432\u0435\u0436\u0438\u0439 \u0441\u043D\u0430\u043F\u0448\u043E\u0442 \u0437\u0430\u0434\u0430\u0447\u0438 (\u043E\u043F\u0438\u0441\u0430\u043D\u0438\u0435+\u043A\u0440\u0438\u0442\u0435\u0440\u0438\u0438 \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438+\u043A\u043E\u043C\u043C\u0435\u043D\u0442\u044B+\u0434\u043E\u043A\u0438+\u0438\u0441\u0445\u043E\u0434\u044B \u0441\u043E\u0441\u0435\u0434\u043D\u0438\u0445 \u0437\u0430\u0434\u0430\u0447 \u043F\u043E \u0437\u043E\u043D\u0435 \u043A\u043E\u0434\u0430) \u0431\u0435\u0437 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u043E\u0432, \u0435\u0441\u043B\u0438 \u0442\u0440\u0435\u0431\u043E\u0432\u0430\u043D\u0438\u044F \u043C\u043E\u0433\u043B\u0438 \u0434\u043E\u043F\u0438\u0441\u0430\u0442\u044C \u043F\u043E\u0441\u043B\u0435 \u0441\u0442\u0430\u0440\u0442\u0430; ask(question, options?) \u2014 \u0435\u0441\u043B\u0438 \u0443\u043F\u0451\u0440\u0441\u044F \u0432 \u0420\u0415\u0428\u0415\u041D\u0418\u0415, \u0441\u043F\u0440\u043E\u0441\u0438 \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440\u0430 (\u0434\u0430\u0439 2\u20134 \u0432\u0430\u0440\u0438\u0430\u043D\u0442\u0430 \u0432 options, \u0435\u0441\u043B\u0438 \u0440\u0430\u0437\u0432\u0438\u043B\u043A\u0430 \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u043D\u0430\u044F) \u0438 \u0434\u043E\u0436\u0434\u0438\u0441\u044C \u043E\u0442\u0432\u0435\u0442\u0430 (\u041D\u0415 \u0443\u0433\u0430\u0434\u044B\u0432\u0430\u0439); done(pr_url) \u2014 \u043A\u043E\u0433\u0434\u0430 \u043E\u0442\u043A\u0440\u043E\u0435\u0448\u044C PR; note(text) \u2014 \u0437\u0430\u043C\u0435\u0442\u043A\u0430 \xAB\u0437\u0430\u043C\u0435\u0447\u0435\u043D\u043E \u043F\u043E \u043F\u0443\u0442\u0438\xBB \u0411\u0415\u0417 \u0431\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u043A\u0438: \u043D\u0430\u0442\u043A\u043D\u0443\u043B\u0441\u044F \u043D\u0430 \u043F\u0440\u043E\u0431\u0435\u043B \u0432 \u0434\u0438\u0437\u0430\u0439\u043D-\u0441\u0438\u0441\u0442\u0435\u043C\u0435, \u043F\u0440\u043E\u0442\u0443\u0445\u0448\u0443\u044E \u0438\u043D\u0441\u0442\u0440\u0443\u043A\u0446\u0438\u044E, \u0431\u0430\u0433 \u0440\u044F\u0434\u043E\u043C \u0441\u043E \u0441\u0432\u043E\u0438\u043C \u0434\u0438\u0444\u0444\u043E\u043C \u2014 \u0441\u043A\u0430\u0436\u0438 \u0438 \u0440\u0430\u0431\u043E\u0442\u0430\u0439 \u0434\u0430\u043B\u044C\u0448\u0435, \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440 \u0443\u0432\u0438\u0434\u0438\u0442 \u0438 \u0441\u0430\u043C \u0440\u0435\u0448\u0438\u0442, \u0437\u0430\u0432\u043E\u0434\u0438\u0442\u044C \u043B\u0438 \u0437\u0430\u0434\u0430\u0447\u0443 (\u043D\u0435 \u043F\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0439 \u0442\u0430\u043A\u043E\u0435 \u0432 \u0434\u043E\u0440\u043E\u0433\u043E\u0439 \u0431\u043B\u043E\u043A\u0438\u0440\u0443\u044E\u0449\u0438\u0439 ask \u0438 \u043D\u0435 \u0445\u043E\u0440\u043E\u043D\u0438 \u0432 \u043E\u0442\u0447\u0451\u0442\u0435 \u043E \u0441\u0434\u0430\u0447\u0435).",
|
|
14033
|
+
"\u0418\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u044B overmind (MCP): report_step(text) \u2014 \u043B\u043E\u0433\u0438\u0440\u0443\u0439 \u0445\u043E\u0434 \u0440\u0430\u0431\u043E\u0442\u044B; read_task() \u2014 \u0441\u0432\u0435\u0436\u0438\u0439 \u0441\u043D\u0430\u043F\u0448\u043E\u0442 \u0437\u0430\u0434\u0430\u0447\u0438 (\u043E\u043F\u0438\u0441\u0430\u043D\u0438\u0435+\u043A\u0440\u0438\u0442\u0435\u0440\u0438\u0438 \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438+\u043A\u043E\u043C\u043C\u0435\u043D\u0442\u044B+\u0434\u043E\u043A\u0438+\u0438\u0441\u0445\u043E\u0434\u044B \u0441\u043E\u0441\u0435\u0434\u043D\u0438\u0445 \u0437\u0430\u0434\u0430\u0447 \u043F\u043E \u0437\u043E\u043D\u0435 \u043A\u043E\u0434\u0430) \u0431\u0435\u0437 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u043E\u0432, \u0435\u0441\u043B\u0438 \u0442\u0440\u0435\u0431\u043E\u0432\u0430\u043D\u0438\u044F \u043C\u043E\u0433\u043B\u0438 \u0434\u043E\u043F\u0438\u0441\u0430\u0442\u044C \u043F\u043E\u0441\u043B\u0435 \u0441\u0442\u0430\u0440\u0442\u0430; ask(question, options?) \u2014 \u0435\u0441\u043B\u0438 \u0443\u043F\u0451\u0440\u0441\u044F \u0432 \u0420\u0415\u0428\u0415\u041D\u0418\u0415, \u0441\u043F\u0440\u043E\u0441\u0438 \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440\u0430 (\u0434\u0430\u0439 2\u20134 \u0432\u0430\u0440\u0438\u0430\u043D\u0442\u0430 \u0432 options, \u0435\u0441\u043B\u0438 \u0440\u0430\u0437\u0432\u0438\u043B\u043A\u0430 \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u043D\u0430\u044F) \u0438 \u0434\u043E\u0436\u0434\u0438\u0441\u044C \u043E\u0442\u0432\u0435\u0442\u0430 (\u041D\u0415 \u0443\u0433\u0430\u0434\u044B\u0432\u0430\u0439); report_acceptance_check(id, state, evidence) \u2014 \u0437\u0430\u043A\u0440\u043E\u0439 \u041A\u0410\u0416\u0414\u042B\u0419 \u043F\u0443\u043D\u043A\u0442 \u043A\u0440\u0438\u0442\u0435\u0440\u0438\u0435\u0432 \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438 \u0437\u0430\u0434\u0430\u0447\u0438 (id \u0431\u0435\u0440\u0451\u0442\u0441\u044F \u0438\u0437 \u0431\u043B\u043E\u043A\u0430 \xAB\u041A\u0440\u0438\u0442\u0435\u0440\u0438\u0438 \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438\xBB, state = passed|failed|pending \u043F\u043E \u0444\u0430\u043A\u0442\u0443 \u043F\u0440\u043E\u0433\u043E\u043D\u0430, evidence \u2014 \u0432\u044B\u0432\u043E\u0434 \u043A\u043E\u043C\u0430\u043D\u0434\u044B/\u0441\u0441\u044B\u043B\u043A\u0430/\u0447\u0442\u043E \u043D\u0430\u0431\u043B\u044E\u0434\u0430\u043B); \u043F\u0440\u043E\u0439\u0434\u0438\u0441\u044C \u043F\u043E \u043D\u0438\u043C \u041F\u0415\u0420\u0415\u0414 done(), \u0438\u043D\u0430\u0447\u0435 \u0433\u0430\u043B\u043E\u0447\u043A\u0438 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u0442 \u0440\u0443\u043A\u0430\u043C\u0438 \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440; done(pr_url) \u2014 \u043A\u043E\u0433\u0434\u0430 \u043E\u0442\u043A\u0440\u043E\u0435\u0448\u044C PR; note(text) \u2014 \u0437\u0430\u043C\u0435\u0442\u043A\u0430 \xAB\u0437\u0430\u043C\u0435\u0447\u0435\u043D\u043E \u043F\u043E \u043F\u0443\u0442\u0438\xBB \u0411\u0415\u0417 \u0431\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u043A\u0438: \u043D\u0430\u0442\u043A\u043D\u0443\u043B\u0441\u044F \u043D\u0430 \u043F\u0440\u043E\u0431\u0435\u043B \u0432 \u0434\u0438\u0437\u0430\u0439\u043D-\u0441\u0438\u0441\u0442\u0435\u043C\u0435, \u043F\u0440\u043E\u0442\u0443\u0445\u0448\u0443\u044E \u0438\u043D\u0441\u0442\u0440\u0443\u043A\u0446\u0438\u044E, \u0431\u0430\u0433 \u0440\u044F\u0434\u043E\u043C \u0441\u043E \u0441\u0432\u043E\u0438\u043C \u0434\u0438\u0444\u0444\u043E\u043C \u2014 \u0441\u043A\u0430\u0436\u0438 \u0438 \u0440\u0430\u0431\u043E\u0442\u0430\u0439 \u0434\u0430\u043B\u044C\u0448\u0435, \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440 \u0443\u0432\u0438\u0434\u0438\u0442 \u0438 \u0441\u0430\u043C \u0440\u0435\u0448\u0438\u0442, \u0437\u0430\u0432\u043E\u0434\u0438\u0442\u044C \u043B\u0438 \u0437\u0430\u0434\u0430\u0447\u0443 (\u043D\u0435 \u043F\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0439 \u0442\u0430\u043A\u043E\u0435 \u0432 \u0434\u043E\u0440\u043E\u0433\u043E\u0439 \u0431\u043B\u043E\u043A\u0438\u0440\u0443\u044E\u0449\u0438\u0439 ask \u0438 \u043D\u0435 \u0445\u043E\u0440\u043E\u043D\u0438 \u0432 \u043E\u0442\u0447\u0451\u0442\u0435 \u043E \u0441\u0434\u0430\u0447\u0435).",
|
|
13958
14034
|
"\u041F\u0440\u0430\u0432\u0438\u043B\u0430: \u0442\u0440\u043E\u0433\u0430\u0435\u0448\u044C UI \u2014 \u0421\u041D\u0410\u0427\u0410\u041B\u0410 \u043F\u043E\u0441\u043C\u043E\u0442\u0440\u0438, \u0435\u0441\u0442\u044C \u043B\u0438 \u0432 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0438 \u0441\u043A\u0438\u043B\u043B \u0441 UI-\u043F\u0440\u0430\u0432\u0438\u043B\u0430\u043C\u0438 \u043F\u0440\u043E\u0435\u043A\u0442\u0430, \u0438 \u0441\u043B\u0435\u0434\u0443\u0439 \u0435\u0433\u043E \u0434\u0438\u0437\u0430\u0439\u043D-\u0441\u0438\u0441\u0442\u0435\u043C\u0435 (\u043D\u0435\u0442 \u043D\u0443\u0436\u043D\u043E\u0433\u043E \u043A\u043E\u043D\u0442\u0440\u043E\u043B\u0430 \u2014 \u0437\u0430\u0432\u0435\u0434\u0438 \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u0443\u044E \u0437\u0430\u0434\u0430\u0447\u0443, \u043D\u0435 \u0445\u0430\u0440\u0434\u043A\u043E\u0434\u044C \u043E\u0434\u043D\u043E\u0440\u0430\u0437\u043E\u0432\u043E\u0435); \u043A\u043E\u043C\u043C\u0438\u0442\u044B \u0441\u043E slug \u0437\u0430\u0434\u0430\u0447\u0438 \u0432 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0438; \u043F\u043E\u0441\u043B\u0435 UI-\u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0439 \u043F\u0440\u0438\u043B\u043E\u0436\u0438 \u0441\u043A\u0440\u0438\u043D\u044B mobile+desktop \u041A \u0417\u0410\u0414\u0410\u0427\u0415 (\u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 screenshots \u0443 done); \u043E\u0442\u043A\u0440\u043E\u0439 PR \u0447\u0435\u0440\u0435\u0437 gh \u0438 \u0432\u044B\u0437\u043E\u0432\u0438 done(pr_url).",
|
|
13959
14035
|
// TASWM-293: живой случай SCE-5 — ревьюер заблокировал PR за отсутствие CI (у проекта
|
|
13960
14036
|
// его нет и не предполагается), автора разбудили «закрывать замечания», замечаний по коду
|
|
@@ -16117,6 +16193,7 @@ async function runDaemon(opts) {
|
|
|
16117
16193
|
}
|
|
16118
16194
|
} : void 0;
|
|
16119
16195
|
let lastDroneCap = null;
|
|
16196
|
+
let lastSwarmModels = null;
|
|
16120
16197
|
let lastOwnCapacity = null;
|
|
16121
16198
|
const hostCommandState = hostCommandStatePath(SWARM_HOME);
|
|
16122
16199
|
let hostMaxDrones = loadMaxDronesOverride(hostCommandState);
|
|
@@ -16129,7 +16206,8 @@ async function runDaemon(opts) {
|
|
|
16129
16206
|
executor: EXECUTOR,
|
|
16130
16207
|
droneIsolation: DRONE_ISOLATION,
|
|
16131
16208
|
channel: droneChannelLaunch,
|
|
16132
|
-
droneCap: () => lastDroneCap
|
|
16209
|
+
droneCap: () => lastDroneCap,
|
|
16210
|
+
swarmModels: () => lastSwarmModels
|
|
16133
16211
|
});
|
|
16134
16212
|
let prepareReader;
|
|
16135
16213
|
const zoneModels = new ZoneModels({ manualAreas: () => new Map(db.listRuns().map((r) => [r.task_slug, r.area])) });
|
|
@@ -16265,12 +16343,20 @@ async function runDaemon(opts) {
|
|
|
16265
16343
|
if (SWARM_BACKEND === "client" && db instanceof SwarmClient) {
|
|
16266
16344
|
const client = db;
|
|
16267
16345
|
const readMaxDrones = makeMaxDronesReader({
|
|
16268
|
-
|
|
16346
|
+
// TASWM-364: одним чтением берём и кап, и модели роя — это соседние поля ОДНОГО
|
|
16347
|
+
// ответа who_am_i. Модели складываем в снимок для спавна тем же побочным ходом,
|
|
16348
|
+
// что и кап ниже: второго сетевого канала за ними заводить незачем.
|
|
16349
|
+
fetch: async () => {
|
|
16350
|
+
const settings = await client.ownerSwarmSettings();
|
|
16351
|
+
if (settings) lastSwarmModels = settings.models;
|
|
16352
|
+
return settings?.maxDrones ?? null;
|
|
16353
|
+
},
|
|
16269
16354
|
fallback: SWARM_MAX_IN_FLIGHT > 0 ? SWARM_MAX_IN_FLIGHT : 3,
|
|
16270
16355
|
ttlMs: 1e4
|
|
16271
16356
|
});
|
|
16272
16357
|
maxDrones = async () => {
|
|
16273
|
-
const
|
|
16358
|
+
const live = await readMaxDrones();
|
|
16359
|
+
const own = lastOwnCapacity = hostMaxDrones ?? live;
|
|
16274
16360
|
return lastDroneCap = operatorMaxDrones != null ? Math.min(own, operatorMaxDrones) : own;
|
|
16275
16361
|
};
|
|
16276
16362
|
}
|
|
@@ -16467,7 +16553,9 @@ async function runDaemon(opts) {
|
|
|
16467
16553
|
repoHasCi: (run) => repoHasCiWorkflows(run.worktree_path, run.repo || opts.repo),
|
|
16468
16554
|
isAlive: pidAlive,
|
|
16469
16555
|
// Учёт cost/usage (TASWM-188): реальный аккаунтант поверх RUN_LOGS_DIR + db.
|
|
16470
|
-
|
|
16556
|
+
// TASWM-364: swarmModels — ТОТ ЖЕ снимок, что уехал в launcher: цена токенов считается
|
|
16557
|
+
// по модели, на которой прогон реально работал.
|
|
16558
|
+
accountCost: makeCostAccountant({ runLogsDir: RUN_LOGS_DIR, db, executor: EXECUTOR, swarmModels: () => lastSwarmModels }),
|
|
16471
16559
|
// Классификация выхода прогона (TASWM-229): result-файл того же RUN_LOGS_DIR — «вышел сам»
|
|
16472
16560
|
// (graceful) vs «убит на полпути» (crash). Тот же каталог, что читает accountCost.
|
|
16473
16561
|
exitOutcome: makeExitClassifier(RUN_LOGS_DIR, EXECUTOR),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taskless-app/swarm",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.5",
|
|
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": [
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"execa": "^10.0.0",
|
|
39
39
|
"zod": "3.25.76"
|
|
40
40
|
},
|
|
41
|
-
"gitHead": "
|
|
41
|
+
"gitHead": "76ff5edd816a2b9dd7f10db62c8fde89eec7771f",
|
|
42
42
|
"scripts": {
|
|
43
43
|
"overmind": "NODE_OPTIONS=\"${NODE_OPTIONS:-} --conditions=development\" tsx src/overmind.ts",
|
|
44
44
|
"swarm": "NODE_OPTIONS=\"${NODE_OPTIONS:-} --conditions=development\" tsx src/cli.ts",
|