@taskless-app/swarm 0.6.33 → 0.6.34
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 +43 -11
- package/dist/overmind.js +307 -15
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -1202,6 +1202,37 @@ var init_runGuards = __esm({
|
|
|
1202
1202
|
}
|
|
1203
1203
|
});
|
|
1204
1204
|
|
|
1205
|
+
// ../swarm-core/src/taskWeight.ts
|
|
1206
|
+
function isHeavyGrantEvent(e) {
|
|
1207
|
+
return has(e, HEAVY_GRANT_MARK);
|
|
1208
|
+
}
|
|
1209
|
+
function grantedCeilingUsd(events) {
|
|
1210
|
+
let max = null;
|
|
1211
|
+
for (const e of events) {
|
|
1212
|
+
if (!isHeavyGrantEvent(e)) continue;
|
|
1213
|
+
const m = /потолок \$([0-9]+(?:\.[0-9]+)?)/.exec(e.text ?? "");
|
|
1214
|
+
if (!m) continue;
|
|
1215
|
+
const v = Number(m[1]);
|
|
1216
|
+
if (Number.isFinite(v) && (max == null || v > max)) max = v;
|
|
1217
|
+
}
|
|
1218
|
+
return max;
|
|
1219
|
+
}
|
|
1220
|
+
function effectiveCostCeilingUsd(baseUsd, events) {
|
|
1221
|
+
if (!(baseUsd > 0)) return baseUsd;
|
|
1222
|
+
const granted = grantedCeilingUsd(events);
|
|
1223
|
+
if (granted == null) return baseUsd;
|
|
1224
|
+
return Math.min(Math.max(baseUsd, granted), baseUsd * HEAVY_CEILING_MAX_FACTOR);
|
|
1225
|
+
}
|
|
1226
|
+
var HEAVY_CEILING_MAX_FACTOR, HEAVY_GRANT_MARK, has;
|
|
1227
|
+
var init_taskWeight = __esm({
|
|
1228
|
+
"../swarm-core/src/taskWeight.ts"() {
|
|
1229
|
+
"use strict";
|
|
1230
|
+
HEAVY_CEILING_MAX_FACTOR = 2;
|
|
1231
|
+
HEAVY_GRANT_MARK = "\u0432\u0435\u0441 \u043F\u0440\u043E\u0433\u043E\u043D\u0430: \u0442\u044F\u0436\u0451\u043B\u0430\u044F";
|
|
1232
|
+
has = (e, mark) => !!e.text?.includes(mark);
|
|
1233
|
+
}
|
|
1234
|
+
});
|
|
1235
|
+
|
|
1205
1236
|
// ../swarm-core/src/codeZones.ts
|
|
1206
1237
|
function hasZoneModel(m) {
|
|
1207
1238
|
return m.tasks > 0 && m.zones.length > 0;
|
|
@@ -1661,6 +1692,7 @@ var init_src = __esm({
|
|
|
1661
1692
|
init_cost();
|
|
1662
1693
|
init_modelPricing();
|
|
1663
1694
|
init_runGuards();
|
|
1695
|
+
init_taskWeight();
|
|
1664
1696
|
init_codeZones();
|
|
1665
1697
|
init_effort();
|
|
1666
1698
|
init_queuePlan();
|
|
@@ -3242,7 +3274,7 @@ var init_package = __esm({
|
|
|
3242
3274
|
"package.json"() {
|
|
3243
3275
|
package_default = {
|
|
3244
3276
|
name: "@taskless-app/swarm",
|
|
3245
|
-
version: "0.6.
|
|
3277
|
+
version: "0.6.34",
|
|
3246
3278
|
type: "module",
|
|
3247
3279
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
3248
3280
|
keywords: [
|
|
@@ -3293,7 +3325,7 @@ var init_package = __esm({
|
|
|
3293
3325
|
execa: "^10.0.0",
|
|
3294
3326
|
zod: "3.25.76"
|
|
3295
3327
|
},
|
|
3296
|
-
gitHead: "
|
|
3328
|
+
gitHead: "4eabd911d4dfd557bfbfcbc27afd36415714b7eb"
|
|
3297
3329
|
};
|
|
3298
3330
|
}
|
|
3299
3331
|
});
|
|
@@ -6077,10 +6109,10 @@ function detectPlatformKind(io = {}) {
|
|
|
6077
6109
|
function detectSystemPm(kind, io = {}) {
|
|
6078
6110
|
const env = io.env ?? process.env;
|
|
6079
6111
|
const platform = io.platform ?? process.platform;
|
|
6080
|
-
const
|
|
6081
|
-
if (kind === "macos") return
|
|
6082
|
-
if (kind === "windows") return
|
|
6083
|
-
return LINUX_PMS.find((p) =>
|
|
6112
|
+
const has2 = io.hasCommand ?? ((n) => hasCommandInPath(n, env, platform));
|
|
6113
|
+
if (kind === "macos") return has2("brew") ? "brew" : null;
|
|
6114
|
+
if (kind === "windows") return has2("winget") ? "winget" : null;
|
|
6115
|
+
return LINUX_PMS.find((p) => has2(p.cmd))?.pm ?? null;
|
|
6084
6116
|
}
|
|
6085
6117
|
function detectPlatform(io = {}) {
|
|
6086
6118
|
const kind = detectPlatformKind(io);
|
|
@@ -6120,8 +6152,8 @@ function detectGlobalPm(entry, io = {}) {
|
|
|
6120
6152
|
if (/\/node_modules\//.test(p)) return "npm";
|
|
6121
6153
|
const env = io.env ?? process.env;
|
|
6122
6154
|
const platform = io.platform ?? process.platform;
|
|
6123
|
-
const
|
|
6124
|
-
return
|
|
6155
|
+
const has2 = io.hasCommand ?? ((n) => hasCommandInPath(n, env, platform));
|
|
6156
|
+
return has2("npm") ? "npm" : "unknown";
|
|
6125
6157
|
}
|
|
6126
6158
|
function globalInstallCommand(pm, spec) {
|
|
6127
6159
|
switch (pm) {
|
|
@@ -11939,8 +11971,8 @@ function resolveTsxCli() {
|
|
|
11939
11971
|
}
|
|
11940
11972
|
}
|
|
11941
11973
|
var MCP_SERVER_NAME = "overmind";
|
|
11942
|
-
function launchBudgetUsd(limit, spentUsd, env = process.env) {
|
|
11943
|
-
return remainingRunBudgetUsd(limit ?? envCapUsd(env), spentUsd);
|
|
11974
|
+
function launchBudgetUsd(limit, spentUsd, env = process.env, weightEvents = []) {
|
|
11975
|
+
return remainingRunBudgetUsd(effectiveCostCeilingUsd(limit ?? envCapUsd(env), weightEvents), spentUsd);
|
|
11944
11976
|
}
|
|
11945
11977
|
function envCapUsd(env) {
|
|
11946
11978
|
const raw = env.SWARM_MAX_COST_USD;
|
|
@@ -12106,7 +12138,7 @@ function makeLauncher(cfg) {
|
|
|
12106
12138
|
// момент её совершения. Прод-сторож остаётся страховкой, но он по устройству видит
|
|
12107
12139
|
// стоимость только по записанному итогу: живой прогон стоит для него ноль, сколько бы
|
|
12108
12140
|
// ни жёг, — отсюда и $74 при лимите $20.
|
|
12109
|
-
maxBudgetUsd: launchBudgetUsd(cfg.maxCostUsd?.() ?? null, run.cost_usd),
|
|
12141
|
+
maxBudgetUsd: launchBudgetUsd(cfg.maxCostUsd?.() ?? null, run.cost_usd, process.env, cfg.weightEvents?.(run) ?? []),
|
|
12110
12142
|
// TASWM-395: усилие рассуждения — харнессу флагом (claude `--effort`). null = флага нет.
|
|
12111
12143
|
effort
|
|
12112
12144
|
});
|
package/dist/overmind.js
CHANGED
|
@@ -1310,6 +1310,152 @@ var init_runGuards = __esm({
|
|
|
1310
1310
|
}
|
|
1311
1311
|
});
|
|
1312
1312
|
|
|
1313
|
+
// ../swarm-core/src/taskWeight.ts
|
|
1314
|
+
function median(values) {
|
|
1315
|
+
const xs = [...values].sort((a, b) => a - b);
|
|
1316
|
+
const mid = Math.floor(xs.length / 2);
|
|
1317
|
+
return xs.length % 2 ? xs[mid] : (xs[mid - 1] + xs[mid]) / 2;
|
|
1318
|
+
}
|
|
1319
|
+
function classify(expectedUsd, t) {
|
|
1320
|
+
if (expectedUsd >= t.medianUsd * t.heavyFactor) return "heavy";
|
|
1321
|
+
if (expectedUsd <= t.medianUsd * t.lightFactor) return "light";
|
|
1322
|
+
return "normal";
|
|
1323
|
+
}
|
|
1324
|
+
function estimateTaskWeight(samples, opts) {
|
|
1325
|
+
const t = opts?.thresholds ?? DEFAULT_WEIGHT_THRESHOLDS;
|
|
1326
|
+
const usable = samples.filter((s) => s.productive && Number.isFinite(s.costUsd) && s.costUsd > 0);
|
|
1327
|
+
const own = usable.filter((s) => s.ownTask);
|
|
1328
|
+
const pool = own.length ? own : usable;
|
|
1329
|
+
if (pool.length) {
|
|
1330
|
+
const expectedUsd = median(pool.map((s) => s.costUsd));
|
|
1331
|
+
return { weight: classify(expectedUsd, t), expectedUsd, basis: own.length ? "own" : "similar", samples: pool.length };
|
|
1332
|
+
}
|
|
1333
|
+
if (opts?.hint) {
|
|
1334
|
+
const expectedUsd = opts.hint === "heavy" ? t.medianUsd * t.heavyFactor : opts.hint === "light" ? t.medianUsd * t.lightFactor : t.medianUsd;
|
|
1335
|
+
return { weight: opts.hint, expectedUsd, basis: "hint", samples: 0 };
|
|
1336
|
+
}
|
|
1337
|
+
return { weight: "normal", expectedUsd: t.medianUsd, basis: "default", samples: 0 };
|
|
1338
|
+
}
|
|
1339
|
+
function isRunProgressing(p) {
|
|
1340
|
+
return p.commits > 0 || p.hasPr || p.acceptanceChecks > 0;
|
|
1341
|
+
}
|
|
1342
|
+
function raisedCeilingUsd(baseUsd, grantedUsd) {
|
|
1343
|
+
if (!(baseUsd > 0)) return 0;
|
|
1344
|
+
const from = grantedUsd != null && Number.isFinite(grantedUsd) && grantedUsd > baseUsd ? grantedUsd : baseUsd;
|
|
1345
|
+
const next = from + baseUsd * HEAVY_CEILING_STEP;
|
|
1346
|
+
return Math.round(Math.min(next, baseUsd * HEAVY_CEILING_MAX_FACTOR) * 100) / 100;
|
|
1347
|
+
}
|
|
1348
|
+
function decideHeavyClaim(input) {
|
|
1349
|
+
const spent = Number.isFinite(input.spentUsd) && input.spentUsd > 0 ? input.spentUsd : 0;
|
|
1350
|
+
const bar = input.estimate.expectedUsd * HEAVY_CLAIM_MIN_SPENT_RATIO;
|
|
1351
|
+
if (spent < bar) {
|
|
1352
|
+
return {
|
|
1353
|
+
verdict: "too_early",
|
|
1354
|
+
ceilingUsd: null,
|
|
1355
|
+
reason: `\u043F\u043E\u0442\u0440\u0430\u0447\u0435\u043D\u043E $${spent.toFixed(2)} \u043F\u0440\u0438 \u043E\u0436\u0438\u0434\u0430\u0435\u043C\u044B\u0445 $${input.estimate.expectedUsd.toFixed(2)} \u2014 \u0434\u043E \u043F\u043E\u043B\u043E\u0432\u0438\u043D\u044B \u043E\u0436\u0438\u0434\u0430\u0435\u043C\u043E\u0433\u043E \u0435\u0449\u0451 \u0434\u0430\u043B\u0435\u043A\u043E, \u043E\u0431\u0441\u043B\u0443\u0436\u0438\u0432\u0430\u0442\u044C \u043F\u043E\u043A\u0430 \u043D\u0435\u0447\u0435\u0433\u043E`
|
|
1356
|
+
};
|
|
1357
|
+
}
|
|
1358
|
+
if (!isRunProgressing(input.progress)) {
|
|
1359
|
+
return {
|
|
1360
|
+
verdict: "stalled",
|
|
1361
|
+
ceilingUsd: null,
|
|
1362
|
+
reason: `\u0442\u0440\u0430\u0442\u0430 \u0440\u0430\u0441\u0442\u0451\u0442 ($${spent.toFixed(2)}), \u0430 \u043F\u0440\u043E\u0434\u0432\u0438\u0436\u0435\u043D\u0438\u044F \u043D\u0435\u0442: \u043D\u0438 \u043A\u043E\u043C\u043C\u0438\u0442\u043E\u0432 \u0432 \u0432\u0435\u0442\u043A\u0435, \u043D\u0438 PR, \u043D\u0438 \u043E\u0434\u043D\u043E\u0433\u043E \u043E\u0442\u043C\u0435\u0447\u0435\u043D\u043D\u043E\u0433\u043E \u043A\u0440\u0438\u0442\u0435\u0440\u0438\u044F. \u042D\u0442\u043E \u043D\u0435 \u0442\u044F\u0436\u0451\u043B\u0430\u044F \u0440\u0430\u0431\u043E\u0442\u0430, \u0430 \u043F\u0440\u043E\u0433\u043E\u043D, \u0441\u0442\u043E\u044F\u0449\u0438\u0439 \u043D\u0430 \u043C\u0435\u0441\u0442\u0435, \u2014 \u0432\u0435\u0441\u0430 \u043D\u0435 \u0434\u0430\u0451\u043C, \u0431\u044E\u0434\u0436\u0435\u0442 \u043D\u0435 \u043F\u043E\u0434\u043D\u0438\u043C\u0430\u0435\u043C`
|
|
1363
|
+
};
|
|
1364
|
+
}
|
|
1365
|
+
const granted = input.grantedUsd ?? null;
|
|
1366
|
+
const next = raisedCeilingUsd(input.baseCeilingUsd, granted);
|
|
1367
|
+
if (granted != null && next <= granted) {
|
|
1368
|
+
return {
|
|
1369
|
+
verdict: "capped",
|
|
1370
|
+
ceilingUsd: granted,
|
|
1371
|
+
reason: `\u0432\u0435\u0441 \u0443\u0436\u0435 \u043F\u0440\u0438\u0437\u043D\u0430\u043D, \u043F\u043E\u0442\u043E\u043B\u043E\u043A \u043F\u043E\u0434\u043D\u044F\u0442 \u0434\u043E $${granted.toFixed(2)} \u2014 \u044D\u0442\u043E \u043F\u0440\u0435\u0434\u0435\u043B \u0434\u043E\u0431\u0430\u0432\u043A\u0438 (${HEAVY_CEILING_MAX_FACTOR}\xD7 \u0431\u0430\u0437\u043E\u0432\u043E\u0433\u043E $${input.baseCeilingUsd.toFixed(2)})`
|
|
1372
|
+
};
|
|
1373
|
+
}
|
|
1374
|
+
return {
|
|
1375
|
+
verdict: "granted",
|
|
1376
|
+
ceilingUsd: next,
|
|
1377
|
+
reason: `\u0440\u0430\u0431\u043E\u0442\u0430 \u0442\u044F\u0436\u0451\u043B\u0430\u044F \u043F\u043E \u0438\u0437\u043C\u0435\u0440\u0435\u043D\u0438\u044E: \u043F\u043E\u0442\u0440\u0430\u0447\u0435\u043D\u043E $${spent.toFixed(2)} \u043F\u0440\u0438 \u043E\u0436\u0438\u0434\u0430\u0435\u043C\u044B\u0445 $${input.estimate.expectedUsd.toFixed(2)}, \u043F\u0440\u043E\u0433\u043E\u043D \u043F\u0440\u043E\u0434\u0432\u0438\u0433\u0430\u0435\u0442\u0441\u044F (${progressWords(input.progress)}) \u2014 \u043F\u043E\u0442\u043E\u043B\u043E\u043A \u043F\u043E\u0434\u043D\u044F\u0442 \u0434\u043E $${next.toFixed(2)}`
|
|
1378
|
+
};
|
|
1379
|
+
}
|
|
1380
|
+
function progressWords(p) {
|
|
1381
|
+
const parts = [];
|
|
1382
|
+
if (p.commits > 0) parts.push(`\u043A\u043E\u043C\u043C\u0438\u0442\u043E\u0432: ${p.commits}`);
|
|
1383
|
+
if (p.hasPr) parts.push("PR \u043E\u0442\u043A\u0440\u044B\u0442");
|
|
1384
|
+
if (p.acceptanceChecks > 0) parts.push(`\u043A\u0440\u0438\u0442\u0435\u0440\u0438\u0435\u0432 \u0437\u0430\u043A\u0440\u044B\u0442\u043E: ${p.acceptanceChecks}`);
|
|
1385
|
+
return parts.join(", ") || "\u0434\u0432\u0438\u0436\u0435\u043D\u0438\u0435 \u0435\u0441\u0442\u044C";
|
|
1386
|
+
}
|
|
1387
|
+
function heavyClaimText(note) {
|
|
1388
|
+
return `${HEAVY_CLAIM_MARK} \u2014 ${note}`;
|
|
1389
|
+
}
|
|
1390
|
+
function heavyGrantText(ceilingUsd, reason) {
|
|
1391
|
+
return `${HEAVY_GRANT_MARK} (\u043F\u043E\u0442\u043E\u043B\u043E\u043A $${ceilingUsd.toFixed(2)}) \u2014 ${reason}`;
|
|
1392
|
+
}
|
|
1393
|
+
function heavyRefusedText(reason) {
|
|
1394
|
+
return `${HEAVY_REFUSED_MARK} \u2014 ${reason}`;
|
|
1395
|
+
}
|
|
1396
|
+
function isHeavyClaimEvent(e) {
|
|
1397
|
+
return has(e, HEAVY_CLAIM_MARK);
|
|
1398
|
+
}
|
|
1399
|
+
function isHeavyGrantEvent(e) {
|
|
1400
|
+
return has(e, HEAVY_GRANT_MARK);
|
|
1401
|
+
}
|
|
1402
|
+
function isHeavyRefusedEvent(e) {
|
|
1403
|
+
return has(e, HEAVY_REFUSED_MARK);
|
|
1404
|
+
}
|
|
1405
|
+
function grantedCeilingUsd(events) {
|
|
1406
|
+
let max = null;
|
|
1407
|
+
for (const e of events) {
|
|
1408
|
+
if (!isHeavyGrantEvent(e)) continue;
|
|
1409
|
+
const m = /потолок \$([0-9]+(?:\.[0-9]+)?)/.exec(e.text ?? "");
|
|
1410
|
+
if (!m) continue;
|
|
1411
|
+
const v = Number(m[1]);
|
|
1412
|
+
if (Number.isFinite(v) && (max == null || v > max)) max = v;
|
|
1413
|
+
}
|
|
1414
|
+
return max;
|
|
1415
|
+
}
|
|
1416
|
+
function countAcceptanceChecks(events) {
|
|
1417
|
+
return events.filter((e) => has(e, ACCEPTANCE_CHECK_MARK)).length;
|
|
1418
|
+
}
|
|
1419
|
+
function isHeavyRun(events) {
|
|
1420
|
+
return events.some(isHeavyGrantEvent);
|
|
1421
|
+
}
|
|
1422
|
+
function hasOpenHeavyClaim(events) {
|
|
1423
|
+
let open = false;
|
|
1424
|
+
for (const e of events) {
|
|
1425
|
+
if (isHeavyClaimEvent(e)) open = true;
|
|
1426
|
+
else if (isHeavyGrantEvent(e) || isHeavyRefusedEvent(e)) open = false;
|
|
1427
|
+
}
|
|
1428
|
+
return open;
|
|
1429
|
+
}
|
|
1430
|
+
function effectiveCostCeilingUsd(baseUsd, events) {
|
|
1431
|
+
if (!(baseUsd > 0)) return baseUsd;
|
|
1432
|
+
const granted = grantedCeilingUsd(events);
|
|
1433
|
+
if (granted == null) return baseUsd;
|
|
1434
|
+
return Math.min(Math.max(baseUsd, granted), baseUsd * HEAVY_CEILING_MAX_FACTOR);
|
|
1435
|
+
}
|
|
1436
|
+
function intakeHoldReason(heavyLabel) {
|
|
1437
|
+
return `\u0442\u044F\u0436\u0451\u043B\u044B\u0439 \u043F\u0440\u043E\u0433\u043E\u043D \u0432 \u0440\u0430\u0431\u043E\u0442\u0435 (${heavyLabel}) \u2014 \u043D\u043E\u0432\u0443\u044E \u0440\u0430\u0431\u043E\u0442\u0443 \u043D\u0435 \u0431\u0435\u0440\u0451\u043C, \u043F\u043E\u043A\u0430 \u043E\u043D \u043D\u0435 \u0441\u0434\u0430\u0441\u0442: \u0435\u043C\u0443 \u043D\u0443\u0436\u043D\u043E \u043C\u0435\u0441\u0442\u043E, \u0430 \u043D\u0435 \u0441\u043E\u0441\u0435\u0434\u0438 (TASWM-535)`;
|
|
1438
|
+
}
|
|
1439
|
+
var DEFAULT_WEIGHT_THRESHOLDS, HEAVY_CLAIM_MIN_SPENT_RATIO, HEAVY_CEILING_STEP, HEAVY_CEILING_MAX_FACTOR, HEAVY_CLAIM_MARK, HEAVY_GRANT_MARK, HEAVY_REFUSED_MARK, ACCEPTANCE_CHECK_MARK, has;
|
|
1440
|
+
var init_taskWeight = __esm({
|
|
1441
|
+
"../swarm-core/src/taskWeight.ts"() {
|
|
1442
|
+
"use strict";
|
|
1443
|
+
DEFAULT_WEIGHT_THRESHOLDS = {
|
|
1444
|
+
medianUsd: 1.81,
|
|
1445
|
+
lightFactor: 0.5,
|
|
1446
|
+
heavyFactor: 3
|
|
1447
|
+
};
|
|
1448
|
+
HEAVY_CLAIM_MIN_SPENT_RATIO = 0.5;
|
|
1449
|
+
HEAVY_CEILING_STEP = 0.5;
|
|
1450
|
+
HEAVY_CEILING_MAX_FACTOR = 2;
|
|
1451
|
+
HEAVY_CLAIM_MARK = "\u0432\u0435\u0441 \u043F\u0440\u043E\u0433\u043E\u043D\u0430: \u0442\u044F\u0436\u0435\u043B\u0435\u0435 \u043E\u0436\u0438\u0434\u0430\u043D\u0438\u0439";
|
|
1452
|
+
HEAVY_GRANT_MARK = "\u0432\u0435\u0441 \u043F\u0440\u043E\u0433\u043E\u043D\u0430: \u0442\u044F\u0436\u0451\u043B\u0430\u044F";
|
|
1453
|
+
HEAVY_REFUSED_MARK = "\u0432\u0435\u0441 \u043F\u0440\u043E\u0433\u043E\u043D\u0430: \u043F\u0440\u043E\u0434\u0432\u0438\u0436\u0435\u043D\u0438\u044F \u043D\u0435\u0442";
|
|
1454
|
+
ACCEPTANCE_CHECK_MARK = "\u043A\u0440\u0438\u0442\u0435\u0440\u0438\u0439 \u043F\u0440\u0438\u0451\u043C\u043A\u0438";
|
|
1455
|
+
has = (e, mark) => !!e.text?.includes(mark);
|
|
1456
|
+
}
|
|
1457
|
+
});
|
|
1458
|
+
|
|
1313
1459
|
// ../swarm-core/src/codeZones.ts
|
|
1314
1460
|
function hasZoneModel(m) {
|
|
1315
1461
|
return m.tasks > 0 && m.zones.length > 0;
|
|
@@ -1806,6 +1952,7 @@ var init_src = __esm({
|
|
|
1806
1952
|
init_cost();
|
|
1807
1953
|
init_modelPricing();
|
|
1808
1954
|
init_runGuards();
|
|
1955
|
+
init_taskWeight();
|
|
1809
1956
|
init_codeZones();
|
|
1810
1957
|
init_effort();
|
|
1811
1958
|
init_queuePlan();
|
|
@@ -10005,6 +10152,7 @@ function loadHostIdentity(deps) {
|
|
|
10005
10152
|
}
|
|
10006
10153
|
|
|
10007
10154
|
// src/overmind.ts
|
|
10155
|
+
init_src();
|
|
10008
10156
|
init_resources();
|
|
10009
10157
|
|
|
10010
10158
|
// src/relief.ts
|
|
@@ -10038,9 +10186,15 @@ function pauseDue(reliefSince, lastPauseAt, now, cfg) {
|
|
|
10038
10186
|
if (reliefSince == null || now - reliefSince < cfg.sustainMs) return false;
|
|
10039
10187
|
return lastPauseAt == null || now - lastPauseAt >= cfg.pauseWindowMs;
|
|
10040
10188
|
}
|
|
10041
|
-
function pickPauseCandidate(runs) {
|
|
10189
|
+
function pickPauseCandidate(runs, protectedRunIds) {
|
|
10042
10190
|
const candidates = runs.filter(
|
|
10043
|
-
(r) => r.kind === "drone" && r.status === "running" && r.pid != null && r.resolves_run_id == null && r.reviews_run_id == null
|
|
10191
|
+
(r) => r.kind === "drone" && r.status === "running" && r.pid != null && r.resolves_run_id == null && r.reviews_run_id == null && // TASWM-535: прогон, признанный ТЯЖЁЛЫМ, разгрузка не снимает. Правильная реакция на
|
|
10192
|
+
// «тяжело» — уменьшить число соседей, а не убить того, кто работает: 27.08 перегруженная
|
|
10193
|
+
// машина снимала дрона разгрузкой, он начинал заново, и так задача сожгла $20.01
|
|
10194
|
+
// кругами (TASWM-531). Тяжёлого паузим только тогда, когда паузить больше некого, —
|
|
10195
|
+
// нет: не паузим вовсе. Освобождает машину придержанный интейк (соседи доигрывают и не
|
|
10196
|
+
// заменяются новыми), а не снятие того, кто ближе всех к сдаче.
|
|
10197
|
+
!protectedRunIds?.has(r.id)
|
|
10044
10198
|
);
|
|
10045
10199
|
if (!candidates.length) return null;
|
|
10046
10200
|
return candidates.reduce((youngest, r) => r.created_at > youngest.created_at ? r : youngest);
|
|
@@ -10161,7 +10315,7 @@ var ReliefLoopStore = class {
|
|
|
10161
10315
|
};
|
|
10162
10316
|
|
|
10163
10317
|
// src/reliefCost.ts
|
|
10164
|
-
function
|
|
10318
|
+
function median2(xs) {
|
|
10165
10319
|
const s = [...xs].sort((a, b) => a - b);
|
|
10166
10320
|
return s[Math.floor((s.length - 1) / 2)];
|
|
10167
10321
|
}
|
|
@@ -10217,7 +10371,7 @@ function computeReliefCost(state, now, windowMs) {
|
|
|
10217
10371
|
pauses: inWindow.length,
|
|
10218
10372
|
runs: byRun.size,
|
|
10219
10373
|
lostMs,
|
|
10220
|
-
stepsBetween: gaps.length ?
|
|
10374
|
+
stepsBetween: gaps.length ? median2(gaps) : null,
|
|
10221
10375
|
worst
|
|
10222
10376
|
};
|
|
10223
10377
|
}
|
|
@@ -10441,8 +10595,8 @@ function resolveTsxCli() {
|
|
|
10441
10595
|
}
|
|
10442
10596
|
}
|
|
10443
10597
|
var MCP_SERVER_NAME = "overmind";
|
|
10444
|
-
function launchBudgetUsd(limit, spentUsd, env = process.env) {
|
|
10445
|
-
return remainingRunBudgetUsd(limit ?? envCapUsd(env), spentUsd);
|
|
10598
|
+
function launchBudgetUsd(limit, spentUsd, env = process.env, weightEvents = []) {
|
|
10599
|
+
return remainingRunBudgetUsd(effectiveCostCeilingUsd(limit ?? envCapUsd(env), weightEvents), spentUsd);
|
|
10446
10600
|
}
|
|
10447
10601
|
function envCapUsd(env) {
|
|
10448
10602
|
const raw = env.SWARM_MAX_COST_USD;
|
|
@@ -10608,7 +10762,7 @@ function makeLauncher(cfg) {
|
|
|
10608
10762
|
// момент её совершения. Прод-сторож остаётся страховкой, но он по устройству видит
|
|
10609
10763
|
// стоимость только по записанному итогу: живой прогон стоит для него ноль, сколько бы
|
|
10610
10764
|
// ни жёг, — отсюда и $74 при лимите $20.
|
|
10611
|
-
maxBudgetUsd: launchBudgetUsd(cfg.maxCostUsd?.() ?? null, run.cost_usd),
|
|
10765
|
+
maxBudgetUsd: launchBudgetUsd(cfg.maxCostUsd?.() ?? null, run.cost_usd, process.env, cfg.weightEvents?.(run) ?? []),
|
|
10612
10766
|
// TASWM-395: усилие рассуждения — харнессу флагом (claude `--effort`). null = флага нет.
|
|
10613
10767
|
effort
|
|
10614
10768
|
});
|
|
@@ -11709,7 +11863,7 @@ function parkReasonUnretriable(reason) {
|
|
|
11709
11863
|
// package.json
|
|
11710
11864
|
var package_default = {
|
|
11711
11865
|
name: "@taskless-app/swarm",
|
|
11712
|
-
version: "0.6.
|
|
11866
|
+
version: "0.6.34",
|
|
11713
11867
|
type: "module",
|
|
11714
11868
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
11715
11869
|
keywords: [
|
|
@@ -11760,7 +11914,7 @@ var package_default = {
|
|
|
11760
11914
|
execa: "^10.0.0",
|
|
11761
11915
|
zod: "3.25.76"
|
|
11762
11916
|
},
|
|
11763
|
-
gitHead: "
|
|
11917
|
+
gitHead: "4eabd911d4dfd557bfbfcbc27afd36415714b7eb"
|
|
11764
11918
|
};
|
|
11765
11919
|
|
|
11766
11920
|
// src/version.ts
|
|
@@ -12560,6 +12714,20 @@ async function collectRunDiff(worktree, opts = {}) {
|
|
|
12560
12714
|
...truncatedFiles ? { truncated: true } : {}
|
|
12561
12715
|
};
|
|
12562
12716
|
}
|
|
12717
|
+
async function runCommitCount(worktree, opts = {}) {
|
|
12718
|
+
if (!worktree) return 0;
|
|
12719
|
+
try {
|
|
12720
|
+
const isWt = (await $4({ reject: false })`git -C ${worktree} rev-parse --is-inside-work-tree`).stdout.trim();
|
|
12721
|
+
if (isWt !== "true") return 0;
|
|
12722
|
+
const base3 = await resolveBase(worktree, opts.baseBranch);
|
|
12723
|
+
if (!base3) return 0;
|
|
12724
|
+
const out = (await $4({ reject: false })`git -C ${worktree} rev-list --count ${`${base3}..HEAD`}`).stdout.trim();
|
|
12725
|
+
const n = Number(out);
|
|
12726
|
+
return Number.isInteger(n) && n > 0 ? n : 0;
|
|
12727
|
+
} catch {
|
|
12728
|
+
return 0;
|
|
12729
|
+
}
|
|
12730
|
+
}
|
|
12563
12731
|
async function changedPaths(worktree, opts = {}) {
|
|
12564
12732
|
if (!worktree) return [];
|
|
12565
12733
|
try {
|
|
@@ -12624,6 +12792,7 @@ function collectZoneNoteConfirmations(report) {
|
|
|
12624
12792
|
// src/droneServer.ts
|
|
12625
12793
|
init_src();
|
|
12626
12794
|
init_src();
|
|
12795
|
+
init_src();
|
|
12627
12796
|
|
|
12628
12797
|
// src/reviewCycle.ts
|
|
12629
12798
|
init_src();
|
|
@@ -12835,6 +13004,8 @@ ${failText}` : failText }],
|
|
|
12835
13004
|
isError: true
|
|
12836
13005
|
};
|
|
12837
13006
|
}
|
|
13007
|
+
await store.addEvent(null, "step", `${ACCEPTANCE_CHECK_MARK}: ${id} \u2192 ${state}`, null).catch(() => {
|
|
13008
|
+
});
|
|
12838
13009
|
return { content: [{ type: "text", text }] };
|
|
12839
13010
|
}
|
|
12840
13011
|
);
|
|
@@ -12871,6 +13042,29 @@ ${failText}` : failText }],
|
|
|
12871
13042
|
return { content: [{ type: "text", text: "\u0437\u0430\u043C\u0435\u0442\u043A\u0430 \u0437\u0430\u043F\u0438\u0441\u0430\u043D\u0430 \u0438 \u0443\u0435\u0434\u0435\u0442 \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440\u0443; \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0430\u0439 \u0440\u0430\u0431\u043E\u0442\u0443 \u2014 \u043E\u0442\u0432\u0435\u0442\u0430 \u043D\u0435 \u0436\u0434\u0438." }] };
|
|
12872
13043
|
})
|
|
12873
13044
|
);
|
|
13045
|
+
server.tool(
|
|
13046
|
+
"report_weight",
|
|
13047
|
+
"\u0421\u043A\u0430\u0437\u0430\u0442\u044C \u0434\u0435\u043C\u043E\u043D\u0443, \u0447\u0442\u043E \u0420\u0410\u0411\u041E\u0422\u0410 \u0422\u042F\u0416\u0415\u041B\u0415\u0415 \u041E\u0416\u0418\u0414\u0410\u041D\u0418\u0419 \u2014 \u043F\u043E \u0445\u043E\u0434\u0443 \u0434\u0435\u043B\u0430, \u0430 \u043D\u0435 \u0432 \u043E\u0442\u0447\u0451\u0442\u0435. \u0417\u043E\u0432\u0438, \u043A\u043E\u0433\u0434\u0430 \u0441\u043E\u0436\u0436\u0435\u043D\u043E \u0431\u043E\u043B\u044C\u0448\u0435 \u043F\u043E\u043B\u043E\u0432\u0438\u043D\u044B \u0431\u044E\u0434\u0436\u0435\u0442\u0430 \u043F\u0440\u043E\u0433\u043E\u043D\u0430, \u0430 \u0434\u043E \u0441\u0434\u0430\u0447\u0438 \u0435\u0449\u0451 \u0434\u0430\u043B\u0435\u043A\u043E. \u0414\u0435\u043C\u043E\u043D \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442 \u043F\u043E \u043B\u0435\u043D\u0442\u0435, \u0447\u0442\u043E \u0442\u044B \u041F\u0420\u041E\u0414\u0412\u0418\u0413\u0410\u0415\u0428\u042C\u0421\u042F (\u043A\u043E\u043C\u043C\u0438\u0442\u044B/PR/\u0437\u0430\u043A\u0440\u044B\u0442\u044B\u0435 \u043A\u0440\u0438\u0442\u0435\u0440\u0438\u0438), \u0438 \u0435\u0441\u043B\u0438 \u0434\u0430 \u2014 \u043F\u0440\u0438\u0434\u0435\u0440\u0436\u0438\u0442 \u043D\u043E\u0432\u0443\u044E \u0440\u0430\u0431\u043E\u0442\u0443 \u043D\u0430 \u043C\u0430\u0448\u0438\u043D\u0435, \u043D\u0435 \u0441\u043D\u0438\u043C\u0435\u0442 \u0442\u0435\u0431\u044F \u0440\u0430\u0437\u0433\u0440\u0443\u0437\u043A\u043E\u0439 \u0438 \u043F\u043E\u0434\u043D\u0438\u043C\u0435\u0442 \u043F\u043E\u0442\u043E\u043B\u043E\u043A \u0442\u0440\u0430\u0442 \u0432 \u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u0445 \u043F\u0440\u0435\u0434\u0435\u043B\u0430\u0445. \u0415\u0441\u043B\u0438 \u043F\u0440\u043E\u0434\u0432\u0438\u0436\u0435\u043D\u0438\u044F \u043D\u0435\u0442 \u2014 \u0434\u043E\u0431\u0430\u0432\u043A\u0438 \u043D\u0435 \u0431\u0443\u0434\u0435\u0442 \u0438 \u0437\u0430\u0434\u0430\u0447\u0443 \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u0442 \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440: \u0442\u0440\u0430\u0442\u0430 \u0431\u0435\u0437 \u0434\u0432\u0438\u0436\u0435\u043D\u0438\u044F \u044D\u0442\u043E \u043D\u0435 \u0442\u044F\u0436\u0435\u0441\u0442\u044C, \u0430 \u043F\u043E\u043B\u043E\u043C\u043A\u0430. \u041D\u0415 \u0431\u043B\u043E\u043A\u0438\u0440\u0443\u0435\u0442: \u0441\u043A\u0430\u0437\u0430\u043B \u0438 \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0448\u044C \u0434\u0430\u043B\u044C\u0448\u0435.",
|
|
13048
|
+
{
|
|
13049
|
+
note: z.string().describe("\u043F\u043E\u0447\u0435\u043C\u0443 \u0442\u044F\u0436\u0435\u043B\u0435\u0435 \u043E\u0436\u0438\u0434\u0430\u043D\u0438\u0439: \u0447\u0442\u043E \u043E\u043A\u0430\u0437\u0430\u043B\u043E\u0441\u044C \u0431\u043E\u043B\u044C\u0448\u0435, \u0447\u0435\u043C \u0432\u044B\u0433\u043B\u044F\u0434\u0435\u043B\u043E (\u043F\u0440\u0430\u0432\u043A\u0430 \u0440\u0430\u0441\u043F\u043E\u043B\u0437\u043B\u0430\u0441\u044C \u043D\u0430 N \u043F\u0430\u043A\u0435\u0442\u043E\u0432, \u043C\u0438\u0433\u0440\u0430\u0446\u0438\u044F, \u0447\u0443\u0436\u043E\u0439 \u0441\u043B\u043E\u043C\u0430\u043D\u043D\u044B\u0439 \u0442\u0435\u0441\u0442\u2026)")
|
|
13050
|
+
},
|
|
13051
|
+
guard(async ({ note }) => {
|
|
13052
|
+
if (await overmindDead()) return freeze();
|
|
13053
|
+
const clean = note.trim();
|
|
13054
|
+
if (!clean) {
|
|
13055
|
+
return { content: [{ type: "text", text: "\u043F\u0443\u0441\u0442\u0430\u044F \u0437\u0430\u044F\u0432\u043A\u0430: \u043D\u0430\u0437\u043E\u0432\u0438, \u0427\u0422\u041E \u043E\u043A\u0430\u0437\u0430\u043B\u043E\u0441\u044C \u0442\u044F\u0436\u0435\u043B\u0435\u0435 \u043E\u0436\u0438\u0434\u0430\u043D\u0438\u0439 \u2014 \u043F\u043E \u043F\u0443\u0441\u0442\u043E\u0439 \u0434\u0435\u043C\u043E\u043D \u0440\u0435\u0448\u0435\u043D\u0438\u044F \u043D\u0435 \u043F\u0440\u0438\u043C\u0435\u0442." }], isError: true };
|
|
13056
|
+
}
|
|
13057
|
+
await store.addEvent(null, "note", heavyClaimText(clean), null);
|
|
13058
|
+
return {
|
|
13059
|
+
content: [
|
|
13060
|
+
{
|
|
13061
|
+
type: "text",
|
|
13062
|
+
text: "\u0437\u0430\u044F\u0432\u043A\u0430 \u0437\u0430\u043F\u0438\u0441\u0430\u043D\u0430 \u2014 \u0434\u0435\u043C\u043E\u043D \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u0442 \u0435\u0451 \u043D\u0430 \u0431\u043B\u0438\u0436\u0430\u0439\u0448\u0435\u043C \u0442\u0438\u043A\u0435 \u043F\u043E \u0438\u0437\u043C\u0435\u0440\u0435\u043D\u0438\u044E (\u0442\u0440\u0430\u0442\u0430 \u043F\u0440\u043E\u0442\u0438\u0432 \u0438\u0441\u0442\u043E\u0440\u0438\u0438 \u0437\u0430\u0434\u0430\u0447\u0438) \u0438 \u043F\u043E \u0442\u0432\u043E\u0435\u043C\u0443 \u043F\u0440\u043E\u0434\u0432\u0438\u0436\u0435\u043D\u0438\u044E. \u041E\u0442\u0432\u0435\u0442\u0430 \u043D\u0435 \u0436\u0434\u0438, \u0440\u0430\u0431\u043E\u0442\u0430\u0439 \u0434\u0430\u043B\u044C\u0448\u0435: \u0440\u0435\u0448\u0435\u043D\u0438\u0435 \u043F\u0440\u0438\u0435\u0434\u0435\u0442 \u0432 \u043B\u0435\u043D\u0442\u0443 \u043F\u0440\u043E\u0433\u043E\u043D\u0430, \u0430 \u043F\u043E\u0434\u043D\u044F\u0442\u044B\u0439 \u043F\u043E\u0442\u043E\u043B\u043E\u043A \u2014 \u0432 \u0431\u044E\u0434\u0436\u0435\u0442 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0435\u0433\u043E \u0437\u0430\u043F\u0443\u0441\u043A\u0430. \u041F\u0440\u043E\u0434\u0432\u0438\u0436\u0435\u043D\u0438\u044F \u043D\u0435\u0442 (\u043D\u0438 \u043A\u043E\u043C\u043C\u0438\u0442\u043E\u0432, \u043D\u0438 PR, \u043D\u0438 \u0437\u0430\u043A\u0440\u044B\u0442\u044B\u0445 \u043A\u0440\u0438\u0442\u0435\u0440\u0438\u0435\u0432) \u2014 \u0434\u043E\u0431\u0430\u0432\u043A\u0438 \u043D\u0435 \u0431\u0443\u0434\u0435\u0442, \u043F\u043E\u0437\u043E\u0432\u0443\u0442 \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440\u0430."
|
|
13063
|
+
}
|
|
13064
|
+
]
|
|
13065
|
+
};
|
|
13066
|
+
})
|
|
13067
|
+
);
|
|
12874
13068
|
server.tool(
|
|
12875
13069
|
"return_task",
|
|
12876
13070
|
"\u0412\u0435\u0440\u043D\u0443\u0442\u044C \u0437\u0430\u0434\u0430\u0447\u0443 \u0410\u0412\u0422\u041E\u0420\u0423 \u043D\u0430 \u0443\u0442\u043E\u0447\u043D\u0435\u043D\u0438\u0435 \u0438 \u0437\u0430\u043A\u0440\u044B\u0442\u044C \u043F\u0440\u043E\u0433\u043E\u043D (\u0441\u043B\u043E\u0442 \u043E\u0441\u0432\u043E\u0431\u043E\u0434\u0438\u0442\u0441\u044F, \u0440\u043E\u0439 \u0432\u043E\u0437\u044C\u043C\u0451\u0442 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0443\u044E \u0437\u0430\u0434\u0430\u0447\u0443). \u0417\u043E\u0432\u0438, \u0422\u041E\u041B\u042C\u041A\u041E \u0435\u0441\u043B\u0438 \u0437\u0430\u0434\u0430\u0447\u0443 \u043D\u0435\u043B\u044C\u0437\u044F \u0432\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u044C \u043D\u0438 \u0432 \u043E\u0434\u043D\u043E\u043C \u0440\u0430\u0437\u0443\u043C\u043D\u043E\u043C \u0442\u043E\u043B\u043A\u043E\u0432\u0430\u043D\u0438\u0438 \u0418\u041B\u0418 \u043D\u0435\u043F\u043E\u043D\u044F\u0442\u043D\u043E, \u0447\u0435\u043C \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0442\u044C \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442. \u0414\u0432\u0430 \u043E\u0441\u043C\u044B\u0441\u043B\u0435\u043D\u043D\u044B\u0445 \u0442\u043E\u043B\u043A\u043E\u0432\u0430\u043D\u0438\u044F \u2014 \u041D\u0415 \u043F\u043E\u0432\u043E\u0434: \u0432\u044B\u0431\u0435\u0440\u0438 \u043E\u0447\u0435\u0432\u0438\u0434\u043D\u043E\u0435, \u0441\u0434\u0435\u043B\u0430\u0439 \u0438 \u043D\u0430\u0437\u043E\u0432\u0438 \u0440\u0430\u0437\u0432\u0438\u043B\u043A\u0443 \u0432 \u043E\u043F\u0438\u0441\u0430\u043D\u0438\u0438 PR. \u041F\u043E\u043D\u044F\u0442\u043D\u0430\u044F \u0437\u0430\u0434\u0430\u0447\u0430, \u043A\u043E\u0442\u043E\u0440\u0430\u044F \u0432 \u043E\u0434\u043D\u043E\u043C \u043F\u0443\u043D\u043A\u0442\u0435 \u043F\u0440\u043E\u0442\u0438\u0432\u043E\u0440\u0435\u0447\u0438\u0442 \u043F\u0440\u0430\u0432\u0438\u043B\u0443 \u043F\u0440\u043E\u0435\u043A\u0442\u0430, \u2014 \u0442\u043E\u0436\u0435 \u043D\u0435 \u043F\u043E\u0432\u043E\u0434: \u044D\u0442\u043E ask. \u041E\u0442\u0434\u0435\u043B\u044C\u043D\u044B\u0439 \u0437\u0430\u043A\u043E\u043D\u043D\u044B\u0439 \u0441\u043B\u0443\u0447\u0430\u0439 \u2014 \u0437\u0430\u0434\u0430\u0447\u0430 \u0421\u041B\u0418\u0428\u041A\u041E\u041C \u0412\u0415\u041B\u0418\u041A\u0410 (reason=too_big): \u043F\u043E\u043D\u044F\u0442\u043D\u0430 \u0438 \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0435\u043C\u0430, \u043D\u043E \u044D\u0442\u043E \u043B\u0438\u0441\u0442 \u043D\u0430 \u043D\u0435\u0441\u043A\u043E\u043B\u044C\u043A\u043E \u043F\u0440\u043E\u0433\u043E\u043D\u043E\u0432, \u0438 \u0443\u043F\u0435\u0440\u0435\u0442\u044C\u0441\u044F \u0432 \u043F\u043E\u0442\u043E\u043B\u043E\u043A \u0442\u0440\u0430\u0442 \u043D\u0430 \u0441\u0435\u0440\u0435\u0434\u0438\u043D\u0435 \u0445\u0443\u0436\u0435, \u0447\u0435\u043C \u0432\u0435\u0440\u043D\u0443\u0442\u044C \u0435\u0451 \u0441\u0440\u0430\u0437\u0443; \u0440\u0430\u0437\u0431\u0438\u0435\u043D\u0438\u0435 \u043C\u043E\u0436\u0435\u0448\u044C \u041F\u0420\u0415\u0414\u041B\u041E\u0416\u0418\u0422\u042C (split), \u0430 \u043F\u043E\u0434\u0437\u0430\u0434\u0430\u0447\u0438 \u043D\u0435 \u0437\u0430\u0432\u043E\u0434\u0438 \u2014 \u044D\u0442\u043E \u0440\u0435\u0448\u0435\u043D\u0438\u0435 \u0430\u0432\u0442\u043E\u0440\u0430. \u0417\u0430\u0434\u0430\u0447\u0430 \u0443\u0439\u0434\u0451\u0442 \u0430\u0432\u0442\u043E\u0440\u0443 (\u043D\u0430\u0437\u043D\u0430\u0447\u0438\u043C \u043D\u0430 \u043D\u0435\u0433\u043E \u0438 \u043F\u0435\u0440\u0435\u0432\u0435\u0434\u0451\u043C \u0432 \u0440\u0430\u0431\u043E\u0442\u0443), \u0432\u043E\u043F\u0440\u043E\u0441\u044B \u0443\u0435\u0434\u0443\u0442 \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u043E\u043C \u043E\u0442 \u0442\u0432\u043E\u0435\u0433\u043E \u0438\u043C\u0435\u043D\u0438. \u041F\u043E\u0441\u043B\u0435 \u0432\u044B\u0437\u043E\u0432\u0430 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u044B \u0431\u043E\u043B\u044C\u0448\u0435 \u043D\u0435 \u0437\u043E\u0432\u0438 \u2014 \u0437\u0430\u0432\u0435\u0440\u0448\u0438 \u0441\u0435\u0441\u0441\u0438\u044E.",
|
|
@@ -14661,8 +14855,8 @@ function detectGlobalPm(entry, io = {}) {
|
|
|
14661
14855
|
if (/\/node_modules\//.test(p)) return "npm";
|
|
14662
14856
|
const env = io.env ?? process.env;
|
|
14663
14857
|
const platform = io.platform ?? process.platform;
|
|
14664
|
-
const
|
|
14665
|
-
return
|
|
14858
|
+
const has2 = io.hasCommand ?? ((n) => hasCommandInPath(n, env, platform));
|
|
14859
|
+
return has2("npm") ? "npm" : "unknown";
|
|
14666
14860
|
}
|
|
14667
14861
|
function globalInstallCommand(pm, spec) {
|
|
14668
14862
|
switch (pm) {
|
|
@@ -17950,7 +18144,7 @@ ${task.description}` : `\u0417\u0430\u0434\u0430\u0447\u0430 ${run.task_slug} (\
|
|
|
17950
18144
|
// вторую ветку мимо PR. Пишем ту, что реально записана на прогоне; пусто (первый спавн —
|
|
17951
18145
|
// ветку заводит spawnDrone из слага) — прежняя формулировка.
|
|
17952
18146
|
`\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"}.`,
|
|
17953
|
-
"\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; return_task(reason, missing, readings, assumed, questions) \u2014 \u0432\u0435\u0440\u043D\u0443\u0442\u044C \u0421\u042B\u0420\u0423\u042E \u0437\u0430\u0434\u0430\u0447\u0443 \u0430\u0432\u0442\u043E\u0440\u0443 (\u0441\u043C. \u043F\u0440\u0430\u0432\u0438\u043B\u043E \u043D\u0438\u0436\u0435); 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).",
|
|
18147
|
+
"\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; return_task(reason, missing, readings, assumed, questions) \u2014 \u0432\u0435\u0440\u043D\u0443\u0442\u044C \u0421\u042B\u0420\u0423\u042E \u0437\u0430\u0434\u0430\u0447\u0443 \u0430\u0432\u0442\u043E\u0440\u0443 (\u0441\u043C. \u043F\u0440\u0430\u0432\u0438\u043B\u043E \u043D\u0438\u0436\u0435); 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). report_weight(note) \u2014 \u0441\u043A\u0430\u0436\u0438 \u0434\u0435\u043C\u043E\u043D\u0443, \u0447\u0442\u043E \u0420\u0410\u0411\u041E\u0422\u0410 \u0422\u042F\u0416\u0415\u041B\u0415\u0415 \u041E\u0416\u0418\u0414\u0410\u041D\u0418\u0419, \u043A\u043E\u0433\u0434\u0430 \u0441\u043E\u0436\u0436\u0435\u043D\u043E \u0431\u043E\u043B\u044C\u0448\u0435 \u043F\u043E\u043B\u043E\u0432\u0438\u043D\u044B \u0442\u0432\u043E\u0435\u0433\u043E \u0431\u044E\u0434\u0436\u0435\u0442\u0430, \u0430 \u0434\u043E \u0441\u0434\u0430\u0447\u0438 \u0434\u0430\u043B\u0435\u043A\u043E: \u043E\u043D \u043F\u0440\u0438\u0434\u0435\u0440\u0436\u0438\u0442 \u043D\u043E\u0432\u0443\u044E \u0440\u0430\u0431\u043E\u0442\u0443 \u043D\u0430 \u043C\u0430\u0448\u0438\u043D\u0435, \u043D\u0435 \u0441\u043D\u0438\u043C\u0435\u0442 \u0442\u0435\u0431\u044F \u0440\u0430\u0437\u0433\u0440\u0443\u0437\u043A\u043E\u0439 \u0438 \u043F\u043E\u0434\u043D\u0438\u043C\u0435\u0442 \u043F\u043E\u0442\u043E\u043B\u043E\u043A \u0442\u0440\u0430\u0442 \u0432 \u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u0445 \u043F\u0440\u0435\u0434\u0435\u043B\u0430\u0445. \u041F\u0440\u043E\u0432\u0435\u0440\u044F\u0435\u0442\u0441\u044F \u043F\u043E \u0444\u0430\u043A\u0442\u0443 \u2014 \u0432\u0435\u0441 \u0434\u0430\u044E\u0442 \u0442\u043E\u043C\u0443, \u043A\u0442\u043E \u041F\u0420\u041E\u0414\u0412\u0418\u0413\u0410\u0415\u0422\u0421\u042F (\u043A\u043E\u043C\u043C\u0438\u0442\u044B/PR/\u0437\u0430\u043A\u0440\u044B\u0442\u044B\u0435 \u043A\u0440\u0438\u0442\u0435\u0440\u0438\u0438); \u0442\u0440\u0430\u0442\u0430 \u0431\u0435\u0437 \u0434\u0432\u0438\u0436\u0435\u043D\u0438\u044F \u0431\u044E\u0434\u0436\u0435\u0442\u0430 \u043D\u0435 \u043F\u043E\u043B\u0443\u0447\u0430\u0435\u0442, \u0435\u0451 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u0442 \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440. \u0417\u043E\u0432\u0438 \u041F\u041E \u0425\u041E\u0414\u0423, \u0430 \u043D\u0435 \u0432 \u043E\u0442\u0447\u0451\u0442\u0435: \u043F\u043E\u0441\u0442\u0444\u0430\u043A\u0442\u0443\u043C \u043E\u0431\u0441\u043B\u0443\u0436\u0438\u0432\u0430\u0442\u044C \u0443\u0436\u0435 \u043D\u0435\u0447\u0435\u0433\u043E.",
|
|
17954
18148
|
// TASWM-412: третий выход из непонятной задачи. Раньше их было два, и оба плохие —
|
|
17955
18149
|
// угадать постановку (сделает не то) или ask (слот занят, а ответить может только автор
|
|
17956
18150
|
// задачи, не оператор роя). Граница здесь ОБЯЗАТЕЛЬНА: дрон, легко возвращающий задачи,
|
|
@@ -18947,6 +19141,13 @@ async function trySpawnQueuedRun(deps, run) {
|
|
|
18947
19141
|
// причина одна на машину — в лог уходит одной строкой, а не по строке на прогон
|
|
18948
19142
|
});
|
|
18949
19143
|
}
|
|
19144
|
+
const heavy = heavyRunsInFlight(deps);
|
|
19145
|
+
if (heavy.length && heavy.every((h) => h.id !== run.id)) {
|
|
19146
|
+
return deferSpawn(deps, run, intakeHoldReason(heavy.map(droneLabel).join(", ")), {
|
|
19147
|
+
logKey: "weight-hold"
|
|
19148
|
+
// причина одна на машину — в лог одной строкой, а не по строке на прогон
|
|
19149
|
+
});
|
|
19150
|
+
}
|
|
18950
19151
|
const spentAttempts = attemptsFor(deps, run.task_slug);
|
|
18951
19152
|
if (spentAttempts >= PRE_START_ATTEMPT_LIMIT) {
|
|
18952
19153
|
const last = lastPreStartAttempt(deps.db.listRuns(), run.task_slug);
|
|
@@ -19234,6 +19435,79 @@ async function applyWatchdogAction(deps, action) {
|
|
|
19234
19435
|
}
|
|
19235
19436
|
}
|
|
19236
19437
|
var GATE_LOG_HEARTBEAT_TICKS = 30;
|
|
19438
|
+
function wasProductive(r) {
|
|
19439
|
+
return r.pr_url != null || r.status === "done" || r.status === "review";
|
|
19440
|
+
}
|
|
19441
|
+
function weightSamples(history, run) {
|
|
19442
|
+
const all = history.filter((r) => r.id !== run.id && r.kind === "drone");
|
|
19443
|
+
const own = all.filter((r) => r.task_slug === run.task_slug);
|
|
19444
|
+
const similar = run.area ? all.filter((r) => r.area === run.area) : all;
|
|
19445
|
+
return [...own, ...similar.filter((r) => r.task_slug !== run.task_slug)].map((r) => ({
|
|
19446
|
+
costUsd: r.cost_usd,
|
|
19447
|
+
productive: wasProductive(r),
|
|
19448
|
+
ownTask: r.task_slug === run.task_slug
|
|
19449
|
+
}));
|
|
19450
|
+
}
|
|
19451
|
+
function refreshHeavyRuns(deps) {
|
|
19452
|
+
const live = deps.db.listRuns("running");
|
|
19453
|
+
deps.weightState = { heavy: live.filter((r) => r.kind === "drone" && isHeavyRun(deps.db.events(r.id))) };
|
|
19454
|
+
}
|
|
19455
|
+
function heavyRunsInFlight(deps) {
|
|
19456
|
+
return deps.weightState?.heavy ?? [];
|
|
19457
|
+
}
|
|
19458
|
+
async function manageWeight(deps) {
|
|
19459
|
+
const claimants = deps.db.listRuns("running").filter((r) => r.kind === "drone").map((run) => ({ run, events: deps.db.events(run.id) })).filter(({ events }) => hasOpenHeavyClaim(events));
|
|
19460
|
+
const history = claimants.length ? deps.db.listRuns() : [];
|
|
19461
|
+
for (const { run, events } of claimants) {
|
|
19462
|
+
let commits = 0;
|
|
19463
|
+
if (deps.runCommits) {
|
|
19464
|
+
try {
|
|
19465
|
+
commits = await deps.runCommits(run);
|
|
19466
|
+
} catch (e) {
|
|
19467
|
+
console.warn(`[overmind] \u0432\u0435\u0441: \u043D\u0435 \u0441\u043C\u043E\u0433 \u043F\u043E\u0441\u0447\u0438\u0442\u0430\u0442\u044C \u043A\u043E\u043C\u043C\u0438\u0442\u044B ${droneLabel(run)}:`, e);
|
|
19468
|
+
}
|
|
19469
|
+
}
|
|
19470
|
+
const estimate = estimateTaskWeight(weightSamples(history, run));
|
|
19471
|
+
const decision = decideHeavyClaim({
|
|
19472
|
+
spentUsd: run.cost_usd,
|
|
19473
|
+
estimate,
|
|
19474
|
+
progress: { commits, hasPr: run.pr_url != null, acceptanceChecks: countAcceptanceChecks(events) },
|
|
19475
|
+
baseCeilingUsd: deps.maxCostUsd?.() ?? DEFAULT_RUN_LIMITS.maxCostUsd,
|
|
19476
|
+
grantedUsd: grantedCeilingUsd(events)
|
|
19477
|
+
});
|
|
19478
|
+
const basis = `${estimate.basis}, \u043F\u0440\u043E\u0433\u043E\u043D\u043E\u0432 \u0432 \u0432\u044B\u0431\u043E\u0440\u043A\u0435: ${estimate.samples}`;
|
|
19479
|
+
if (decision.verdict === "stalled") {
|
|
19480
|
+
const why = `${heavyRefusedText(decision.reason)} (\u0438\u0437\u043C\u0435\u0440\u0435\u043D\u0438\u0435: ${basis})`;
|
|
19481
|
+
deps.db.addEvent(run.id, "note", why);
|
|
19482
|
+
deps.db.addEvent(run.id, "anomaly", why);
|
|
19483
|
+
narrate(deps, `${droneLabel(run)} \u043F\u0440\u043E\u0441\u0438\u0442 \u0431\u044E\u0434\u0436\u0435\u0442, \u043D\u043E \u043D\u0435 \u0434\u0432\u0438\u0433\u0430\u0435\u0442\u0441\u044F \u2014 \u0432\u0435\u0441\u0430 \u043D\u0435 \u0434\u0430\u044E, \u0437\u043E\u0432\u0443 \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440\u0430 (TASWM-535).`);
|
|
19484
|
+
if (deps.watchdog?.notify) {
|
|
19485
|
+
try {
|
|
19486
|
+
await deps.watchdog.notify({
|
|
19487
|
+
key: `weight_stalled:${run.id}`,
|
|
19488
|
+
title: signalTitle(run, "\u0442\u0440\u0430\u0442\u0438\u0442, \u043D\u043E \u043D\u0435 \u0434\u0432\u0438\u0433\u0430\u0435\u0442\u0441\u044F"),
|
|
19489
|
+
body: `${run.task_slug}: \u0434\u0440\u043E\u043D \u043F\u0440\u043E\u0441\u0438\u0442 \u043F\u0440\u0438\u0437\u043D\u0430\u0442\u044C \u0440\u0430\u0431\u043E\u0442\u0443 \u0442\u044F\u0436\u0451\u043B\u043E\u0439, \u043D\u043E \u043F\u0440\u043E\u0434\u0432\u0438\u0436\u0435\u043D\u0438\u044F \u043D\u0435\u0442 \u2014 \u043D\u0438 \u043A\u043E\u043C\u043C\u0438\u0442\u043E\u0432 \u0432 \u0432\u0435\u0442\u043A\u0435, \u043D\u0438 PR, \u043D\u0438 \u043E\u0434\u043D\u043E\u0433\u043E \u0437\u0430\u043A\u0440\u044B\u0442\u043E\u0433\u043E \u043A\u0440\u0438\u0442\u0435\u0440\u0438\u044F \u043F\u0440\u0438 \u043F\u043E\u0442\u0440\u0430\u0447\u0435\u043D\u043D\u044B\u0445 $${run.cost_usd.toFixed(2)}. \u0411\u044E\u0434\u0436\u0435\u0442 \u041D\u0415 \u043F\u043E\u0434\u043D\u044F\u0442: \u044D\u0442\u043E \u043F\u043E\u0445\u043E\u0436\u0435 \u043D\u0430 \u043F\u0440\u043E\u0433\u043E\u043D, \u043A\u0440\u0443\u0442\u044F\u0449\u0438\u0439\u0441\u044F \u043D\u0430 \u043C\u0435\u0441\u0442\u0435, \u0430 \u043D\u0435 \u043D\u0430 \u0442\u044F\u0436\u0451\u043B\u0443\u044E \u0437\u0430\u0434\u0430\u0447\u0443. \u041F\u043E\u0441\u043C\u043E\u0442\u0440\u0438, \u0447\u0442\u043E \u043E\u043D \u0434\u0435\u043B\u0430\u0435\u0442.`,
|
|
19490
|
+
runId: run.id,
|
|
19491
|
+
...hrefOf(run.task_url)
|
|
19492
|
+
});
|
|
19493
|
+
} catch (e) {
|
|
19494
|
+
console.error(`[overmind] \u0441\u0438\u0433\u043D\u0430\u043B \xAB\u0442\u0440\u0430\u0442\u0438\u0442, \u043D\u043E \u043D\u0435 \u0434\u0432\u0438\u0433\u0430\u0435\u0442\u0441\u044F\xBB \u043F\u043E \u043F\u0440\u043E\u0433\u043E\u043D\u0443 #${run.id} \u043D\u0435 \u0434\u043E\u043B\u0435\u0442\u0435\u043B:`, e);
|
|
19495
|
+
}
|
|
19496
|
+
}
|
|
19497
|
+
continue;
|
|
19498
|
+
}
|
|
19499
|
+
if (decision.verdict === "too_early") {
|
|
19500
|
+
deps.db.addEvent(run.id, "step", `\u0432\u0435\u0441 \u043F\u0440\u043E\u0433\u043E\u043D\u0430: \u0437\u0430\u044F\u0432\u043A\u0430 \u0440\u0430\u043D\u043E \u2014 ${decision.reason} (\u0438\u0437\u043C\u0435\u0440\u0435\u043D\u0438\u0435: ${basis})`);
|
|
19501
|
+
continue;
|
|
19502
|
+
}
|
|
19503
|
+
deps.db.addEvent(run.id, "note", `${heavyGrantText(decision.ceilingUsd ?? 0, decision.reason)} (\u0438\u0437\u043C\u0435\u0440\u0435\u043D\u0438\u0435: ${basis})`);
|
|
19504
|
+
narrate(
|
|
19505
|
+
deps,
|
|
19506
|
+
`${droneLabel(run)}: \u0440\u0430\u0431\u043E\u0442\u0430 \u043F\u0440\u0438\u0437\u043D\u0430\u043D\u0430 \u0442\u044F\u0436\u0451\u043B\u043E\u0439 \u2014 \u043F\u043E\u0442\u043E\u043B\u043E\u043A $${(decision.ceilingUsd ?? 0).toFixed(2)}, \u043D\u043E\u0432\u0443\u044E \u0440\u0430\u0431\u043E\u0442\u0443 \u043F\u043E\u043A\u0430 \u043D\u0435 \u0431\u0435\u0440\u0443 (TASWM-535).`
|
|
19507
|
+
);
|
|
19508
|
+
}
|
|
19509
|
+
refreshHeavyRuns(deps);
|
|
19510
|
+
}
|
|
19237
19511
|
async function manageRelief(deps, now, droneCap, stormActive) {
|
|
19238
19512
|
const state = deps.relief ?? (deps.relief = {});
|
|
19239
19513
|
const cfg = state.config ? resolveReliefConfig(state.config) : DEFAULT_RELIEF_CONFIG;
|
|
@@ -19242,7 +19516,7 @@ async function manageRelief(deps, now, droneCap, stormActive) {
|
|
|
19242
19516
|
state.reliefSince = needsRelief ? state.reliefSince ?? now : null;
|
|
19243
19517
|
if (!resourcesOk2 || needsRelief) state.overloadedAt = now;
|
|
19244
19518
|
if (needsRelief && deps.kill && pauseDue(state.reliefSince, state.lastPauseAt ?? null, now, cfg)) {
|
|
19245
|
-
const candidate = pickPauseCandidate(deps.db.listRuns("running"));
|
|
19519
|
+
const candidate = pickPauseCandidate(deps.db.listRuns("running"), new Set(heavyRunsInFlight(deps).map((r) => r.id)));
|
|
19246
19520
|
if (candidate) {
|
|
19247
19521
|
let stepsSinceResume = null;
|
|
19248
19522
|
try {
|
|
@@ -19749,6 +20023,11 @@ async function tickOnce(deps) {
|
|
|
19749
20023
|
}
|
|
19750
20024
|
const droneCap = deps.maxDrones ? await deps.maxDrones() : Infinity;
|
|
19751
20025
|
if (stormActive) noteStormStall(deps);
|
|
20026
|
+
try {
|
|
20027
|
+
await manageWeight(deps);
|
|
20028
|
+
} catch (e) {
|
|
20029
|
+
console.error("[overmind] \u0440\u0430\u0437\u0431\u043E\u0440 \u0432\u0435\u0441\u0430 \u043F\u0440\u043E\u0433\u043E\u043D\u043E\u0432 \u0441\u043E\u0440\u0432\u0430\u043B\u0441\u044F:", e);
|
|
20030
|
+
}
|
|
19752
20031
|
if (deps.resourcesOk) {
|
|
19753
20032
|
await manageRelief(deps, now, droneCap, stormActive);
|
|
19754
20033
|
} else if (!stormActive) {
|
|
@@ -20343,7 +20622,12 @@ async function tickOnce(deps) {
|
|
|
20343
20622
|
console.error("[overmind] \u0441\u0442\u043E\u0440\u043E\u0436 \u043F\u0440\u043E\u0433\u0440\u0435\u0441\u0441\u0430: \u0442\u0438\u043A \u0441\u043E\u0440\u0432\u0430\u043B\u0441\u044F:", e);
|
|
20344
20623
|
}
|
|
20345
20624
|
}
|
|
20346
|
-
|
|
20625
|
+
const heavyInFlight = heavyRunsInFlight(deps);
|
|
20626
|
+
if (heavyInFlight.length && deps.intake) {
|
|
20627
|
+
const d = noteDefer(deps.spawnDefer ??= /* @__PURE__ */ new Map(), "weight-intake-hold", intakeHoldReason(heavyInFlight.map(droneLabel).join(", ")), GATE_LOG_HEARTBEAT_TICKS);
|
|
20628
|
+
if (d.log) console.error(`[overmind] \u0430\u0432\u0442\u043E-\u0438\u043D\u0442\u0435\u0439\u043A \u043F\u0440\u0438\u0434\u0435\u0440\u0436\u0430\u043D: ${intakeHoldReason(heavyInFlight.map(droneLabel).join(", "))}${d.changed ? "" : ` \u2014 \u0435\u0449\u0451 \u0432\u0438\u0441\u0438\u0442, \u0442\u0438\u043A ${d.ticks}`}`);
|
|
20629
|
+
}
|
|
20630
|
+
if (deps.intake && !stormActive && !deps.control?.paused && !heavyInFlight.length && deps.intake.maxInFlight > 0 && (!deps.resourcesOk || deps.resourcesOk())) {
|
|
20347
20631
|
const it = deps.intake;
|
|
20348
20632
|
const claimCap = deps.maxDrones ? droneCap : it.maxInFlight;
|
|
20349
20633
|
const sinceLastClaim = it.lastClaimAt == null ? Infinity : now - it.lastClaimAt;
|
|
@@ -20928,7 +21212,10 @@ async function runDaemon(opts) {
|
|
|
20928
21212
|
recordEffort: (runId, effort) => {
|
|
20929
21213
|
db.updateRun(runId, { effort });
|
|
20930
21214
|
},
|
|
20931
|
-
maxCostUsd: () => lastMaxCostUsd
|
|
21215
|
+
maxCostUsd: () => lastMaxCostUsd,
|
|
21216
|
+
// TASWM-535: поднятый потолок тяжёлого прогона живёт в его ленте — спавн читает её
|
|
21217
|
+
// оттуда же, откуда потом прочитает прод-сторож.
|
|
21218
|
+
weightEvents: (run) => db.events(run.id)
|
|
20932
21219
|
});
|
|
20933
21220
|
let prepareReader;
|
|
20934
21221
|
const zoneModels = new ZoneModels({ manualAreas: () => new Map(db.listRuns().map((r) => [r.task_slug, r.area])) });
|
|
@@ -21498,6 +21785,11 @@ async function runDaemon(opts) {
|
|
|
21498
21785
|
// mtime транскрипта claude-сессии как liveness (TASWM-136): точнее коммитов — обновляется
|
|
21499
21786
|
// на каждое действие дрона (Edit/Read/tool-use), не только на коммит.
|
|
21500
21787
|
transcriptMtimeMs: (p) => EXECUTOR.session.mtimeMs(p),
|
|
21788
|
+
// ВЕС ЗАДАЧИ (TASWM-535): чем демон проверяет, что заявивший о тяжести дрон РЕАЛЬНО
|
|
21789
|
+
// продвигается (коммиты от базы прогона), и от какого потолка считать ему добавку —
|
|
21790
|
+
// от той же живой настройки роя, что уезжает харнессу на спавне.
|
|
21791
|
+
runCommits: (run) => runCommitCount(run.worktree_path, { baseBranch: run.base_branch ?? null }),
|
|
21792
|
+
maxCostUsd: () => lastMaxCostUsd,
|
|
21501
21793
|
// Ресурс-гейт спавна (TASWM-130): реальные показания хоста (load1 / free RAM).
|
|
21502
21794
|
resourcesOk: hostResourcesOk,
|
|
21503
21795
|
// Замер занятости CPU раз в тик (TASWM-397): окно фиксированной длины набирает пульс
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taskless-app/swarm",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.34",
|
|
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": "
|
|
42
|
+
"gitHead": "4eabd911d4dfd557bfbfcbc27afd36415714b7eb",
|
|
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",
|