@taskless-app/swarm 0.6.9 → 0.6.11
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 +299 -4
- package/dist/overmind.js +138 -26
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -2055,7 +2055,7 @@ var init_package = __esm({
|
|
|
2055
2055
|
"package.json"() {
|
|
2056
2056
|
package_default = {
|
|
2057
2057
|
name: "@taskless-app/swarm",
|
|
2058
|
-
version: "0.6.
|
|
2058
|
+
version: "0.6.11",
|
|
2059
2059
|
type: "module",
|
|
2060
2060
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
2061
2061
|
keywords: [
|
|
@@ -2105,7 +2105,7 @@ var init_package = __esm({
|
|
|
2105
2105
|
execa: "^10.0.0",
|
|
2106
2106
|
zod: "3.25.76"
|
|
2107
2107
|
},
|
|
2108
|
-
gitHead: "
|
|
2108
|
+
gitHead: "f228c3fd9ac879e828e5b813bf8ff077402fbe23"
|
|
2109
2109
|
};
|
|
2110
2110
|
}
|
|
2111
2111
|
});
|
|
@@ -4182,8 +4182,8 @@ var init_updateCli = __esm({
|
|
|
4182
4182
|
|
|
4183
4183
|
// src/cli.ts
|
|
4184
4184
|
init_cliIo();
|
|
4185
|
-
import { basename as basename4 } from "path";
|
|
4186
|
-
import { existsSync as existsSync14, readdirSync as readdirSync9, statSync as statSync9, openSync as openSync4, readSync as readSync2, closeSync as closeSync4 } from "fs";
|
|
4185
|
+
import { basename as basename4, join as join23 } from "path";
|
|
4186
|
+
import { existsSync as existsSync14, readFileSync as readFileSync16, readdirSync as readdirSync9, statSync as statSync9, openSync as openSync4, readSync as readSync2, closeSync as closeSync4, rmSync as rmSync2 } from "fs";
|
|
4187
4187
|
import { setTimeout as sleep2 } from "timers/promises";
|
|
4188
4188
|
|
|
4189
4189
|
// src/swarmClient.ts
|
|
@@ -5635,6 +5635,51 @@ var SwarmClient = class _SwarmClient {
|
|
|
5635
5635
|
if (!Array.isArray(prepare)) return null;
|
|
5636
5636
|
return prepare.filter((c) => typeof c === "string" && c.trim().length > 0).map((c) => c.trim());
|
|
5637
5637
|
}
|
|
5638
|
+
/**
|
|
5639
|
+
* РАЗМЕТКА репозитория (TASWM-381) из того же swarm_repo_config: зоны, чем поднять
|
|
5640
|
+
* окружение, чем проверять, конвенции, общий хребет, бриф — плюс карта источников
|
|
5641
|
+
* (кто вписал поле: разведчик или человек). Отдаём КАК ЕСТЬ, объектом: строгая
|
|
5642
|
+
* схема разметки живёт в проде (@taskless-app/shared), и второй её копии в демоне
|
|
5643
|
+
* быть не должно — разъехавшись, они спорили бы о том, что считать валидным.
|
|
5644
|
+
*
|
|
5645
|
+
* null — разметки нет (разведка не проходила; РАБОЧЕЕ состояние), репо не смэплено
|
|
5646
|
+
* на swarm-проект владельца токена или прод недоступен.
|
|
5647
|
+
*/
|
|
5648
|
+
async repoProfile(repoFullName) {
|
|
5649
|
+
let res;
|
|
5650
|
+
try {
|
|
5651
|
+
res = await this.call("swarm_repo_config", { repoFullName });
|
|
5652
|
+
} catch {
|
|
5653
|
+
return null;
|
|
5654
|
+
}
|
|
5655
|
+
if (res?.isError) return null;
|
|
5656
|
+
const sc = res.structuredContent ?? {};
|
|
5657
|
+
const p = sc.profile;
|
|
5658
|
+
return p && typeof p === "object" && !Array.isArray(p) ? p : null;
|
|
5659
|
+
}
|
|
5660
|
+
/**
|
|
5661
|
+
* РАЗВЕДКА репозитория (TASWM-382): отправить в прод то, что разведчик вычитал в коде.
|
|
5662
|
+
* Живую разметку это НЕ меняет — предложение ложится рядом и ждёт человека; поэтому
|
|
5663
|
+
* ошибка здесь дорога ровно на стоимость прогона разведки, и мы её возвращаем, а не
|
|
5664
|
+
* глотаем, как чтения выше.
|
|
5665
|
+
*
|
|
5666
|
+
* Мимо outbox (в отличие от мутаций прогонов): предложение имеет смысл только вместе
|
|
5667
|
+
* со свежим состоянием репозитория, и доехавшее через сутки после разведки — хуже,
|
|
5668
|
+
* чем не доехавшее вовсе. Прод недоступен — человек перезапустит разведку.
|
|
5669
|
+
*/
|
|
5670
|
+
async reportRepoScout(repoFullName, report, by) {
|
|
5671
|
+
let res;
|
|
5672
|
+
try {
|
|
5673
|
+
res = await this.call("swarm_repo_scout_report", { repoFullName, report, ...by ? { by } : {} });
|
|
5674
|
+
} catch (e) {
|
|
5675
|
+
return { ok: false, error: `\u043F\u0440\u043E\u0434 \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D: ${e.message}` };
|
|
5676
|
+
}
|
|
5677
|
+
const text = res?.content?.map((c) => "text" in c ? c.text : "").join(" ") ?? "";
|
|
5678
|
+
if (res?.isError) return { ok: false, error: text || "\u043F\u0440\u043E\u0434 \u043E\u0442\u043A\u043B\u043E\u043D\u0438\u043B \u043F\u0440\u0435\u0434\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u0440\u0430\u0437\u0432\u0435\u0434\u043A\u0438" };
|
|
5679
|
+
const sc = res.structuredContent ?? {};
|
|
5680
|
+
const diff = Array.isArray(sc.diff) ? sc.diff : [];
|
|
5681
|
+
return { ok: true, diff, display: text };
|
|
5682
|
+
}
|
|
5638
5683
|
/**
|
|
5639
5684
|
* Live ТРЕБОВАНИЯ К ОКРУЖЕНИЮ машины из Taskless (TASWM-313): тот же swarm_repo_config по
|
|
5640
5685
|
* repoFullName — Project.swarmConfig.requires. Демон проверяет их ПЕРЕД спавном дрона и не
|
|
@@ -9343,6 +9388,12 @@ async function removeWorktree(repo, path) {
|
|
|
9343
9388
|
await detachWorktree(repo, path);
|
|
9344
9389
|
if (branch) await $5({ reject: false })`git -C ${repo} branch -D ${branch}`;
|
|
9345
9390
|
}
|
|
9391
|
+
var GITHUB_REMOTE_RE = /github\.com[:/]([^/]+\/[^/]+?)(?:\.git)?\/?$/i;
|
|
9392
|
+
async function remoteRepoFullName(repo) {
|
|
9393
|
+
const url = (await $5({ reject: false })`git -C ${repo} remote get-url origin`).stdout.trim();
|
|
9394
|
+
const m = url.match(GITHUB_REMOTE_RE);
|
|
9395
|
+
return m ? m[1] : null;
|
|
9396
|
+
}
|
|
9346
9397
|
|
|
9347
9398
|
// src/cli.ts
|
|
9348
9399
|
init_agentToken();
|
|
@@ -9537,6 +9588,191 @@ function resilientSwarmMcp(opts = {}) {
|
|
|
9537
9588
|
};
|
|
9538
9589
|
}
|
|
9539
9590
|
|
|
9591
|
+
// src/repoScout.ts
|
|
9592
|
+
import { HEADLESS_BLOCK } from "./overmind.js";
|
|
9593
|
+
var SCOUT_FIELDS = ["brief", "zones", "env", "verify", "conventions", "spine"];
|
|
9594
|
+
var SHAPE = `{
|
|
9595
|
+
"brief": "\u0427\u0442\u043E \u044D\u0442\u043E \u0437\u0430 \u043F\u0440\u043E\u0434\u0443\u043A\u0442 \u0438 \u043D\u0430 \u0447\u0451\u043C \u043D\u0430\u043F\u0438\u0441\u0430\u043D \u2014 3-5 \u0441\u0442\u0440\u043E\u043A, \u0447\u0442\u043E\u0431\u044B \u0434\u0440\u043E\u043D \u043D\u0435 \u0432\u044B\u0432\u043E\u0434\u0438\u043B \u044D\u0442\u043E \u0438\u0437 \u043A\u043E\u0434\u0430 \u0437\u0430\u043D\u043E\u0432\u043E.",
|
|
9596
|
+
"zones": [
|
|
9597
|
+
{ "label": "area:<\u043A\u043E\u0440\u043E\u0442\u043A\u043E\u0435-\u0438\u043C\u044F>", "about": "\u0447\u0442\u043E \u044D\u0442\u043E \u0437\u0430 \u0437\u043E\u043D\u0430 \u043E\u0434\u043D\u043E\u0439 \u0441\u0442\u0440\u043E\u043A\u043E\u0439", "paths": ["packages/api/"] }
|
|
9598
|
+
],
|
|
9599
|
+
"env": {
|
|
9600
|
+
"database": "\u0447\u0435\u043C \u043F\u043E\u0434\u043D\u044F\u0442\u044C \u0431\u0430\u0437\u0443, \u0440\u043E\u0432\u043D\u043E \u043E\u0434\u043D\u0430 \u043A\u043E\u043C\u0430\u043D\u0434\u0430",
|
|
9601
|
+
"migrations": "\u0447\u0435\u043C \u043D\u0430\u043A\u0430\u0442\u0438\u0442\u044C \u043C\u0438\u0433\u0440\u0430\u0446\u0438\u0438, \u0440\u043E\u0432\u043D\u043E \u043E\u0434\u043D\u0430 \u043A\u043E\u043C\u0430\u043D\u0434\u0430",
|
|
9602
|
+
"vars": ["\u0418\u041C\u0415\u041D\u0410", "\u041F\u0415\u0420\u0415\u041C\u0415\u041D\u041D\u042B\u0425", "\u0411\u0415\u0417_\u0417\u041D\u0410\u0427\u0415\u041D\u0418\u0419"]
|
|
9603
|
+
},
|
|
9604
|
+
"verify": {
|
|
9605
|
+
"commands": ["pnpm typecheck", "pnpm test"],
|
|
9606
|
+
"green": "\u0447\u0442\u043E \u0437\u0434\u0435\u0441\u044C \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F \u0437\u0435\u043B\u0451\u043D\u044B\u043C \u0441\u043B\u043E\u0432\u0430\u043C\u0438: \u0447\u0442\u043E \u0433\u043E\u043D\u044F\u0435\u0442\u0441\u044F \u043B\u043E\u043A\u0430\u043B\u044C\u043D\u043E, \u0447\u0442\u043E \u0442\u043E\u043B\u044C\u043A\u043E \u043D\u0430 CI, \u043A\u0430\u043A\u043E\u0439 \u0447\u0435\u043A \u0444\u043E\u0440\u043C\u0430\u043B\u044C\u043D\u044B\u0439 \u043F\u0440\u0438\u0437\u043D\u0430\u043A"
|
|
9607
|
+
},
|
|
9608
|
+
"conventions": { "commitLanguage": "ru|en", "slugInCommit": true, "baseBranch": "main" },
|
|
9609
|
+
"spine": ["packages/api/prisma/schema.prisma", "packages/shared/src/"]
|
|
9610
|
+
}`;
|
|
9611
|
+
function buildScoutPrompt(input) {
|
|
9612
|
+
const name = input.name ?? "\u0440\u0430\u0437\u0432\u0435\u0434\u0447\u0438\u043A";
|
|
9613
|
+
const known = describeKnownProfile(input.profile ?? null);
|
|
9614
|
+
return [
|
|
9615
|
+
`\u0422\u044B \u2014 ${name}, \u0420\u0410\u0417\u0412\u0415\u0414\u0427\u0418\u041A \u0440\u043E\u044F: headless-\u0441\u0435\u0441\u0441\u0438\u044F (\u041D\u0415 \u0438\u043D\u0442\u0435\u0440\u0430\u043A\u0442\u0438\u0432\u043D\u044B\u0439 \u0447\u0430\u0442), \u043E\u0434\u043D\u043E\u0440\u0430\u0437\u043E\u0432\u044B\u0439 \u043F\u0440\u043E\u0433\u043E\u043D \xAB\u0440\u0430\u0437\u0432\u0435\u0434\u043A\u0430 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F\xBB.`,
|
|
9616
|
+
"",
|
|
9617
|
+
HEADLESS_BLOCK,
|
|
9618
|
+
"",
|
|
9619
|
+
`\u0420\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0439: ${input.repoFullName}, \u043A\u043B\u043E\u043D \u043D\u0430 \u044D\u0442\u043E\u0439 \u043C\u0430\u0448\u0438\u043D\u0435: ${input.repoPath}. \u0422\u044B \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0448\u044C \u0432 \u043D\u0451\u043C.`,
|
|
9620
|
+
"",
|
|
9621
|
+
"\u0427\u0422\u041E \u041E\u0422 \u0422\u0415\u0411\u042F \u041D\u0423\u0416\u041D\u041E. \u0420\u043E\u0439 \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0438\u043B\u0438 \u043A \u044D\u0442\u043E\u043C\u0443 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044E, \u0438 \u0434\u0430\u043B\u044C\u0448\u0435 \u043E\u043D \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u0432\u0441\u043B\u0435\u043F\u0443\u044E: \u0437\u043E\u043D\u044B \u0434\u043B\u044F \u0437\u0430\u0434\u0430\u0447 \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0440\u0430\u0441\u0441\u0442\u0430\u0432\u043B\u044F\u0435\u0442 \u0440\u0443\u043A\u0430\u043C\u0438, \u043A\u0430\u043A \u043F\u043E\u0434\u043D\u044F\u0442\u044C \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u2014 \u0434\u0440\u043E\u043D \u0443\u0433\u0430\u0434\u044B\u0432\u0430\u0435\u0442, \u0447\u0442\u043E \u0441\u0447\u0438\u0442\u0430\u0442\u044C \u0437\u0435\u043B\u0451\u043D\u044B\u043C \u2014 \u043D\u0435 \u0437\u043D\u0430\u0435\u0442 \u043D\u0438\u043A\u0442\u043E. \u041F\u0440\u043E\u0447\u0438\u0442\u0430\u0439 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0439 \u0438 \u043F\u0440\u0435\u0434\u043B\u043E\u0436\u0438 \u0440\u0430\u0437\u043C\u0435\u0442\u043A\u0443: \u0442\u043E, \u0447\u0442\u043E \u0434\u0440\u043E\u043D \u043E\u0431\u044F\u0437\u0430\u043D \u0437\u043D\u0430\u0442\u044C \u0414\u041E \u043F\u0435\u0440\u0432\u043E\u0439 \u0437\u0430\u0434\u0430\u0447\u0438.",
|
|
9622
|
+
"",
|
|
9623
|
+
"\u0421\u043E\u0431\u0435\u0440\u0438 \u0448\u0435\u0441\u0442\u044C \u043F\u043E\u043B\u0435\u0439:",
|
|
9624
|
+
"1. `brief` \u2014 \u0447\u0442\u043E \u044D\u0442\u043E \u0437\u0430 \u043F\u0440\u043E\u0434\u0443\u043A\u0442 \u0438 \u043D\u0430 \u0447\u0451\u043C \u043D\u0430\u043F\u0438\u0441\u0430\u043D. \u041A\u043E\u0440\u043E\u0442\u043A\u043E, \u0447\u0442\u043E\u0431\u044B \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0439 \u0434\u0440\u043E\u043D \u043D\u0435 \u0432\u044B\u0432\u043E\u0434\u0438\u043B \u044D\u0442\u043E \u0438\u0437 \u043A\u043E\u0434\u0430 \u0437\u0430\u043D\u043E\u0432\u043E.",
|
|
9625
|
+
"2. `zones` \u2014 \u0437\u043E\u043D\u044B \u043A\u043E\u0434\u0430, \u043B\u0435\u0439\u0431\u043B\u044B `area:*`: \u043F\u0430\u043A\u0435\u0442\u044B, \u043C\u043E\u0434\u0443\u043B\u0438, \u043A\u0430\u0442\u0430\u043B\u043E\u0433\u0438 \u0444\u0438\u0447. \u041F\u043E \u043D\u0438\u043C \u0440\u043E\u0439 \u0440\u0430\u0437\u0432\u043E\u0434\u0438\u0442 \u043F\u0430\u0440\u0430\u043B\u043B\u0435\u043B\u044C\u043D\u044B\u0435 \u0437\u0430\u0434\u0430\u0447\u0438, \u043F\u043E\u044D\u0442\u043E\u043C\u0443 \u0443 \u043A\u0430\u0436\u0434\u043E\u0439 \u0437\u043E\u043D\u044B \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u044B `paths` (\u043A\u0430\u0442\u0430\u043B\u043E\u0433/\u043F\u0440\u0435\u0444\u0438\u043A\u0441, glob). \u0414\u0440\u043E\u0431\u0438 \u043F\u043E \u0420\u0415\u0410\u041B\u042C\u041D\u041E\u0419 \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0435 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F, \u0430 \u043D\u0435 \u043F\u043E \u043A\u0440\u0430\u0441\u0438\u0432\u044B\u043C \u0441\u043B\u043E\u0432\u0430\u043C: \u0437\u043E\u043D\u0430, \u043A\u043E\u0442\u043E\u0440\u043E\u0439 \u043D\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043A\u0430\u0442\u0430\u043B\u043E\u0433, \u0431\u0435\u0441\u043F\u043E\u043B\u0435\u0437\u043D\u0430.",
|
|
9626
|
+
"3. `env` \u2014 \u043A\u0430\u043A \u043F\u043E\u0434\u043D\u044F\u0442\u044C \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435: \u0447\u0435\u043C \u043F\u043E\u0434\u043D\u0438\u043C\u0430\u0435\u0442\u0441\u044F \u0431\u0430\u0437\u0430 (`database`), \u0447\u0435\u043C \u043D\u0430\u043A\u0430\u0442\u044B\u0432\u0430\u044E\u0442\u0441\u044F \u043C\u0438\u0433\u0440\u0430\u0446\u0438\u0438 (`migrations`), \u043A\u0430\u043A\u0438\u0435 \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0435 \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u044F \u043D\u0443\u0436\u043D\u044B (`vars` \u2014 \u0422\u041E\u041B\u042C\u041A\u041E \u0418\u041C\u0415\u041D\u0410; \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F \u044D\u0442\u043E \u0441\u0435\u043A\u0440\u0435\u0442\u044B, \u043E\u043D\u0438 \u0443\u0435\u0434\u0443\u0442 \u0432 \u043F\u0440\u043E\u043C\u043F\u0442 \u0434\u0440\u043E\u043D\u0430 \u0438 \u0432 \u0438\u043D\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043A\u0430\u043A \u043E\u0431\u044B\u0447\u043D\u044B\u0439 \u0442\u0435\u043A\u0441\u0442). \u042D\u0442\u043E \u043F\u0440\u043E \u0442\u043E, \u0447\u0435\u043C \u043F\u043E\u0434\u043D\u0438\u043C\u0430\u044E\u0442 \u0421\u0410\u041C\u041E \u041F\u0420\u0418\u041B\u041E\u0416\u0415\u041D\u0418\u0415, \u0430 \u043D\u0435 \u0442\u0435\u0441\u0442\u044B: \u0432\u043E \u043C\u043D\u043E\u0433\u0438\u0445 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F\u0445 \u0442\u0435\u0441\u0442\u043E\u0432\u0430\u044F \u0431\u0430\u0437\u0430 \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u0430\u044F \u2014 \u0441\u0432\u043E\u0439 compose-\u0444\u0430\u0439\u043B, \u0441\u0432\u043E\u0439 \u0441\u043A\u0440\u0438\u043F\u0442, \u0441\u0432\u043E\u0439 \u043F\u043E\u0440\u0442, \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u0430\u044F \u0432\u0438\u0434\u0430 `TEST_DATABASE_URL`. \u041E\u043D\u0430 \u0441\u044E\u0434\u0430 \u041D\u0415 \u0438\u0434\u0451\u0442. \u041C\u0438\u0433\u0440\u0430\u0446\u0438\u0438, \u043D\u0430\u043A\u0430\u0442\u0430\u043D\u043D\u044B\u0435 \u0432 \u0442\u0435\u0441\u0442\u043E\u0432\u0443\u044E \u0431\u0430\u0437\u0443, \u043E\u0441\u0442\u0430\u0432\u044F\u0442 \u0440\u0430\u0431\u043E\u0447\u0443\u044E \u043D\u0430 \u0441\u0442\u0430\u0440\u043E\u0439 \u0441\u0445\u0435\u043C\u0435, \u0430 \u0434\u0440\u043E\u043D \u0431\u0443\u0434\u0435\u0442 \u0441\u0447\u0438\u0442\u0430\u0442\u044C \u0435\u0451 \u043E\u0431\u043D\u043E\u0432\u043B\u0451\u043D\u043D\u043E\u0439. \u0418\u0449\u0438 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u0432\u0445\u043E\u0434: \u0441\u043A\u0440\u0438\u043F\u0442 \u0437\u0430\u043F\u0443\u0441\u043A\u0430 \u0432 `scripts/`, `dev`/`start` \u0432 \u043C\u0430\u043D\u0438\u0444\u0435\u0441\u0442\u0435, \u0440\u0430\u0437\u0434\u0435\u043B README \xAB\u043A\u0430\u043A \u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C\xBB, \u0444\u0430\u0439\u043B \u043F\u0440\u0430\u0432\u0438\u043B \u0434\u043B\u044F \u0430\u0433\u0435\u043D\u0442\u043E\u0432.",
|
|
9627
|
+
"4. `verify` \u2014 \u0447\u0435\u043C \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0442\u044C (`commands`) \u0438 \u0447\u0442\u043E \u0437\u0434\u0435\u0441\u044C \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F \u0437\u0435\u043B\u0451\u043D\u044B\u043C (`green` \u2014 \u0441\u043B\u043E\u0432\u0430\u043C\u0438: \u0447\u0442\u043E \u0433\u043E\u043D\u044F\u0435\u0442\u0441\u044F \u043B\u043E\u043A\u0430\u043B\u044C\u043D\u043E, \u0447\u0442\u043E \u0442\u043E\u043B\u044C\u043A\u043E \u043D\u0430 CI, \u043A\u0430\u043A\u043E\u0439 \u0447\u0435\u043A \u0441\u043B\u0443\u0436\u0438\u0442 \u0444\u043E\u0440\u043C\u0430\u043B\u044C\u043D\u044B\u043C \u043F\u0440\u0438\u0437\u043D\u0430\u043A\u043E\u043C \u0437\u0435\u043B\u0435\u043D\u0438).",
|
|
9628
|
+
"5. `conventions` \u2014 \u044F\u0437\u044B\u043A \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0439 \u043A\u043E\u043C\u043C\u0438\u0442\u043E\u0432 (`commitLanguage`), \u043D\u0443\u0436\u0435\u043D \u043B\u0438 \u0441\u043B\u0430\u0433 \u0437\u0430\u0434\u0430\u0447\u0438 \u0432 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0438 (`slugInCommit`), \u0431\u0430\u0437\u043E\u0432\u0430\u044F \u0432\u0435\u0442\u043A\u0430 (`baseBranch`).",
|
|
9629
|
+
"6. `spine` \u2014 \u041E\u0411\u0429\u0418\u0419 \u0425\u0420\u0415\u0411\u0415\u0422: \u0444\u0430\u0439\u043B\u044B \u0438 \u043A\u0430\u0442\u0430\u043B\u043E\u0433\u0438, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u043A\u0430\u0442\u044F\u0442\u0441\u044F \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u044B\u043C\u0438 PR \u0438 \u043D\u0435 \u043F\u0430\u0440\u0430\u043B\u043B\u0435\u043B\u044F\u0442\u0441\u044F (\u0441\u0445\u0435\u043C\u0430 \u0411\u0414, \u043E\u0431\u0449\u0438\u0435 \u0442\u0438\u043F\u044B, \u0440\u043E\u0443\u0442\u0438\u043D\u0433, \u043A\u043E\u043D\u0444\u0438\u0433 \u0441\u0431\u043E\u0440\u043A\u0438). \u0414\u0432\u0430 \u0434\u0440\u043E\u043D\u0430, \u043F\u0440\u0430\u0432\u044F\u0449\u0438\u0435 \u0442\u0430\u043A\u043E\u0435 \u043E\u0434\u043D\u043E\u0432\u0440\u0435\u043C\u0435\u043D\u043D\u043E, \u0433\u0430\u0440\u0430\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u043E \u0440\u0430\u0441\u0445\u043E\u0434\u044F\u0442\u0441\u044F \u0432 \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442\u0435.",
|
|
9630
|
+
"",
|
|
9631
|
+
"\u0413\u0414\u0415 \u0421\u041C\u041E\u0422\u0420\u0415\u0422\u042C (\u043D\u0435 \u0447\u0438\u0442\u0430\u0439 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0439 \u0446\u0435\u043B\u0438\u043A\u043E\u043C \u2014 \u0441\u0435\u0441\u0441\u0438\u044F \u043E\u0433\u0440\u0430\u043D\u0438\u0447\u0435\u043D\u0430 \u043F\u043E\u0442\u043E\u043B\u043A\u043E\u043C \u0442\u0440\u0430\u0442): README \u0438 \u0444\u0430\u0439\u043B\u044B \u043F\u0440\u0430\u0432\u0438\u043B \u0434\u043B\u044F \u0430\u0433\u0435\u043D\u0442\u043E\u0432 (CLAUDE.md, AGENTS.md, .cursorrules, \u043A\u0430\u0442\u0430\u043B\u043E\u0433 .claude/skills), \u043C\u0430\u043D\u0438\u0444\u0435\u0441\u0442 \u043F\u0430\u043A\u0435\u0442\u043D\u043E\u0433\u043E \u043C\u0435\u043D\u0435\u0434\u0436\u0435\u0440\u0430 \u0438 \u0435\u0433\u043E scripts, \u043A\u043E\u043D\u0444\u0438\u0433 \u043C\u043E\u043D\u043E\u0440\u0435\u043F\u043E (workspaces/turbo/nx/lerna), docker-compose \u0438 Makefile, .env.example (\u0418\u041C\u0415\u041D\u0410 \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0445), \u043A\u0430\u0442\u0430\u043B\u043E\u0433 \u043C\u0438\u0433\u0440\u0430\u0446\u0438\u0439, CI-\u0432\u043E\u0440\u043A\u0444\u043B\u043E\u0443 (.github/workflows \u0438 \u0430\u043D\u0430\u043B\u043E\u0433\u0438), \u0432\u0435\u0440\u0445\u043D\u0438\u0439 \u0443\u0440\u043E\u0432\u0435\u043D\u044C \u043A\u0430\u0442\u0430\u043B\u043E\u0433\u043E\u0432 \u043A\u043E\u0434\u0430, `git log --oneline -30` (\u044F\u0437\u044B\u043A \u043A\u043E\u043C\u043C\u0438\u0442\u043E\u0432 \u0438 \u0435\u0441\u0442\u044C \u043B\u0438 \u0432 \u043D\u0438\u0445 \u0441\u043B\u0430\u0433 \u0437\u0430\u0434\u0430\u0447\u0438) \u0438 `git symbolic-ref refs/remotes/origin/HEAD` (\u0431\u0430\u0437\u043E\u0432\u0430\u044F \u0432\u0435\u0442\u043A\u0430).",
|
|
9632
|
+
"",
|
|
9633
|
+
"\u0427\u0415\u0413\u041E \u041D\u0415 \u0414\u0415\u041B\u0410\u0422\u042C:",
|
|
9634
|
+
"\u2022 \u041D\u0418\u0427\u0415\u0413\u041E \u041D\u0415 \u041F\u0420\u0410\u0412\u042C \u0432 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0438: \u043D\u0438 \u0444\u0430\u0439\u043B\u043E\u0432, \u043D\u0438 \u0432\u0435\u0442\u043E\u043A, \u043D\u0438 \u043A\u043E\u043C\u043C\u0438\u0442\u043E\u0432. \u0422\u044B \u0447\u0438\u0442\u0430\u0435\u0448\u044C, \u0430 \u043D\u0435 \u0447\u0438\u043D\u0438\u0448\u044C. \u041D\u0435\u0442 CI \u0438\u043B\u0438 \u0442\u0435\u0441\u0442\u043E\u0432 \u2014 \u0442\u0430\u043A \u0438 \u0437\u0430\u043F\u0438\u0448\u0438, \u044D\u0442\u043E \u0444\u0430\u043A\u0442 \u043E \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0438, \u0430 \u043D\u0435 \u0437\u0430\u0434\u0430\u0447\u0430 \u0442\u0435\u0431\u0435.",
|
|
9635
|
+
"\u2022 \u041D\u0415 \u0412\u042B\u0414\u0423\u041C\u042B\u0412\u0410\u0419 \u043A\u043E\u043C\u0430\u043D\u0434\u044B. \u041A\u0430\u0436\u0434\u0430\u044F \u043A\u043E\u043C\u0430\u043D\u0434\u0430, \u043A\u043E\u0442\u043E\u0440\u0443\u044E \u0442\u044B \u043F\u0438\u0448\u0435\u0448\u044C, \u0434\u043E\u043B\u0436\u043D\u0430 \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u0442\u044C\u0441\u044F \u0432 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0438 \u0426\u0415\u041B\u0418\u041A\u041E\u041C \u2014 \u0441\u0442\u0440\u043E\u043A\u043E\u0439, \u043A\u043E\u0442\u043E\u0440\u0443\u044E \u043C\u043E\u0436\u043D\u043E \u0441\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u0442\u044C (scripts, \u043C\u0430\u043D\u0438\u0444\u0435\u0441\u0442 \u043F\u0430\u043A\u0435\u0442\u0430, compose, Makefile, \u0432\u043E\u0440\u043A\u0444\u043B\u043E\u0443, README) \u2014 \u043F\u043E \u044D\u0442\u0438\u043C \u043A\u043E\u043C\u0430\u043D\u0434\u0430\u043C \u0434\u0440\u043E\u043D \u0431\u0443\u0434\u0435\u0442 \u043F\u043E\u0434\u043D\u0438\u043C\u0430\u0442\u044C \u0447\u0443\u0436\u0443\u044E \u0431\u0430\u0437\u0443. \u041D\u0435 \u043D\u0430\u0448\u0451\u043B \u2014 \u043F\u043E\u043B\u0435 \u043D\u0435 \u043F\u0440\u0438\u0441\u044B\u043B\u0430\u0439.",
|
|
9636
|
+
"\u2022 \u041D\u0415 \u0421\u041A\u041B\u0415\u0418\u0412\u0410\u0419 \u043A\u043E\u043C\u0430\u043D\u0434\u0443 \u0438\u0437 \u043A\u0443\u0441\u043A\u043E\u0432. \u0414\u0432\u0435 \u043D\u0430\u0441\u0442\u043E\u044F\u0449\u0438\u0435 \u0441\u0442\u0440\u043E\u043A\u0438, \u0441\u043E\u0435\u0434\u0438\u043D\u0451\u043D\u043D\u044B\u0435 \u0442\u043E\u0431\u043E\u0439 \u0432 \u043E\u0434\u043D\u0443 (\u043F\u043E\u0434\u0441\u0442\u0430\u0432\u0438\u043B URL \u0438\u0437 \u043E\u0434\u043D\u043E\u0433\u043E \u0441\u043A\u0440\u0438\u043F\u0442\u0430 \u0432 \u0432\u044B\u0437\u043E\u0432 \u0438\u0437 \u0434\u0440\u0443\u0433\u043E\u0433\u043E, \u0434\u043E\u043F\u0438\u0441\u0430\u043B \u0444\u043B\u0430\u0433, \u043E\u0431\u0435\u0440\u043D\u0443\u043B \u0432 \u043F\u0440\u0438\u0441\u0432\u0430\u0438\u0432\u0430\u043D\u0438\u0435 \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u043E\u0439), \u0434\u0430\u044E\u0442 \u043A\u043E\u043C\u0430\u043D\u0434\u0443, \u043A\u043E\u0442\u043E\u0440\u043E\u0439 \u0432 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0438 \u043D\u0435\u0442 \u0438 \u043A\u043E\u0442\u043E\u0440\u0443\u044E \u043D\u0438\u043A\u0442\u043E \u043D\u0438\u043A\u043E\u0433\u0434\u0430 \u043D\u0435 \u0437\u0430\u043F\u0443\u0441\u043A\u0430\u043B. \u0412\u044B\u0433\u043B\u044F\u0434\u0438\u0442 \u043E\u043D\u0430 \u043F\u0440\u0438 \u044D\u0442\u043E\u043C \u043A\u0430\u043A \u0444\u0430\u043A\u0442. \u041D\u0435 \u0443\u0432\u0435\u0440\u0435\u043D, \u0447\u0442\u043E \u0441\u0442\u0440\u043E\u043A\u0430 \u0437\u0430\u043F\u0443\u0441\u043A\u0430\u0435\u0442\u0441\u044F \u0440\u043E\u0432\u043D\u043E \u0432 \u0442\u0430\u043A\u043E\u043C \u0432\u0438\u0434\u0435, \u2014 \u043D\u0435 \u043F\u0440\u0438\u0441\u044B\u043B\u0430\u0439 \u0435\u0451.",
|
|
9637
|
+
"\u2022 \u041F\u043E\u043B\u0435, \u043F\u0440\u043E \u043A\u043E\u0442\u043E\u0440\u043E\u0435 \u0441\u043A\u0430\u0437\u0430\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E, \u041F\u0420\u041E\u041F\u0423\u0421\u0422\u0418 \u0446\u0435\u043B\u0438\u043A\u043E\u043C. \u041F\u0440\u043E\u043F\u0443\u0441\u043A \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0441\u0442\u0438\u0440\u0430\u0435\u0442; \u0432\u044B\u0434\u0443\u043C\u0430\u043D\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u2014 \u0441\u0442\u0438\u0440\u0430\u0435\u0442 \u043F\u0440\u0430\u0432\u0434\u0443.",
|
|
9638
|
+
"\u2022 \u041D\u0438\u043A\u0430\u043A\u0438\u0445 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0439 \u0441\u0435\u043A\u0440\u0435\u0442\u043E\u0432, \u0442\u043E\u043A\u0435\u043D\u043E\u0432 \u0438 \u043F\u0430\u0440\u043E\u043B\u0435\u0439 \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u0438\u043C\u0435\u043D\u0430 \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0445.",
|
|
9639
|
+
"\u2022 \u041A\u043E\u043C\u0430\u043D\u0434\u044B \u043F\u043E\u0434\u043D\u044F\u0442\u0438\u044F \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u044F \u041D\u0415 \u0417\u0410\u041F\u0423\u0421\u041A\u0410\u0419 (\u043C\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u043D\u0430 \u0436\u0438\u0432\u043E\u0439 \u0431\u0430\u0437\u0435 \u2014 \u043D\u0435 \u0440\u0430\u0437\u0432\u0435\u0434\u043A\u0430).",
|
|
9640
|
+
"",
|
|
9641
|
+
known,
|
|
9642
|
+
"",
|
|
9643
|
+
`\u041A\u0410\u041A \u0421\u0414\u0410\u0422\u042C. \u0417\u0430\u043F\u0438\u0448\u0438 \u043F\u0440\u0435\u0434\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u041E\u0414\u041D\u0418\u041C JSON-\u043E\u0431\u044A\u0435\u043A\u0442\u043E\u043C \u0432 \u0444\u0430\u0439\u043B \`${input.outFile}\` (\u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0438\u0448\u0438, \u0435\u0441\u043B\u0438 \u043E\u043D \u0435\u0441\u0442\u044C) \u2014 \u0438 \u043D\u0430 \u044D\u0442\u043E\u043C \u0437\u0430\u043A\u043E\u043D\u0447\u0438: \u0431\u043E\u043B\u044C\u0448\u0435 \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0434\u0435\u043B\u0430\u0439 \u0438 \u043D\u0435 \u0432\u044B\u0432\u043E\u0434\u0438 \u0432 stdout \u043D\u0438\u0447\u0435\u0433\u043E, \u043A\u0440\u043E\u043C\u0435 \u043A\u043E\u0440\u043E\u0442\u043A\u043E\u0439 \u0441\u0442\u0440\u043E\u043A\u0438 \xAB\u0433\u043E\u0442\u043E\u0432\u043E\xBB. \u0424\u0430\u0439\u043B \u0447\u0438\u0442\u0430\u0435\u0442 \u0434\u0435\u043C\u043E\u043D \u0440\u043E\u044F; \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0443\u0432\u0438\u0434\u0438\u0442 \u0442\u0432\u043E\u0451 \u043F\u0440\u0435\u0434\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u043D\u0430 \u044D\u043A\u0440\u0430\u043D\u0435 \u043F\u0440\u0438\u0451\u043C\u043A\u0438 \u0438 \u0440\u0435\u0448\u0438\u0442, \u0447\u0442\u043E \u043F\u0440\u0438\u043D\u044F\u0442\u044C.`,
|
|
9644
|
+
"",
|
|
9645
|
+
"\u0424\u043E\u0440\u043C\u0430 \u043E\u0442\u0432\u0435\u0442\u0430 (\u043B\u0438\u0448\u043D\u0438\u0435 \u043A\u043B\u044E\u0447\u0438 \u043D\u0435 \u0434\u043E\u0431\u0430\u0432\u043B\u044F\u0439, \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044E\u0449\u0438\u0435 \u043F\u043E\u043B\u044F \u043F\u0440\u043E\u0441\u0442\u043E \u043D\u0435 \u043F\u0438\u0448\u0438):",
|
|
9646
|
+
"```json",
|
|
9647
|
+
SHAPE,
|
|
9648
|
+
"```",
|
|
9649
|
+
"",
|
|
9650
|
+
"\u0422\u0412\u041E\u0401 \u041F\u0420\u0415\u0414\u041B\u041E\u0416\u0415\u041D\u0418\u0415 \u041D\u0415 \u041F\u0420\u0418\u041C\u0415\u041D\u042F\u0415\u0422\u0421\u042F \u041C\u041E\u041B\u0427\u0410: \u0435\u0433\u043E \u043F\u0440\u0438\u043D\u0438\u043C\u0430\u0435\u0442 \u0447\u0435\u043B\u043E\u0432\u0435\u043A, \u043F\u043E \u043E\u0434\u043D\u043E\u043C\u0443 \u043F\u043E\u043B\u044E. \u041F\u043E\u044D\u0442\u043E\u043C\u0443 \u043D\u0435 \u0437\u0430\u043D\u0438\u0436\u0430\u0439 \u043F\u043E\u0434\u0440\u043E\u0431\u043D\u043E\u0441\u0442\u044C \u0438\u0437 \u043E\u0441\u0442\u043E\u0440\u043E\u0436\u043D\u043E\u0441\u0442\u0438 \u2014 \u043D\u043E \u0438 \u043D\u0435 \u0432\u044B\u0434\u0430\u0432\u0430\u0439 \u0434\u043E\u0433\u0430\u0434\u043A\u0443 \u0437\u0430 \u043D\u0430\u0431\u043B\u044E\u0434\u0435\u043D\u0438\u0435: \u0442\u043E, \u0432 \u0447\u0451\u043C \u043D\u0435 \u0443\u0432\u0435\u0440\u0435\u043D, \u043B\u0443\u0447\u0448\u0435 \u043E\u0431\u044A\u044F\u0441\u043D\u0438 \u0441\u043B\u043E\u0432\u0430\u043C\u0438 \u0432 `green`/`about`, \u0447\u0435\u043C \u0443\u0433\u0430\u0434\u044B\u0432\u0430\u0439 \u043A\u043E\u043C\u0430\u043D\u0434\u043E\u0439."
|
|
9651
|
+
].join("\n");
|
|
9652
|
+
}
|
|
9653
|
+
function describeKnownProfile(profile) {
|
|
9654
|
+
if (!profile) {
|
|
9655
|
+
return "\u0420\u0410\u0417\u041C\u0415\u0422\u041A\u0418 \u0423 \u042D\u0422\u041E\u0413\u041E \u0420\u0415\u041F\u041E\u0417\u0418\u0422\u041E\u0420\u0418\u042F \u0415\u0429\u0401 \u041D\u0415\u0422 \u2014 \u0442\u044B \u0440\u0430\u0437\u043C\u0435\u0447\u0430\u0435\u0448\u044C \u0435\u0433\u043E \u043F\u0435\u0440\u0432\u044B\u043C. \u041F\u0440\u0435\u0434\u043B\u0430\u0433\u0430\u0439 \u0432\u0441\u0435 \u0448\u0435\u0441\u0442\u044C \u043F\u043E\u043B\u0435\u0439, \u043A\u0430\u043A\u0438\u0435 \u0441\u043C\u043E\u0436\u0435\u0448\u044C \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044C \u043A\u043E\u0434\u043E\u043C.";
|
|
9656
|
+
}
|
|
9657
|
+
const filled = SCOUT_FIELDS.filter((f) => profile[f] !== void 0 && profile[f] !== null);
|
|
9658
|
+
const byHuman = filled.filter((f) => profile.sources?.[f] === "human");
|
|
9659
|
+
const lines = [
|
|
9660
|
+
"\u0420\u0415\u041F\u041E\u0417\u0418\u0422\u041E\u0420\u0418\u0419 \u0423\u0416\u0415 \u0420\u0410\u0417\u041C\u0415\u0427\u0415\u041D \u2014 \u044D\u0442\u043E \u041F\u041E\u0412\u0422\u041E\u0420\u041D\u0410\u042F \u0440\u0430\u0437\u0432\u0435\u0434\u043A\u0430. \u0427\u0442\u043E \u0437\u0430\u043F\u0438\u0441\u0430\u043D\u043E \u0441\u0435\u0439\u0447\u0430\u0441:",
|
|
9661
|
+
"```json",
|
|
9662
|
+
JSON.stringify(pickFields(profile), null, 2),
|
|
9663
|
+
"```",
|
|
9664
|
+
"\u0422\u0432\u043E\u044F \u0437\u0430\u0434\u0430\u0447\u0430 \u0442\u0435\u043F\u0435\u0440\u044C \u2014 \u0420\u0410\u0417\u041D\u0418\u0426\u0410, \u0430 \u043D\u0435 \u043F\u0435\u0440\u0435\u0441\u043A\u0430\u0437: \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0439 \u0436\u0438\u0432\u0451\u0442, \u043F\u0430\u043A\u0435\u0442\u044B \u0434\u043E\u0431\u0430\u0432\u043B\u044F\u044E\u0442\u0441\u044F, \u043A\u043E\u043C\u0430\u043D\u0434\u044B \u043C\u0435\u043D\u044F\u044E\u0442\u0441\u044F. \u041F\u043E\u043B\u0435, \u043A\u043E\u0442\u043E\u0440\u043E\u0435 \u043F\u043E-\u043F\u0440\u0435\u0436\u043D\u0435\u043C\u0443 \u0432\u0435\u0440\u043D\u043E, \u041D\u0415 \u041F\u0420\u0418\u0421\u042B\u041B\u0410\u0419 \u0412\u041E\u0412\u0421\u0415 \u2014 \u043F\u0440\u043E\u043F\u0443\u0441\u043A \u0438 \u0435\u0441\u0442\u044C \xAB\u0442\u0443\u0442 \u0431\u0435\u0437 \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0439\xBB.",
|
|
9665
|
+
"\xAB\u041F\u0440\u0438\u0441\u043B\u0430\u0442\u044C \u043A\u0430\u043A \u0435\u0441\u0442\u044C\xBB \u2014 \u041D\u0415 \u0442\u043E \u0436\u0435 \u0441\u0430\u043C\u043E\u0435, \u0438 \u044D\u0442\u043E \u0433\u043B\u0430\u0432\u043D\u0430\u044F \u043B\u043E\u0432\u0443\u0448\u043A\u0430 \u043F\u043E\u0432\u0442\u043E\u0440\u043D\u043E\u0439 \u0440\u0430\u0437\u0432\u0435\u0434\u043A\u0438: \u0437\u0430\u043D\u043E\u0432\u043E \u0442\u044B \u043D\u0430\u043F\u0438\u0448\u0435\u0448\u044C \u0434\u0440\u0443\u0433\u0438\u043C\u0438 \u0441\u043B\u043E\u0432\u0430\u043C\u0438, \u043F\u043E\u0434\u0440\u043E\u0431\u043D\u0435\u0435 \u0438 \u0434\u043B\u0438\u043D\u043D\u0435\u0435, \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u043F\u043E\u043B\u0443\u0447\u0438\u0442 \u044D\u0442\u043E \u043A\u0430\u043A \xAB\u0438\u0437\u043C\u0435\u043D\u0438\u043B\u043E\u0441\u044C\xBB, \u0438 \u043D\u0430\u0441\u0442\u043E\u044F\u0449\u0430\u044F \u043F\u0440\u0430\u0432\u043A\u0430 \u0443\u0442\u043E\u043D\u0435\u0442 \u0441\u0440\u0435\u0434\u0438 \u043F\u0435\u0440\u0435\u0444\u043E\u0440\u043C\u0443\u043B\u0438\u0440\u043E\u0432\u043E\u043A. \u041F\u0440\u0438\u0441\u044B\u043B\u0430\u0439 \u043F\u043E\u043B\u0435, \u0442\u043E\u043B\u044C\u043A\u043E \u0435\u0441\u043B\u0438 \u043A\u043E\u0434 \u043F\u0440\u044F\u043C\u043E \u041F\u0420\u041E\u0422\u0418\u0412\u041E\u0420\u0415\u0427\u0418\u0422 \u0437\u0430\u043F\u0438\u0441\u0430\u043D\u043D\u043E\u043C\u0443: \u043A\u043E\u043C\u0430\u043D\u0434\u044B \u0431\u043E\u043B\u044C\u0448\u0435 \u043D\u0435\u0442, \u043A\u0430\u0442\u0430\u043B\u043E\u0433 \u043F\u0435\u0440\u0435\u0438\u043C\u0435\u043D\u043E\u0432\u0430\u043D, \u043F\u043E\u044F\u0432\u0438\u043B\u0441\u044F \u043F\u0430\u043A\u0435\u0442, \u0438\u0437\u043C\u0435\u043D\u0438\u043B\u0441\u044F \u043A\u0440\u0438\u0442\u0435\u0440\u0438\u0439 \u0437\u0435\u043B\u0435\u043D\u0438. \u0421\u0442\u0430\u043B\u043E \u043A\u0440\u0430\u0441\u0438\u0432\u0435\u0435 \u2014 \u043D\u0435 \u043F\u043E\u0432\u043E\u0434.",
|
|
9666
|
+
"\u041F\u0440\u0438\u0441\u044B\u043B\u0430\u0435\u0448\u044C \u2014 \u043F\u0440\u0438\u0441\u044B\u043B\u0430\u0439 \u043F\u043E\u043B\u0435 \u0426\u0415\u041B\u0418\u041A\u041E\u041C (\u043E\u043D\u043E \u0437\u0430\u043C\u0435\u043D\u044F\u0435\u0442 \u043F\u0440\u0435\u0436\u043D\u0435\u0435), \u043D\u043E \u0440\u043E\u0432\u043D\u043E \u0441 \u0442\u043E\u0439 \u043F\u0440\u0430\u0432\u043A\u043E\u0439, \u0440\u0430\u0434\u0438 \u043A\u043E\u0442\u043E\u0440\u043E\u0439 \u043F\u0440\u0438\u0441\u043B\u0430\u043B: \u043E\u0441\u0442\u0430\u043B\u044C\u043D\u043E\u0435 \u0432\u043D\u0443\u0442\u0440\u0438 \u043D\u0435\u0433\u043E \u043E\u0441\u0442\u0430\u0432\u044C \u0414\u041E\u0421\u041B\u041E\u0412\u041D\u041E \u0442\u0430\u043A, \u043A\u0430\u043A \u0437\u0430\u043F\u0438\u0441\u0430\u043D\u043E \u0441\u0435\u0439\u0447\u0430\u0441, \u0432\u043F\u043B\u043E\u0442\u044C \u0434\u043E \u0444\u043E\u0440\u043C\u0443\u043B\u0438\u0440\u043E\u0432\u043E\u043A. \u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043E\u0434\u043D\u0443 \u0437\u043E\u043D\u0443 \u2014 \u044D\u0442\u043E \u0441\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0441\u043F\u0438\u0441\u043E\u043A \u0438 \u0434\u043E\u043F\u0438\u0441\u0430\u0442\u044C \u0432 \u043D\u0435\u0433\u043E \u0441\u0442\u0440\u043E\u043A\u0443, \u0430 \u043D\u0435 \u043F\u0435\u0440\u0435\u043F\u0438\u0441\u0430\u0442\u044C \u0441\u043F\u0438\u0441\u043E\u043A \u0437\u0430\u043D\u043E\u0432\u043E."
|
|
9667
|
+
];
|
|
9668
|
+
if (byHuman.length) {
|
|
9669
|
+
lines.push(
|
|
9670
|
+
`\u26A0\uFE0F \u042D\u0422\u0418 \u041F\u041E\u041B\u042F \u0412\u041F\u0418\u0421\u0410\u041B \u0427\u0415\u041B\u041E\u0412\u0415\u041A: ${byHuman.join(", ")}. \u041E\u043D \u0437\u043D\u0430\u0435\u0442 \u043F\u0440\u043E \u043F\u0440\u043E\u0435\u043A\u0442 \u0442\u043E, \u0447\u0435\u0433\u043E \u0432 \u043A\u043E\u0434\u0435 \u043D\u0435 \u043D\u0430\u043F\u0438\u0441\u0430\u043D\u043E, \u2014 \u043D\u0435 \u043F\u0435\u0440\u0435\u043F\u0438\u0441\u044B\u0432\u0430\u0439 \u0438\u0445 \xAB\u0434\u043B\u044F \u043F\u043E\u0440\u044F\u0434\u043A\u0430\xBB \u0438 \u043D\u0435 \u043F\u0440\u0438\u0432\u043E\u0434\u0438 \u043A \u0441\u0432\u043E\u0435\u043C\u0443 \u0441\u0442\u0438\u043B\u044E. \u041C\u0435\u043D\u044F\u0439, \u0442\u043E\u043B\u044C\u043A\u043E \u0435\u0441\u043B\u0438 \u043A\u043E\u0434 \u043F\u0440\u044F\u043C\u043E \u043F\u0440\u043E\u0442\u0438\u0432\u043E\u0440\u0435\u0447\u0438\u0442 \u0437\u0430\u043F\u0438\u0441\u0430\u043D\u043D\u043E\u043C\u0443 (\u043A\u043E\u043C\u0430\u043D\u0434\u044B \u0431\u043E\u043B\u044C\u0448\u0435 \u043D\u0435\u0442, \u043A\u0430\u0442\u0430\u043B\u043E\u0433 \u043F\u0435\u0440\u0435\u0438\u043C\u0435\u043D\u043E\u0432\u0430\u043D), \u0438 \u0442\u043E\u0433\u0434\u0430 \u043E\u0431\u044A\u044F\u0441\u043D\u0438 \u0440\u0430\u0441\u0445\u043E\u0436\u0434\u0435\u043D\u0438\u0435 \u0432 \u0442\u0435\u043A\u0441\u0442\u0435 \u043F\u043E\u043B\u044F: \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0443\u0432\u0438\u0434\u0438\u0442 \u0435\u0433\u043E \u043D\u0430 \u043F\u0440\u0438\u0451\u043C\u043A\u0435 \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E\u0439 \u043F\u043E\u043C\u0435\u0442\u043A\u043E\u0439 \u0438 \u0440\u0435\u0448\u0438\u0442 \u0441\u0430\u043C.`
|
|
9671
|
+
);
|
|
9672
|
+
}
|
|
9673
|
+
return lines.join("\n");
|
|
9674
|
+
}
|
|
9675
|
+
function pickFields(profile) {
|
|
9676
|
+
const out = {};
|
|
9677
|
+
for (const f of SCOUT_FIELDS) if (profile[f] !== void 0 && profile[f] !== null) out[f] = profile[f];
|
|
9678
|
+
return out;
|
|
9679
|
+
}
|
|
9680
|
+
function parseScoutReport(text) {
|
|
9681
|
+
const json = stripFence(text).trim();
|
|
9682
|
+
if (!json) return { ok: false, error: "\u0440\u0430\u0437\u0432\u0435\u0434\u0447\u0438\u043A \u043D\u0435 \u0437\u0430\u043F\u0438\u0441\u0430\u043B \u043F\u0440\u0435\u0434\u043B\u043E\u0436\u0435\u043D\u0438\u0435 (\u0444\u0430\u0439\u043B \u043F\u0443\u0441\u0442)" };
|
|
9683
|
+
let raw;
|
|
9684
|
+
try {
|
|
9685
|
+
raw = JSON.parse(json);
|
|
9686
|
+
} catch (e) {
|
|
9687
|
+
return { ok: false, error: `\u043F\u0440\u0435\u0434\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u043D\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044F \u043A\u0430\u043A JSON: ${e.message}` };
|
|
9688
|
+
}
|
|
9689
|
+
if (raw == null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
9690
|
+
return { ok: false, error: "\u043F\u0440\u0435\u0434\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C JSON-\u043E\u0431\u044A\u0435\u043A\u0442\u043E\u043C \u0441 \u043F\u043E\u043B\u044F\u043C\u0438 \u0440\u0430\u0437\u043C\u0435\u0442\u043A\u0438" };
|
|
9691
|
+
}
|
|
9692
|
+
const src = raw;
|
|
9693
|
+
const report = {};
|
|
9694
|
+
const fields = [];
|
|
9695
|
+
for (const f of SCOUT_FIELDS) {
|
|
9696
|
+
const value = src[f];
|
|
9697
|
+
if (value === void 0 || value === null) continue;
|
|
9698
|
+
report[f] = value;
|
|
9699
|
+
fields.push(f);
|
|
9700
|
+
}
|
|
9701
|
+
if (fields.length === 0) {
|
|
9702
|
+
const foreign = Object.keys(src).filter((k) => !SCOUT_FIELDS.includes(k));
|
|
9703
|
+
if (foreign.length) {
|
|
9704
|
+
return { ok: false, error: `\u0432 \u043F\u0440\u0435\u0434\u043B\u043E\u0436\u0435\u043D\u0438\u0438 \u043D\u0435\u0442 \u043D\u0438 \u043E\u0434\u043D\u043E\u0433\u043E \u043F\u043E\u043B\u044F \u0440\u0430\u0437\u043C\u0435\u0442\u043A\u0438 (\u0435\u0441\u0442\u044C \u0442\u043E\u043B\u044C\u043A\u043E: ${foreign.slice(0, 5).join(", ")})` };
|
|
9705
|
+
}
|
|
9706
|
+
}
|
|
9707
|
+
return { ok: true, report, fields };
|
|
9708
|
+
}
|
|
9709
|
+
function stripFence(text) {
|
|
9710
|
+
const fenced = /```(?:json)?\s*([\s\S]*?)```/.exec(text);
|
|
9711
|
+
return fenced?.[1] ?? text;
|
|
9712
|
+
}
|
|
9713
|
+
function renderScoutOutcome(repoFullName, diff) {
|
|
9714
|
+
const label = { new: "\u043D\u043E\u0432\u043E\u0435", changed: "\u0438\u0437\u043C\u0435\u043D\u0438\u043B\u043E\u0441\u044C", same: "\u043A\u0430\u043A \u0431\u044B\u043B\u043E", gone: "\u043D\u0435 \u0442\u0440\u043E\u0433\u0430\u0435\u0442" };
|
|
9715
|
+
const changed = diff.filter((d) => d.change === "new" || d.change === "changed");
|
|
9716
|
+
if (!changed.length) {
|
|
9717
|
+
return [`\u0420\u0430\u0437\u0432\u0435\u0434\u043A\u0430 ${repoFullName}: \u043D\u043E\u0432\u043E\u0433\u043E \u043D\u0438\u0447\u0435\u0433\u043E \u2014 \u043F\u0440\u0435\u0434\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u0441\u043E\u0432\u043F\u0430\u043B\u043E \u0441 \u0442\u0435\u043C, \u0447\u0442\u043E \u0443\u0436\u0435 \u0437\u0430\u043F\u0438\u0441\u0430\u043D\u043E.`];
|
|
9718
|
+
}
|
|
9719
|
+
const lines = [`\u0420\u0430\u0437\u0432\u0435\u0434\u043A\u0430 ${repoFullName}: \u043F\u0440\u0435\u0434\u043B\u043E\u0436\u0435\u043D\u043E \u043A \u043F\u0440\u0438\u0451\u043C\u043A\u0435 ${changed.length} \u043F\u043E\u043B(\u044F/\u0435\u0439).`];
|
|
9720
|
+
for (const d of changed) {
|
|
9721
|
+
const human = d.overwritesHuman ? " \u26A0\uFE0F \u043F\u0435\u0440\u0435\u043F\u0438\u0441\u0430\u043B\u043E \u0431\u044B \u043F\u0440\u0430\u0432\u043A\u0443 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u2014 \u0440\u0435\u0448\u0438\u0442 \u043E\u043D \u0441\u0430\u043C" : "";
|
|
9722
|
+
lines.push(` \u2022 ${d.field} \u2014 ${label[d.change] ?? d.change}${human}`);
|
|
9723
|
+
}
|
|
9724
|
+
const untouched = diff.filter((d) => d.change === "gone").map((d) => d.field);
|
|
9725
|
+
if (untouched.length) lines.push(` \u0420\u0430\u0437\u0432\u0435\u0434\u043A\u0430 \u043F\u0440\u043E\u043C\u043E\u043B\u0447\u0430\u043B\u0430 (\u043E\u0441\u0442\u0430\u043D\u0435\u0442\u0441\u044F \u043A\u0430\u043A \u0435\u0441\u0442\u044C): ${untouched.join(", ")}`);
|
|
9726
|
+
lines.push("\u0416\u0438\u0432\u0430\u044F \u0440\u0430\u0437\u043C\u0435\u0442\u043A\u0430 \u041D\u0415 \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0430: \u043F\u0440\u0435\u0434\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u043F\u0440\u0438\u043C\u0435\u043D\u044F\u0435\u0442 \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u043D\u0430 \u044D\u043A\u0440\u0430\u043D\u0435 \u043F\u0440\u0438\u0451\u043C\u043A\u0438.");
|
|
9727
|
+
return lines;
|
|
9728
|
+
}
|
|
9729
|
+
async function runRepoScout(deps) {
|
|
9730
|
+
const profile = await deps.readProfile();
|
|
9731
|
+
deps.log(
|
|
9732
|
+
profile ? `\u0420\u0430\u0437\u0432\u0435\u0434\u043A\u0430 ${deps.repoFullName}: \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0439 \u0443\u0436\u0435 \u0440\u0430\u0437\u043C\u0435\u0447\u0435\u043D \u2014 \u0438\u0449\u0435\u043C \u0420\u0410\u0417\u041D\u0418\u0426\u0423 (\u0440\u0443\u0447\u043D\u044B\u0435 \u043F\u0440\u0430\u0432\u043A\u0438 \u0440\u0430\u0437\u0432\u0435\u0434\u043A\u0430 \u043D\u0435 \u043F\u0435\u0440\u0435\u043F\u0438\u0441\u044B\u0432\u0430\u0435\u0442 \u043C\u043E\u043B\u0447\u0430).` : `\u0420\u0430\u0437\u0432\u0435\u0434\u043A\u0430 ${deps.repoFullName}: \u0440\u0430\u0437\u043C\u0435\u0442\u043A\u0438 \u043D\u0435\u0442 \u2014 \u0440\u0430\u0437\u043C\u0435\u0447\u0430\u0435\u043C \u0432\u043F\u0435\u0440\u0432\u044B\u0435.`
|
|
9733
|
+
);
|
|
9734
|
+
const prompt = buildScoutPrompt({
|
|
9735
|
+
repoFullName: deps.repoFullName,
|
|
9736
|
+
repoPath: deps.repoPath,
|
|
9737
|
+
outFile: deps.outFile,
|
|
9738
|
+
profile,
|
|
9739
|
+
...deps.name ? { name: deps.name } : {}
|
|
9740
|
+
});
|
|
9741
|
+
deps.clearOut();
|
|
9742
|
+
const code = await deps.runScout(prompt);
|
|
9743
|
+
const raw = deps.readOut();
|
|
9744
|
+
if (raw == null) {
|
|
9745
|
+
deps.log(`\u0420\u0430\u0437\u0432\u0435\u0434\u0447\u0438\u043A \u043D\u0435 \u043E\u0441\u0442\u0430\u0432\u0438\u043B \u043F\u0440\u0435\u0434\u043B\u043E\u0436\u0435\u043D\u0438\u044F (${deps.outFile} \u043D\u0435 \u0441\u043E\u0437\u0434\u0430\u043D, \u043A\u043E\u0434 \u0432\u044B\u0445\u043E\u0434\u0430 ${code}). \u0420\u0430\u0437\u043C\u0435\u0442\u043A\u0430 \u043D\u0435 \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0430.`);
|
|
9746
|
+
return 1;
|
|
9747
|
+
}
|
|
9748
|
+
const parsed = parseScoutReport(raw);
|
|
9749
|
+
if (!parsed.ok) {
|
|
9750
|
+
deps.log(`\u041F\u0440\u0435\u0434\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u0440\u0430\u0437\u0432\u0435\u0434\u0447\u0438\u043A\u0430 \u043D\u0435 \u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F: ${parsed.error}. \u0420\u0430\u0437\u043C\u0435\u0442\u043A\u0430 \u043D\u0435 \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0430, \u0444\u0430\u0439\u043B \u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D: ${deps.outFile}`);
|
|
9751
|
+
return 1;
|
|
9752
|
+
}
|
|
9753
|
+
if (parsed.fields.length === 0) {
|
|
9754
|
+
deps.log(
|
|
9755
|
+
profile ? `\u0420\u0430\u0437\u0432\u0435\u0434\u043A\u0430 ${deps.repoFullName}: \u0440\u0430\u0437\u043D\u0438\u0446\u044B \u043D\u0435\u0442 \u2014 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0439 \u0441\u043E\u0432\u043F\u0430\u043B \u0441 \u0442\u0435\u043C, \u0447\u0442\u043E \u0443\u0436\u0435 \u0437\u0430\u043F\u0438\u0441\u0430\u043D\u043E. \u0420\u0430\u0437\u043C\u0435\u0442\u043A\u0430 \u043D\u0435 \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0430.` : `\u0420\u0430\u0437\u0432\u0435\u0434\u043A\u0430 ${deps.repoFullName}: \u0440\u0430\u0437\u0432\u0435\u0434\u0447\u0438\u043A \u043D\u0435 \u043D\u0430\u0448\u0451\u043B, \u0447\u0442\u043E \u043F\u0440\u0435\u0434\u043B\u043E\u0436\u0438\u0442\u044C, \u2014 \u0440\u0430\u0437\u043C\u0435\u0442\u043A\u0430 \u043E\u0441\u0442\u0430\u043B\u0430\u0441\u044C \u043F\u0443\u0441\u0442\u043E\u0439. \u042D\u0442\u043E \u043E\u0442\u0432\u0435\u0442, \u0430 \u043D\u0435 \u0441\u0431\u043E\u0439: \u043F\u0443\u0441\u0442\u043E\u0435 \u043F\u043E\u043B\u0435 \u0447\u0435\u0441\u0442\u043D\u0435\u0435 \u0432\u044B\u0434\u0443\u043C\u0430\u043D\u043D\u043E\u0433\u043E.`
|
|
9756
|
+
);
|
|
9757
|
+
return 0;
|
|
9758
|
+
}
|
|
9759
|
+
deps.log(`\u0420\u0430\u0437\u0432\u0435\u0434\u0447\u0438\u043A \u043F\u0440\u0435\u0434\u043B\u043E\u0436\u0438\u043B \u043F\u043E\u043B\u044F: ${parsed.fields.join(", ")}. \u041E\u0442\u043F\u0440\u0430\u0432\u043B\u044F\u044E \u0432 Taskless \u2014 \u043F\u0440\u0438\u043C\u0435\u043D\u044F\u0442\u044C \u0431\u0443\u0434\u0435\u0442 \u0447\u0435\u043B\u043E\u0432\u0435\u043A.`);
|
|
9760
|
+
const sent = await deps.report(parsed.report);
|
|
9761
|
+
if (!sent.ok) {
|
|
9762
|
+
deps.log(`\u041E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C \u043F\u0440\u0435\u0434\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C: ${sent.error}. \u041E\u043D\u043E \u043E\u0441\u0442\u0430\u043B\u043E\u0441\u044C \u0432 ${deps.outFile} \u2014 \u043C\u043E\u0436\u043D\u043E \u043F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u044C \u0440\u0430\u0437\u0432\u0435\u0434\u043A\u0443.`);
|
|
9763
|
+
return 1;
|
|
9764
|
+
}
|
|
9765
|
+
deps.clearOut();
|
|
9766
|
+
for (const line of renderScoutOutcome(deps.repoFullName, sent.diff)) deps.log(line);
|
|
9767
|
+
return 0;
|
|
9768
|
+
}
|
|
9769
|
+
|
|
9770
|
+
// src/cli.ts
|
|
9771
|
+
init_names2();
|
|
9772
|
+
init_executors();
|
|
9773
|
+
init_claudeCode();
|
|
9774
|
+
import { spawn as spawn3 } from "child_process";
|
|
9775
|
+
|
|
9540
9776
|
// src/login.ts
|
|
9541
9777
|
import { execa as execa2 } from "execa";
|
|
9542
9778
|
import { createServer } from "net";
|
|
@@ -10297,6 +10533,12 @@ function usage() {
|
|
|
10297
10533
|
swarm spawn <slug> [area] [\u0444\u043B\u0430\u0433\u0438 \u043D\u0438\u0436\u0435]
|
|
10298
10534
|
\u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0437\u0430\u0434\u0430\u0447\u0443 \u0432 \u043E\u0447\u0435\u0440\u0435\u0434\u044C
|
|
10299
10535
|
swarm ls [\u0441\u0442\u0430\u0442\u0443\u0441] \u043F\u0440\u043E\u0433\u043E\u043D\u044B \u0436\u0438\u0432\u043E\u0433\u043E \u0434\u0435\u043C\u043E\u043D\u0430 \u2014 \u0440\u043E\u0432\u043D\u043E \u0442\u0435, \u0447\u0442\u043E \u0432 \u0434\u0430\u0448\u0431\u043E\u0440\u0434\u0435
|
|
10536
|
+
swarm scout [--repo <path>]
|
|
10537
|
+
\u0420\u0410\u0417\u0412\u0415\u0414\u041A\u0410 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F: \u0434\u0440\u043E\u043D \u0447\u0438\u0442\u0430\u0435\u0442 \u043A\u043E\u0434 \u043D\u0430 \u044D\u0442\u043E\u0439 \u043C\u0430\u0448\u0438\u043D\u0435 \u0438 \u043F\u0440\u0435\u0434\u043B\u0430\u0433\u0430\u0435\u0442
|
|
10538
|
+
\u0440\u0430\u0437\u043C\u0435\u0442\u043A\u0443 \u2014 \u0437\u043E\u043D\u044B area:*, \u0447\u0435\u043C \u043F\u043E\u0434\u043D\u044F\u0442\u044C \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435, \u0447\u0435\u043C \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0442\u044C \u0438 \u0447\u0442\u043E
|
|
10539
|
+
\u0437\u0434\u0435\u0441\u044C \u0437\u0435\u043B\u0451\u043D\u043E\u0435, \u043A\u043E\u043D\u0432\u0435\u043D\u0446\u0438\u0438, \u043E\u0431\u0449\u0438\u0439 \u0445\u0440\u0435\u0431\u0435\u0442, \u0431\u0440\u0438\u0444. \u041D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u043F\u0440\u0438\u043C\u0435\u043D\u044F\u0435\u0442:
|
|
10540
|
+
\u043F\u0440\u0435\u0434\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u043F\u0440\u0438\u043D\u0438\u043C\u0430\u0435\u0442 \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0432 Taskless (\u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438 \u043F\u0440\u043E\u0435\u043A\u0442\u0430).
|
|
10541
|
+
\u041F\u043E\u0432\u0442\u043E\u0440\u043D\u044B\u0439 \u0437\u0430\u043F\u0443\u0441\u043A \u043D\u0430 \u0440\u0430\u0437\u043C\u0435\u0447\u0435\u043D\u043D\u043E\u043C \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0438 \u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442 \u0440\u0430\u0437\u043D\u0438\u0446\u0443
|
|
10300
10542
|
swarm zones [check|suggest <\u0442\u0435\u043A\u0441\u0442|slug>]
|
|
10301
10543
|
\u0437\u043E\u043D\u044B \u043A\u043E\u0434\u0430, \u0432\u044B\u0432\u0435\u0434\u0435\u043D\u043D\u044B\u0435 \u0438\u0437 \u0438\u0441\u0442\u043E\u0440\u0438\u0438 \u0440\u0435\u043F\u043E (\u043A\u0430\u043A\u0438\u0435 \u0444\u0430\u0439\u043B\u044B \u043C\u0435\u043D\u044F\u044E\u0442\u0441\u044F
|
|
10302
10544
|
\u0432\u043C\u0435\u0441\u0442\u0435, \u0447\u0442\u043E \u0442\u0443\u0442 \u043E\u0431\u0449\u0438\u0439 \u0445\u0440\u0435\u0431\u0435\u0442). check \u2014 \u0441\u0432\u0435\u0440\u043A\u0430 \u0441 \u0440\u0443\u0447\u043D\u043E\u0439
|
|
@@ -10384,6 +10626,45 @@ async function makeCliStore(repo) {
|
|
|
10384
10626
|
client.reconcileRuntime({ worktreesDir: effectiveWorktreesDir(), listProcesses: listDroneProcesses });
|
|
10385
10627
|
return client;
|
|
10386
10628
|
}
|
|
10629
|
+
async function runScoutCommand(repo) {
|
|
10630
|
+
const repoFullName = await remoteRepoFullName(repo);
|
|
10631
|
+
if (!repoFullName) {
|
|
10632
|
+
console.error(`\u043D\u0435 \u043F\u043E\u043D\u044F\u043B, \u0447\u0442\u043E \u0437\u0430 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0439 \u0432 ${repo}: \u0443 origin \u043D\u0435\u0442 GitHub-\u0430\u0434\u0440\u0435\u0441\u0430. \u0420\u0430\u0437\u043C\u0435\u0442\u043A\u0430 \u0430\u0434\u0440\u0435\u0441\u0443\u0435\u0442\u0441\u044F \u043F\u043E owner/repo.`);
|
|
10633
|
+
return 1;
|
|
10634
|
+
}
|
|
10635
|
+
const call = resilientSwarmMcp({
|
|
10636
|
+
onDown: (ms) => console.warn(`Swarm MCP \u043C\u043E\u043B\u0447\u0438\u0442 ${Math.round(ms / 1e3)}\u0441 \u2014 \u043F\u0440\u043E\u0432\u0435\u0440\u044C \u0441\u0432\u044F\u0437\u044C \u0441 \u043F\u0440\u043E\u0434\u043E\u043C.`),
|
|
10637
|
+
onUp: () => console.warn("Swarm MCP \u0441\u043D\u043E\u0432\u0430 \u043D\u0430 \u0441\u0432\u044F\u0437\u0438.")
|
|
10638
|
+
});
|
|
10639
|
+
const client = new SwarmClient({ call, outboxPath: SWARM_OUTBOX, defaultRepo: repo, autoFlush: false });
|
|
10640
|
+
const name = pickName([]);
|
|
10641
|
+
const outFile = join23(SWARM_HOME, `scout-${repoFullName.replace(/[^\w.-]+/g, "-")}.json`);
|
|
10642
|
+
const bin = resolveExecutor().resolveBin();
|
|
10643
|
+
const code = await runRepoScout({
|
|
10644
|
+
repoFullName,
|
|
10645
|
+
repoPath: repo,
|
|
10646
|
+
name,
|
|
10647
|
+
outFile,
|
|
10648
|
+
readProfile: () => client.repoProfile(repoFullName),
|
|
10649
|
+
runScout: (prompt) => new Promise((resolve4) => {
|
|
10650
|
+
const child = spawn3(bin, [...ISOLATION_FLAGS, "--dangerously-skip-permissions", "-p", prompt], {
|
|
10651
|
+
cwd: repo,
|
|
10652
|
+
stdio: ["ignore", "inherit", "inherit"]
|
|
10653
|
+
// человек смотрит на разведку живьём
|
|
10654
|
+
});
|
|
10655
|
+
child.on("error", (e) => {
|
|
10656
|
+
console.error(`\u043D\u0435 \u0437\u0430\u043F\u0443\u0441\u0442\u0438\u043B\u0441\u044F \u0438\u0441\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C (${bin}): ${e.message}`);
|
|
10657
|
+
resolve4(1);
|
|
10658
|
+
});
|
|
10659
|
+
child.on("exit", (c) => resolve4(c ?? 1));
|
|
10660
|
+
}),
|
|
10661
|
+
readOut: () => existsSync14(outFile) ? readFileSync16(outFile, "utf8") : null,
|
|
10662
|
+
clearOut: () => rmSync2(outFile, { force: true }),
|
|
10663
|
+
report: (report) => client.reportRepoScout(repoFullName, report, name),
|
|
10664
|
+
log: (line) => console.log(line)
|
|
10665
|
+
});
|
|
10666
|
+
return code;
|
|
10667
|
+
}
|
|
10387
10668
|
async function runZones(db2, repo, args) {
|
|
10388
10669
|
const manual = new Map(db2.listRuns().map((r) => [r.task_slug, r.area]));
|
|
10389
10670
|
const raw = await readTaskHistory(repo);
|
|
@@ -10876,6 +11157,20 @@ switch (cmd) {
|
|
|
10876
11157
|
// swarm zones — какие зоны видит рой и что считает общим хребтом
|
|
10877
11158
|
// swarm zones check — сверка с ручной разметкой area:* на прошлых задачах
|
|
10878
11159
|
// swarm zones suggest <текст|slug> — какую зону предложить задаче ПРИ ПОСТАНОВКЕ
|
|
11160
|
+
// TASWM-379/382: РАЗВЕДКА репозитория — одноразовый прогон, после которого рой знает
|
|
11161
|
+
// про чужой репозиторий то, что на taskless записано в CLAUDE.md и скиллах. Предложение
|
|
11162
|
+
// разведчика НЕ применяется: его принимает человек (см. repoScout.ts).
|
|
11163
|
+
case "scout": {
|
|
11164
|
+
const { repo: repoFlag, rest } = takeRepo(rawArgs);
|
|
11165
|
+
const repo = repoFlag ?? rest[0] ?? SWARM_REPO;
|
|
11166
|
+
if (!repo) {
|
|
11167
|
+
console.error("\u043D\u0435\u0442 \u0440\u0435\u043F\u043E: \u0437\u0430\u0434\u0430\u0439 --repo <path> \u0438\u043B\u0438 SWARM_REPO");
|
|
11168
|
+
process.exit(1);
|
|
11169
|
+
}
|
|
11170
|
+
const code = await runScoutCommand(repo);
|
|
11171
|
+
db.close();
|
|
11172
|
+
process.exit(code);
|
|
11173
|
+
}
|
|
10879
11174
|
case "zones": {
|
|
10880
11175
|
const { repo: repoFlag, rest } = takeRepo(rawArgs);
|
|
10881
11176
|
const repo = repoFlag ?? SWARM_REPO;
|
package/dist/overmind.js
CHANGED
|
@@ -7046,6 +7046,51 @@ var SwarmClient = class _SwarmClient {
|
|
|
7046
7046
|
if (!Array.isArray(prepare)) return null;
|
|
7047
7047
|
return prepare.filter((c) => typeof c === "string" && c.trim().length > 0).map((c) => c.trim());
|
|
7048
7048
|
}
|
|
7049
|
+
/**
|
|
7050
|
+
* РАЗМЕТКА репозитория (TASWM-381) из того же swarm_repo_config: зоны, чем поднять
|
|
7051
|
+
* окружение, чем проверять, конвенции, общий хребет, бриф — плюс карта источников
|
|
7052
|
+
* (кто вписал поле: разведчик или человек). Отдаём КАК ЕСТЬ, объектом: строгая
|
|
7053
|
+
* схема разметки живёт в проде (@taskless-app/shared), и второй её копии в демоне
|
|
7054
|
+
* быть не должно — разъехавшись, они спорили бы о том, что считать валидным.
|
|
7055
|
+
*
|
|
7056
|
+
* null — разметки нет (разведка не проходила; РАБОЧЕЕ состояние), репо не смэплено
|
|
7057
|
+
* на swarm-проект владельца токена или прод недоступен.
|
|
7058
|
+
*/
|
|
7059
|
+
async repoProfile(repoFullName) {
|
|
7060
|
+
let res;
|
|
7061
|
+
try {
|
|
7062
|
+
res = await this.call("swarm_repo_config", { repoFullName });
|
|
7063
|
+
} catch {
|
|
7064
|
+
return null;
|
|
7065
|
+
}
|
|
7066
|
+
if (res?.isError) return null;
|
|
7067
|
+
const sc = res.structuredContent ?? {};
|
|
7068
|
+
const p = sc.profile;
|
|
7069
|
+
return p && typeof p === "object" && !Array.isArray(p) ? p : null;
|
|
7070
|
+
}
|
|
7071
|
+
/**
|
|
7072
|
+
* РАЗВЕДКА репозитория (TASWM-382): отправить в прод то, что разведчик вычитал в коде.
|
|
7073
|
+
* Живую разметку это НЕ меняет — предложение ложится рядом и ждёт человека; поэтому
|
|
7074
|
+
* ошибка здесь дорога ровно на стоимость прогона разведки, и мы её возвращаем, а не
|
|
7075
|
+
* глотаем, как чтения выше.
|
|
7076
|
+
*
|
|
7077
|
+
* Мимо outbox (в отличие от мутаций прогонов): предложение имеет смысл только вместе
|
|
7078
|
+
* со свежим состоянием репозитория, и доехавшее через сутки после разведки — хуже,
|
|
7079
|
+
* чем не доехавшее вовсе. Прод недоступен — человек перезапустит разведку.
|
|
7080
|
+
*/
|
|
7081
|
+
async reportRepoScout(repoFullName, report, by) {
|
|
7082
|
+
let res;
|
|
7083
|
+
try {
|
|
7084
|
+
res = await this.call("swarm_repo_scout_report", { repoFullName, report, ...by ? { by } : {} });
|
|
7085
|
+
} catch (e) {
|
|
7086
|
+
return { ok: false, error: `\u043F\u0440\u043E\u0434 \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D: ${e.message}` };
|
|
7087
|
+
}
|
|
7088
|
+
const text = res?.content?.map((c) => "text" in c ? c.text : "").join(" ") ?? "";
|
|
7089
|
+
if (res?.isError) return { ok: false, error: text || "\u043F\u0440\u043E\u0434 \u043E\u0442\u043A\u043B\u043E\u043D\u0438\u043B \u043F\u0440\u0435\u0434\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u0440\u0430\u0437\u0432\u0435\u0434\u043A\u0438" };
|
|
7090
|
+
const sc = res.structuredContent ?? {};
|
|
7091
|
+
const diff = Array.isArray(sc.diff) ? sc.diff : [];
|
|
7092
|
+
return { ok: true, diff, display: text };
|
|
7093
|
+
}
|
|
7049
7094
|
/**
|
|
7050
7095
|
* Live ТРЕБОВАНИЯ К ОКРУЖЕНИЮ машины из Taskless (TASWM-313): тот же swarm_repo_config по
|
|
7051
7096
|
* repoFullName — Project.swarmConfig.requires. Демон проверяет их ПЕРЕД спавном дрона и не
|
|
@@ -10779,11 +10824,26 @@ function buildAnomalyCandidates(db, now, thresholds, opts) {
|
|
|
10779
10824
|
group: PR_GROUP,
|
|
10780
10825
|
build: () => ({
|
|
10781
10826
|
runId: run.id,
|
|
10782
|
-
//
|
|
10783
|
-
//
|
|
10827
|
+
// В ЛЕНТУ, не пушем (TASWM-417). Раньше тут стоял "decision" с обоснованием «рой
|
|
10828
|
+
// этого сам не расшивает» — оно перестало быть правдой ровно на том же пороге:
|
|
10829
|
+
// wakeAuthorOnChanges поднимает автора (`--continue`), а нечем продолжать —
|
|
10830
|
+
// свежего дрона на ту же ветку и тот же PR. Значит в момент, когда это правило
|
|
10831
|
+
// созревает, рой УЖЕ действует, и пуш звал бы человека к работе, которую делают
|
|
10832
|
+
// без него — ровно тот шум, из-за которого настоящие сигналы тонут. Настоящий
|
|
10833
|
+
// «нужен человек» приходит отдельно и позже: рой исчерпал побудки (маркер
|
|
10834
|
+
// CHANGES_WAKE_ESCALATION_MARK, NEEDS_HUMAN_MARKS → buildEscalationCandidates)
|
|
10835
|
+
// или упёрся в потолок трат. Правило остаётся страховкой ВИДИМОСТИ: если подъём
|
|
10836
|
+
// почему-то не случился вовсе, ленту это всё равно покажет.
|
|
10837
|
+
//
|
|
10838
|
+
// …и всё-таки ПУШ (TASWM-417, ревью диффа). Понизить его было соблазнительно, но
|
|
10839
|
+
// подъём гарантирован не во всех исходах: рой не лезет на ветку, где после вердикта
|
|
10840
|
+
// появились чужие коммиты, и молча ждёт, пока проект/ресурс-гейт откроется. В этих
|
|
10841
|
+
// случаях лента — это снова «никто не заметит», ровно инцидент 13.08. Пусть лучше
|
|
10842
|
+
// один лишний пуш на PR, который рой в итоге расшил сам, чем тишина на том, который
|
|
10843
|
+
// не расшил: цена ошибки несимметрична.
|
|
10784
10844
|
level: "decision",
|
|
10785
10845
|
title: runTitle(run, "PR \u0437\u0430\u0441\u0442\u0440\u044F\u043B \u043D\u0430 \xAB\u043D\u0443\u0436\u043D\u044B \u043F\u0440\u0430\u0432\u043A\u0438\xBB"),
|
|
10786
|
-
body: `${droneOf(run)}: \u0432\u0435\u0440\u0434\u0438\u043A\u0442 \xAB\u043D\u0443\u0436\u043D\u044B \u043F\u0440\u0430\u0432\u043A\u0438\xBB \u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044F \u2265${Math.round(thresholds.prNoReviewerMs / 6e4)} \u043C\u0438\u043D
|
|
10846
|
+
body: `${droneOf(run)}: \u0432\u0435\u0440\u0434\u0438\u043A\u0442 \xAB\u043D\u0443\u0436\u043D\u044B \u043F\u0440\u0430\u0432\u043A\u0438\xBB \u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044F \u2265${Math.round(thresholds.prNoReviewerMs / 6e4)} \u043C\u0438\u043D \u0431\u0435\u0437 \u0440\u0435-\u0440\u0435\u0432\u044C\u044E\u0435\u0440\u0430 \u2014 \u0440\u043E\u0439 \u043F\u043E\u0434\u043D\u0438\u043C\u0430\u0435\u0442 \u0430\u0432\u0442\u043E\u0440\u0430 \u043D\u0430 \u0444\u0438\u043A\u0441-\u0438\u0442\u0435\u0440\u0430\u0446\u0438\u044E \u0441\u0430\u043C; \u043D\u0435 \u043F\u043E\u0434\u043D\u0438\u043C\u0435\u0442\u0441\u044F \u0437\u0430 \u043E\u0442\u0432\u0435\u0434\u0451\u043D\u043D\u044B\u0435 \u043F\u043E\u043F\u044B\u0442\u043A\u0438 \u2014 \u043F\u043E\u0437\u043E\u0432\u0451\u0442 \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E \u2014 ${run.pr_url}.`,
|
|
10787
10847
|
...hrefOf(run.task_url)
|
|
10788
10848
|
})
|
|
10789
10849
|
});
|
|
@@ -11605,7 +11665,7 @@ async function changedPaths(worktree, opts = {}) {
|
|
|
11605
11665
|
// package.json
|
|
11606
11666
|
var package_default = {
|
|
11607
11667
|
name: "@taskless-app/swarm",
|
|
11608
|
-
version: "0.6.
|
|
11668
|
+
version: "0.6.11",
|
|
11609
11669
|
type: "module",
|
|
11610
11670
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
11611
11671
|
keywords: [
|
|
@@ -11655,7 +11715,7 @@ var package_default = {
|
|
|
11655
11715
|
execa: "^10.0.0",
|
|
11656
11716
|
zod: "3.25.76"
|
|
11657
11717
|
},
|
|
11658
|
-
gitHead: "
|
|
11718
|
+
gitHead: "f228c3fd9ac879e828e5b813bf8ff077402fbe23"
|
|
11659
11719
|
};
|
|
11660
11720
|
|
|
11661
11721
|
// src/version.ts
|
|
@@ -14140,9 +14200,11 @@ var CI_POLL_WINDOW_MS = Math.max(
|
|
|
14140
14200
|
);
|
|
14141
14201
|
var CI_WAIT_ESCALATION_MARK = "\u043E\u0436\u0438\u0434\u0430\u043D\u0438\u0435 CI \u0437\u0430\u0442\u044F\u043D\u0443\u043B\u043E\u0441\u044C";
|
|
14142
14202
|
var CHANGES_WAKE_COOLDOWN_MS = Number(process.env.SWARM_CHANGES_WAKE_COOLDOWN_MS) || 3 * 60 * 1e3;
|
|
14143
|
-
var CHANGES_WAKE_LIMIT = Number(process.env.SWARM_CHANGES_WAKE_LIMIT) ||
|
|
14203
|
+
var CHANGES_WAKE_LIMIT = Number(process.env.SWARM_CHANGES_WAKE_LIMIT) || 2;
|
|
14204
|
+
var CHANGES_FRESH_WAKE_AFTER_MS = Number(process.env.SWARM_CHANGES_FRESH_WAKE_AFTER_MS) || SWARM_ANOMALY_PR_NO_REVIEWER_MS;
|
|
14144
14205
|
var CHANGES_WAKE_MARK = "\u0444\u0438\u043A\u0441-\u0438\u0442\u0435\u0440\u0430\u0446\u0438\u044F \u043F\u043E \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u0443 \xAB\u043D\u0443\u0436\u043D\u044B \u043F\u0440\u0430\u0432\u043A\u0438\xBB";
|
|
14145
14206
|
var CHANGES_WAKE_ESCALATION_MARK = "\u0444\u0438\u043A\u0441-\u0438\u0442\u0435\u0440\u0430\u0446\u0438\u044F \u043D\u0435 \u043F\u043E\u0434\u043D\u044F\u043B\u0430\u0441\u044C";
|
|
14207
|
+
var CHANGES_WAKE_FAILED_MARK = "\u043F\u043E\u0431\u0443\u0434\u043A\u0430 \u0441\u043E\u0440\u0432\u0430\u043B\u0430\u0441\u044C";
|
|
14146
14208
|
var BUDGET_STOP_REASON = "\u043D\u0435 \u0443\u043B\u043E\u0436\u0438\u043B\u0441\u044F \u0432 \u043F\u043E\u0442\u043E\u043B\u043E\u043A \u0442\u0440\u0430\u0442: \u0441\u0435\u0441\u0441\u0438\u044E \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u043B \u0431\u044E\u0434\u0436\u0435\u0442 \u043F\u0440\u043E\u0433\u043E\u043D\u0430";
|
|
14147
14209
|
var NO_AUTO_WAKE_REASONS = [EXITED_NO_DONE_REASON, BUDGET_STOP_REASON];
|
|
14148
14210
|
var REVIEW_BUDGET_MARK = "\u0440\u0435\u0432\u044C\u044E \u043D\u0435 \u0443\u043B\u043E\u0436\u0438\u043B\u043E\u0441\u044C \u0432 \u043F\u043E\u0442\u043E\u043B\u043E\u043A \u0442\u0440\u0430\u0442";
|
|
@@ -14684,14 +14746,20 @@ ${priorReview}` : "",
|
|
|
14684
14746
|
"- [ ] \u0415\u0441\u043B\u0438 \u043F\u0440\u0430\u0432\u0438\u0442\u0441\u044F router.tsx \u2014 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0430 per-page meta \u0434\u043B\u044F \u0430\u0433\u0435\u043D\u0442\u0441\u043A\u043E\u0433\u043E \u043A\u043E\u043D\u0442\u0440\u043E\u043B\u0430 (\u0438\u043D\u0430\u0447\u0435 NL-\u043D\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u044F \u043C\u043E\u043B\u0447\u0430 \u043B\u043E\u043C\u0430\u0435\u0442\u0441\u044F)."
|
|
14685
14747
|
].join("\n");
|
|
14686
14748
|
}
|
|
14687
|
-
|
|
14749
|
+
var VERDICT_EVENT_PREFIXES = ["\u0432\u0435\u0440\u0434\u0438\u043A\u0442 \u0440\u0435\u0432\u044C\u044E \u043E\u0442", "\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"];
|
|
14750
|
+
function lastVerdictEvent(db, reviewRunId) {
|
|
14688
14751
|
const events = db.events(reviewRunId);
|
|
14689
14752
|
for (let i = events.length - 1; i >= 0; i--) {
|
|
14690
|
-
|
|
14691
|
-
if (text.startsWith("\u0432\u0435\u0440\u0434\u0438\u043A\u0442 \u0440\u0435\u0432\u044C\u044E \u043E\u0442")) return text;
|
|
14753
|
+
if (VERDICT_EVENT_PREFIXES.some((p) => (events[i].text ?? "").startsWith(p))) return events[i];
|
|
14692
14754
|
}
|
|
14693
14755
|
return null;
|
|
14694
14756
|
}
|
|
14757
|
+
function lastChangesSummary(db, reviewRunId) {
|
|
14758
|
+
return lastVerdictEvent(db, reviewRunId)?.text ?? null;
|
|
14759
|
+
}
|
|
14760
|
+
function changesVerdictAt(db, reviewRunId) {
|
|
14761
|
+
return lastVerdictEvent(db, reviewRunId)?.at ?? null;
|
|
14762
|
+
}
|
|
14695
14763
|
var REVIEW_SCOPE_BLOCK = [
|
|
14696
14764
|
"\u{1F4B8} \u041A\u041E\u041D\u0422\u0423\u0420 \u0420\u0415\u0412\u042C\u042E (\u0436\u0451\u0441\u0442\u043A\u043E). \u0422\u0432\u043E\u044F \u0441\u0435\u0441\u0441\u0438\u044F \u043E\u0433\u0440\u0430\u043D\u0438\u0447\u0435\u043D\u0430 \u0431\u044E\u0434\u0436\u0435\u0442\u043E\u043C \u043F\u0440\u043E\u0433\u043E\u043D\u0430, \u0438 \u043E\u043D \u0441\u0440\u0435\u0436\u0435\u0442 \u0435\u0451 \u0411\u0415\u0417 \u043F\u0440\u0435\u0434\u0443\u043F\u0440\u0435\u0436\u0434\u0435\u043D\u0438\u044F: \u0443\u043F\u0440\u0451\u0448\u044C\u0441\u044F \u2014 \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u0430 \u043D\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u043E\u0432\u0441\u0435, \u0430 PR \u0443\u0439\u0434\u0451\u0442 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443. \u041F\u043E\u044D\u0442\u043E\u043C\u0443:",
|
|
14697
14765
|
"\u2022 \u0427\u0438\u0442\u0430\u0439 \u0414\u0418\u0424\u0424 \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u0442\u043E, \u0447\u0435\u0433\u043E \u043E\u043D \u043A\u0430\u0441\u0430\u0435\u0442\u0441\u044F: \u0441\u0430\u043C\u0438 \u0438\u0437\u043C\u0435\u043D\u0451\u043D\u043D\u044B\u0435 \u0444\u0430\u0439\u043B\u044B + \u043C\u0435\u0441\u0442\u0430, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0438\u043C\u0438 \u043B\u043E\u043C\u0430\u044E\u0442\u0441\u044F. \u0420\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0439 \xAB\u0434\u043B\u044F \u043E\u0431\u0449\u0435\u0433\u043E \u043F\u043E\u043D\u0438\u043C\u0430\u043D\u0438\u044F\xBB \u043D\u0435 \u0441\u043A\u0430\u043D\u0438\u0440\u0443\u0439 \u2014 \u043D\u0430 \u044D\u0442\u043E \u0443\u0445\u043E\u0434\u0438\u0442 \u0432\u0435\u0441\u044C \u0431\u044E\u0434\u0436\u0435\u0442 \u0438 \u043D\u0435 \u043D\u0430\u0445\u043E\u0434\u0438\u0442\u0441\u044F \u043D\u0438\u0447\u0435\u0433\u043E.",
|
|
@@ -15119,29 +15187,70 @@ async function wakeAuthorOnChanges(deps, run, now, droneCap) {
|
|
|
15119
15187
|
if (countActiveDrones(deps.db) >= droneCap) return false;
|
|
15120
15188
|
if (!await projectQuotaGateAllows(deps, run)) return false;
|
|
15121
15189
|
if (run.review_cycle >= REVIEW_CYCLE_LIMIT) return false;
|
|
15122
|
-
const
|
|
15123
|
-
|
|
15124
|
-
|
|
15125
|
-
|
|
15126
|
-
|
|
15190
|
+
const prUrl = run.pr_url;
|
|
15191
|
+
const events = deps.db.events(run.id);
|
|
15192
|
+
const mark = `${CHANGES_WAKE_ESCALATION_MARK} (\u043A\u0440\u0443\u0433 ${run.review_cycle ?? 0})`;
|
|
15193
|
+
const escalate = (why, said) => {
|
|
15194
|
+
if (!events.some((e) => (e.text ?? "").includes(mark))) {
|
|
15195
|
+
deps.db.addEvent(run.id, "step", `${mark}: ${why} \u2014 \u043D\u0443\u0436\u0435\u043D \u0447\u0435\u043B\u043E\u0432\u0435\u043A`);
|
|
15196
|
+
narrate(deps, said);
|
|
15127
15197
|
}
|
|
15128
15198
|
return false;
|
|
15199
|
+
};
|
|
15200
|
+
const alreadyEscalated = events.some((e) => (e.text ?? "").includes(mark));
|
|
15201
|
+
if (run.stop_reason?.startsWith(BUDGET_STOP_REASON)) {
|
|
15202
|
+
return escalate(
|
|
15203
|
+
"\u0444\u0438\u043A\u0441-\u0438\u0442\u0435\u0440\u0430\u0446\u0438\u044E \u043D\u0435 \u043F\u043E\u0434\u043D\u044F\u0442\u044C: \u043F\u0440\u043E\u0448\u043B\u0443\u044E \u0441\u0435\u0441\u0441\u0438\u044E \u0441\u0440\u0435\u0437\u0430\u043B \u043F\u043E\u0442\u043E\u043B\u043E\u043A \u0442\u0440\u0430\u0442 \u043F\u0440\u043E\u0433\u043E\u043D\u0430, \u043F\u043E\u0432\u0442\u043E\u0440 \u0443\u043F\u0440\u0451\u0442\u0441\u044F \u0432 \u0442\u043E\u0442 \u0436\u0435",
|
|
15204
|
+
`${droneLabel(run)} \u043D\u0435 \u043C\u043E\u0436\u0435\u0442 \u0432\u0437\u044F\u0442\u044C\u0441\u044F \u0437\u0430 \u043F\u0440\u0430\u0432\u043A\u0438 \u2014 \u0443\u043F\u0451\u0440\u0441\u044F \u0432 \u043F\u043E\u0442\u043E\u043B\u043E\u043A \u0442\u0440\u0430\u0442 \u043F\u0440\u043E\u0433\u043E\u043D\u0430. \u041F\u043E\u0434\u043D\u0438\u043C\u0438 \u043B\u0438\u043C\u0438\u0442 \u0438\u043B\u0438 \u0434\u043E\u0434\u0435\u043B\u0430\u0439 \u0440\u0443\u043A\u0430\u043C\u0438.`
|
|
15205
|
+
);
|
|
15206
|
+
}
|
|
15207
|
+
if (alreadyEscalated) return false;
|
|
15208
|
+
const attempts = events.filter((e) => e.kind === "resumed" && (e.text ?? "").includes(CHANGES_WAKE_MARK));
|
|
15209
|
+
const lastAttemptMs = attempts.length ? sqliteMs(attempts[attempts.length - 1].at) : null;
|
|
15210
|
+
if (lastAttemptMs != null && now - lastAttemptMs < CHANGES_WAKE_COOLDOWN_MS) return false;
|
|
15211
|
+
const wakes = attempts.filter((e) => !(e.text ?? "").includes(CHANGES_WAKE_FAILED_MARK));
|
|
15212
|
+
if (wakes.length >= CHANGES_WAKE_LIMIT) {
|
|
15213
|
+
const streakStart = wakes[wakes.length - CHANGES_WAKE_LIMIT].at;
|
|
15214
|
+
const moved = deps.commitsSince ? await deps.commitsSince(prUrl, streakStart).catch(() => false) : false;
|
|
15215
|
+
if (!moved) {
|
|
15216
|
+
return escalate(
|
|
15217
|
+
`${CHANGES_WAKE_LIMIT} \u043F\u043E\u0431\u0443\u0434(\u043E\u043A) \u043F\u043E\u0434\u0440\u044F\u0434 \u043D\u0435 \u043F\u043E\u043B\u043E\u0436\u0438\u043B\u0438 \u0432 \u0432\u0435\u0442\u043A\u0443 \u043D\u0438 \u043E\u0434\u043D\u043E\u0433\u043E \u043A\u043E\u043C\u043C\u0438\u0442\u0430`,
|
|
15218
|
+
`${droneLabel(run)} \u043F\u043E\u0434\u043D\u0438\u043C\u0430\u043B\u0441\u044F \u043D\u0430 \u043F\u0440\u0430\u0432\u043A\u0438 ${CHANGES_WAKE_LIMIT} \u0440\u0430\u0437(\u0430) \u0438 \u043D\u0435 \u0441\u0434\u0435\u043B\u0430\u043B \u043D\u0438 \u043A\u043E\u043C\u043C\u0438\u0442\u0430 \u2014 \u0434\u0430\u043B\u044C\u0448\u0435 \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440.`
|
|
15219
|
+
);
|
|
15220
|
+
}
|
|
15129
15221
|
}
|
|
15130
|
-
const lastWakeMs = wakes.length ? Date.parse(wakes[wakes.length - 1].at.replace(" ", "T") + "Z") : null;
|
|
15131
|
-
if (lastWakeMs != null && now - lastWakeMs < CHANGES_WAKE_COOLDOWN_MS) return false;
|
|
15132
15222
|
const wt = run.worktree_path;
|
|
15133
|
-
|
|
15223
|
+
const mode = wt && worktreeAndTranscriptAlive(deps, wt) ? "continue" : "fresh";
|
|
15224
|
+
if (mode === "fresh" && !await freshChangesWakeAllowed(deps, run, prUrl, now)) return false;
|
|
15225
|
+
const nudge = buildChangesWakeNudge(prUrl, lastChangesSummary(deps.db, run.id));
|
|
15134
15226
|
try {
|
|
15135
|
-
await deps.respawn(run,
|
|
15136
|
-
deps.db.
|
|
15137
|
-
|
|
15227
|
+
await deps.respawn(run, mode, nudge);
|
|
15228
|
+
if (run.stop_reason != null) deps.db.updateRun(run.id, { stop_reason: null });
|
|
15229
|
+
const how = mode === "continue" ? "\u0431\u0443\u0436\u0443 \u0430\u0432\u0442\u043E\u0440\u0430 (--continue) \u0437\u0430\u043A\u0440\u044B\u0432\u0430\u0442\u044C \u0437\u0430\u043C\u0435\u0447\u0430\u043D\u0438\u044F" : "\u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0430\u0442\u044C \u043D\u0435\u0447\u0435\u043C (worktree/\u0441\u0435\u0441\u0441\u0438\u044F \u043F\u043E\u0442\u0435\u0440\u044F\u043D\u044B) \u2014 \u043F\u043E\u0434\u043D\u0438\u043C\u0430\u044E \u0441\u0432\u0435\u0436\u0435\u0433\u043E \u0434\u0440\u043E\u043D\u0430 \u043D\u0430 \u0442\u0443 \u0436\u0435 \u0432\u0435\u0442\u043A\u0443 \u0438 \u0442\u043E\u0442 \u0436\u0435 PR";
|
|
15230
|
+
deps.db.addEvent(run.id, "resumed", `${CHANGES_WAKE_MARK} \u2014 ${how}`);
|
|
15231
|
+
narrate(
|
|
15232
|
+
deps,
|
|
15233
|
+
mode === "continue" ? `\u0420\u0435\u0432\u044C\u044E\u0435\u0440 \u043F\u043E\u043F\u0440\u043E\u0441\u0438\u043B \u043F\u0440\u0430\u0432\u043A\u0438 \u0443 ${droneLabel(run)} \u2014 \u0431\u0443\u0436\u0443 \u0430\u0432\u0442\u043E\u0440\u0430 \u043D\u0430 \u0444\u0438\u043A\u0441-\u0438\u0442\u0435\u0440\u0430\u0446\u0438\u044E.` : `\u0420\u0435\u0432\u044C\u044E\u0435\u0440 \u043F\u043E\u043F\u0440\u043E\u0441\u0438\u043B \u043F\u0440\u0430\u0432\u043A\u0438 \u0443 ${droneLabel(run)}, \u0430 \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0430\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E \u2014 \u043F\u043E\u0434\u043D\u0438\u043C\u0430\u044E \u0441\u0432\u0435\u0436\u0435\u0433\u043E \u0434\u0440\u043E\u043D\u0430 \u043D\u0430 \u0442\u0443 \u0436\u0435 \u0432\u0435\u0442\u043A\u0443.`
|
|
15234
|
+
);
|
|
15138
15235
|
return true;
|
|
15139
15236
|
} catch (e) {
|
|
15140
|
-
deps.db.addEvent(run.id, "resumed", `${CHANGES_WAKE_MARK}:
|
|
15237
|
+
deps.db.addEvent(run.id, "resumed", `${CHANGES_WAKE_MARK}: ${CHANGES_WAKE_FAILED_MARK} \u2014 ${String(e)}`);
|
|
15141
15238
|
narrate(deps, `\u043F\u043E\u0431\u0443\u0434\u043A\u0430 ${droneLabel(run)} \u043D\u0430 \u0444\u0438\u043A\u0441-\u0438\u0442\u0435\u0440\u0430\u0446\u0438\u044E \u0441\u043E\u0440\u0432\u0430\u043B\u0430\u0441\u044C.`);
|
|
15142
15239
|
return false;
|
|
15143
15240
|
}
|
|
15144
15241
|
}
|
|
15242
|
+
var freshWakeProbeAt = /* @__PURE__ */ new Map();
|
|
15243
|
+
async function freshChangesWakeAllowed(deps, run, prUrl, now) {
|
|
15244
|
+
const verdictAt = changesVerdictAt(deps.db, run.id);
|
|
15245
|
+
const verdictMs = verdictAt ? sqliteMs(verdictAt) : NaN;
|
|
15246
|
+
if (Number.isFinite(verdictMs) && now - verdictMs < CHANGES_FRESH_WAKE_AFTER_MS) return false;
|
|
15247
|
+
if (!deps.commitsSince) return true;
|
|
15248
|
+
const probedAt = freshWakeProbeAt.get(run.id);
|
|
15249
|
+
if (probedAt != null && now - probedAt < CHANGES_WAKE_COOLDOWN_MS) return false;
|
|
15250
|
+
freshWakeProbeAt.set(run.id, now);
|
|
15251
|
+
const moved = await deps.commitsSince(prUrl, verdictAt ?? run.created_at).catch(() => true);
|
|
15252
|
+
return !moved;
|
|
15253
|
+
}
|
|
15145
15254
|
async function prodStillAllows(deps, run, allowed) {
|
|
15146
15255
|
if (!deps.db.refreshRun) return true;
|
|
15147
15256
|
let fresh;
|
|
@@ -16525,9 +16634,12 @@ async function spawnReviewer(deps, reviewRun, files) {
|
|
|
16525
16634
|
}
|
|
16526
16635
|
}
|
|
16527
16636
|
async function respawnRun(deps, run, mode, nudge) {
|
|
16528
|
-
const wt = run.worktree_path;
|
|
16529
|
-
if (!wt) throw new Error(`\u043D\u0435\u0442 worktree_path \u0434\u043B\u044F \u043E\u0436\u0438\u0432\u043B\u0435\u043D\u0438\u044F \u043F\u0440\u043E\u0433\u043E\u043D\u0430 #${run.id}`);
|
|
16530
16637
|
const repo = normalizeRepo(run.repo || deps.repoFallback);
|
|
16638
|
+
const wt = run.worktree_path || (mode === "fresh" ? droneWorktreePath(deps.worktreesDir, repo, run.task_slug) : null);
|
|
16639
|
+
if (!wt) throw new Error(`\u043D\u0435\u0442 worktree_path \u0434\u043B\u044F \u043E\u0436\u0438\u0432\u043B\u0435\u043D\u0438\u044F \u043F\u0440\u043E\u0433\u043E\u043D\u0430 #${run.id}`);
|
|
16640
|
+
if (!run.worktree_path && worktreePathHeldLive(deps.db, wt, run.id)) {
|
|
16641
|
+
throw new Error(`worktree ${wt} \u0434\u0435\u0440\u0436\u0438\u0442 \u0434\u0440\u0443\u0433\u043E\u0439 \u0436\u0438\u0432\u043E\u0439 \u043F\u0440\u043E\u0433\u043E\u043D \u2014 \u043E\u0436\u0438\u0432\u043B\u0435\u043D\u0438\u0435 #${run.id} \u043E\u0442\u043C\u0435\u043D\u0435\u043D\u043E (TASWM-417)`);
|
|
16642
|
+
}
|
|
16531
16643
|
if (mode === "continue") {
|
|
16532
16644
|
const prompt2 = nudge ?? (run.kind === "hero" ? HERO_CONTINUE_NUDGE : CONTINUE_NUDGE);
|
|
16533
16645
|
const pid2 = deps.launch({ worktree: wt, run, prompt: prompt2, continueSession: true });
|
|
@@ -16563,9 +16675,7 @@ async function respawnRun(deps, run, mode, nudge) {
|
|
|
16563
16675
|
});
|
|
16564
16676
|
const freshPrompt = runToSpawn.kind === "hero" ? buildHeroPrompt(task, runToSpawn, taskContext, attachments) : buildPrompt(task, runToSpawn, verifyMode, taskContext, attachments);
|
|
16565
16677
|
const notice = depsPromptNotice(depsReport);
|
|
16566
|
-
const prompt = notice
|
|
16567
|
-
|
|
16568
|
-
${notice}` : freshPrompt;
|
|
16678
|
+
const prompt = [freshPrompt, notice, nudge].filter(Boolean).join("\n\n");
|
|
16569
16679
|
const pid = deps.launch({ worktree: wt, run: runToSpawn, prompt });
|
|
16570
16680
|
deps.db.updateRun(run.id, { status: "running", pid });
|
|
16571
16681
|
}
|
|
@@ -17696,8 +17806,10 @@ if (isEntrypoint) {
|
|
|
17696
17806
|
export {
|
|
17697
17807
|
AWAITING_CI_REASON,
|
|
17698
17808
|
BUDGET_STOP_REASON,
|
|
17809
|
+
CHANGES_FRESH_WAKE_AFTER_MS,
|
|
17699
17810
|
CHANGES_WAKE_COOLDOWN_MS,
|
|
17700
17811
|
CHANGES_WAKE_ESCALATION_MARK,
|
|
17812
|
+
CHANGES_WAKE_FAILED_MARK,
|
|
17701
17813
|
CHANGES_WAKE_LIMIT,
|
|
17702
17814
|
CHANGES_WAKE_MARK,
|
|
17703
17815
|
CI_CHECK_COOLDOWN_MS,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taskless-app/swarm",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.11",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
6
6
|
"keywords": [
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"execa": "^10.0.0",
|
|
39
39
|
"zod": "3.25.76"
|
|
40
40
|
},
|
|
41
|
-
"gitHead": "
|
|
41
|
+
"gitHead": "f228c3fd9ac879e828e5b813bf8ff077402fbe23",
|
|
42
42
|
"scripts": {
|
|
43
43
|
"overmind": "NODE_OPTIONS=\"${NODE_OPTIONS:-} --conditions=development\" tsx src/overmind.ts",
|
|
44
44
|
"swarm": "NODE_OPTIONS=\"${NODE_OPTIONS:-} --conditions=development\" tsx src/cli.ts",
|