@taskless-app/swarm 0.6.45 → 0.6.47
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 +55 -10
- package/dist/overmind.js +168 -17
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -123,7 +123,16 @@ var init_types = __esm({
|
|
|
123
123
|
// TASWM-412: дрон вернул сырую задачу автору (см. RunStatus "returned"). Веха, а не step:
|
|
124
124
|
// прогон на этом кончается, и в истории должно быть видно, что он кончился ВОЗВРАТОМ —
|
|
125
125
|
// иначе возврат читается как брошенная посреди работы задача.
|
|
126
|
-
"returned"
|
|
126
|
+
"returned",
|
|
127
|
+
// Одна находка ревьюера машиночитаемо (TASWM-561). text — JSON:
|
|
128
|
+
// { category, severity: "blocker" | "major" | "nit", path, line, what }.
|
|
129
|
+
// Одно событие = одна находка: только так их можно считать, фильтровать по severity
|
|
130
|
+
// и сводить по прогонам — текст вердикта на PR для этого разбирать нечем.
|
|
131
|
+
"finding",
|
|
132
|
+
// Как ревьюер вынес вердикт (TASWM-561): text = "ran" (тест прогнан) | "read" (судил
|
|
133
|
+
// чтением). Отдельный kind, а не поле находки: режим один на вердикт, а находок ноль
|
|
134
|
+
// или много — «проверено чтением» должно быть видно и когда не найдено ничего.
|
|
135
|
+
"review_mode"
|
|
127
136
|
];
|
|
128
137
|
MILESTONE_KINDS = [
|
|
129
138
|
"spawned",
|
|
@@ -652,15 +661,28 @@ function defaultModelFor(role, providerId = null) {
|
|
|
652
661
|
const provider = findProvider(providerId) ?? findProvider(DEFAULT_PROVIDER_ID);
|
|
653
662
|
return provider.roles[role];
|
|
654
663
|
}
|
|
655
|
-
var MODEL_PROVIDERS, DEFAULT_PROVIDER_ID;
|
|
664
|
+
var HARNESS_DEFAULT_MODEL, MODEL_PROVIDERS, DEFAULT_PROVIDER_ID;
|
|
656
665
|
var init_modelPolicy = __esm({
|
|
657
666
|
"../swarm-core/src/modelPolicy.ts"() {
|
|
658
667
|
"use strict";
|
|
668
|
+
HARNESS_DEFAULT_MODEL = "default";
|
|
659
669
|
MODEL_PROVIDERS = [
|
|
660
670
|
{
|
|
661
671
|
id: "anthropic",
|
|
662
672
|
label: "Anthropic",
|
|
673
|
+
executorId: "claude-code",
|
|
674
|
+
selectable: true,
|
|
663
675
|
roles: { executor: "claude-opus-5", review: "claude-sonnet-5" }
|
|
676
|
+
},
|
|
677
|
+
// TASWM-565 · шаг 1 из четырёх: провайдер в реестре ЕСТЬ, выбрать его ещё нельзя.
|
|
678
|
+
// Имён моделей здесь нет СОЗНАТЕЛЬНО: у владельца подписка, состав моделей в ней нам
|
|
679
|
+
// неизвестен, а выдуманное имя хуже маркера «решает Codex».
|
|
680
|
+
{
|
|
681
|
+
id: "openai",
|
|
682
|
+
label: "OpenAI (ChatGPT)",
|
|
683
|
+
executorId: "codex",
|
|
684
|
+
selectable: false,
|
|
685
|
+
roles: { executor: HARNESS_DEFAULT_MODEL, review: HARNESS_DEFAULT_MODEL }
|
|
664
686
|
}
|
|
665
687
|
];
|
|
666
688
|
DEFAULT_PROVIDER_ID = MODEL_PROVIDERS[0].id;
|
|
@@ -3390,7 +3412,7 @@ var init_package = __esm({
|
|
|
3390
3412
|
"package.json"() {
|
|
3391
3413
|
package_default = {
|
|
3392
3414
|
name: "@taskless-app/swarm",
|
|
3393
|
-
version: "0.6.
|
|
3415
|
+
version: "0.6.47",
|
|
3394
3416
|
type: "module",
|
|
3395
3417
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
3396
3418
|
keywords: [
|
|
@@ -3441,7 +3463,7 @@ var init_package = __esm({
|
|
|
3441
3463
|
execa: "^10.0.0",
|
|
3442
3464
|
zod: "3.25.76"
|
|
3443
3465
|
},
|
|
3444
|
-
gitHead: "
|
|
3466
|
+
gitHead: "561ecd5dfe7de7c9b1a106552bbef19921c65cbf"
|
|
3445
3467
|
};
|
|
3446
3468
|
}
|
|
3447
3469
|
});
|
|
@@ -7589,13 +7611,15 @@ var SwarmClient = class _SwarmClient {
|
|
|
7589
7611
|
const key = this.keyByLocal.get(localId);
|
|
7590
7612
|
if (key) out[prodKey] = runRef(key);
|
|
7591
7613
|
}
|
|
7592
|
-
enqueueRun(run, fields) {
|
|
7614
|
+
enqueueRun(run, fields, opts = {}) {
|
|
7593
7615
|
if (Object.keys(fields).length === 0) return;
|
|
7594
7616
|
this.enqueue({
|
|
7595
7617
|
t: "run",
|
|
7596
7618
|
runKey: run.runKey,
|
|
7597
7619
|
taskRef: run.task_slug,
|
|
7598
7620
|
...run.workspace_id ? { workspaceId: run.workspace_id } : {},
|
|
7621
|
+
create: opts.create === true,
|
|
7622
|
+
// TASWM-562: пометка есть у КАЖДОЙ новой записи — см. resolveArgs
|
|
7599
7623
|
fields
|
|
7600
7624
|
});
|
|
7601
7625
|
}
|
|
@@ -7710,7 +7734,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
7710
7734
|
// закрепление (TASWM-291): true только у явного --host
|
|
7711
7735
|
base_branch: d.base_branch
|
|
7712
7736
|
// базовая ветка PR (TASWM-285), если задана на спавне
|
|
7713
|
-
}));
|
|
7737
|
+
}), { create: true });
|
|
7714
7738
|
const spawnNote = input.resolves_run_id ? `\u0440\u0435\u0437\u043E\u043B\u0432\u0435\u0440 \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442\u0430 \u0434\u043B\u044F #${input.resolves_run_id}` : input.reviews_run_id ? `\u0440\u0435\u0432\u044C\u044E\u0435\u0440 \u0434\u043B\u044F #${input.reviews_run_id}` : input.verifies_run_id ? `\u0432\u0435\u0440\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u0434\u043B\u044F #${input.verifies_run_id}` : input.decision ? `\u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A \u0441 \u0440\u0435\u0448\u0435\u043D\u0438\u0435\u043C \xAB${input.decision.chosen}\xBB` : `run for ${input.task_slug}`;
|
|
7715
7739
|
this.addEvent(id, "spawned", spawnNote);
|
|
7716
7740
|
return this.mat(d);
|
|
@@ -7749,7 +7773,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
7749
7773
|
runLogKeys(id) {
|
|
7750
7774
|
const key = this.runs.get(id)?.runKey;
|
|
7751
7775
|
if (!key) return [];
|
|
7752
|
-
const prodId =
|
|
7776
|
+
const prodId = this.prodIdFor(key);
|
|
7753
7777
|
if (!prodId) return [key];
|
|
7754
7778
|
const canonical = `p:${prodId}`;
|
|
7755
7779
|
const aliases = [key, ...[...this.prodIdByKey.entries()].filter(([, v]) => v === prodId).map(([k]) => k)];
|
|
@@ -9487,11 +9511,31 @@ var SwarmClient = class _SwarmClient {
|
|
|
9487
9511
|
for (const [full, path] of this.repoPathByFullName) if (path === norm) return full;
|
|
9488
9512
|
return /^[^/\s]+\/[^/\s]+$/.test(repo) ? repo : void 0;
|
|
9489
9513
|
}
|
|
9514
|
+
/**
|
|
9515
|
+
* Прод-id прогона по его runKey — ЕДИНСТВЕННЫЙ резолв на пути флаша (TASWM-562) и
|
|
9516
|
+
* в адресах run-лога (runLogKeys). Гидрированный прогон несёт cuid прямо в ключе
|
|
9517
|
+
* (`p:<cuid>`, см. hydrateRun). Карта prodIdByKey ему не подмога: в сайдкар она пишется
|
|
9518
|
+
* только после успешного create-флаша (persistMap), а прогон, РОЖДЁННЫЙ в проде
|
|
9519
|
+
* (claim/hydrate), туда не попадает никогда. Отсюда и брались пустые парные строки:
|
|
9520
|
+
* после рестарта демона recover() планирует флаш ДО первой гидрации, карта пуста —
|
|
9521
|
+
* и лежащий в outbox патч («прогон перешёл в done») заводил в проде второй прогон,
|
|
9522
|
+
* без токенов, цены, времени и PR.
|
|
9523
|
+
*/
|
|
9524
|
+
prodIdFor(runKey) {
|
|
9525
|
+
return runKey.startsWith("p:") ? runKey.slice(2) : this.prodIdByKey.get(runKey);
|
|
9526
|
+
}
|
|
9490
9527
|
async resolveArgs(e) {
|
|
9491
9528
|
if (e.t === "run") {
|
|
9492
9529
|
const fields = this.materializeRefs(e.fields);
|
|
9493
|
-
const prodId2 = this.
|
|
9530
|
+
const prodId2 = this.prodIdFor(e.runKey);
|
|
9494
9531
|
if (prodId2) return { tool: "swarm_run_upsert", args: { runId: prodId2, ...fields } };
|
|
9532
|
+
if (e.create === false) {
|
|
9533
|
+
console.error(
|
|
9534
|
+
`[swarm-client] \u043F\u0430\u0442\u0447 \u043F\u0440\u043E\u0433\u043E\u043D\u0430 \u0432\u044B\u0431\u0440\u043E\u0448\u0435\u043D: \u043F\u0440\u043E\u0434-id \u0434\u043B\u044F runKey=${e.runKey} \u043D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043D, \u0430 \u0437\u0430\u0432\u043E\u0434\u0438\u0442\u044C \u043F\u0440\u043E\u0433\u043E\u043D \u0437\u0430\u043D\u043E\u0432\u043E \u043F\u0430\u0442\u0447 \u043D\u0435 \u0432\u043F\u0440\u0430\u0432\u0435 (\u0438\u043D\u0430\u0447\u0435 \u0432 \u043F\u0440\u043E\u0434\u0435 \u043F\u043E\u044F\u0432\u0438\u0442\u0441\u044F \u043F\u0443\u0441\u0442\u043E\u0439 \u0434\u0432\u043E\u0439\u043D\u0438\u043A). \u041F\u043E\u043B\u044F: ${Object.keys(fields).join(", ")}`
|
|
9535
|
+
);
|
|
9536
|
+
this.poisonedRunKeys.add(e.runKey);
|
|
9537
|
+
return "skip";
|
|
9538
|
+
}
|
|
9495
9539
|
const taskId = await this.resolveTaskCuid(e.taskRef, this.repoFullNameFor(fields.repo), e.workspaceId);
|
|
9496
9540
|
if (taskId === "transient") {
|
|
9497
9541
|
throw new Error(`slug\u2192cuid \u0434\u043B\u044F \xAB${e.taskRef}\xBB \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D (\u043F\u0440\u043E\u0434 \u043C\u043E\u0440\u0433\u043D\u0443\u043B) \u2014 retry`);
|
|
@@ -9509,7 +9553,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
9509
9553
|
console.error(`[swarm-client] ${e.t}-\u0444\u043B\u0430\u0448 \u043F\u0440\u043E\u043F\u0443\u0449\u0435\u043D: create \u043F\u0440\u043E\u0433\u043E\u043D\u0430 runKey=${e.runKey} \u043D\u0435 \u0440\u0435\u0437\u043E\u043B\u0432\u0438\u043B\u0441\u044F \u0440\u0430\u043D\u0435\u0435 \u2014 \u0437\u0430\u043F\u0438\u0441\u044C \u0432\u044B\u0431\u0440\u043E\u0448\u0435\u043D\u0430 \u0438\u0437 outbox`);
|
|
9510
9554
|
return "skip";
|
|
9511
9555
|
}
|
|
9512
|
-
const prodId = this.
|
|
9556
|
+
const prodId = this.prodIdFor(e.runKey);
|
|
9513
9557
|
if (!prodId) throw new Error(`\u043D\u0435\u0442 prod-id \u0434\u043B\u044F ${e.runKey} \u2014 \u043F\u0440\u043E\u0433\u043E\u043D \u0435\u0449\u0451 \u043D\u0435 \u0441\u043E\u0437\u0434\u0430\u043D \u0432 \u043F\u0440\u043E\u0434\u0435`);
|
|
9514
9558
|
if (e.t === "event") return { tool: "swarm_event_append", args: { runId: prodId, kind: e.kind, text: e.text, actor: e.actor } };
|
|
9515
9559
|
return { tool: "swarm_ask", args: { runId: prodId, text: e.text } };
|
|
@@ -9522,7 +9566,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
9522
9566
|
const out = {};
|
|
9523
9567
|
for (const [k, v] of Object.entries(fields)) {
|
|
9524
9568
|
if (isRunRef(v)) {
|
|
9525
|
-
const cuid = this.
|
|
9569
|
+
const cuid = this.prodIdFor(v.__runRef);
|
|
9526
9570
|
if (cuid) out[k] = cuid;
|
|
9527
9571
|
} else {
|
|
9528
9572
|
out[k] = v;
|
|
@@ -9562,6 +9606,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
9562
9606
|
if (tries >= _SwarmClient.REJECT_LIMIT) {
|
|
9563
9607
|
this.pending.shift();
|
|
9564
9608
|
this.rejected.delete(e.seq);
|
|
9609
|
+
if (e.t === "run" && e.create === true) this.poisonedRunKeys.add(e.runKey);
|
|
9565
9610
|
console.error(
|
|
9566
9611
|
`[swarm-client] \u043F\u0440\u043E\u0434 \u043E\u0442\u0432\u0435\u0440\u0433 ${call.tool} ${tries} \u0440\u0430\u0437(\u0430) \u2014 \u0412\u042B\u0411\u0420\u0410\u0421\u042B\u0412\u0410\u042E \u044D\u0442\u0443 \u0437\u0430\u043F\u0438\u0441\u044C, \u0438\u043D\u0430\u0447\u0435 \u043E\u043D\u0430 \u0434\u0435\u0440\u0436\u0438\u0442 \u0432\u0441\u044E \u043E\u0447\u0435\u0440\u0435\u0434\u044C. \u041F\u043E\u0442\u0435\u0440\u044F\u043D\u043E: ${e.t}${e.t === "event" ? ` (${e.kind})` : ""}. \u041F\u0440\u0438\u0447\u0438\u043D\u0430 \u043E\u0442\u043A\u0430\u0437\u0430: ${reason}`
|
|
9567
9612
|
);
|
package/dist/overmind.js
CHANGED
|
@@ -92,7 +92,16 @@ var init_types = __esm({
|
|
|
92
92
|
// TASWM-412: дрон вернул сырую задачу автору (см. RunStatus "returned"). Веха, а не step:
|
|
93
93
|
// прогон на этом кончается, и в истории должно быть видно, что он кончился ВОЗВРАТОМ —
|
|
94
94
|
// иначе возврат читается как брошенная посреди работы задача.
|
|
95
|
-
"returned"
|
|
95
|
+
"returned",
|
|
96
|
+
// Одна находка ревьюера машиночитаемо (TASWM-561). text — JSON:
|
|
97
|
+
// { category, severity: "blocker" | "major" | "nit", path, line, what }.
|
|
98
|
+
// Одно событие = одна находка: только так их можно считать, фильтровать по severity
|
|
99
|
+
// и сводить по прогонам — текст вердикта на PR для этого разбирать нечем.
|
|
100
|
+
"finding",
|
|
101
|
+
// Как ревьюер вынес вердикт (TASWM-561): text = "ran" (тест прогнан) | "read" (судил
|
|
102
|
+
// чтением). Отдельный kind, а не поле находки: режим один на вердикт, а находок ноль
|
|
103
|
+
// или много — «проверено чтением» должно быть видно и когда не найдено ничего.
|
|
104
|
+
"review_mode"
|
|
96
105
|
];
|
|
97
106
|
MILESTONE_KINDS = [
|
|
98
107
|
"spawned",
|
|
@@ -646,15 +655,28 @@ function defaultModelFor(role, providerId = null) {
|
|
|
646
655
|
const provider = findProvider(providerId) ?? findProvider(DEFAULT_PROVIDER_ID);
|
|
647
656
|
return provider.roles[role];
|
|
648
657
|
}
|
|
649
|
-
var MODEL_PROVIDERS, DEFAULT_PROVIDER_ID;
|
|
658
|
+
var HARNESS_DEFAULT_MODEL, MODEL_PROVIDERS, DEFAULT_PROVIDER_ID;
|
|
650
659
|
var init_modelPolicy = __esm({
|
|
651
660
|
"../swarm-core/src/modelPolicy.ts"() {
|
|
652
661
|
"use strict";
|
|
662
|
+
HARNESS_DEFAULT_MODEL = "default";
|
|
653
663
|
MODEL_PROVIDERS = [
|
|
654
664
|
{
|
|
655
665
|
id: "anthropic",
|
|
656
666
|
label: "Anthropic",
|
|
667
|
+
executorId: "claude-code",
|
|
668
|
+
selectable: true,
|
|
657
669
|
roles: { executor: "claude-opus-5", review: "claude-sonnet-5" }
|
|
670
|
+
},
|
|
671
|
+
// TASWM-565 · шаг 1 из четырёх: провайдер в реестре ЕСТЬ, выбрать его ещё нельзя.
|
|
672
|
+
// Имён моделей здесь нет СОЗНАТЕЛЬНО: у владельца подписка, состав моделей в ней нам
|
|
673
|
+
// неизвестен, а выдуманное имя хуже маркера «решает Codex».
|
|
674
|
+
{
|
|
675
|
+
id: "openai",
|
|
676
|
+
label: "OpenAI (ChatGPT)",
|
|
677
|
+
executorId: "codex",
|
|
678
|
+
selectable: false,
|
|
679
|
+
roles: { executor: HARNESS_DEFAULT_MODEL, review: HARNESS_DEFAULT_MODEL }
|
|
658
680
|
}
|
|
659
681
|
];
|
|
660
682
|
DEFAULT_PROVIDER_ID = MODEL_PROVIDERS[0].id;
|
|
@@ -7827,13 +7849,15 @@ var SwarmClient = class _SwarmClient {
|
|
|
7827
7849
|
const key = this.keyByLocal.get(localId);
|
|
7828
7850
|
if (key) out[prodKey] = runRef(key);
|
|
7829
7851
|
}
|
|
7830
|
-
enqueueRun(run, fields) {
|
|
7852
|
+
enqueueRun(run, fields, opts = {}) {
|
|
7831
7853
|
if (Object.keys(fields).length === 0) return;
|
|
7832
7854
|
this.enqueue({
|
|
7833
7855
|
t: "run",
|
|
7834
7856
|
runKey: run.runKey,
|
|
7835
7857
|
taskRef: run.task_slug,
|
|
7836
7858
|
...run.workspace_id ? { workspaceId: run.workspace_id } : {},
|
|
7859
|
+
create: opts.create === true,
|
|
7860
|
+
// TASWM-562: пометка есть у КАЖДОЙ новой записи — см. resolveArgs
|
|
7837
7861
|
fields
|
|
7838
7862
|
});
|
|
7839
7863
|
}
|
|
@@ -7948,7 +7972,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
7948
7972
|
// закрепление (TASWM-291): true только у явного --host
|
|
7949
7973
|
base_branch: d.base_branch
|
|
7950
7974
|
// базовая ветка PR (TASWM-285), если задана на спавне
|
|
7951
|
-
}));
|
|
7975
|
+
}), { create: true });
|
|
7952
7976
|
const spawnNote = input.resolves_run_id ? `\u0440\u0435\u0437\u043E\u043B\u0432\u0435\u0440 \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442\u0430 \u0434\u043B\u044F #${input.resolves_run_id}` : input.reviews_run_id ? `\u0440\u0435\u0432\u044C\u044E\u0435\u0440 \u0434\u043B\u044F #${input.reviews_run_id}` : input.verifies_run_id ? `\u0432\u0435\u0440\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u0434\u043B\u044F #${input.verifies_run_id}` : input.decision ? `\u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A \u0441 \u0440\u0435\u0448\u0435\u043D\u0438\u0435\u043C \xAB${input.decision.chosen}\xBB` : `run for ${input.task_slug}`;
|
|
7953
7977
|
this.addEvent(id, "spawned", spawnNote);
|
|
7954
7978
|
return this.mat(d);
|
|
@@ -7987,7 +8011,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
7987
8011
|
runLogKeys(id) {
|
|
7988
8012
|
const key = this.runs.get(id)?.runKey;
|
|
7989
8013
|
if (!key) return [];
|
|
7990
|
-
const prodId =
|
|
8014
|
+
const prodId = this.prodIdFor(key);
|
|
7991
8015
|
if (!prodId) return [key];
|
|
7992
8016
|
const canonical = `p:${prodId}`;
|
|
7993
8017
|
const aliases = [key, ...[...this.prodIdByKey.entries()].filter(([, v]) => v === prodId).map(([k]) => k)];
|
|
@@ -9725,11 +9749,31 @@ var SwarmClient = class _SwarmClient {
|
|
|
9725
9749
|
for (const [full, path] of this.repoPathByFullName) if (path === norm) return full;
|
|
9726
9750
|
return /^[^/\s]+\/[^/\s]+$/.test(repo) ? repo : void 0;
|
|
9727
9751
|
}
|
|
9752
|
+
/**
|
|
9753
|
+
* Прод-id прогона по его runKey — ЕДИНСТВЕННЫЙ резолв на пути флаша (TASWM-562) и
|
|
9754
|
+
* в адресах run-лога (runLogKeys). Гидрированный прогон несёт cuid прямо в ключе
|
|
9755
|
+
* (`p:<cuid>`, см. hydrateRun). Карта prodIdByKey ему не подмога: в сайдкар она пишется
|
|
9756
|
+
* только после успешного create-флаша (persistMap), а прогон, РОЖДЁННЫЙ в проде
|
|
9757
|
+
* (claim/hydrate), туда не попадает никогда. Отсюда и брались пустые парные строки:
|
|
9758
|
+
* после рестарта демона recover() планирует флаш ДО первой гидрации, карта пуста —
|
|
9759
|
+
* и лежащий в outbox патч («прогон перешёл в done») заводил в проде второй прогон,
|
|
9760
|
+
* без токенов, цены, времени и PR.
|
|
9761
|
+
*/
|
|
9762
|
+
prodIdFor(runKey) {
|
|
9763
|
+
return runKey.startsWith("p:") ? runKey.slice(2) : this.prodIdByKey.get(runKey);
|
|
9764
|
+
}
|
|
9728
9765
|
async resolveArgs(e) {
|
|
9729
9766
|
if (e.t === "run") {
|
|
9730
9767
|
const fields = this.materializeRefs(e.fields);
|
|
9731
|
-
const prodId2 = this.
|
|
9768
|
+
const prodId2 = this.prodIdFor(e.runKey);
|
|
9732
9769
|
if (prodId2) return { tool: "swarm_run_upsert", args: { runId: prodId2, ...fields } };
|
|
9770
|
+
if (e.create === false) {
|
|
9771
|
+
console.error(
|
|
9772
|
+
`[swarm-client] \u043F\u0430\u0442\u0447 \u043F\u0440\u043E\u0433\u043E\u043D\u0430 \u0432\u044B\u0431\u0440\u043E\u0448\u0435\u043D: \u043F\u0440\u043E\u0434-id \u0434\u043B\u044F runKey=${e.runKey} \u043D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043D, \u0430 \u0437\u0430\u0432\u043E\u0434\u0438\u0442\u044C \u043F\u0440\u043E\u0433\u043E\u043D \u0437\u0430\u043D\u043E\u0432\u043E \u043F\u0430\u0442\u0447 \u043D\u0435 \u0432\u043F\u0440\u0430\u0432\u0435 (\u0438\u043D\u0430\u0447\u0435 \u0432 \u043F\u0440\u043E\u0434\u0435 \u043F\u043E\u044F\u0432\u0438\u0442\u0441\u044F \u043F\u0443\u0441\u0442\u043E\u0439 \u0434\u0432\u043E\u0439\u043D\u0438\u043A). \u041F\u043E\u043B\u044F: ${Object.keys(fields).join(", ")}`
|
|
9773
|
+
);
|
|
9774
|
+
this.poisonedRunKeys.add(e.runKey);
|
|
9775
|
+
return "skip";
|
|
9776
|
+
}
|
|
9733
9777
|
const taskId = await this.resolveTaskCuid(e.taskRef, this.repoFullNameFor(fields.repo), e.workspaceId);
|
|
9734
9778
|
if (taskId === "transient") {
|
|
9735
9779
|
throw new Error(`slug\u2192cuid \u0434\u043B\u044F \xAB${e.taskRef}\xBB \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D (\u043F\u0440\u043E\u0434 \u043C\u043E\u0440\u0433\u043D\u0443\u043B) \u2014 retry`);
|
|
@@ -9747,7 +9791,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
9747
9791
|
console.error(`[swarm-client] ${e.t}-\u0444\u043B\u0430\u0448 \u043F\u0440\u043E\u043F\u0443\u0449\u0435\u043D: create \u043F\u0440\u043E\u0433\u043E\u043D\u0430 runKey=${e.runKey} \u043D\u0435 \u0440\u0435\u0437\u043E\u043B\u0432\u0438\u043B\u0441\u044F \u0440\u0430\u043D\u0435\u0435 \u2014 \u0437\u0430\u043F\u0438\u0441\u044C \u0432\u044B\u0431\u0440\u043E\u0448\u0435\u043D\u0430 \u0438\u0437 outbox`);
|
|
9748
9792
|
return "skip";
|
|
9749
9793
|
}
|
|
9750
|
-
const prodId = this.
|
|
9794
|
+
const prodId = this.prodIdFor(e.runKey);
|
|
9751
9795
|
if (!prodId) throw new Error(`\u043D\u0435\u0442 prod-id \u0434\u043B\u044F ${e.runKey} \u2014 \u043F\u0440\u043E\u0433\u043E\u043D \u0435\u0449\u0451 \u043D\u0435 \u0441\u043E\u0437\u0434\u0430\u043D \u0432 \u043F\u0440\u043E\u0434\u0435`);
|
|
9752
9796
|
if (e.t === "event") return { tool: "swarm_event_append", args: { runId: prodId, kind: e.kind, text: e.text, actor: e.actor } };
|
|
9753
9797
|
return { tool: "swarm_ask", args: { runId: prodId, text: e.text } };
|
|
@@ -9760,7 +9804,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
9760
9804
|
const out = {};
|
|
9761
9805
|
for (const [k, v] of Object.entries(fields)) {
|
|
9762
9806
|
if (isRunRef(v)) {
|
|
9763
|
-
const cuid = this.
|
|
9807
|
+
const cuid = this.prodIdFor(v.__runRef);
|
|
9764
9808
|
if (cuid) out[k] = cuid;
|
|
9765
9809
|
} else {
|
|
9766
9810
|
out[k] = v;
|
|
@@ -9800,6 +9844,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
9800
9844
|
if (tries >= _SwarmClient.REJECT_LIMIT) {
|
|
9801
9845
|
this.pending.shift();
|
|
9802
9846
|
this.rejected.delete(e.seq);
|
|
9847
|
+
if (e.t === "run" && e.create === true) this.poisonedRunKeys.add(e.runKey);
|
|
9803
9848
|
console.error(
|
|
9804
9849
|
`[swarm-client] \u043F\u0440\u043E\u0434 \u043E\u0442\u0432\u0435\u0440\u0433 ${call.tool} ${tries} \u0440\u0430\u0437(\u0430) \u2014 \u0412\u042B\u0411\u0420\u0410\u0421\u042B\u0412\u0410\u042E \u044D\u0442\u0443 \u0437\u0430\u043F\u0438\u0441\u044C, \u0438\u043D\u0430\u0447\u0435 \u043E\u043D\u0430 \u0434\u0435\u0440\u0436\u0438\u0442 \u0432\u0441\u044E \u043E\u0447\u0435\u0440\u0435\u0434\u044C. \u041F\u043E\u0442\u0435\u0440\u044F\u043D\u043E: ${e.t}${e.t === "event" ? ` (${e.kind})` : ""}. \u041F\u0440\u0438\u0447\u0438\u043D\u0430 \u043E\u0442\u043A\u0430\u0437\u0430: ${reason}`
|
|
9805
9850
|
);
|
|
@@ -12314,7 +12359,7 @@ function parkReasonUnretriable(reason) {
|
|
|
12314
12359
|
// package.json
|
|
12315
12360
|
var package_default = {
|
|
12316
12361
|
name: "@taskless-app/swarm",
|
|
12317
|
-
version: "0.6.
|
|
12362
|
+
version: "0.6.47",
|
|
12318
12363
|
type: "module",
|
|
12319
12364
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
12320
12365
|
keywords: [
|
|
@@ -12365,7 +12410,7 @@ var package_default = {
|
|
|
12365
12410
|
execa: "^10.0.0",
|
|
12366
12411
|
zod: "3.25.76"
|
|
12367
12412
|
},
|
|
12368
|
-
gitHead: "
|
|
12413
|
+
gitHead: "561ecd5dfe7de7c9b1a106552bbef19921c65cbf"
|
|
12369
12414
|
};
|
|
12370
12415
|
|
|
12371
12416
|
// src/version.ts
|
|
@@ -12741,6 +12786,70 @@ async function closePR(prUrl, run = realRunner) {
|
|
|
12741
12786
|
async function postPrComment(prUrl, body, run = realRunner) {
|
|
12742
12787
|
await run(["pr", "comment", prUrl, "--body", body]);
|
|
12743
12788
|
}
|
|
12789
|
+
var FINDING_CATEGORIES = [
|
|
12790
|
+
"correctness",
|
|
12791
|
+
"security",
|
|
12792
|
+
"reuse",
|
|
12793
|
+
"boundaries",
|
|
12794
|
+
"over-abstraction",
|
|
12795
|
+
"duplication",
|
|
12796
|
+
"spine",
|
|
12797
|
+
"tests",
|
|
12798
|
+
"ui-rules"
|
|
12799
|
+
];
|
|
12800
|
+
var FINDING_SEVERITIES = ["blocker", "major", "nit"];
|
|
12801
|
+
var FINDINGS_BLOCK_RE = /```findings[^\n]*\n([\s\S]*?)```/gi;
|
|
12802
|
+
var READ_ONLY_PHRASE_RE = /прогнать не мог|окружения нет/i;
|
|
12803
|
+
var FINDING_WHAT_MAX = 400;
|
|
12804
|
+
var FINDING_PATH_MAX = 300;
|
|
12805
|
+
var FINDINGS_MAX = 50;
|
|
12806
|
+
function oneOf(dict, v) {
|
|
12807
|
+
return typeof v === "string" && dict.includes(v) ? v : null;
|
|
12808
|
+
}
|
|
12809
|
+
function normalizeFinding(raw) {
|
|
12810
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
12811
|
+
const r = raw;
|
|
12812
|
+
const what = typeof r.what === "string" ? r.what.trim().slice(0, FINDING_WHAT_MAX) : "";
|
|
12813
|
+
if (!what) return null;
|
|
12814
|
+
const rawLine = typeof r.line === "number" ? r.line : typeof r.line === "string" && r.line.trim() ? Number(r.line) : NaN;
|
|
12815
|
+
return {
|
|
12816
|
+
category: oneOf(FINDING_CATEGORIES, r.category),
|
|
12817
|
+
severity: oneOf(FINDING_SEVERITIES, r.severity),
|
|
12818
|
+
path: typeof r.path === "string" && r.path.trim() ? r.path.trim().slice(0, FINDING_PATH_MAX) : null,
|
|
12819
|
+
// Номер строки — только целый положительный: «7.5», «-1» и NaN значат, что ревьюер
|
|
12820
|
+
// строку не знал, а не что дефект на строке −1 (по такому числу потом ищут в файле).
|
|
12821
|
+
line: Number.isInteger(rawLine) && rawLine > 0 ? rawLine : null,
|
|
12822
|
+
what
|
|
12823
|
+
};
|
|
12824
|
+
}
|
|
12825
|
+
function parseFindingsBlock(body) {
|
|
12826
|
+
const byPhrase = READ_ONLY_PHRASE_RE.test(body) ? "read" : null;
|
|
12827
|
+
const blocks = [...body.matchAll(FINDINGS_BLOCK_RE)];
|
|
12828
|
+
const last = blocks[blocks.length - 1];
|
|
12829
|
+
if (!last) return { findings: null, mode: byPhrase };
|
|
12830
|
+
let payload;
|
|
12831
|
+
try {
|
|
12832
|
+
payload = JSON.parse(last[1]);
|
|
12833
|
+
} catch {
|
|
12834
|
+
console.warn("[gh] \u0431\u043B\u043E\u043A findings \u0432 \u0432\u0435\u0440\u0434\u0438\u043A\u0442-\u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0435 \u043D\u0435 \u0440\u0430\u0437\u043E\u0431\u0440\u0430\u043D (\u0431\u0438\u0442\u044B\u0439 JSON) \u2014 \u0432\u0435\u0440\u0434\u0438\u043A\u0442 \u0437\u0430\u0441\u0447\u0438\u0442\u0430\u043D, \u043D\u0430\u0445\u043E\u0434\u043E\u043A \u043D\u0435\u0442");
|
|
12835
|
+
return { findings: null, mode: byPhrase };
|
|
12836
|
+
}
|
|
12837
|
+
const arr = Array.isArray(payload) ? payload : payload && typeof payload === "object" && Array.isArray(payload.findings) ? payload.findings : null;
|
|
12838
|
+
const mode = payload && typeof payload === "object" && !Array.isArray(payload) ? oneOf(["ran", "read"], payload.mode) ?? byPhrase : byPhrase;
|
|
12839
|
+
if (!arr) {
|
|
12840
|
+
console.warn("[gh] \u0431\u043B\u043E\u043A findings \u0432 \u0432\u0435\u0440\u0434\u0438\u043A\u0442-\u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0435 \u043D\u0435 \u0441\u043E\u0434\u0435\u0440\u0436\u0438\u0442 \u043C\u0430\u0441\u0441\u0438\u0432\u0430 \u043D\u0430\u0445\u043E\u0434\u043E\u043A \u2014 \u0432\u0435\u0440\u0434\u0438\u043A\u0442 \u0437\u0430\u0441\u0447\u0438\u0442\u0430\u043D, \u043D\u0430\u0445\u043E\u0434\u043E\u043A \u043D\u0435\u0442");
|
|
12841
|
+
return { findings: null, mode };
|
|
12842
|
+
}
|
|
12843
|
+
const capped = arr.slice(0, FINDINGS_MAX);
|
|
12844
|
+
if (arr.length > capped.length) {
|
|
12845
|
+
console.warn(`[gh] \u0432 \u0431\u043B\u043E\u043A\u0435 findings ${arr.length} \u0437\u0430\u043F\u0438\u0441\u0435\u0439 \u2014 \u0431\u0435\u0440\u0443 \u043F\u0435\u0440\u0432\u044B\u0435 ${FINDINGS_MAX}, \u043E\u0441\u0442\u0430\u043B\u044C\u043D\u043E\u0435 \u043E\u0442\u0431\u0440\u043E\u0448\u0435\u043D\u043E`);
|
|
12846
|
+
}
|
|
12847
|
+
const findings = capped.map((raw) => normalizeFinding(raw)).filter((f) => f != null);
|
|
12848
|
+
if (findings.length < capped.length) {
|
|
12849
|
+
console.warn("[gh] \u0432 \u0431\u043B\u043E\u043A\u0435 findings \u043F\u0440\u043E\u043F\u0443\u0449\u0435\u043D\u043E \u0437\u0430\u043F\u0438\u0441\u0435\u0439 \u0431\u0435\u0437 \u0441\u0443\u0442\u0438: " + (capped.length - findings.length));
|
|
12850
|
+
}
|
|
12851
|
+
return { findings, mode };
|
|
12852
|
+
}
|
|
12744
12853
|
var realCommentsRunner = (prUrl) => runGh(["pr", "view", prUrl, "--json", "comments"], GH_CALL_TIMEOUT_MS);
|
|
12745
12854
|
var VERDICT_RE = /^[^A-Za-z]*(APPROVED?|LGTM|(?:REQUEST(?:ED)?\s+)?CHANGES(?:\s+REQUESTED)?)\b/i;
|
|
12746
12855
|
var APPROVE_RE = /^(APPROVE|LGTM)/i;
|
|
@@ -12748,11 +12857,15 @@ function verdictLabel(verdict) {
|
|
|
12748
12857
|
return verdict === "approve" ? "\u2705 APPROVE" : "\u274C REQUEST CHANGES";
|
|
12749
12858
|
}
|
|
12750
12859
|
async function latestVerdictComment(prUrl, sinceIso, run = realCommentsRunner) {
|
|
12751
|
-
|
|
12860
|
+
const found = await scanPrComments(prUrl, sinceIso, run, (body) => {
|
|
12752
12861
|
const m = body.match(VERDICT_RE);
|
|
12753
12862
|
if (!m) return null;
|
|
12754
|
-
|
|
12863
|
+
const verdict = APPROVE_RE.test(m[1]) ? "approve" : "changes";
|
|
12864
|
+
const { findings, mode } = parseFindingsBlock(body);
|
|
12865
|
+
return { verdict, findings, reviewMode: mode };
|
|
12755
12866
|
});
|
|
12867
|
+
if (!found) return null;
|
|
12868
|
+
return { verdict: found.verdict.verdict, createdAt: found.createdAt, findings: found.verdict.findings, reviewMode: found.verdict.reviewMode };
|
|
12756
12869
|
}
|
|
12757
12870
|
async function scanPrComments(prUrl, sinceIso, run, pick4) {
|
|
12758
12871
|
if (!isGithubPrUrl(prUrl)) return null;
|
|
@@ -18808,14 +18921,19 @@ function ciTrustLine(prUrl, verifyMode) {
|
|
|
18808
18921
|
return `\u041D\u0435 \u043F\u0435\u0440\u0435\u0433\u043E\u043D\u044F\u0439 \u0442\u0435\u0441\u0442-\u0441\u044C\u044E\u0442/typecheck \u0437\u0430\u043D\u043E\u0432\u043E \u2014 \u044D\u0442\u043E \u0443\u0436\u0435 \u0441\u0434\u0435\u043B\u0430\u043B CI \u043D\u0430 \u044D\u0442\u043E\u043C \u0436\u0435 \u043A\u043E\u043C\u043C\u0438\u0442\u0435 (\u0434\u0432\u043E\u0439\u043D\u043E\u0439 \u043F\u0440\u043E\u0433\u043E\u043D \u043D\u0430 \u043C\u0430\u0448\u0438\u043D\u0435 \u0432\u043B\u0430\u0434\u0435\u043B\u044C\u0446\u0430 \u043E\u0442\u043C\u0435\u043D\u0451\u043D, TASWM-249). \u041F\u0440\u043E\u0447\u0438\u0442\u0430\u0439 \u0435\u0433\u043E \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442 \u0441\u0430\u043C: ${readChecks}. \u0414\u0430\u043B\u044C\u0448\u0435 \u0442\u0440\u0438 \u0440\u0430\u0437\u043D\u044B\u0445 \u0441\u043B\u0443\u0447\u0430\u044F: \u2460 \u0445\u043E\u0442\u044C \u043E\u0434\u0438\u043D \u0447\u0435\u043A \u0435\u0449\u0451 PENDING \u2014 \u0432\u0435\u0440\u0434\u0438\u043A\u0442 \u0432\u043E\u043E\u0431\u0449\u0435 \u043D\u0435 \u0432\u044B\u043D\u043E\u0441\u0438: \u043D\u0435 \u043F\u043E\u0441\u0442\u0438 REQUEST CHANGES, \u043D\u0435 \u0437\u043E\u0432\u0438 done(), \u043F\u0440\u043E\u0441\u0442\u043E \u0437\u0430\u0432\u0435\u0440\u0448\u0438 \u0441\u0435\u0441\u0441\u0438\u044E \u043A\u0430\u043A \u0435\u0441\u0442\u044C \u2014 \u0440\u043E\u0439 \u0441\u0430\u043C \u0437\u0430\u043C\u0435\u0442\u0438\u0442, \u0447\u0442\u043E \u0442\u044B \u0436\u0434\u0451\u0448\u044C CI, \u0438 \u0440\u0430\u0437\u0431\u0443\u0434\u0438\u0442 \u0434\u043E\u0434\u0435\u043B\u0430\u0442\u044C \u0440\u0435\u0432\u044C\u044E, \u043A\u043E\u0433\u0434\u0430 \u0432\u0441\u0435 \u0447\u0435\u043A\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0442\u0441\u044F (\u044D\u0442\u043E \u0448\u0442\u0430\u0442\u043D\u044B\u0439 \u043F\u0443\u0442\u044C, \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440\u0430 \u0437\u0432\u0430\u0442\u044C \u043D\u0435 \u043D\u0443\u0436\u043D\u043E). \u2461 \u0432\u0441\u0435 \u0447\u0435\u043A\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043B\u0438\u0441\u044C \u0438 \u0435\u0441\u0442\u044C FAIL \u2014 REQUEST CHANGES, \u043D\u0430\u0437\u043E\u0432\u0438 \u043F\u043E\u0438\u043C\u0451\u043D\u043D\u043E, \u0447\u0442\u043E \u0443\u043F\u0430\u043B\u043E. \u2462 \u043D\u0430 \u044D\u0442\u043E\u043C \u043A\u043E\u043C\u043C\u0438\u0442\u0435 \u0447\u0435\u043A\u043E\u0432 \u043D\u0435\u0442 \u0432\u043E\u0432\u0441\u0435 \u2014 \u0442\u043E\u0436\u0435 REQUEST CHANGES: \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C \u043D\u0435\u0447\u0435\u043C (\u0443 \u044D\u0442\u043E\u0433\u043E \u043F\u0440\u043E\u0435\u043A\u0442\u0430 verifyMode=ci, \u0442\u043E \u0435\u0441\u0442\u044C CI \u043E\u0431\u044F\u0437\u0430\u043D \u0431\u044B\u0442\u044C). ${dontTrustAuthor}`;
|
|
18809
18922
|
}
|
|
18810
18923
|
var REVIEW_DEFECT_CLASSES = [
|
|
18811
|
-
"\u041A\u043B\u0430\u0441\u0441\u044B \u0434\u0435\u0444\u0435\u043A\u0442\u043E\u0432 \u2014 \u043F\u0440\u043E\u0439\u0434\u0438 \u043F\u043E \u043A\u0430\u0436\u0434\u043E\u043C\u0443 \u0438 \u0434\u0430\u0439 \u043E\u0442\u0432\u0435\u0442 \u0432 \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u0435; \xAB\u043D\u0435 \u043F\u0440\u0438\u043C\u0435\u043D\u0438\u043C\u043E\xBB \u2014 \u0437\u0430\u043A\u043E\u043D\u043D\u044B\u0439 \u043E\u0442\u0432\u0435\u0442, \u043D\u043E \u043D\u0430\u0437\u0432\u0430\u043D\u043D\u044B\u0439 \u0438 \u0441 \u043F\u0440\u0438\u0447\u0438\u043D\u043E\u0439 \u0432 \u043F\u043E\u043B\u0441\u0442\u0440\u043E\u043A\u0438 (\xAB\u0440\u0443\u0447\u0435\u043A \u043D\u0435 \u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u043E\xBB, \xAB\u043F\u0435\u0440\u0435\u0447\u0438\u0441\u043B\u0435\u043D\u0438\u0439 \u043D\u0435 \u0442\u0440\u043E\u043D\u0443\u0442\u043E\xBB). \
|
|
18924
|
+
"\u041A\u043B\u0430\u0441\u0441\u044B \u0434\u0435\u0444\u0435\u043A\u0442\u043E\u0432 \u2014 \u043F\u0440\u043E\u0439\u0434\u0438 \u043F\u043E \u043A\u0430\u0436\u0434\u043E\u043C\u0443 \u0438 \u0434\u0430\u0439 \u043E\u0442\u0432\u0435\u0442 \u0432 \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u0435; \xAB\u043D\u0435 \u043F\u0440\u0438\u043C\u0435\u043D\u0438\u043C\u043E\xBB \u2014 \u0437\u0430\u043A\u043E\u043D\u043D\u044B\u0439 \u043E\u0442\u0432\u0435\u0442, \u043D\u043E \u043D\u0430\u0437\u0432\u0430\u043D\u043D\u044B\u0439 \u0438 \u0441 \u043F\u0440\u0438\u0447\u0438\u043D\u043E\u0439 \u0432 \u043F\u043E\u043B\u0441\u0442\u0440\u043E\u043A\u0438 (\xAB\u0440\u0443\u0447\u0435\u043A \u043D\u0435 \u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u043E\xBB, \xAB\u043F\u0435\u0440\u0435\u0447\u0438\u0441\u043B\u0435\u043D\u0438\u0439 \u043D\u0435 \u0442\u0440\u043E\u043D\u0443\u0442\u043E\xBB). \xAB\u041D\u0435 \u043F\u0440\u0438\u043C\u0435\u043D\u0438\u043C\u043E\xBB \u0431\u0435\u0437 \u043F\u0440\u0438\u0447\u0438\u043D\u044B \u043F\u043E \u0432\u0441\u0435\u043C \u043F\u0443\u043D\u043A\u0442\u0430\u043C \u043F\u043E\u0434\u0440\u044F\u0434 \u2014 \u043D\u0435 \u0440\u0435\u0432\u044C\u044E, \u0430 \u043E\u0442\u043F\u0438\u0441\u043A\u0430:",
|
|
18812
18925
|
"- [ ] \u041F\u0440\u0430\u0432\u0430 \u0430\u043A\u0442\u043E\u0440\u0430 \u0438 \u0432\u043E\u0440\u043A\u0441\u043F\u0435\u0439\u0441: \u043A\u0442\u043E \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043A\u0438 \u043C\u043E\u0436\u0435\u0442 \u043F\u043E\u0437\u0432\u0430\u0442\u044C \u043D\u043E\u0432\u0443\u044E \u0440\u0443\u0447\u043A\u0443 \u0438\u043B\u0438 \u043D\u0430\u0436\u0430\u0442\u044C \u043A\u043D\u043E\u043F\u043A\u0443 \u2014 \u0447\u0435\u043B\u043E\u0432\u0435\u043A, \u0434\u0440\u043E\u043D \u0440\u043E\u044F, \u0433\u043E\u0441\u0442\u044C, \u0443\u0447\u0430\u0441\u0442\u043D\u0438\u043A \u0427\u0423\u0416\u041E\u0413\u041E \u0432\u043E\u0440\u043A\u0441\u043F\u0435\u0439\u0441\u0430? \u0414\u0435\u0439\u0441\u0442\u0432\u0438\u0435, \u043A\u043E\u0442\u043E\u0440\u043E\u0435 \u0437\u0430\u0434\u0430\u0447\u0430 \u0437\u0430\u0432\u043E\u0434\u0438\u043B\u0430 \u0440\u0430\u0434\u0438 \u0420\u0415\u0428\u0415\u041D\u0418\u042F \u0427\u0415\u041B\u041E\u0412\u0415\u041A\u0410 (\u043F\u0443\u0431\u043B\u0438\u043A\u0430\u0446\u0438\u044F, \u0430\u043F\u0440\u0443\u0432, \u043E\u043F\u043B\u0430\u0442\u0430, \u0440\u0430\u0441\u0441\u044B\u043B\u043A\u0430), \u043E\u0431\u044F\u0437\u0430\u043D\u043E \u043E\u0442\u0431\u0438\u0432\u0430\u0442\u044C \u0430\u0433\u0435\u043D\u0442\u0430 \u044F\u0432\u043D\u043E (denyAgentActor \u0438 \u0430\u043D\u0430\u043B\u043E\u0433\u0438), \u0430 \u043D\u0435 \u043F\u043E\u043B\u0430\u0433\u0430\u0442\u044C\u0441\u044F \u043D\u0430 \u0442\u043E, \u0447\u0442\u043E \u0443 \u043D\u0435\u0433\u043E \u0440\u043E\u043B\u044C \u043F\u043E\u0436\u0438\u0436\u0435 \u2014 \u0443 \u0434\u0440\u043E\u043D\u0430 \u043E\u043D\u0430 \u043E\u0431\u044B\u0447\u043D\u043E \u043A\u0430\u043A \u0443 \u0432\u043B\u0430\u0434\u0435\u043B\u044C\u0446\u0430. \u041B\u044E\u0431\u043E\u0439 id, \u043F\u0440\u0438\u0435\u0445\u0430\u0432\u0448\u0438\u0439 \u0432 \u0442\u0435\u043B\u0435 \u0437\u0430\u043F\u0440\u043E\u0441\u0430, \u043E\u0431\u044F\u0437\u0430\u043D \u0441\u0432\u0435\u0440\u044F\u0442\u044C\u0441\u044F \u0441 \u0432\u043E\u0440\u043A\u0441\u043F\u0435\u0439\u0441\u043E\u043C \u0437\u0432\u043E\u043D\u044F\u0449\u0435\u0433\u043E: \u0440\u043E\u0443\u0442 \u0431\u0435\u0437 \u0442\u0430\u043A\u043E\u0439 \u0441\u0432\u0435\u0440\u043A\u0438 \u2014 \u043A\u0440\u043E\u0441\u0441-\u0442\u0435\u043D\u0430\u043D\u0442\u043D\u0430\u044F \u0434\u044B\u0440\u0430, \u0438 \u0432 \u044D\u0442\u043E\u043C \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0438 \u044D\u0442\u043E \u0441\u0430\u043C\u044B\u0439 \u0447\u0430\u0441\u0442\u044B\u0439 \u043A\u043B\u0430\u0441\u0441.",
|
|
18813
18926
|
"- [ ] \u041F\u043E\u043B\u043D\u043E\u0442\u0430 \u0432\u0430\u0440\u0438\u0430\u043D\u0442\u043E\u0432: PR \u0434\u043E\u0431\u0430\u0432\u0438\u043B \u0432\u0430\u0440\u0438\u0430\u043D\u0442 \u0432 enum/union/\u043D\u0430\u0431\u043E\u0440 \u0441\u0442\u0440\u043E\u043A \u2014 \u043D\u0430\u0439\u0434\u0438 \u0412\u0421\u0415 \u043C\u0435\u0441\u0442\u0430, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u044D\u0442\u0438 \u0432\u0430\u0440\u0438\u0430\u043D\u0442\u044B \u043F\u0435\u0440\u0435\u0447\u0438\u0441\u043B\u044F\u044E\u0442 (\u0431\u0435\u043B\u044B\u0435 \u0441\u043F\u0438\u0441\u043A\u0438, switch, \u043C\u0430\u043F\u043F\u0438\u043D\u0433\u0438, \u0443\u0441\u043B\u043E\u0432\u0438\u044F \u0432 UI), \u0438 \u043F\u0440\u043E\u0432\u0435\u0440\u044C, \u0447\u0442\u043E \u043D\u043E\u0432\u044B\u0439 \u0442\u0430\u043C \u0435\u0441\u0442\u044C. typecheck \u044D\u0442\u043E \u043F\u0440\u043E\u043F\u0443\u0441\u043A\u0430\u0435\u0442, \u043A\u043E\u0433\u0434\u0430 \u0441\u043F\u0438\u0441\u043E\u043A \u2014 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435, \u0430 \u043D\u0435 exhaustive-switch. \u042D\u0442\u043E \u041E\u0414\u0418\u041D grep \u043F\u043E \u0438\u043C\u0435\u043D\u0438 \u0442\u0438\u043F\u0430 \u0438\u043B\u0438 \u043F\u043E \u0441\u0430\u043C\u043E\u043C\u0443 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044E, \u0430 \u043D\u0435 \u0447\u0442\u0435\u043D\u0438\u0435 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F \xAB\u0434\u043B\u044F \u043F\u043E\u043D\u0438\u043C\u0430\u043D\u0438\u044F\xBB \u2014 \u043A\u043E\u043D\u0442\u0443\u0440 \u044D\u043A\u043E\u043D\u043E\u043C\u0438\u0438 \u0442\u0430\u043A\u043E\u0433\u043E \u043D\u0435 \u0437\u0430\u043F\u0440\u0435\u0449\u0430\u0435\u0442.",
|
|
18814
18927
|
"- [ ] \u0412\u0441\u0435 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u044F \u0438\u0441\u0442\u043E\u0447\u043D\u0438\u043A\u0430: \u0443 \u0441\u0443\u0449\u043D\u043E\u0441\u0442\u0438 \u043F\u043E\u0447\u0442\u0438 \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u043E\u043B\u044C\u0448\u0435 \u0434\u0432\u0443\u0445 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0439 (\u0432\u044B\u043A\u043B\u044E\u0447\u0435\u043D\u043E, \u043F\u0430\u0443\u0437\u0430, drain, \u043C\u043E\u043B\u0447\u0438\u0442, \u0434\u0430\u043D\u043D\u044B\u0445 \u0435\u0449\u0451 \u043D\u0435\u0442, \u0434\u043E\u0441\u0442\u0443\u043F \u0437\u0430\u043A\u0440\u044B\u0442). \u0420\u0430\u0437\u043E\u0431\u0440\u0430\u043D\u044B \u0412\u0421\u0415 \u0438\u043B\u0438 \u0442\u043E\u043B\u044C\u043A\u043E happy path \u0438 \u043E\u0434\u043D\u0430 \u043E\u0448\u0438\u0431\u043A\u0430? \u0427\u0430\u0441\u0442\u043E \u043F\u043E\u043B\u043D\u044B\u0439 \u043D\u0430\u0431\u043E\u0440 \u0443\u0436\u0435 \u043B\u0435\u0436\u0438\u0442 \u0440\u044F\u0434\u043E\u043C \u0432 \u044F\u0434\u0440\u0435 \u2014 \u043F\u043E\u0438\u0449\u0438 \u0435\u0433\u043E, \u043F\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043C \u0441\u0447\u0438\u0442\u0430\u0442\u044C \u043F\u0435\u0440\u0435\u0447\u0438\u0441\u043B\u0435\u043D\u0438\u0435 \u043F\u043E\u043B\u043D\u044B\u043C.",
|
|
18815
18928
|
"- [ ] \u041E\u0448\u0438\u0431\u043A\u0430 \u0434\u043E\u0445\u043E\u0434\u0438\u0442 \u0434\u043E \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430: \u043E\u0442\u043A\u0430\u0437 \u0437\u0430\u043F\u0440\u043E\u0441\u0430, \u043F\u0440\u043E\u0432\u0430\u043B \u0432\u0430\u043B\u0438\u0434\u0430\u0446\u0438\u0438, \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442 \u2014 \u0432\u0438\u0434\u043D\u044B \u0432 \u0438\u043D\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435, \u0430 \u043D\u0435 \u0442\u043E\u043B\u044C\u043A\u043E \u0432 console.warn/\u043B\u043E\u0433. \u041A\u043D\u043E\u043F\u043A\u0430, \u043A\u043E\u0442\u043E\u0440\u0430\u044F \u043C\u043E\u043B\u0447\u0430 \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0441\u0434\u0435\u043B\u0430\u043B\u0430, \u2014 \u0434\u0435\u0444\u0435\u043A\u0442, \u0434\u0430\u0436\u0435 \u0435\u0441\u043B\u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u043E\u0442\u0432\u0435\u0442\u0438\u043B \u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u043E.",
|
|
18816
18929
|
"- [ ] \u0414\u0435\u0444\u043E\u043B\u0442 \u043F\u0440\u0438 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0438 \u0434\u0430\u043D\u043D\u044B\u0445: \u043F\u043E\u043B\u044F \u043D\u0435\u0442, \u043E\u0442\u0432\u0435\u0442 \u043F\u0443\u0441\u0442\u043E\u0439, \u0437\u0430\u0432\u0438\u0441\u0438\u043C\u043E\u0441\u0442\u044C \u043C\u043E\u043B\u0447\u0438\u0442 \u2014 \u043A\u0443\u0434\u0430 \u043F\u0430\u0434\u0430\u0435\u0442 \u0440\u0435\u0448\u0435\u043D\u0438\u0435? \u0414\u043B\u044F \u0443\u0434\u0430\u043B\u044F\u044E\u0449\u0438\u0445, \u043F\u0443\u0431\u043B\u0438\u043A\u0443\u044E\u0449\u0438\u0445 \u0438 \u0441\u043F\u0438\u0441\u044B\u0432\u0430\u044E\u0449\u0438\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u0434\u0435\u0444\u043E\u043B\u0442 \u043E\u0431\u044F\u0437\u0430\u043D \u0431\u044B\u0442\u044C \u0432 \u0431\u0435\u0437\u043E\u043F\u0430\u0441\u043D\u0443\u044E \u0441\u0442\u043E\u0440\u043E\u043D\u0443 (\u043D\u0435 \u0434\u0435\u043B\u0430\u0442\u044C), \u0430 \xAB\u043D\u0435\u0442 \u0434\u0430\u043D\u043D\u044B\u0445\xBB \u043D\u0435 \u0441\u043C\u0435\u0435\u0442 \u0447\u0438\u0442\u0430\u0442\u044C\u0441\u044F \u043A\u0430\u043A \xAB\u0447\u0438\u0441\u0442\u043E, \u043C\u043E\u0436\u043D\u043E\xBB.",
|
|
18817
18930
|
"- [ ] \u0422\u0435\u0441\u0442\u044B PR \u0434\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u044E\u0442 \u0437\u0430\u044F\u0432\u043B\u0435\u043D\u043D\u043E\u0435. \u0415\u0441\u043B\u0438 \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u0423\u0416\u0415 \u043F\u043E\u0434\u043D\u044F\u0442\u043E (\u0432 worktree \u0435\u0441\u0442\u044C node_modules \u0438 \u043F\u0430\u043A\u0435\u0442\u044B \u0441\u043E\u0431\u0440\u0430\u043D\u044B): \u0441\u043D\u0438\u043C\u0438 \u0432 \u041A\u041E\u0414\u0415 \u0442\u0443 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0443, \u043A\u043E\u0442\u043E\u0440\u0443\u044E \u043D\u043E\u0432\u044B\u0439 \u0442\u0435\u0441\u0442 \u044F\u043A\u043E\u0431\u044B \u0441\u0442\u043E\u0440\u043E\u0436\u0438\u0442 (\u043E\u0434\u043D\u0443 \u0441\u0442\u0440\u043E\u043A\u0443 \u2014 \u0433\u0435\u0439\u0442, \u0443\u0441\u043B\u043E\u0432\u0438\u0435, \u0432\u0430\u043B\u0438\u0434\u0430\u0446\u0438\u044E), \u043F\u0440\u043E\u0433\u043E\u043D\u0438 \u041E\u0414\u0418\u041D \u044D\u0442\u043E\u0442 \u0442\u0435\u0441\u0442 (\u043D\u0435 \u0432\u0435\u0441\u044C \u0441\u044C\u044E\u0442), \u0432\u0435\u0440\u043D\u0438 \u0444\u0430\u0439\u043B \u043A\u0430\u043A \u0431\u044B\u043B\u043E. \u0422\u0435\u0441\u0442 \u043E\u0431\u044F\u0437\u0430\u043D \u043F\u043E\u043A\u0440\u0430\u0441\u043D\u0435\u0442\u044C; \u043E\u0441\u0442\u0430\u043B\u0441\u044F \u0437\u0435\u043B\u0451\u043D\u044B\u043C \u2014 \u043D\u0430\u0445\u043E\u0434\u043A\u0430: \u043E\u043D \u043D\u0435 \u0441\u0442\u043E\u0440\u043E\u0436\u0438\u0442 \u043D\u0438\u0447\u0435\u0433\u043E.",
|
|
18818
|
-
" \u041E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u041D\u0415 \u043F\u043E\u0434\u043D\u044F\u0442\u043E \u2014 \u0442\u0430\u043A \u0438 \u0431\u0443\u0434\u0435\u0442: \u0442\u0435\u0431\u0435 \u043F\u043E\u0434\u043D\u044F\u043B\u0438 \u0447\u0438\u0441\u0442\u044B\u0439 \u0447\u0435\u043A\u0430\u0443\u0442, \u0437\u0430\u0432\u0438\u0441\u0438\u043C\u043E\u0441\u0442\u0438 \u043D\u0438\u043A\u0442\u043E \u043D\u0435 \u0441\u0442\u0430\u0432\u0438\u043B. \u041F\u043E\u0434\u043D\u0438\u043C\u0430\u0442\u044C \u0438\u0445 \u041D\u0415 \u041D\u0410\u0414\u041E, \u044D\u0442\u043E \u0434\u043E\u0440\u043E\u0436\u0435 \u0432\u0441\u0435\u0433\u043E \u0440\u0435\u0432\u044C\u044E: \u0441\u043A\u0430\u0436\u0438 \u0432 \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u0435 \xAB\u043F\u0440\u043E\u0433\u043D\u0430\u0442\u044C \u043D\u0435 \u043C\u043E\u0433, \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u044F \u043D\u0435\u0442\xBB \u0438 \u043F\u0440\u043E\u0432\u0435\u0440\u044C \u0442\u0435\u0441\u0442 \u0427\u0422\u0415\u041D\u0418\u0415\u041C. \u0422\u0440\u0438 \u0441\u043F\u043E\u0441\u043E\u0431\u0430 \u0441\u043E\u0432\u0440\u0430\u0442\u044C \u0437\u0435\u043B\u0451\u043D\u044B\u043C, \u0432\u0438\u0434\u043D\u044B\u0435 \u0433\u043B\u0430\u0437\u0430\u043C\u0438: (\u0430) \u0438\u0441\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u0435 \u043F\u0440\u043E\u0433\u043B\u043E\u0447\u0435\u043D\u043E (`try/except`, \u0437\u043E\u043D\u0442 \u0441\u0442\u043E\u0440\u043E\u0436\u0430, `.catch(() => {})`) \u2014 \u0442\u0435\u0441\u0442 \u043D\u0435 \u043F\u0430\u0434\u0430\u0435\u0442 \u0442\u0430\u043C, \u0433\u0434\u0435 \u043E\u0431\u044F\u0437\u0430\u043D; (\u0431) \u0430\u0441\u0441\u0435\u0440\u0442 \u043D\u0430 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435, \u0432\u0435\u0440\u043D\u043E\u0435 \u0432\u0441\u0435\u0433\u0434\u0430, \u043D\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043C\u043E \u043E\u0442 \u043F\u0440\u0430\u0432\u043A\u0438; (\u0432) \u0442\u0435\u0441\u0442 \u043D\u0435 \u043F\u0440\u043E\u0445\u043E\u0434\u0438\u0442 \u0447\u0435\u0440\u0435\u0437 \u0438\u0437\u043C\u0435\u043D\u0451\u043D\u043D\u044B\u0439 \u0433\u0435\u0439\u0442 \u0432\u043E\u0432\u0441\u0435 \u2014 \u0434\u0451\u0440\u0433\u0430\u0435\u0442 \u0441\u043E\u0441\u0435\u0434\u043D\u0438\u0439 \u043F\u0443\u0442\u044C."
|
|
18931
|
+
" \u041E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u041D\u0415 \u043F\u043E\u0434\u043D\u044F\u0442\u043E \u2014 \u0442\u0430\u043A \u0438 \u0431\u0443\u0434\u0435\u0442: \u0442\u0435\u0431\u0435 \u043F\u043E\u0434\u043D\u044F\u043B\u0438 \u0447\u0438\u0441\u0442\u044B\u0439 \u0447\u0435\u043A\u0430\u0443\u0442, \u0437\u0430\u0432\u0438\u0441\u0438\u043C\u043E\u0441\u0442\u0438 \u043D\u0438\u043A\u0442\u043E \u043D\u0435 \u0441\u0442\u0430\u0432\u0438\u043B. \u041F\u043E\u0434\u043D\u0438\u043C\u0430\u0442\u044C \u0438\u0445 \u041D\u0415 \u041D\u0410\u0414\u041E, \u044D\u0442\u043E \u0434\u043E\u0440\u043E\u0436\u0435 \u0432\u0441\u0435\u0433\u043E \u0440\u0435\u0432\u044C\u044E: \u0441\u043A\u0430\u0436\u0438 \u0432 \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u0435 \xAB\u043F\u0440\u043E\u0433\u043D\u0430\u0442\u044C \u043D\u0435 \u043C\u043E\u0433, \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u044F \u043D\u0435\u0442\xBB \u0438 \u043F\u0440\u043E\u0432\u0435\u0440\u044C \u0442\u0435\u0441\u0442 \u0427\u0422\u0415\u041D\u0418\u0415\u041C. \u0422\u0440\u0438 \u0441\u043F\u043E\u0441\u043E\u0431\u0430 \u0441\u043E\u0432\u0440\u0430\u0442\u044C \u0437\u0435\u043B\u0451\u043D\u044B\u043C, \u0432\u0438\u0434\u043D\u044B\u0435 \u0433\u043B\u0430\u0437\u0430\u043C\u0438: (\u0430) \u0438\u0441\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u0435 \u043F\u0440\u043E\u0433\u043B\u043E\u0447\u0435\u043D\u043E (`try/except`, \u0437\u043E\u043D\u0442 \u0441\u0442\u043E\u0440\u043E\u0436\u0430, `.catch(() => {})`) \u2014 \u0442\u0435\u0441\u0442 \u043D\u0435 \u043F\u0430\u0434\u0430\u0435\u0442 \u0442\u0430\u043C, \u0433\u0434\u0435 \u043E\u0431\u044F\u0437\u0430\u043D; (\u0431) \u0430\u0441\u0441\u0435\u0440\u0442 \u043D\u0430 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435, \u0432\u0435\u0440\u043D\u043E\u0435 \u0432\u0441\u0435\u0433\u0434\u0430, \u043D\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043C\u043E \u043E\u0442 \u043F\u0440\u0430\u0432\u043A\u0438; (\u0432) \u0442\u0435\u0441\u0442 \u043D\u0435 \u043F\u0440\u043E\u0445\u043E\u0434\u0438\u0442 \u0447\u0435\u0440\u0435\u0437 \u0438\u0437\u043C\u0435\u043D\u0451\u043D\u043D\u044B\u0439 \u0433\u0435\u0439\u0442 \u0432\u043E\u0432\u0441\u0435 \u2014 \u0434\u0451\u0440\u0433\u0430\u0435\u0442 \u0441\u043E\u0441\u0435\u0434\u043D\u0438\u0439 \u043F\u0443\u0442\u044C.",
|
|
18932
|
+
"- [ ] \u041D\u0430\u043F\u0438\u0441\u0430\u043D\u043E \u0437\u0430\u043D\u043E\u0432\u043E \u0442\u043E, \u0447\u0442\u043E \u0443\u0436\u0435 \u0435\u0441\u0442\u044C \u0432 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0438: \u043D\u043E\u0432\u044B\u0439 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442, \u0443\u0442\u0438\u043B\u0438\u0442\u0430 \u0438\u043B\u0438 \u0445\u0435\u043B\u043F\u0435\u0440 \u043F\u0440\u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044E\u0449\u0435\u043C \u0430\u043D\u0430\u043B\u043E\u0433\u0435 \u0432 \u0434\u0438\u0437\u0430\u0439\u043D-\u0441\u0438\u0441\u0442\u0435\u043C\u0435 \u0438\u043B\u0438 \u043E\u0431\u0449\u0435\u043C \u043F\u0430\u043A\u0435\u0442\u0435 \u043F\u0440\u043E\u0435\u043A\u0442\u0430 (\u0433\u0434\u0435 \u043E\u043D\u0438 \u043B\u0435\u0436\u0430\u0442 \u2014 \u0432 CLAUDE.md \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F, \u0435\u0441\u043B\u0438 \u043E\u043D \u0435\u0441\u0442\u044C). \u0414\u0443\u0431\u043B\u0438\u043A\u0430\u0442 \u043F\u043E\u0434 \u0434\u0440\u0443\u0433\u0438\u043C \u0438\u043C\u0435\u043D\u0435\u043C \u2014 \u043D\u0430\u0445\u043E\u0434\u043A\u0430.",
|
|
18933
|
+
'- [ ] \u0418\u043C\u043F\u043E\u0440\u0442 \u0447\u0435\u0440\u0435\u0437 \u0433\u0440\u0430\u043D\u0438\u0446\u0443 \u043F\u0430\u043A\u0435\u0442\u0430: \u043E\u0442\u043D\u043E\u0441\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0439 \u043F\u0443\u0442\u044C \u0432\u0433\u043B\u0443\u0431\u044C \u0447\u0443\u0436\u043E\u0433\u043E \u043F\u0430\u043A\u0435\u0442\u0430 \u0438\u043B\u0438 subpath \u0432\u0438\u0434\u0430 `<\u043F\u0430\u043A\u0435\u0442>/src/\u2026` \u0432\u043C\u0435\u0441\u0442\u043E \u043F\u0443\u0431\u043B\u0438\u0447\u043D\u043E\u0433\u043E \u044D\u043A\u0441\u043F\u043E\u0440\u0442\u0430 \u2014 \u043D\u0430\u0445\u043E\u0434\u043A\u0430. \u0410\u0432\u0442\u043E\u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u0433\u0440\u0430\u043D\u0438\u0446 \u043F\u0430\u043A\u0435\u0442\u043E\u0432, \u0435\u0441\u043B\u0438 \u043E\u043D\u0430 \u0432 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0438 \u0435\u0441\u0442\u044C, \u043E\u0431\u044B\u0447\u043D\u043E \u043B\u043E\u0432\u0438\u0442 \u0442\u043E\u043B\u044C\u043A\u043E \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438\u0435 \u043E\u0442\u043D\u043E\u0441\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0435 `from "../\u2026"`; subpath \u0447\u0435\u0440\u0435\u0437 \u0438\u043C\u044F \u043F\u0430\u043A\u0435\u0442\u0430 \u0438 require/\u0434\u0438\u043D\u0430\u043C\u0438\u0447\u0435\u0441\u043A\u0438\u0439 import \u043C\u0438\u043C\u043E \u043D\u0435\u0451 \u043F\u0440\u043E\u0445\u043E\u0434\u044F\u0442 \u043D\u0435\u0437\u0430\u043C\u0435\u0447\u0435\u043D\u043D\u044B\u043C\u0438.',
|
|
18934
|
+
"- [ ] \u0410\u0431\u0441\u0442\u0440\u0430\u043A\u0446\u0438\u044F \u0431\u0435\u0437 \u0432\u0442\u043E\u0440\u043E\u0433\u043E \u043F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u044F: \u0438\u043D\u0442\u0435\u0440\u0444\u0435\u0439\u0441, \u0444\u0430\u0431\u0440\u0438\u043A\u0430 \u0438\u043B\u0438 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 \xAB\u043D\u0430 \u0432\u044B\u0440\u043E\u0441\u0442\xBB \u043F\u0440\u0438 \u043E\u0434\u043D\u043E\u043C \u0432\u044B\u0437\u044B\u0432\u0430\u044E\u0449\u0435\u043C \u2014 \u043D\u0430\u0445\u043E\u0434\u043A\u0430. \u041F\u0435\u0440\u0435\u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u043C\u044B\u043C \u043A\u043E\u0434 \u0434\u0435\u043B\u0430\u044E\u0442 \u043F\u0440\u0438 \u0412\u0422\u041E\u0420\u041E\u041C \u0440\u0435\u0430\u043B\u044C\u043D\u043E\u043C \u043F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u0435, \u043D\u0435 \u0437\u0430\u0440\u0430\u043D\u0435\u0435.",
|
|
18935
|
+
"- [ ] \u0414\u0443\u0431\u043B\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0435 \u043B\u043E\u0433\u0438\u043A\u0438: \u0442\u043E\u0442 \u0436\u0435 \u0440\u0430\u0441\u0447\u0451\u0442, \u043D\u043E\u0440\u043C\u0430\u043B\u0438\u0437\u0430\u0446\u0438\u044F \u0438\u043B\u0438 \u0444\u043E\u0440\u043C\u0430\u0442 \u0443\u0436\u0435 \u0435\u0441\u0442\u044C \u0432 \u0441\u043E\u0441\u0435\u0434\u043D\u0435\u043C \u0444\u0430\u0439\u043B\u0435 \u2014 \u043D\u0430\u0445\u043E\u0434\u043A\u0430.",
|
|
18936
|
+
"- [ ] \u041F\u0440\u0430\u0432\u043A\u0430 \u043E\u0431\u0449\u0435\u0433\u043E \u0445\u0440\u0435\u0431\u0442\u0430 \u0432\u043F\u0435\u0440\u0435\u043C\u0435\u0448\u043A\u0443 \u0441 \u0444\u0438\u0447\u0435\u0439: \u0447\u0442\u043E \u0432 \u044D\u0442\u043E\u043C \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0438 \u0445\u0440\u0435\u0431\u0435\u0442 (\u043E\u0431\u0449\u0438\u0435 \u043F\u0430\u043A\u0435\u0442\u044B, \u0441\u0445\u0435\u043C\u0430 \u0411\u0414, \u0440\u043E\u0443\u0442\u0438\u043D\u0433\u2026) \u2014 \u0441\u043C\u043E\u0442\u0440\u0438 CLAUDE.md \u043F\u0440\u043E\u0435\u043A\u0442\u0430 \u0438\u043B\u0438 \u043F\u0440\u043E\u0444\u0438\u043B\u044C \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F (spine). \u0422\u0430\u043A\u0430\u044F \u043F\u0440\u0430\u0432\u043A\u0430 \u0432 \u043E\u0434\u043D\u043E\u043C PR \u0441 \u0444\u0438\u0447\u0435\u0439 \u2014 \u043D\u0430\u0445\u043E\u0434\u043A\u0430: \u0445\u0440\u0435\u0431\u0442\u0443 \u043D\u0443\u0436\u0435\u043D \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u044B\u0439 PR."
|
|
18819
18937
|
].join("\n");
|
|
18820
18938
|
function buildReviewChecklist(reviewRun, files, priorReview, verifyMode = SWARM_VERIFY) {
|
|
18821
18939
|
const header = files.length ? `\u0424\u0430\u0439\u043B\u044B \u0434\u0438\u0444\u0444\u0430 (${files.length}):
|
|
@@ -18839,7 +18957,8 @@ ${priorReview}` : "",
|
|
|
18839
18957
|
"- [ ] \u041D\u043E\u0432\u044B\u0435 \u043A\u043E\u043C\u043C\u0438\u0442\u044B \u043D\u0435 \u043F\u0440\u0438\u0432\u043D\u0435\u0441\u043B\u0438 \u043D\u043E\u0432\u044B\u0445 \u043F\u0440\u043E\u0431\u043B\u0435\u043C: \u0433\u043E\u043D\u043A\u0438/\u043C\u0438\u0433\u0440\u0430\u0446\u0438\u0438/UI \u043F\u043E \u043F\u0440\u0438\u043C\u0435\u043D\u0438\u043C\u043E\u0441\u0442\u0438 \u2014 \u0438 \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E \u043F\u0440\u0430\u0432\u0430 \u0430\u043A\u0442\u043E\u0440\u0430, \u0434\u0435\u0444\u043E\u043B\u0442 \u043F\u0440\u0438 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0438 \u0434\u0430\u043D\u043D\u044B\u0445, \u043F\u043E\u043B\u043D\u043E\u0442\u0430 \u0432\u0430\u0440\u0438\u0430\u043D\u0442\u043E\u0432. \u041F\u0440\u0430\u0432\u043A\u0430 \u043F\u043E \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u0443 \u0442\u0440\u043E\u0433\u0430\u0435\u0442 \u0442\u0435 \u0436\u0435 \u043C\u0435\u0441\u0442\u0430, \u0433\u0434\u0435 \u0434\u0435\u0444\u0435\u043A\u0442 \u0438 \u0431\u044B\u043B, \u043F\u043E\u044D\u0442\u043E\u043C\u0443 \u0438\u043C\u0435\u043D\u043D\u043E \u043E\u043D\u0430 \u0447\u0430\u0449\u0435 \u0432\u0441\u0435\u0433\u043E \u043F\u0440\u0438\u043D\u043E\u0441\u0438\u0442 \u043D\u043E\u0432\u044B\u0439.",
|
|
18840
18958
|
// Единственный класс из REVIEW_DEFECT_CLASSES, который на втором круге обязателен:
|
|
18841
18959
|
// правки по вердикту почти всегда приносят НОВЫЕ тесты, и именно тут прошёл #819.
|
|
18842
|
-
// Остальные пять
|
|
18960
|
+
// Остальные классы (включая пять про качество кода, TASWM-559) заново не гоняем —
|
|
18961
|
+
// ре-чек намеренно короткий (TASWM-437).
|
|
18843
18962
|
"- [ ] \u041D\u043E\u0432\u044B\u0435 \u0442\u0435\u0441\u0442\u044B \u043F\u0440\u0430\u0432\u043A\u0438: \u0441\u043D\u0438\u043C\u0438 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0443, \u043A\u043E\u0442\u043E\u0440\u0443\u044E \u0442\u0435\u0441\u0442 \u0441\u0442\u043E\u0440\u043E\u0436\u0438\u0442, \u043F\u0440\u043E\u0433\u043E\u043D\u0438 \u041E\u0414\u0418\u041D \u044D\u0442\u043E\u0442 \u0442\u0435\u0441\u0442, \u0432\u0435\u0440\u043D\u0438 \u043A\u0430\u043A \u0431\u044B\u043B\u043E \u2014 \u043E\u043D \u043E\u0431\u044F\u0437\u0430\u043D \u043F\u043E\u043A\u0440\u0430\u0441\u043D\u0435\u0442\u044C."
|
|
18844
18963
|
].filter(Boolean).join("\n");
|
|
18845
18964
|
}
|
|
@@ -18886,6 +19005,19 @@ var REVIEW_MISSION_BLOCK = [
|
|
|
18886
19005
|
"\u2022 \u041D\u0430\u0445\u043E\u0434\u043A\u0430 \u0434\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442\u0441\u044F \u0421\u0426\u0415\u041D\u0410\u0420\u0418\u0415\u041C: \xAB\u0442\u0430\u043A\u043E\u0439 \u0432\u0445\u043E\u0434 \u0438\u043B\u0438 \u0442\u0430\u043A\u043E\u0435 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435 \u2192 \u0432\u043E\u0442 \u0442\u0430\u043A\u043E\u0439 \u043D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442\xBB. \xAB\u0412\u044B\u0433\u043B\u044F\u0434\u0438\u0442 \u043D\u0435\u0431\u0435\u0437\u043E\u043F\u0430\u0441\u043D\u043E\xBB, \xAB\u0441\u0442\u043E\u0438\u0442 \u043F\u0435\u0440\u0435\u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C\xBB, \xAB\u0436\u0435\u043B\u0430\u0442\u0435\u043B\u044C\u043D\u043E \u043F\u043E\u043A\u0440\u044B\u0442\u044C \u0442\u0435\u0441\u0442\u0430\u043C\u0438\xBB \u2014 \u043D\u0435 \u043D\u0430\u0445\u043E\u0434\u043A\u0438; \u0442\u0430\u043A\u043E\u0435 \u043D\u0435 \u043F\u0438\u0448\u0438.",
|
|
18887
19006
|
"\u2022 \u041D\u043E\u043B\u044C \u043D\u0430\u0445\u043E\u0434\u043E\u043A \u2014 \u0437\u0430\u043A\u043E\u043D\u043D\u044B\u0439 \u0432\u0435\u0440\u0434\u0438\u043A\u0442, \u043D\u043E \u0442\u043E\u0433\u0434\u0430 \u043D\u0430\u0437\u043E\u0432\u0438, \u0427\u0422\u041E \u0438\u043C\u0435\u043D\u043D\u043E \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u043B \u0438 \u043A\u0430\u043A\u0438\u043C \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0435\u043C. APPROVE \u0431\u0435\u0437 \u044D\u0442\u043E\u0433\u043E \u0440\u043E\u0439 \u0447\u0438\u0442\u0430\u0435\u0442 \u043A\u0430\u043A \u043F\u0435\u0440\u0435\u0441\u043A\u0430\u0437, \u0438 \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0435\u0442 PR \u0437\u0430\u043D\u043E\u0432\u043E \u0432\u0440\u0443\u0447\u043D\u0443\u044E."
|
|
18888
19007
|
].join("\n");
|
|
19008
|
+
var REVIEW_FINDINGS_BLOCK = [
|
|
19009
|
+
"\u{1F4E6} \u041F\u041E\u0421\u041B\u0415\u0414\u041D\u0418\u0419 \u0411\u041B\u041E\u041A \u041A\u041E\u041C\u041C\u0415\u041D\u0422\u0410 \u2014 \u041D\u0410\u0425\u041E\u0414\u041A\u0418 \u041C\u0410\u0428\u0418\u041D\u041E\u0427\u0418\u0422\u0410\u0415\u041C\u041E (\u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E). \u0421\u0432\u043E\u0431\u043E\u0434\u043D\u044B\u0439 \u0442\u0435\u043A\u0441\u0442 \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u0430 \u0440\u043E\u0439 \u0441\u0447\u0438\u0442\u0430\u0442\u044C \u043D\u0435 \u0443\u043C\u0435\u0435\u0442; \u044D\u0442\u043E\u0442 \u0431\u043B\u043E\u043A \u043E\u043D \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u0442 \u0438 \u0441\u043A\u043B\u0430\u0434\u044B\u0432\u0430\u0435\u0442 \u0432 \u043B\u0435\u043D\u0442\u0443 \u043F\u0440\u043E\u0433\u043E\u043D\u0430. \u041F\u0435\u0447\u0430\u0442\u0430\u0439 \u0435\u0433\u043E \u0412\u0421\u0415\u0413\u0414\u0410 \u0438 \u0432\u0441\u0435\u0433\u0434\u0430 \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0438\u043C:",
|
|
19010
|
+
"```findings",
|
|
19011
|
+
'{"mode": "read", "findings": [{"category": "correctness", "severity": "blocker", "path": "packages/api/src/foo.ts", "line": 42, "what": "\u043E\u0434\u043D\u043E \u043F\u0440\u0435\u0434\u043B\u043E\u0436\u0435\u043D\u0438\u0435: \u0442\u0430\u043A\u043E\u0439 \u0432\u0445\u043E\u0434 \u2192 \u0442\u0430\u043A\u043E\u0439 \u043D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442"}]}',
|
|
19012
|
+
"```",
|
|
19013
|
+
// Словари — ИЗ ОДНОГО МЕСТА с разбором (gh.FINDING_CATEGORIES/FINDING_SEVERITIES): значение,
|
|
19014
|
+
// названное промптом, но не знакомое парсеру, молча превращается в `null` — находка приедет
|
|
19015
|
+
// без класса, и никто этого не заметит.
|
|
19016
|
+
`\u2022 \`category\` \u2014 \u043E\u0434\u0438\u043D \u0438\u0437: ${FINDING_CATEGORIES.join(" | ")}. \`severity\` \u2014 ${FINDING_SEVERITIES.join(" | ")}. \`path\`/\`line\` \u2014 \u0444\u0430\u0439\u043B \u0438 \u0441\u0442\u0440\u043E\u043A\u0430, \u0433\u0434\u0435 \u0434\u0435\u0444\u0435\u043A\u0442 (\u0441\u0442\u0440\u043E\u043A\u0438 \u043D\u0435 \u0437\u043D\u0430\u0435\u0448\u044C \u2014 \`null\`). \`what\` \u2014 \u041E\u0414\u041D\u041E \u043F\u0440\u0435\u0434\u043B\u043E\u0436\u0435\u043D\u0438\u0435.`,
|
|
19017
|
+
"\u2022 `mode` \u2014 \u043A\u0430\u043A \u0442\u044B \u0441\u0443\u0434\u0438\u043B: `ran` (\u0441\u0430\u043C \u043F\u0440\u043E\u0433\u043D\u0430\u043B \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438) \u0438\u043B\u0438 `read` (\u0441\u0443\u0434\u0438\u043B \u0447\u0442\u0435\u043D\u0438\u0435\u043C, \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u043D\u0435 \u043F\u043E\u0434\u043D\u0438\u043C\u0430\u043B \u2014 \u044D\u0442\u043E \u0437\u0430\u043A\u043E\u043D\u043D\u043E \u0438 \u0438\u043C\u0435\u043D\u043D\u043E \u044D\u0442\u043E\u0433\u043E \u043E\u0442 \u0442\u0435\u0431\u044F \u0436\u0434\u0443\u0442). \u041D\u0430\u0437\u043E\u0432\u0438 \u0447\u0435\u0441\u0442\u043D\u043E: \u044D\u0442\u043E \u043D\u0435 \u043E\u0446\u0435\u043D\u043A\u0430 \u0442\u0435\u0431\u0435, \u044D\u0442\u043E \u0432\u0435\u0441 \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u0430 \u0432 \u0430\u043D\u0430\u043B\u0438\u0442\u0438\u043A\u0435.",
|
|
19018
|
+
'\u2022 \u041D\u0430\u0445\u043E\u0434\u043E\u043A \u043D\u0435\u0442 \u2014 \u0431\u043B\u043E\u043A \u0432\u0441\u0451 \u0440\u0430\u0432\u043D\u043E \u043F\u0435\u0447\u0430\u0442\u0430\u0439, \u0441 \u043F\u0443\u0441\u0442\u044B\u043C \u043C\u0430\u0441\u0441\u0438\u0432\u043E\u043C: {"mode": "read", "findings": []}.',
|
|
19019
|
+
"\u2022 \u041F\u0435\u0440\u0432\u0443\u044E \u0441\u0442\u0440\u043E\u043A\u0443 \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430 \u0431\u043B\u043E\u043A \u041D\u0415 \u043E\u0442\u043C\u0435\u043D\u044F\u0435\u0442: APPROVE / REQUEST CHANGES \u0437\u0430\u0433\u043B\u0430\u0432\u043D\u044B\u043C\u0438 \u2014 \u043A\u0430\u043A \u0431\u044B\u043B\u043E. \u041D\u0430\u0445\u043E\u0434\u043A\u0438 \u0432 \u0431\u043B\u043E\u043A\u0435 \u0434\u0443\u0431\u043B\u0438\u0440\u0443\u044E\u0442 \u0442\u043E, \u0447\u0442\u043E \u0442\u044B \u0438 \u0442\u0430\u043A \u043D\u0430\u043F\u0438\u0441\u0430\u043B \u0442\u0435\u043A\u0441\u0442\u043E\u043C, \u0430 \u043D\u0435 \u0437\u0430\u043C\u0435\u043D\u044F\u044E\u0442 \u0440\u0430\u0437\u0431\u043E\u0440."
|
|
19020
|
+
].join("\n");
|
|
18889
19021
|
function buildReviewerPrompt(reviewRun, reviewer, checklist, branch, attachmentsBlock, verifyMode = SWARM_VERIFY, pendingRules = []) {
|
|
18890
19022
|
const name = reviewer.name || `#${reviewer.id}`;
|
|
18891
19023
|
const rulesBlock = renderPendingRulesBlock(pendingRules);
|
|
@@ -18919,15 +19051,17 @@ function buildReviewerPrompt(reviewRun, reviewer, checklist, branch, attachments
|
|
|
18919
19051
|
"",
|
|
18920
19052
|
checklist,
|
|
18921
19053
|
"",
|
|
19054
|
+
REVIEW_FINDINGS_BLOCK,
|
|
19055
|
+
"",
|
|
18922
19056
|
"\u041F\u043E\u0440\u044F\u0434\u043E\u043A:",
|
|
18923
19057
|
...verifyMode === "local" ? [
|
|
18924
19058
|
`1. \u041F\u0440\u043E\u0439\u0434\u0438 \u0447\u0435\u043A-\u043B\u0438\u0441\u0442 \u0432\u044B\u0448\u0435: \u0433\u0435\u0439\u0442 \u043F\u0440\u043E\u0435\u043A\u0442\u0430 \u043F\u0440\u043E\u0433\u043E\u043D\u0438 \u0421\u0410\u041C \u0432 \u0441\u0432\u043E\u0451\u043C worktree (\u044D\u0442\u043E \u0438 \u0435\u0441\u0442\u044C \u0434\u043E\u043A\u0430\u0437\u0430\u0442\u0435\u043B\u044C\u0441\u0442\u0432\u043E \u0437\u0435\u043B\u0451\u043D\u043E\u0433\u043E \u2014 \u0443 \u043F\u0440\u043E\u0435\u043A\u0442\u0430 verifyMode=local), ${classesStep}\u043F\u0440\u043E\u0432\u0435\u0440\u044C \u043C\u0438\u0433\u0440\u0430\u0446\u0438\u0438/\u0433\u043E\u043D\u043A\u0438/UI/per-page meta \u043F\u043E \u043F\u0440\u0438\u043C\u0435\u043D\u0438\u043C\u043E\u0441\u0442\u0438.`,
|
|
18925
19059
|
" \u0427\u0435\u043A\u043E\u0432 \u043D\u0430 \u043A\u043E\u043C\u043C\u0438\u0442\u0435 \u043D\u0435\u0442 (\u0432 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0438 \u043D\u0435\u0442 CI) \u2014 \u044D\u0442\u043E \u041D\u0415 \u0434\u0435\u0444\u0435\u043A\u0442 PR \u0438 \u041D\u0415 \u043F\u043E\u0432\u043E\u0434 \u0434\u043B\u044F REQUEST CHANGES: \u043D\u0435 \u0436\u0434\u0438 \u0438\u0445, \u043D\u0435 \u0442\u0440\u0435\u0431\u0443\u0439 \u0437\u0430\u0432\u0435\u0441\u0442\u0438 workflow, \u0441\u0443\u0434\u0438 \u043F\u043E \u0441\u0432\u043E\u0435\u043C\u0443 \u043F\u0440\u043E\u0433\u043E\u043D\u0443. \u041A\u0440\u0430\u0441\u043D\u044B\u0439 \u0417\u0410\u0412\u0415\u0420\u0428\u0418\u0412\u0428\u0418\u0419\u0421\u042F \u0447\u0435\u043A, \u0435\u0441\u043B\u0438 CI \u0432 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0438 \u0432\u0441\u0451-\u0442\u0430\u043A\u0438 \u0435\u0441\u0442\u044C, \u2014 \u043F\u043E-\u043F\u0440\u0435\u0436\u043D\u0435\u043C\u0443 \u0431\u043B\u043E\u043A.",
|
|
18926
|
-
`2. \u041F\u0440\u043E\u0433\u043E\u043D \u0437\u0430\u043A\u043E\u043D\u0447\u0435\u043D \u2014 \u043E\u0441\u0442\u0430\u0432\u044C \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 \u043D\u0430 \u0441\u0430\u043C PR: \`gh pr comment ${prUrl} --body "..."\` (\u041D\u0415 \`gh pr review\` \u2014 GitHub \u0435\u0433\u043E \u043E\u0442\u043A\u043B\u043E\u043D\u0438\u0442 \u043D\u0430 \u0441\u0432\u043E\u0451\u043C PR). \u041D\u0430\u0447\u043D\u0438 \u0441 **APPROVE** \u0438\u043B\u0438 **REQUEST CHANGES** \u0437\u0430\u0433\u043B\u0430\u0432\u043D\u044B\u043C\u0438, \u0434\u0430\u043B\u044C\u0448\u0435 \u2014 \u043A\u043E\u043D\u043A\u0440\u0435\u0442\u0438\u043A\u0430: \u0447\u0442\u043E \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u043B (\u043F\u0440\u0438\u0432\u0435\u0434\u0438 \u0432\u044B\u0432\u043E\u0434 \u0441\u0432\u043E\u0435\u0433\u043E \u043F\u0440\u043E\u0433\u043E\u043D\u0430), \u0447\u0442\u043E \u043D\u0430\u0448\u0451\u043B; \u0434\u043B\u044F REQUEST CHANGES \u2014 \u0442\u043E\u0447\u043D\u044B\u0435 \u0444\u0430\u0439\u043B\u044B/\u0441\u0442\u0440\u043E\u043A\u0438 \u0438 \u0447\u0442\u043E \u0447\u0438\u043D\u0438\u0442\u044C. \u041F\u0440\u0435\u0442\u0435\u043D\u0437\u0438\u044F \u043A \u0438\u043D\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0435 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F (\u043D\u0435\u0442 CI, \u043A\u043E\u043D\u0444\u0438\u0433\u0438, \u0434\u0435\u043F\u043B\u043E\u0439) \u2014 \u043D\u0435 \u0432\u0435\u0440\u0434\u0438\u043A\u0442 \u043F\u043E PR: \u0441\u0447\u0438\u0442\u0430\u0435\u0448\u044C, \u0447\u0442\u043E \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044E \u043D\u0443\u0436\u0435\u043D CI, \u2014 \u0441\u043A\u0430\u0436\u0438 \u044D\u0442\u043E \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E\u0439 \u0441\u0442\u0440\u043E\u043A\u043E\u0439 \u0432 \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0435, \u043D\u043E \u0432\u0435\u0440\u0434\u0438\u043A\u0442 \u043E\u0442 \u043D\u0435\u0451 \u043D\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442.`
|
|
19060
|
+
`2. \u041F\u0440\u043E\u0433\u043E\u043D \u0437\u0430\u043A\u043E\u043D\u0447\u0435\u043D \u2014 \u043E\u0441\u0442\u0430\u0432\u044C \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 \u043D\u0430 \u0441\u0430\u043C PR: \`gh pr comment ${prUrl} --body "..."\` (\u041D\u0415 \`gh pr review\` \u2014 GitHub \u0435\u0433\u043E \u043E\u0442\u043A\u043B\u043E\u043D\u0438\u0442 \u043D\u0430 \u0441\u0432\u043E\u0451\u043C PR). \u041D\u0430\u0447\u043D\u0438 \u0441 **APPROVE** \u0438\u043B\u0438 **REQUEST CHANGES** \u0437\u0430\u0433\u043B\u0430\u0432\u043D\u044B\u043C\u0438, \u0434\u0430\u043B\u044C\u0448\u0435 \u2014 \u043A\u043E\u043D\u043A\u0440\u0435\u0442\u0438\u043A\u0430: \u0447\u0442\u043E \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u043B (\u043F\u0440\u0438\u0432\u0435\u0434\u0438 \u0432\u044B\u0432\u043E\u0434 \u0441\u0432\u043E\u0435\u0433\u043E \u043F\u0440\u043E\u0433\u043E\u043D\u0430), \u0447\u0442\u043E \u043D\u0430\u0448\u0451\u043B; \u0434\u043B\u044F REQUEST CHANGES \u2014 \u0442\u043E\u0447\u043D\u044B\u0435 \u0444\u0430\u0439\u043B\u044B/\u0441\u0442\u0440\u043E\u043A\u0438 \u0438 \u0447\u0442\u043E \u0447\u0438\u043D\u0438\u0442\u044C; \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0438\u043C \u0431\u043B\u043E\u043A\u043E\u043C \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430 \u2014 \`\`\`findings (\u0444\u043E\u0440\u043C\u0430\u0442 \u0432\u044B\u0448\u0435, \u043F\u0435\u0447\u0430\u0442\u0430\u0435\u0442\u0441\u044F \u0432\u0441\u0435\u0433\u0434\u0430). \u041F\u0440\u0435\u0442\u0435\u043D\u0437\u0438\u044F \u043A \u0438\u043D\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0435 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F (\u043D\u0435\u0442 CI, \u043A\u043E\u043D\u0444\u0438\u0433\u0438, \u0434\u0435\u043F\u043B\u043E\u0439) \u2014 \u043D\u0435 \u0432\u0435\u0440\u0434\u0438\u043A\u0442 \u043F\u043E PR: \u0441\u0447\u0438\u0442\u0430\u0435\u0448\u044C, \u0447\u0442\u043E \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044E \u043D\u0443\u0436\u0435\u043D CI, \u2014 \u0441\u043A\u0430\u0436\u0438 \u044D\u0442\u043E \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E\u0439 \u0441\u0442\u0440\u043E\u043A\u043E\u0439 \u0432 \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0435, \u043D\u043E \u0432\u0435\u0440\u0434\u0438\u043A\u0442 \u043E\u0442 \u043D\u0435\u0451 \u043D\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442.`
|
|
18927
19061
|
] : [
|
|
18928
19062
|
`1. \u041F\u0440\u043E\u0439\u0434\u0438 \u0447\u0435\u043A-\u043B\u0438\u0441\u0442 \u0432\u044B\u0448\u0435: \u0441\u0442\u0430\u0442\u0443\u0441 CI \u043F\u043E \u044D\u0442\u043E\u043C\u0443 \u043A\u043E\u043C\u043C\u0438\u0442\u0443 \u0447\u0438\u0442\u0430\u0439 \u0441\u0430\u043C (\u043D\u0435 \u0432\u0435\u0440\u044C \u043E\u0442\u0447\u0451\u0442\u0443 \u0430\u0432\u0442\u043E\u0440\u0430 PR, \u043D\u043E \u0438 \u043D\u0435 \u043F\u0435\u0440\u0435\u0433\u043E\u043D\u044F\u0439 CI \u0432\u0440\u0443\u0447\u043D\u0443\u044E), ${classesStep}\u043F\u0440\u043E\u0432\u0435\u0440\u044C \u043C\u0438\u0433\u0440\u0430\u0446\u0438\u0438/\u0433\u043E\u043D\u043A\u0438/UI/per-page meta \u043F\u043E \u043F\u0440\u0438\u043C\u0435\u043D\u0438\u043C\u043E\u0441\u0442\u0438.`,
|
|
18929
19063
|
" \u0415\u0441\u043B\u0438 \u0445\u043E\u0442\u044C \u043E\u0434\u0438\u043D \u0447\u0435\u043A \u0435\u0449\u0451 PENDING \u2014 \u043D\u0430 \u044D\u0442\u043E\u043C \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0441\u044C: \u0448\u0430\u0433\u0438 2 \u0438 3 \u043D\u0438\u0436\u0435 \u043F\u0440\u043E\u043F\u0443\u0441\u0442\u0438 \u0446\u0435\u043B\u0438\u043A\u043E\u043C, \u0432\u0435\u0440\u0434\u0438\u043A\u0442 \u043D\u0435 \u0432\u044B\u043D\u043E\u0441\u0438, \u043F\u0440\u043E\u0441\u0442\u043E \u0437\u0430\u0432\u0435\u0440\u0448\u0438 \u0441\u0435\u0441\u0441\u0438\u044E (\u0441\u043C. \u0447\u0435\u043A-\u043B\u0438\u0441\u0442 \u0432\u044B\u0448\u0435, \u043F\u043E\u0447\u0435\u043C\u0443 \u044D\u0442\u043E \u0431\u0435\u0437\u043E\u043F\u0430\u0441\u043D\u043E \u0438 \u0447\u0442\u043E \u043F\u0440\u043E\u0438\u0437\u043E\u0439\u0434\u0451\u0442 \u0434\u0430\u043B\u044C\u0448\u0435).",
|
|
18930
|
-
`2. \u0427\u0435\u043A\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043B\u0438\u0441\u044C (\u0437\u0435\u043B\u0451\u043D\u044B\u0435 \u0438\u043B\u0438 \u0441 \u043A\u0440\u0430\u0441\u043D\u044B\u043C) \u0438\u043B\u0438 \u043D\u0430 \u044D\u0442\u043E\u043C \u043A\u043E\u043C\u043C\u0438\u0442\u0435 \u0438\u0445 \u0432\u043E\u0432\u0441\u0435 \u043D\u0435\u0442 \u2014 \u043E\u0441\u0442\u0430\u0432\u044C \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 \u043D\u0430 \u0441\u0430\u043C PR: \`gh pr comment ${prUrl} --body "..."\` (\u041D\u0415 \`gh pr review\` \u2014 GitHub \u0435\u0433\u043E \u043E\u0442\u043A\u043B\u043E\u043D\u0438\u0442 \u043D\u0430 \u0441\u0432\u043E\u0451\u043C PR). \u041D\u0430\u0447\u043D\u0438 \u0441 **APPROVE** \u0438\u043B\u0438 **REQUEST CHANGES** \u0437\u0430\u0433\u043B\u0430\u0432\u043D\u044B\u043C\u0438, \u0434\u0430\u043B\u044C\u0448\u0435 \u2014 \u043A\u043E\u043D\u043A\u0440\u0435\u0442\u0438\u043A\u0430: \u0447\u0442\u043E \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u043B, \u0447\u0442\u043E \u043D\u0430\u0448\u0451\u043B; \u0434\u043B\u044F REQUEST CHANGES \u2014 \u0442\u043E\u0447\u043D\u044B\u0435 \u0444\u0430\u0439\u043B\u044B/\u0441\u0442\u0440\u043E\u043A\u0438 \u0438 \u0447\u0442\u043E \u0447\u0438\u043D\u0438\u0442\u044C.`
|
|
19064
|
+
`2. \u0427\u0435\u043A\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043B\u0438\u0441\u044C (\u0437\u0435\u043B\u0451\u043D\u044B\u0435 \u0438\u043B\u0438 \u0441 \u043A\u0440\u0430\u0441\u043D\u044B\u043C) \u0438\u043B\u0438 \u043D\u0430 \u044D\u0442\u043E\u043C \u043A\u043E\u043C\u043C\u0438\u0442\u0435 \u0438\u0445 \u0432\u043E\u0432\u0441\u0435 \u043D\u0435\u0442 \u2014 \u043E\u0441\u0442\u0430\u0432\u044C \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 \u043D\u0430 \u0441\u0430\u043C PR: \`gh pr comment ${prUrl} --body "..."\` (\u041D\u0415 \`gh pr review\` \u2014 GitHub \u0435\u0433\u043E \u043E\u0442\u043A\u043B\u043E\u043D\u0438\u0442 \u043D\u0430 \u0441\u0432\u043E\u0451\u043C PR). \u041D\u0430\u0447\u043D\u0438 \u0441 **APPROVE** \u0438\u043B\u0438 **REQUEST CHANGES** \u0437\u0430\u0433\u043B\u0430\u0432\u043D\u044B\u043C\u0438, \u0434\u0430\u043B\u044C\u0448\u0435 \u2014 \u043A\u043E\u043D\u043A\u0440\u0435\u0442\u0438\u043A\u0430: \u0447\u0442\u043E \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u043B, \u0447\u0442\u043E \u043D\u0430\u0448\u0451\u043B; \u0434\u043B\u044F REQUEST CHANGES \u2014 \u0442\u043E\u0447\u043D\u044B\u0435 \u0444\u0430\u0439\u043B\u044B/\u0441\u0442\u0440\u043E\u043A\u0438 \u0438 \u0447\u0442\u043E \u0447\u0438\u043D\u0438\u0442\u044C; \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0438\u043C \u0431\u043B\u043E\u043A\u043E\u043C \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430 \u2014 \`\`\`findings (\u0444\u043E\u0440\u043C\u0430\u0442 \u0432\u044B\u0448\u0435, \u043F\u0435\u0447\u0430\u0442\u0430\u0435\u0442\u0441\u044F \u0432\u0441\u0435\u0433\u0434\u0430).`
|
|
18931
19065
|
],
|
|
18932
19066
|
`3. \u0412\u044B\u0437\u043E\u0432\u0438 done(${prUrl}, verdict: "approve"|"changes", summary: "\u043A\u043E\u0440\u043E\u0442\u043A\u043E \u0447\u0442\u043E \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u043B \u0438 \u0447\u0442\u043E \u0440\u0435\u0448\u0438\u043B") \u2014 \u0440\u043E\u0439 \u0441\u0430\u043C \u0440\u0430\u0437\u043D\u0435\u0441\u0451\u0442 summary \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u043E\u043C \u0432 \u0437\u0430\u0434\u0430\u0447\u0443-\u0438\u0441\u0442\u043E\u0447\u043D\u0438\u043A, \u0430 verdict \u0437\u0430\u043F\u0438\u0448\u0435\u0442 \u043D\u0430 \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0435\u043C\u044B\u0439 \u043F\u0440\u043E\u0433\u043E\u043D (\u0431\u0435\u0439\u0434\u0436 \u0432 \u0432\u0435\u0431\u0435). \u0422\u044B \u0441\u0430\u043C \u0440\u0435\u0432\u044C\u044E \u041D\u0415 \u043F\u043E\u0434\u043B\u0435\u0436\u0438\u0448\u044C \u2014 \u0440\u0435\u043A\u0443\u0440\u0441\u0438\u0438 \u043D\u0435\u0442.`,
|
|
18933
19067
|
...rulesBlock ? ["", rulesBlock] : [],
|
|
@@ -20395,12 +20529,28 @@ async function postScrapedVerdictReport(deps, runId, taskSlug, verdict, droneNam
|
|
|
20395
20529
|
deps.db.addEvent(runId, "step", `\u0434\u0435\u043C\u043E\u043D-\u043E\u0442\u0447\u0451\u0442 \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u0430 \u0432 \u0437\u0430\u0434\u0430\u0447\u0443 ${taskSlug} \u043D\u0435 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D: ${e instanceof Error ? e.message : String(e)}`);
|
|
20396
20530
|
});
|
|
20397
20531
|
}
|
|
20532
|
+
function recordReviewFindings(deps, rv, comment) {
|
|
20533
|
+
const findings = comment.findings ?? null;
|
|
20534
|
+
const mode = comment.reviewMode ?? null;
|
|
20535
|
+
if (findings) for (const f of findings) deps.db.addEvent(rv.id, "finding", JSON.stringify(f));
|
|
20536
|
+
if (mode) deps.db.addEvent(rv.id, "review_mode", mode);
|
|
20537
|
+
if (!findings) deps.db.addEvent(rv.id, "step", "\u043C\u0430\u0448\u0438\u043D\u043E\u0447\u0438\u0442\u0430\u0435\u043C\u043E\u0433\u043E \u0431\u043B\u043E\u043A\u0430 \u043D\u0430\u0445\u043E\u0434\u043E\u043A \u0432 \u0432\u0435\u0440\u0434\u0438\u043A\u0442-\u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0435 \u043D\u0435\u0442 (\u0438\u043B\u0438 \u043E\u043D \u0431\u0438\u0442\u044B\u0439) \u2014 \u0432\u0435\u0440\u0434\u0438\u043A\u0442 \u0437\u0430\u0441\u0447\u0438\u0442\u0430\u043D \u043A\u0430\u043A \u0435\u0441\u0442\u044C, \u043D\u0430\u0445\u043E\u0434\u043A\u0438 \u043D\u0435 \u0440\u0430\u0437\u043E\u0431\u0440\u0430\u043D\u044B");
|
|
20538
|
+
}
|
|
20539
|
+
async function recordReviewFindingsFromPr(deps, rv) {
|
|
20540
|
+
if (!deps.verdictComment || !rv.pr_url) return;
|
|
20541
|
+
try {
|
|
20542
|
+
const found = await deps.verdictComment(rv.pr_url, rv.created_at);
|
|
20543
|
+
if (found) recordReviewFindings(deps, rv, found);
|
|
20544
|
+
} catch {
|
|
20545
|
+
}
|
|
20546
|
+
}
|
|
20398
20547
|
async function salvageVerdictFromPrComment(deps, rv, reviewsRunId, since, ctx) {
|
|
20399
20548
|
if (!deps.verdictComment || !rv.pr_url) return false;
|
|
20400
20549
|
const found = await deps.verdictComment(rv.pr_url, since).catch(() => null);
|
|
20401
20550
|
if (!found) return false;
|
|
20402
20551
|
const verdictText = verdictLabel(found.verdict);
|
|
20403
20552
|
deps.db.updateRun(reviewsRunId, { review_verdict: found.verdict });
|
|
20553
|
+
recordReviewFindings(deps, rv, found);
|
|
20404
20554
|
deps.db.addEvent(reviewsRunId, "step", `\u0432\u0435\u0440\u0434\u0438\u043A\u0442 \u0440\u0435\u0432\u044C\u044E \u043F\u043E\u0434\u0445\u0432\u0430\u0447\u0435\u043D \u0438\u0437 PR-\u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430 (${ctx.how}): ${verdictText}`);
|
|
20405
20555
|
await closeReviewerRun(
|
|
20406
20556
|
deps,
|
|
@@ -20683,6 +20833,7 @@ async function tickOnce(deps) {
|
|
|
20683
20833
|
}
|
|
20684
20834
|
if (run.worktree_path) await deps.removeWorktree(run.repo, run.worktree_path).catch(() => {
|
|
20685
20835
|
});
|
|
20836
|
+
await recordReviewFindingsFromPr(deps, run);
|
|
20686
20837
|
deps.db.updateRun(run.id, { status: "done" });
|
|
20687
20838
|
deps.db.addEvent(run.id, "done", "\u0440\u0435\u0432\u044C\u044E \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u043E, \u0432\u0435\u0440\u0434\u0438\u043A\u0442 \u0432\u044B\u043D\u0435\u0441\u0435\u043D");
|
|
20688
20839
|
narrate(deps, `${droneLabel(run)} \u0432\u044B\u043D\u0435\u0441 \u0432\u0435\u0440\u0434\u0438\u043A\u0442 \u043F\u043E \u0440\u0435\u0432\u044C\u044E \u2014 \u043F\u0440\u043E\u0433\u043E\u043D \u0437\u0430\u043A\u0440\u044B\u0442.`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taskless-app/swarm",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.47",
|
|
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": "561ecd5dfe7de7c9b1a106552bbef19921c65cbf",
|
|
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",
|