@taskless-app/swarm 0.6.48 → 0.6.49
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 +40 -7
- package/dist/overmind.js +76 -18
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -672,7 +672,7 @@ var init_modelPolicy = __esm({
|
|
|
672
672
|
label: "Anthropic",
|
|
673
673
|
executorId: "claude-code",
|
|
674
674
|
selectable: true,
|
|
675
|
-
roles: { executor: "claude-opus-5", review: "claude-sonnet-5" }
|
|
675
|
+
roles: { executor: "claude-opus-5-5", review: "claude-sonnet-5" }
|
|
676
676
|
},
|
|
677
677
|
// TASWM-565 · шаг 1 из четырёх: провайдер в реестре ЕСТЬ, выбрать его ещё нельзя.
|
|
678
678
|
// Имён моделей здесь нет СОЗНАТЕЛЬНО: у владельца подписка, состав моделей в ней нам
|
|
@@ -1169,6 +1169,9 @@ var init_cost = __esm({
|
|
|
1169
1169
|
});
|
|
1170
1170
|
|
|
1171
1171
|
// ../swarm-core/src/modelPricing.ts
|
|
1172
|
+
function cacheReadFactorOf(pricing) {
|
|
1173
|
+
return pricing.cacheReadFactor ?? CACHE_READ_FACTOR;
|
|
1174
|
+
}
|
|
1172
1175
|
function findModelPricing(model, table = MODEL_PRICING) {
|
|
1173
1176
|
if (!model) return void 0;
|
|
1174
1177
|
const exact = table[model];
|
|
@@ -1190,6 +1193,10 @@ var init_modelPricing = __esm({
|
|
|
1190
1193
|
// и «почему прогон вчера стоил иначе» приходится выяснять по коду, а не по таблице.
|
|
1191
1194
|
// Меняется цена — меняется строка, одним видимым коммитом.
|
|
1192
1195
|
"claude-sonnet-5": { inputPerMTok: 2, outputPerMTok: 10 },
|
|
1196
|
+
// Opus 5.5 — 4/20, и чтение из кеша у него 5 % входа ($0.20), а не обычные 10 %.
|
|
1197
|
+
// У дронов чтение из кеша — основная часть токенов: с общим множителем прогон на
|
|
1198
|
+
// Opus 5.5 стоил бы в расчёте почти вдвое больше настоящего.
|
|
1199
|
+
"claude-opus-5-5": { inputPerMTok: 4, outputPerMTok: 20, cacheReadFactor: 0.05 },
|
|
1193
1200
|
"claude-opus-5": { inputPerMTok: 5, outputPerMTok: 25 },
|
|
1194
1201
|
"claude-fable-5": { inputPerMTok: 10, outputPerMTok: 50 },
|
|
1195
1202
|
// Прогоны и вызовы на 4.x остаются в истории — строки держим ради их стоимости.
|
|
@@ -1964,7 +1971,7 @@ function costFromUsage(usage2, model, table = MODEL_PRICING) {
|
|
|
1964
1971
|
const output = usage2.output_tokens ?? 0;
|
|
1965
1972
|
const cacheWrite = usage2.cache_creation_input_tokens ?? 0;
|
|
1966
1973
|
const cacheRead = usage2.cache_read_input_tokens ?? 0;
|
|
1967
|
-
const costUsd = (input * pricing.inputPerMTok + output * pricing.outputPerMTok + cacheWrite * pricing.inputPerMTok * CACHE_WRITE_5M_FACTOR + cacheRead * pricing.inputPerMTok *
|
|
1974
|
+
const costUsd = (input * pricing.inputPerMTok + output * pricing.outputPerMTok + cacheWrite * pricing.inputPerMTok * CACHE_WRITE_5M_FACTOR + cacheRead * pricing.inputPerMTok * cacheReadFactorOf(pricing)) / 1e6;
|
|
1968
1975
|
return { costUsd };
|
|
1969
1976
|
}
|
|
1970
1977
|
var init_pricing = __esm({
|
|
@@ -2943,6 +2950,18 @@ var init_zoneNotes = __esm({
|
|
|
2943
2950
|
}
|
|
2944
2951
|
});
|
|
2945
2952
|
|
|
2953
|
+
// src/store.ts
|
|
2954
|
+
function isCleanResolve(run) {
|
|
2955
|
+
return (run.stop_reason ?? "").includes(RESOLVE_CLEAN_MARK);
|
|
2956
|
+
}
|
|
2957
|
+
var RESOLVE_CLEAN_MARK;
|
|
2958
|
+
var init_store = __esm({
|
|
2959
|
+
"src/store.ts"() {
|
|
2960
|
+
"use strict";
|
|
2961
|
+
RESOLVE_CLEAN_MARK = "\u0447\u0438\u0441\u0442\u043E\u0435 \u0432\u043B\u0438\u0432\u0430\u043D\u0438\u0435 \u0431\u0430\u0437\u044B";
|
|
2962
|
+
}
|
|
2963
|
+
});
|
|
2964
|
+
|
|
2946
2965
|
// src/agentToken.ts
|
|
2947
2966
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, unlinkSync } from "fs";
|
|
2948
2967
|
import { join as join7 } from "path";
|
|
@@ -3412,7 +3431,7 @@ var init_package = __esm({
|
|
|
3412
3431
|
"package.json"() {
|
|
3413
3432
|
package_default = {
|
|
3414
3433
|
name: "@taskless-app/swarm",
|
|
3415
|
-
version: "0.6.
|
|
3434
|
+
version: "0.6.49",
|
|
3416
3435
|
type: "module",
|
|
3417
3436
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
3418
3437
|
keywords: [
|
|
@@ -3463,7 +3482,7 @@ var init_package = __esm({
|
|
|
3463
3482
|
execa: "^10.0.0",
|
|
3464
3483
|
zod: "3.25.76"
|
|
3465
3484
|
},
|
|
3466
|
-
gitHead: "
|
|
3485
|
+
gitHead: "27600667531d4f65761c74793e8c4ee4859dc8ae"
|
|
3467
3486
|
};
|
|
3468
3487
|
}
|
|
3469
3488
|
});
|
|
@@ -4835,6 +4854,7 @@ var init_db = __esm({
|
|
|
4835
4854
|
init_names2();
|
|
4836
4855
|
init_zoneNotes();
|
|
4837
4856
|
init_storm();
|
|
4857
|
+
init_store();
|
|
4838
4858
|
init_src();
|
|
4839
4859
|
TERMINAL_SQL = TERMINAL_STATUSES.map((s) => `'${s}'`).join(",");
|
|
4840
4860
|
RESOLVER_TERMINAL_SQL = [...TERMINAL_STATUSES, "stalled"].map((s) => `'${s}'`).join(",");
|
|
@@ -5188,9 +5208,19 @@ CREATE TABLE IF NOT EXISTS imports (
|
|
|
5188
5208
|
).get(reviewRunId);
|
|
5189
5209
|
return row ? rowToRun(row) : null;
|
|
5190
5210
|
}
|
|
5191
|
-
/**
|
|
5211
|
+
/**
|
|
5212
|
+
* Сколько резолверов С ДРОНОМ уже поднимали на этот review-PR — потолок авто-попыток.
|
|
5213
|
+
*
|
|
5214
|
+
* TASWM-575: чистые вливания базы (RESOLVE_CLEAN_MARK в stop_reason — git свёл сам, дрон
|
|
5215
|
+
* не поднимался, стоимость ноль) в счёт НЕ идут. Потолок защищает от карусели ДРОНОВ на
|
|
5216
|
+
* нетривиальном конфликте (TASWM-127); бесплатное вливание не карусель, а на оживлённом
|
|
5217
|
+
* main оно случается на каждый чужой мерж — три сдвига main выбирали потолок, и PR с
|
|
5218
|
+
* отставшей базой застревал молча (гейт мержа не пускает base_stale, а вливать уже
|
|
5219
|
+
* некому). Всё остальное (failed/stalled резолверы, в т.ч. транзиентные сбои ОС) считается
|
|
5220
|
+
* как раньше — иначе потолок потерял бы смысл на органических смертях.
|
|
5221
|
+
*/
|
|
5192
5222
|
resolverCountFor(reviewRunId) {
|
|
5193
|
-
const row = this.db.prepare("SELECT COUNT(*) n FROM runs WHERE resolves_run_id = ?").get(reviewRunId);
|
|
5223
|
+
const row = this.db.prepare("SELECT COUNT(*) n FROM runs WHERE resolves_run_id = ? AND (stop_reason IS NULL OR stop_reason NOT LIKE ?)").get(reviewRunId, `%${RESOLVE_CLEAN_MARK}%`);
|
|
5194
5224
|
return row.n;
|
|
5195
5225
|
}
|
|
5196
5226
|
/**
|
|
@@ -7232,6 +7262,7 @@ function parsePendingRepoRules(raw) {
|
|
|
7232
7262
|
|
|
7233
7263
|
// src/swarmClient.ts
|
|
7234
7264
|
init_zoneNotes();
|
|
7265
|
+
init_store();
|
|
7235
7266
|
init_toolFailure();
|
|
7236
7267
|
|
|
7237
7268
|
// src/logTail.ts
|
|
@@ -7823,8 +7854,10 @@ var SwarmClient = class _SwarmClient {
|
|
|
7823
7854
|
const cands = [...this.runs.values()].filter((r) => r.resolves_run_id === reviewRunId && !RESOLVER_TERMINAL.has(r.status)).sort((a, b) => b.id - a.id);
|
|
7824
7855
|
return cands.length ? this.mat(cands[0]) : null;
|
|
7825
7856
|
}
|
|
7857
|
+
// Потолок авто-попыток: чистые вливания базы (дрон не поднимался, стоимость ноль) не
|
|
7858
|
+
// считаются — см. db.ts:resolverCountFor и store.ts:RESOLVE_CLEAN_MARK (TASWM-575).
|
|
7826
7859
|
resolverCountFor(reviewRunId) {
|
|
7827
|
-
return [...this.runs.values()].filter((r) => r.resolves_run_id === reviewRunId).length;
|
|
7860
|
+
return [...this.runs.values()].filter((r) => r.resolves_run_id === reviewRunId && !isCleanResolve(r)).length;
|
|
7828
7861
|
}
|
|
7829
7862
|
// failed/stalled ревьюеры (сорвался спавн ДО вердикта) в счёт НЕ идут; stopped/superseded
|
|
7830
7863
|
// тоже (TASWM-253: оператор закрыл зомби-ревьюера/сбросил попытки ревью — POST /swarm/
|
package/dist/overmind.js
CHANGED
|
@@ -666,7 +666,7 @@ var init_modelPolicy = __esm({
|
|
|
666
666
|
label: "Anthropic",
|
|
667
667
|
executorId: "claude-code",
|
|
668
668
|
selectable: true,
|
|
669
|
-
roles: { executor: "claude-opus-5", review: "claude-sonnet-5" }
|
|
669
|
+
roles: { executor: "claude-opus-5-5", review: "claude-sonnet-5" }
|
|
670
670
|
},
|
|
671
671
|
// TASWM-565 · шаг 1 из четырёх: провайдер в реестре ЕСТЬ, выбрать его ещё нельзя.
|
|
672
672
|
// Имён моделей здесь нет СОЗНАТЕЛЬНО: у владельца подписка, состав моделей в ней нам
|
|
@@ -1277,6 +1277,9 @@ var init_cost = __esm({
|
|
|
1277
1277
|
});
|
|
1278
1278
|
|
|
1279
1279
|
// ../swarm-core/src/modelPricing.ts
|
|
1280
|
+
function cacheReadFactorOf(pricing) {
|
|
1281
|
+
return pricing.cacheReadFactor ?? CACHE_READ_FACTOR;
|
|
1282
|
+
}
|
|
1280
1283
|
function findModelPricing(model, table = MODEL_PRICING) {
|
|
1281
1284
|
if (!model) return void 0;
|
|
1282
1285
|
const exact = table[model];
|
|
@@ -1298,6 +1301,10 @@ var init_modelPricing = __esm({
|
|
|
1298
1301
|
// и «почему прогон вчера стоил иначе» приходится выяснять по коду, а не по таблице.
|
|
1299
1302
|
// Меняется цена — меняется строка, одним видимым коммитом.
|
|
1300
1303
|
"claude-sonnet-5": { inputPerMTok: 2, outputPerMTok: 10 },
|
|
1304
|
+
// Opus 5.5 — 4/20, и чтение из кеша у него 5 % входа ($0.20), а не обычные 10 %.
|
|
1305
|
+
// У дронов чтение из кеша — основная часть токенов: с общим множителем прогон на
|
|
1306
|
+
// Opus 5.5 стоил бы в расчёте почти вдвое больше настоящего.
|
|
1307
|
+
"claude-opus-5-5": { inputPerMTok: 4, outputPerMTok: 20, cacheReadFactor: 0.05 },
|
|
1301
1308
|
"claude-opus-5": { inputPerMTok: 5, outputPerMTok: 25 },
|
|
1302
1309
|
"claude-fable-5": { inputPerMTok: 10, outputPerMTok: 50 },
|
|
1303
1310
|
// Прогоны и вызовы на 4.x остаются в истории — строки держим ради их стоимости.
|
|
@@ -2168,7 +2175,7 @@ function costFromUsage(usage, model, table = MODEL_PRICING) {
|
|
|
2168
2175
|
const output = usage.output_tokens ?? 0;
|
|
2169
2176
|
const cacheWrite = usage.cache_creation_input_tokens ?? 0;
|
|
2170
2177
|
const cacheRead = usage.cache_read_input_tokens ?? 0;
|
|
2171
|
-
const costUsd = (input * pricing.inputPerMTok + output * pricing.outputPerMTok + cacheWrite * pricing.inputPerMTok * CACHE_WRITE_5M_FACTOR + cacheRead * pricing.inputPerMTok *
|
|
2178
|
+
const costUsd = (input * pricing.inputPerMTok + output * pricing.outputPerMTok + cacheWrite * pricing.inputPerMTok * CACHE_WRITE_5M_FACTOR + cacheRead * pricing.inputPerMTok * cacheReadFactorOf(pricing)) / 1e6;
|
|
2172
2179
|
return { costUsd };
|
|
2173
2180
|
}
|
|
2174
2181
|
var init_pricing = __esm({
|
|
@@ -3480,6 +3487,18 @@ var init_zoneNotes = __esm({
|
|
|
3480
3487
|
}
|
|
3481
3488
|
});
|
|
3482
3489
|
|
|
3490
|
+
// src/store.ts
|
|
3491
|
+
function isCleanResolve(run) {
|
|
3492
|
+
return (run.stop_reason ?? "").includes(RESOLVE_CLEAN_MARK);
|
|
3493
|
+
}
|
|
3494
|
+
var RESOLVE_CLEAN_MARK;
|
|
3495
|
+
var init_store = __esm({
|
|
3496
|
+
"src/store.ts"() {
|
|
3497
|
+
"use strict";
|
|
3498
|
+
RESOLVE_CLEAN_MARK = "\u0447\u0438\u0441\u0442\u043E\u0435 \u0432\u043B\u0438\u0432\u0430\u043D\u0438\u0435 \u0431\u0430\u0437\u044B";
|
|
3499
|
+
}
|
|
3500
|
+
});
|
|
3501
|
+
|
|
3483
3502
|
// src/agentToken.ts
|
|
3484
3503
|
import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, unlinkSync as unlinkSync2 } from "fs";
|
|
3485
3504
|
import { join as join8 } from "path";
|
|
@@ -6271,6 +6290,7 @@ var init_db = __esm({
|
|
|
6271
6290
|
init_names2();
|
|
6272
6291
|
init_zoneNotes();
|
|
6273
6292
|
init_storm();
|
|
6293
|
+
init_store();
|
|
6274
6294
|
init_src();
|
|
6275
6295
|
TERMINAL_SQL = TERMINAL_STATUSES.map((s) => `'${s}'`).join(",");
|
|
6276
6296
|
RESOLVER_TERMINAL_SQL = [...TERMINAL_STATUSES, "stalled"].map((s) => `'${s}'`).join(",");
|
|
@@ -6624,9 +6644,19 @@ CREATE TABLE IF NOT EXISTS imports (
|
|
|
6624
6644
|
).get(reviewRunId);
|
|
6625
6645
|
return row ? rowToRun(row) : null;
|
|
6626
6646
|
}
|
|
6627
|
-
/**
|
|
6647
|
+
/**
|
|
6648
|
+
* Сколько резолверов С ДРОНОМ уже поднимали на этот review-PR — потолок авто-попыток.
|
|
6649
|
+
*
|
|
6650
|
+
* TASWM-575: чистые вливания базы (RESOLVE_CLEAN_MARK в stop_reason — git свёл сам, дрон
|
|
6651
|
+
* не поднимался, стоимость ноль) в счёт НЕ идут. Потолок защищает от карусели ДРОНОВ на
|
|
6652
|
+
* нетривиальном конфликте (TASWM-127); бесплатное вливание не карусель, а на оживлённом
|
|
6653
|
+
* main оно случается на каждый чужой мерж — три сдвига main выбирали потолок, и PR с
|
|
6654
|
+
* отставшей базой застревал молча (гейт мержа не пускает base_stale, а вливать уже
|
|
6655
|
+
* некому). Всё остальное (failed/stalled резолверы, в т.ч. транзиентные сбои ОС) считается
|
|
6656
|
+
* как раньше — иначе потолок потерял бы смысл на органических смертях.
|
|
6657
|
+
*/
|
|
6628
6658
|
resolverCountFor(reviewRunId) {
|
|
6629
|
-
const row = this.db.prepare("SELECT COUNT(*) n FROM runs WHERE resolves_run_id = ?").get(reviewRunId);
|
|
6659
|
+
const row = this.db.prepare("SELECT COUNT(*) n FROM runs WHERE resolves_run_id = ? AND (stop_reason IS NULL OR stop_reason NOT LIKE ?)").get(reviewRunId, `%${RESOLVE_CLEAN_MARK}%`);
|
|
6630
6660
|
return row.n;
|
|
6631
6661
|
}
|
|
6632
6662
|
/**
|
|
@@ -7312,6 +7342,7 @@ function renderPendingRulesBlock(rules) {
|
|
|
7312
7342
|
|
|
7313
7343
|
// src/swarmClient.ts
|
|
7314
7344
|
init_zoneNotes();
|
|
7345
|
+
init_store();
|
|
7315
7346
|
init_toolFailure();
|
|
7316
7347
|
|
|
7317
7348
|
// src/logTail.ts
|
|
@@ -8061,8 +8092,10 @@ var SwarmClient = class _SwarmClient {
|
|
|
8061
8092
|
const cands = [...this.runs.values()].filter((r) => r.resolves_run_id === reviewRunId && !RESOLVER_TERMINAL.has(r.status)).sort((a, b) => b.id - a.id);
|
|
8062
8093
|
return cands.length ? this.mat(cands[0]) : null;
|
|
8063
8094
|
}
|
|
8095
|
+
// Потолок авто-попыток: чистые вливания базы (дрон не поднимался, стоимость ноль) не
|
|
8096
|
+
// считаются — см. db.ts:resolverCountFor и store.ts:RESOLVE_CLEAN_MARK (TASWM-575).
|
|
8064
8097
|
resolverCountFor(reviewRunId) {
|
|
8065
|
-
return [...this.runs.values()].filter((r) => r.resolves_run_id === reviewRunId).length;
|
|
8098
|
+
return [...this.runs.values()].filter((r) => r.resolves_run_id === reviewRunId && !isCleanResolve(r)).length;
|
|
8066
8099
|
}
|
|
8067
8100
|
// failed/stalled ревьюеры (сорвался спавн ДО вердикта) в счёт НЕ идут; stopped/superseded
|
|
8068
8101
|
// тоже (TASWM-253: оператор закрыл зомби-ревьюера/сбросил попытки ревью — POST /swarm/
|
|
@@ -9927,6 +9960,7 @@ function parseDecision(v) {
|
|
|
9927
9960
|
}
|
|
9928
9961
|
|
|
9929
9962
|
// src/overmind.ts
|
|
9963
|
+
init_store();
|
|
9930
9964
|
init_config();
|
|
9931
9965
|
init_heartbeat();
|
|
9932
9966
|
|
|
@@ -12359,7 +12393,7 @@ function parkReasonUnretriable(reason) {
|
|
|
12359
12393
|
// package.json
|
|
12360
12394
|
var package_default = {
|
|
12361
12395
|
name: "@taskless-app/swarm",
|
|
12362
|
-
version: "0.6.
|
|
12396
|
+
version: "0.6.49",
|
|
12363
12397
|
type: "module",
|
|
12364
12398
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
12365
12399
|
keywords: [
|
|
@@ -12410,7 +12444,7 @@ var package_default = {
|
|
|
12410
12444
|
execa: "^10.0.0",
|
|
12411
12445
|
zod: "3.25.76"
|
|
12412
12446
|
},
|
|
12413
|
-
gitHead: "
|
|
12447
|
+
gitHead: "27600667531d4f65761c74793e8c4ee4859dc8ae"
|
|
12414
12448
|
};
|
|
12415
12449
|
|
|
12416
12450
|
// src/version.ts
|
|
@@ -18150,6 +18184,8 @@ var EXITED_CONTINUE_NUDGE = "\u0422\u0432\u043E\u044F \u043F\u0440\u043E\u0448\u
|
|
|
18150
18184
|
var STORM_DEAD_LIMIT = Number(process.env.SWARM_STORM_DEAD_LIMIT) || 3;
|
|
18151
18185
|
var CONFLICT_RESOLVE_COOLDOWN_MS = Number(process.env.SWARM_CONFLICT_COOLDOWN_MS) || 3 * 60 * 1e3;
|
|
18152
18186
|
var RESOLVE_LIMIT = Number(process.env.SWARM_RESOLVE_LIMIT) || 3;
|
|
18187
|
+
var BASE_MERGED_MARK = "\u0431\u0430\u0437\u0430 \u0432\u043B\u0438\u0442\u0430 \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438";
|
|
18188
|
+
var BASE_NOOP_MARK = "\u0432\u043B\u0438\u0432\u0430\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E";
|
|
18153
18189
|
var REVIEW_SPAWN_LIMIT = Number(process.env.SWARM_REVIEW_SPAWN_LIMIT) || 3;
|
|
18154
18190
|
var REVIEW_CYCLE_LIMIT = Number(process.env.SWARM_REVIEW_CYCLE_LIMIT) || 3;
|
|
18155
18191
|
var CI_WAKE_LIMIT = Number(process.env.SWARM_CI_WAKE_LIMIT) || 3;
|
|
@@ -18231,10 +18267,17 @@ function lastConflictAttemptMs(db, runId) {
|
|
|
18231
18267
|
if (!evs.length) return null;
|
|
18232
18268
|
return Date.parse(evs[evs.length - 1].at.replace(" ", "T") + "Z");
|
|
18233
18269
|
}
|
|
18270
|
+
function lastBaseMergeWasNoop(db, runId) {
|
|
18271
|
+
const outcomes = db.events(runId).filter((e) => e.kind === "conflict" && ((e.text ?? "").includes(BASE_NOOP_MARK) || (e.text ?? "").includes(BASE_MERGED_MARK)));
|
|
18272
|
+
return (outcomes[outcomes.length - 1]?.text ?? "").includes(BASE_NOOP_MARK);
|
|
18273
|
+
}
|
|
18274
|
+
function resolveEscalated(db, runId) {
|
|
18275
|
+
return db.events(runId).some((e) => e.kind === "conflict" && (e.text ?? "").includes(RESOLVE_ESCALATION_MARK));
|
|
18276
|
+
}
|
|
18234
18277
|
async function needsBaseRefreshNow(deps, run, stormActive, now) {
|
|
18235
18278
|
if (!deps.mergeQueue || !deps.resolveConflict || stormActive) return false;
|
|
18236
18279
|
if (deps.db.activeResolverFor(run.id)) return false;
|
|
18237
|
-
if (deps.db
|
|
18280
|
+
if (resolveEscalated(deps.db, run.id)) return false;
|
|
18238
18281
|
const last = lastConflictAttemptMs(deps.db, run.id);
|
|
18239
18282
|
if (last != null && now - last < CONFLICT_RESOLVE_COOLDOWN_MS) return false;
|
|
18240
18283
|
return needsBaseRefresh(await deps.mergeQueue(run).catch(() => null));
|
|
@@ -20899,16 +20942,30 @@ async function tickOnce(deps) {
|
|
|
20899
20942
|
await retireOutdatedReviewers(deps, run);
|
|
20900
20943
|
const baseStale = !st.conflicting && await needsBaseRefreshNow(deps, run, stormActive, now);
|
|
20901
20944
|
if ((st.conflicting || baseStale) && deps.resolveConflict && !stormActive) {
|
|
20902
|
-
if (deps.resourcesOk && !deps.resourcesOk()) continue;
|
|
20903
|
-
if (countActiveDrones(deps.db) >= droneCap) continue;
|
|
20904
|
-
if (!await projectQuotaGateAllows(deps, run)) continue;
|
|
20905
20945
|
if (deps.db.activeResolverFor(run.id)) continue;
|
|
20906
20946
|
if (deps.db.resolverCountFor(run.id) >= RESOLVE_LIMIT) {
|
|
20907
|
-
if (!deps.db
|
|
20908
|
-
deps.db.addEvent(
|
|
20947
|
+
if (!resolveEscalated(deps.db, run.id)) {
|
|
20948
|
+
deps.db.addEvent(
|
|
20949
|
+
run.id,
|
|
20950
|
+
"conflict",
|
|
20951
|
+
st.conflicting ? `${RESOLVE_ESCALATION_MARK}: \u0430\u0432\u0442\u043E-\u0440\u0435\u0437\u043E\u043B\u0432\u0435\u0440 \u043D\u0435 \u0441\u043F\u0440\u0430\u0432\u0438\u043B\u0441\u044F \u0437\u0430 ${RESOLVE_LIMIT} \u043F\u043E\u043F\u044B\u0442(\u043E\u043A) \u2014 \u043D\u0443\u0436\u0435\u043D \u0447\u0435\u043B\u043E\u0432\u0435\u043A` : `${RESOLVE_ESCALATION_MARK}: \u0431\u0430\u0437\u0430 \u043F\u043E\u0434 PR \u0443\u0435\u0445\u0430\u043B\u0430 \u0432\u043F\u0435\u0440\u0451\u0434, \u0430 \u043F\u043E\u0442\u043E\u043B\u043E\u043A \u0430\u0432\u0442\u043E-\u0440\u0435\u0437\u043E\u043B\u0432\u0435\u0440\u043E\u0432 (${RESOLVE_LIMIT}) \u0438\u0441\u0447\u0435\u0440\u043F\u0430\u043D \u2014 \u0432\u043B\u0438\u0442\u044C \u0431\u0430\u0437\u0443 \u0434\u043E\u043B\u0436\u0435\u043D \u0447\u0435\u043B\u043E\u0432\u0435\u043A`
|
|
20952
|
+
);
|
|
20909
20953
|
}
|
|
20910
20954
|
continue;
|
|
20911
20955
|
}
|
|
20956
|
+
if (baseStale && lastBaseMergeWasNoop(deps.db, run.id)) {
|
|
20957
|
+
if (!resolveEscalated(deps.db, run.id)) {
|
|
20958
|
+
deps.db.addEvent(
|
|
20959
|
+
run.id,
|
|
20960
|
+
"conflict",
|
|
20961
|
+
`${RESOLVE_ESCALATION_MARK}: \u043E\u0447\u0435\u0440\u0435\u0434\u044C \u043C\u0435\u0440\u0436\u0430 \u0441\u0447\u0438\u0442\u0430\u0435\u0442 \u0431\u0430\u0437\u0443 \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0435\u0439, \u0430 \u0432\u043B\u0438\u0432\u0430\u0442\u044C \u0432 \u0432\u0435\u0442\u043A\u0443 \u043D\u0435\u0447\u0435\u0433\u043E \u2014 \u0441\u0430\u043C\u0430 \u0441\u043E\u0431\u043E\u0439 \u0442\u0430\u043A\u0430\u044F \u0431\u0430\u0437\u0430 \u043D\u0435 \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u0441\u044F, \u043D\u0443\u0436\u0435\u043D \u0447\u0435\u043B\u043E\u0432\u0435\u043A`
|
|
20962
|
+
);
|
|
20963
|
+
}
|
|
20964
|
+
continue;
|
|
20965
|
+
}
|
|
20966
|
+
if (deps.resourcesOk && !deps.resourcesOk()) continue;
|
|
20967
|
+
if (countActiveDrones(deps.db) >= droneCap) continue;
|
|
20968
|
+
if (!await projectQuotaGateAllows(deps, run)) continue;
|
|
20912
20969
|
const last = lastConflictAttemptMs(deps.db, run.id);
|
|
20913
20970
|
if (last != null && now - last < CONFLICT_RESOLVE_COOLDOWN_MS) continue;
|
|
20914
20971
|
deps.db.addEvent(
|
|
@@ -21514,13 +21571,14 @@ async function resolveConflict(deps, reviewRun) {
|
|
|
21514
21571
|
if (m.changed) await deps.git.pushHeadTo(wt, branch);
|
|
21515
21572
|
await deps.git.removeWorktree(repo, wt).catch(() => {
|
|
21516
21573
|
});
|
|
21517
|
-
|
|
21574
|
+
const cleanWhy = m.changed ? `\u0447\u0438\u0441\u0442\u044B\u0439 merge ${mainRef} \u2014 \u0434\u0440\u043E\u043D \u043D\u0435 \u043F\u043E\u043D\u0430\u0434\u043E\u0431\u0438\u043B\u0441\u044F` : `${mainRef} \u0443\u0436\u0435 \u0432\u043B\u0438\u0442 \u2014 \u043D\u0435\u0447\u0435\u0433\u043E \u0434\u0435\u043B\u0430\u0442\u044C`;
|
|
21575
|
+
deps.db.updateRun(resolver.id, { status: "done", stop_reason: `${RESOLVE_CLEAN_MARK}: ${cleanWhy}` });
|
|
21576
|
+
deps.db.addEvent(resolver.id, "done", cleanWhy);
|
|
21518
21577
|
deps.db.addEvent(
|
|
21519
|
-
|
|
21520
|
-
"
|
|
21521
|
-
m.changed ?
|
|
21578
|
+
reviewRun.id,
|
|
21579
|
+
"conflict",
|
|
21580
|
+
m.changed ? `${BASE_MERGED_MARK} (${mainRef}, \u0431\u0435\u0437 \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442\u043E\u0432) \u2014 PR \u043E\u0431\u043D\u043E\u0432\u043B\u0451\u043D` : `${mainRef} \u0443\u0436\u0435 \u0432 \u0432\u0435\u0442\u043A\u0435 \u2014 ${BASE_NOOP_MARK}, \u0431\u0430\u0437\u0430 \u043E\u0442 \u044D\u0442\u043E\u0433\u043E \u043D\u0435 \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u0441\u044F`
|
|
21522
21581
|
);
|
|
21523
|
-
deps.db.addEvent(reviewRun.id, "conflict", `\u0431\u0430\u0437\u0430 \u0432\u043B\u0438\u0442\u0430 \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438 (${mainRef}, \u0431\u0435\u0437 \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442\u043E\u0432) \u2014 PR \u043E\u0431\u043D\u043E\u0432\u043B\u0451\u043D`);
|
|
21524
21582
|
} else {
|
|
21525
21583
|
const prompt = buildResolverPrompt(reviewRun, resolver, m.conflicts, branch, mainRef);
|
|
21526
21584
|
const pid = deps.launch({ worktree: wt, run: resolver, prompt });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taskless-app/swarm",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.49",
|
|
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": "27600667531d4f65761c74793e8c4ee4859dc8ae",
|
|
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",
|