@taskless-app/swarm 0.6.45 → 0.6.46
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 +41 -9
- package/dist/overmind.js +154 -16
- 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",
|
|
@@ -3390,7 +3399,7 @@ var init_package = __esm({
|
|
|
3390
3399
|
"package.json"() {
|
|
3391
3400
|
package_default = {
|
|
3392
3401
|
name: "@taskless-app/swarm",
|
|
3393
|
-
version: "0.6.
|
|
3402
|
+
version: "0.6.46",
|
|
3394
3403
|
type: "module",
|
|
3395
3404
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
3396
3405
|
keywords: [
|
|
@@ -3441,7 +3450,7 @@ var init_package = __esm({
|
|
|
3441
3450
|
execa: "^10.0.0",
|
|
3442
3451
|
zod: "3.25.76"
|
|
3443
3452
|
},
|
|
3444
|
-
gitHead: "
|
|
3453
|
+
gitHead: "09254fc07f88535996f8b3da61c09ce8aeec0e92"
|
|
3445
3454
|
};
|
|
3446
3455
|
}
|
|
3447
3456
|
});
|
|
@@ -7589,13 +7598,15 @@ var SwarmClient = class _SwarmClient {
|
|
|
7589
7598
|
const key = this.keyByLocal.get(localId);
|
|
7590
7599
|
if (key) out[prodKey] = runRef(key);
|
|
7591
7600
|
}
|
|
7592
|
-
enqueueRun(run, fields) {
|
|
7601
|
+
enqueueRun(run, fields, opts = {}) {
|
|
7593
7602
|
if (Object.keys(fields).length === 0) return;
|
|
7594
7603
|
this.enqueue({
|
|
7595
7604
|
t: "run",
|
|
7596
7605
|
runKey: run.runKey,
|
|
7597
7606
|
taskRef: run.task_slug,
|
|
7598
7607
|
...run.workspace_id ? { workspaceId: run.workspace_id } : {},
|
|
7608
|
+
create: opts.create === true,
|
|
7609
|
+
// TASWM-562: пометка есть у КАЖДОЙ новой записи — см. resolveArgs
|
|
7599
7610
|
fields
|
|
7600
7611
|
});
|
|
7601
7612
|
}
|
|
@@ -7710,7 +7721,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
7710
7721
|
// закрепление (TASWM-291): true только у явного --host
|
|
7711
7722
|
base_branch: d.base_branch
|
|
7712
7723
|
// базовая ветка PR (TASWM-285), если задана на спавне
|
|
7713
|
-
}));
|
|
7724
|
+
}), { create: true });
|
|
7714
7725
|
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
7726
|
this.addEvent(id, "spawned", spawnNote);
|
|
7716
7727
|
return this.mat(d);
|
|
@@ -7749,7 +7760,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
7749
7760
|
runLogKeys(id) {
|
|
7750
7761
|
const key = this.runs.get(id)?.runKey;
|
|
7751
7762
|
if (!key) return [];
|
|
7752
|
-
const prodId =
|
|
7763
|
+
const prodId = this.prodIdFor(key);
|
|
7753
7764
|
if (!prodId) return [key];
|
|
7754
7765
|
const canonical = `p:${prodId}`;
|
|
7755
7766
|
const aliases = [key, ...[...this.prodIdByKey.entries()].filter(([, v]) => v === prodId).map(([k]) => k)];
|
|
@@ -9487,11 +9498,31 @@ var SwarmClient = class _SwarmClient {
|
|
|
9487
9498
|
for (const [full, path] of this.repoPathByFullName) if (path === norm) return full;
|
|
9488
9499
|
return /^[^/\s]+\/[^/\s]+$/.test(repo) ? repo : void 0;
|
|
9489
9500
|
}
|
|
9501
|
+
/**
|
|
9502
|
+
* Прод-id прогона по его runKey — ЕДИНСТВЕННЫЙ резолв на пути флаша (TASWM-562) и
|
|
9503
|
+
* в адресах run-лога (runLogKeys). Гидрированный прогон несёт cuid прямо в ключе
|
|
9504
|
+
* (`p:<cuid>`, см. hydrateRun). Карта prodIdByKey ему не подмога: в сайдкар она пишется
|
|
9505
|
+
* только после успешного create-флаша (persistMap), а прогон, РОЖДЁННЫЙ в проде
|
|
9506
|
+
* (claim/hydrate), туда не попадает никогда. Отсюда и брались пустые парные строки:
|
|
9507
|
+
* после рестарта демона recover() планирует флаш ДО первой гидрации, карта пуста —
|
|
9508
|
+
* и лежащий в outbox патч («прогон перешёл в done») заводил в проде второй прогон,
|
|
9509
|
+
* без токенов, цены, времени и PR.
|
|
9510
|
+
*/
|
|
9511
|
+
prodIdFor(runKey) {
|
|
9512
|
+
return runKey.startsWith("p:") ? runKey.slice(2) : this.prodIdByKey.get(runKey);
|
|
9513
|
+
}
|
|
9490
9514
|
async resolveArgs(e) {
|
|
9491
9515
|
if (e.t === "run") {
|
|
9492
9516
|
const fields = this.materializeRefs(e.fields);
|
|
9493
|
-
const prodId2 = this.
|
|
9517
|
+
const prodId2 = this.prodIdFor(e.runKey);
|
|
9494
9518
|
if (prodId2) return { tool: "swarm_run_upsert", args: { runId: prodId2, ...fields } };
|
|
9519
|
+
if (e.create === false) {
|
|
9520
|
+
console.error(
|
|
9521
|
+
`[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(", ")}`
|
|
9522
|
+
);
|
|
9523
|
+
this.poisonedRunKeys.add(e.runKey);
|
|
9524
|
+
return "skip";
|
|
9525
|
+
}
|
|
9495
9526
|
const taskId = await this.resolveTaskCuid(e.taskRef, this.repoFullNameFor(fields.repo), e.workspaceId);
|
|
9496
9527
|
if (taskId === "transient") {
|
|
9497
9528
|
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 +9540,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
9509
9540
|
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
9541
|
return "skip";
|
|
9511
9542
|
}
|
|
9512
|
-
const prodId = this.
|
|
9543
|
+
const prodId = this.prodIdFor(e.runKey);
|
|
9513
9544
|
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
9545
|
if (e.t === "event") return { tool: "swarm_event_append", args: { runId: prodId, kind: e.kind, text: e.text, actor: e.actor } };
|
|
9515
9546
|
return { tool: "swarm_ask", args: { runId: prodId, text: e.text } };
|
|
@@ -9522,7 +9553,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
9522
9553
|
const out = {};
|
|
9523
9554
|
for (const [k, v] of Object.entries(fields)) {
|
|
9524
9555
|
if (isRunRef(v)) {
|
|
9525
|
-
const cuid = this.
|
|
9556
|
+
const cuid = this.prodIdFor(v.__runRef);
|
|
9526
9557
|
if (cuid) out[k] = cuid;
|
|
9527
9558
|
} else {
|
|
9528
9559
|
out[k] = v;
|
|
@@ -9562,6 +9593,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
9562
9593
|
if (tries >= _SwarmClient.REJECT_LIMIT) {
|
|
9563
9594
|
this.pending.shift();
|
|
9564
9595
|
this.rejected.delete(e.seq);
|
|
9596
|
+
if (e.t === "run" && e.create === true) this.poisonedRunKeys.add(e.runKey);
|
|
9565
9597
|
console.error(
|
|
9566
9598
|
`[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
9599
|
);
|
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",
|
|
@@ -7827,13 +7836,15 @@ var SwarmClient = class _SwarmClient {
|
|
|
7827
7836
|
const key = this.keyByLocal.get(localId);
|
|
7828
7837
|
if (key) out[prodKey] = runRef(key);
|
|
7829
7838
|
}
|
|
7830
|
-
enqueueRun(run, fields) {
|
|
7839
|
+
enqueueRun(run, fields, opts = {}) {
|
|
7831
7840
|
if (Object.keys(fields).length === 0) return;
|
|
7832
7841
|
this.enqueue({
|
|
7833
7842
|
t: "run",
|
|
7834
7843
|
runKey: run.runKey,
|
|
7835
7844
|
taskRef: run.task_slug,
|
|
7836
7845
|
...run.workspace_id ? { workspaceId: run.workspace_id } : {},
|
|
7846
|
+
create: opts.create === true,
|
|
7847
|
+
// TASWM-562: пометка есть у КАЖДОЙ новой записи — см. resolveArgs
|
|
7837
7848
|
fields
|
|
7838
7849
|
});
|
|
7839
7850
|
}
|
|
@@ -7948,7 +7959,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
7948
7959
|
// закрепление (TASWM-291): true только у явного --host
|
|
7949
7960
|
base_branch: d.base_branch
|
|
7950
7961
|
// базовая ветка PR (TASWM-285), если задана на спавне
|
|
7951
|
-
}));
|
|
7962
|
+
}), { create: true });
|
|
7952
7963
|
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
7964
|
this.addEvent(id, "spawned", spawnNote);
|
|
7954
7965
|
return this.mat(d);
|
|
@@ -7987,7 +7998,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
7987
7998
|
runLogKeys(id) {
|
|
7988
7999
|
const key = this.runs.get(id)?.runKey;
|
|
7989
8000
|
if (!key) return [];
|
|
7990
|
-
const prodId =
|
|
8001
|
+
const prodId = this.prodIdFor(key);
|
|
7991
8002
|
if (!prodId) return [key];
|
|
7992
8003
|
const canonical = `p:${prodId}`;
|
|
7993
8004
|
const aliases = [key, ...[...this.prodIdByKey.entries()].filter(([, v]) => v === prodId).map(([k]) => k)];
|
|
@@ -9725,11 +9736,31 @@ var SwarmClient = class _SwarmClient {
|
|
|
9725
9736
|
for (const [full, path] of this.repoPathByFullName) if (path === norm) return full;
|
|
9726
9737
|
return /^[^/\s]+\/[^/\s]+$/.test(repo) ? repo : void 0;
|
|
9727
9738
|
}
|
|
9739
|
+
/**
|
|
9740
|
+
* Прод-id прогона по его runKey — ЕДИНСТВЕННЫЙ резолв на пути флаша (TASWM-562) и
|
|
9741
|
+
* в адресах run-лога (runLogKeys). Гидрированный прогон несёт cuid прямо в ключе
|
|
9742
|
+
* (`p:<cuid>`, см. hydrateRun). Карта prodIdByKey ему не подмога: в сайдкар она пишется
|
|
9743
|
+
* только после успешного create-флаша (persistMap), а прогон, РОЖДЁННЫЙ в проде
|
|
9744
|
+
* (claim/hydrate), туда не попадает никогда. Отсюда и брались пустые парные строки:
|
|
9745
|
+
* после рестарта демона recover() планирует флаш ДО первой гидрации, карта пуста —
|
|
9746
|
+
* и лежащий в outbox патч («прогон перешёл в done») заводил в проде второй прогон,
|
|
9747
|
+
* без токенов, цены, времени и PR.
|
|
9748
|
+
*/
|
|
9749
|
+
prodIdFor(runKey) {
|
|
9750
|
+
return runKey.startsWith("p:") ? runKey.slice(2) : this.prodIdByKey.get(runKey);
|
|
9751
|
+
}
|
|
9728
9752
|
async resolveArgs(e) {
|
|
9729
9753
|
if (e.t === "run") {
|
|
9730
9754
|
const fields = this.materializeRefs(e.fields);
|
|
9731
|
-
const prodId2 = this.
|
|
9755
|
+
const prodId2 = this.prodIdFor(e.runKey);
|
|
9732
9756
|
if (prodId2) return { tool: "swarm_run_upsert", args: { runId: prodId2, ...fields } };
|
|
9757
|
+
if (e.create === false) {
|
|
9758
|
+
console.error(
|
|
9759
|
+
`[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(", ")}`
|
|
9760
|
+
);
|
|
9761
|
+
this.poisonedRunKeys.add(e.runKey);
|
|
9762
|
+
return "skip";
|
|
9763
|
+
}
|
|
9733
9764
|
const taskId = await this.resolveTaskCuid(e.taskRef, this.repoFullNameFor(fields.repo), e.workspaceId);
|
|
9734
9765
|
if (taskId === "transient") {
|
|
9735
9766
|
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 +9778,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
9747
9778
|
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
9779
|
return "skip";
|
|
9749
9780
|
}
|
|
9750
|
-
const prodId = this.
|
|
9781
|
+
const prodId = this.prodIdFor(e.runKey);
|
|
9751
9782
|
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
9783
|
if (e.t === "event") return { tool: "swarm_event_append", args: { runId: prodId, kind: e.kind, text: e.text, actor: e.actor } };
|
|
9753
9784
|
return { tool: "swarm_ask", args: { runId: prodId, text: e.text } };
|
|
@@ -9760,7 +9791,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
9760
9791
|
const out = {};
|
|
9761
9792
|
for (const [k, v] of Object.entries(fields)) {
|
|
9762
9793
|
if (isRunRef(v)) {
|
|
9763
|
-
const cuid = this.
|
|
9794
|
+
const cuid = this.prodIdFor(v.__runRef);
|
|
9764
9795
|
if (cuid) out[k] = cuid;
|
|
9765
9796
|
} else {
|
|
9766
9797
|
out[k] = v;
|
|
@@ -9800,6 +9831,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
9800
9831
|
if (tries >= _SwarmClient.REJECT_LIMIT) {
|
|
9801
9832
|
this.pending.shift();
|
|
9802
9833
|
this.rejected.delete(e.seq);
|
|
9834
|
+
if (e.t === "run" && e.create === true) this.poisonedRunKeys.add(e.runKey);
|
|
9803
9835
|
console.error(
|
|
9804
9836
|
`[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
9837
|
);
|
|
@@ -12314,7 +12346,7 @@ function parkReasonUnretriable(reason) {
|
|
|
12314
12346
|
// package.json
|
|
12315
12347
|
var package_default = {
|
|
12316
12348
|
name: "@taskless-app/swarm",
|
|
12317
|
-
version: "0.6.
|
|
12349
|
+
version: "0.6.46",
|
|
12318
12350
|
type: "module",
|
|
12319
12351
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
12320
12352
|
keywords: [
|
|
@@ -12365,7 +12397,7 @@ var package_default = {
|
|
|
12365
12397
|
execa: "^10.0.0",
|
|
12366
12398
|
zod: "3.25.76"
|
|
12367
12399
|
},
|
|
12368
|
-
gitHead: "
|
|
12400
|
+
gitHead: "09254fc07f88535996f8b3da61c09ce8aeec0e92"
|
|
12369
12401
|
};
|
|
12370
12402
|
|
|
12371
12403
|
// src/version.ts
|
|
@@ -12741,6 +12773,70 @@ async function closePR(prUrl, run = realRunner) {
|
|
|
12741
12773
|
async function postPrComment(prUrl, body, run = realRunner) {
|
|
12742
12774
|
await run(["pr", "comment", prUrl, "--body", body]);
|
|
12743
12775
|
}
|
|
12776
|
+
var FINDING_CATEGORIES = [
|
|
12777
|
+
"correctness",
|
|
12778
|
+
"security",
|
|
12779
|
+
"reuse",
|
|
12780
|
+
"boundaries",
|
|
12781
|
+
"over-abstraction",
|
|
12782
|
+
"duplication",
|
|
12783
|
+
"spine",
|
|
12784
|
+
"tests",
|
|
12785
|
+
"ui-rules"
|
|
12786
|
+
];
|
|
12787
|
+
var FINDING_SEVERITIES = ["blocker", "major", "nit"];
|
|
12788
|
+
var FINDINGS_BLOCK_RE = /```findings[^\n]*\n([\s\S]*?)```/gi;
|
|
12789
|
+
var READ_ONLY_PHRASE_RE = /прогнать не мог|окружения нет/i;
|
|
12790
|
+
var FINDING_WHAT_MAX = 400;
|
|
12791
|
+
var FINDING_PATH_MAX = 300;
|
|
12792
|
+
var FINDINGS_MAX = 50;
|
|
12793
|
+
function oneOf(dict, v) {
|
|
12794
|
+
return typeof v === "string" && dict.includes(v) ? v : null;
|
|
12795
|
+
}
|
|
12796
|
+
function normalizeFinding(raw) {
|
|
12797
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
12798
|
+
const r = raw;
|
|
12799
|
+
const what = typeof r.what === "string" ? r.what.trim().slice(0, FINDING_WHAT_MAX) : "";
|
|
12800
|
+
if (!what) return null;
|
|
12801
|
+
const rawLine = typeof r.line === "number" ? r.line : typeof r.line === "string" && r.line.trim() ? Number(r.line) : NaN;
|
|
12802
|
+
return {
|
|
12803
|
+
category: oneOf(FINDING_CATEGORIES, r.category),
|
|
12804
|
+
severity: oneOf(FINDING_SEVERITIES, r.severity),
|
|
12805
|
+
path: typeof r.path === "string" && r.path.trim() ? r.path.trim().slice(0, FINDING_PATH_MAX) : null,
|
|
12806
|
+
// Номер строки — только целый положительный: «7.5», «-1» и NaN значат, что ревьюер
|
|
12807
|
+
// строку не знал, а не что дефект на строке −1 (по такому числу потом ищут в файле).
|
|
12808
|
+
line: Number.isInteger(rawLine) && rawLine > 0 ? rawLine : null,
|
|
12809
|
+
what
|
|
12810
|
+
};
|
|
12811
|
+
}
|
|
12812
|
+
function parseFindingsBlock(body) {
|
|
12813
|
+
const byPhrase = READ_ONLY_PHRASE_RE.test(body) ? "read" : null;
|
|
12814
|
+
const blocks = [...body.matchAll(FINDINGS_BLOCK_RE)];
|
|
12815
|
+
const last = blocks[blocks.length - 1];
|
|
12816
|
+
if (!last) return { findings: null, mode: byPhrase };
|
|
12817
|
+
let payload;
|
|
12818
|
+
try {
|
|
12819
|
+
payload = JSON.parse(last[1]);
|
|
12820
|
+
} catch {
|
|
12821
|
+
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");
|
|
12822
|
+
return { findings: null, mode: byPhrase };
|
|
12823
|
+
}
|
|
12824
|
+
const arr = Array.isArray(payload) ? payload : payload && typeof payload === "object" && Array.isArray(payload.findings) ? payload.findings : null;
|
|
12825
|
+
const mode = payload && typeof payload === "object" && !Array.isArray(payload) ? oneOf(["ran", "read"], payload.mode) ?? byPhrase : byPhrase;
|
|
12826
|
+
if (!arr) {
|
|
12827
|
+
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");
|
|
12828
|
+
return { findings: null, mode };
|
|
12829
|
+
}
|
|
12830
|
+
const capped = arr.slice(0, FINDINGS_MAX);
|
|
12831
|
+
if (arr.length > capped.length) {
|
|
12832
|
+
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`);
|
|
12833
|
+
}
|
|
12834
|
+
const findings = capped.map((raw) => normalizeFinding(raw)).filter((f) => f != null);
|
|
12835
|
+
if (findings.length < capped.length) {
|
|
12836
|
+
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));
|
|
12837
|
+
}
|
|
12838
|
+
return { findings, mode };
|
|
12839
|
+
}
|
|
12744
12840
|
var realCommentsRunner = (prUrl) => runGh(["pr", "view", prUrl, "--json", "comments"], GH_CALL_TIMEOUT_MS);
|
|
12745
12841
|
var VERDICT_RE = /^[^A-Za-z]*(APPROVED?|LGTM|(?:REQUEST(?:ED)?\s+)?CHANGES(?:\s+REQUESTED)?)\b/i;
|
|
12746
12842
|
var APPROVE_RE = /^(APPROVE|LGTM)/i;
|
|
@@ -12748,11 +12844,15 @@ function verdictLabel(verdict) {
|
|
|
12748
12844
|
return verdict === "approve" ? "\u2705 APPROVE" : "\u274C REQUEST CHANGES";
|
|
12749
12845
|
}
|
|
12750
12846
|
async function latestVerdictComment(prUrl, sinceIso, run = realCommentsRunner) {
|
|
12751
|
-
|
|
12847
|
+
const found = await scanPrComments(prUrl, sinceIso, run, (body) => {
|
|
12752
12848
|
const m = body.match(VERDICT_RE);
|
|
12753
12849
|
if (!m) return null;
|
|
12754
|
-
|
|
12850
|
+
const verdict = APPROVE_RE.test(m[1]) ? "approve" : "changes";
|
|
12851
|
+
const { findings, mode } = parseFindingsBlock(body);
|
|
12852
|
+
return { verdict, findings, reviewMode: mode };
|
|
12755
12853
|
});
|
|
12854
|
+
if (!found) return null;
|
|
12855
|
+
return { verdict: found.verdict.verdict, createdAt: found.createdAt, findings: found.verdict.findings, reviewMode: found.verdict.reviewMode };
|
|
12756
12856
|
}
|
|
12757
12857
|
async function scanPrComments(prUrl, sinceIso, run, pick4) {
|
|
12758
12858
|
if (!isGithubPrUrl(prUrl)) return null;
|
|
@@ -18808,14 +18908,19 @@ function ciTrustLine(prUrl, verifyMode) {
|
|
|
18808
18908
|
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
18909
|
}
|
|
18810
18910
|
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). \
|
|
18911
|
+
"\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
18912
|
"- [ ] \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
18913
|
"- [ ] \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
18914
|
"- [ ] \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
18915
|
"- [ ] \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
18916
|
"- [ ] \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
18917
|
"- [ ] \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."
|
|
18918
|
+
" \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.",
|
|
18919
|
+
"- [ ] \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.",
|
|
18920
|
+
'- [ ] \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.',
|
|
18921
|
+
"- [ ] \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.",
|
|
18922
|
+
"- [ ] \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.",
|
|
18923
|
+
"- [ ] \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
18924
|
].join("\n");
|
|
18820
18925
|
function buildReviewChecklist(reviewRun, files, priorReview, verifyMode = SWARM_VERIFY) {
|
|
18821
18926
|
const header = files.length ? `\u0424\u0430\u0439\u043B\u044B \u0434\u0438\u0444\u0444\u0430 (${files.length}):
|
|
@@ -18839,7 +18944,8 @@ ${priorReview}` : "",
|
|
|
18839
18944
|
"- [ ] \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
18945
|
// Единственный класс из REVIEW_DEFECT_CLASSES, который на втором круге обязателен:
|
|
18841
18946
|
// правки по вердикту почти всегда приносят НОВЫЕ тесты, и именно тут прошёл #819.
|
|
18842
|
-
// Остальные пять
|
|
18947
|
+
// Остальные классы (включая пять про качество кода, TASWM-559) заново не гоняем —
|
|
18948
|
+
// ре-чек намеренно короткий (TASWM-437).
|
|
18843
18949
|
"- [ ] \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
18950
|
].filter(Boolean).join("\n");
|
|
18845
18951
|
}
|
|
@@ -18886,6 +18992,19 @@ var REVIEW_MISSION_BLOCK = [
|
|
|
18886
18992
|
"\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
18993
|
"\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
18994
|
].join("\n");
|
|
18995
|
+
var REVIEW_FINDINGS_BLOCK = [
|
|
18996
|
+
"\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:",
|
|
18997
|
+
"```findings",
|
|
18998
|
+
'{"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"}]}',
|
|
18999
|
+
"```",
|
|
19000
|
+
// Словари — ИЗ ОДНОГО МЕСТА с разбором (gh.FINDING_CATEGORIES/FINDING_SEVERITIES): значение,
|
|
19001
|
+
// названное промптом, но не знакомое парсеру, молча превращается в `null` — находка приедет
|
|
19002
|
+
// без класса, и никто этого не заметит.
|
|
19003
|
+
`\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.`,
|
|
19004
|
+
"\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.",
|
|
19005
|
+
'\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": []}.',
|
|
19006
|
+
"\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."
|
|
19007
|
+
].join("\n");
|
|
18889
19008
|
function buildReviewerPrompt(reviewRun, reviewer, checklist, branch, attachmentsBlock, verifyMode = SWARM_VERIFY, pendingRules = []) {
|
|
18890
19009
|
const name = reviewer.name || `#${reviewer.id}`;
|
|
18891
19010
|
const rulesBlock = renderPendingRulesBlock(pendingRules);
|
|
@@ -18919,15 +19038,17 @@ function buildReviewerPrompt(reviewRun, reviewer, checklist, branch, attachments
|
|
|
18919
19038
|
"",
|
|
18920
19039
|
checklist,
|
|
18921
19040
|
"",
|
|
19041
|
+
REVIEW_FINDINGS_BLOCK,
|
|
19042
|
+
"",
|
|
18922
19043
|
"\u041F\u043E\u0440\u044F\u0434\u043E\u043A:",
|
|
18923
19044
|
...verifyMode === "local" ? [
|
|
18924
19045
|
`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
19046
|
" \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.`
|
|
19047
|
+
`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
19048
|
] : [
|
|
18928
19049
|
`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
19050
|
" \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.`
|
|
19051
|
+
`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
19052
|
],
|
|
18932
19053
|
`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
19054
|
...rulesBlock ? ["", rulesBlock] : [],
|
|
@@ -20395,12 +20516,28 @@ async function postScrapedVerdictReport(deps, runId, taskSlug, verdict, droneNam
|
|
|
20395
20516
|
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
20517
|
});
|
|
20397
20518
|
}
|
|
20519
|
+
function recordReviewFindings(deps, rv, comment) {
|
|
20520
|
+
const findings = comment.findings ?? null;
|
|
20521
|
+
const mode = comment.reviewMode ?? null;
|
|
20522
|
+
if (findings) for (const f of findings) deps.db.addEvent(rv.id, "finding", JSON.stringify(f));
|
|
20523
|
+
if (mode) deps.db.addEvent(rv.id, "review_mode", mode);
|
|
20524
|
+
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");
|
|
20525
|
+
}
|
|
20526
|
+
async function recordReviewFindingsFromPr(deps, rv) {
|
|
20527
|
+
if (!deps.verdictComment || !rv.pr_url) return;
|
|
20528
|
+
try {
|
|
20529
|
+
const found = await deps.verdictComment(rv.pr_url, rv.created_at);
|
|
20530
|
+
if (found) recordReviewFindings(deps, rv, found);
|
|
20531
|
+
} catch {
|
|
20532
|
+
}
|
|
20533
|
+
}
|
|
20398
20534
|
async function salvageVerdictFromPrComment(deps, rv, reviewsRunId, since, ctx) {
|
|
20399
20535
|
if (!deps.verdictComment || !rv.pr_url) return false;
|
|
20400
20536
|
const found = await deps.verdictComment(rv.pr_url, since).catch(() => null);
|
|
20401
20537
|
if (!found) return false;
|
|
20402
20538
|
const verdictText = verdictLabel(found.verdict);
|
|
20403
20539
|
deps.db.updateRun(reviewsRunId, { review_verdict: found.verdict });
|
|
20540
|
+
recordReviewFindings(deps, rv, found);
|
|
20404
20541
|
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
20542
|
await closeReviewerRun(
|
|
20406
20543
|
deps,
|
|
@@ -20683,6 +20820,7 @@ async function tickOnce(deps) {
|
|
|
20683
20820
|
}
|
|
20684
20821
|
if (run.worktree_path) await deps.removeWorktree(run.repo, run.worktree_path).catch(() => {
|
|
20685
20822
|
});
|
|
20823
|
+
await recordReviewFindingsFromPr(deps, run);
|
|
20686
20824
|
deps.db.updateRun(run.id, { status: "done" });
|
|
20687
20825
|
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
20826
|
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.46",
|
|
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": "09254fc07f88535996f8b3da61c09ce8aeec0e92",
|
|
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",
|