@taskless-app/swarm 0.6.20 → 0.6.22
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 +82 -6
- package/dist/overmind.js +497 -76
- package/package.json +2 -2
- package/roles/drone/skills/swarm-verify-green/SKILL.md +33 -0
package/dist/cli.js
CHANGED
|
@@ -1776,10 +1776,24 @@ function asTokenUsage(m) {
|
|
|
1776
1776
|
function budgetExhausted(result) {
|
|
1777
1777
|
return result.subtype === "error_max_budget_usd" || result.terminal_reason === "budget_exhausted";
|
|
1778
1778
|
}
|
|
1779
|
+
function sessionAbort(result) {
|
|
1780
|
+
if (budgetExhausted(result)) return null;
|
|
1781
|
+
const reason = result.terminal_reason ?? "";
|
|
1782
|
+
const subtype = result.subtype ?? "";
|
|
1783
|
+
if (reason === "aborted_tools") return { kind: "tools", raw: reason };
|
|
1784
|
+
if (reason === "aborted_streaming" || reason === "api_error") return { kind: "link", raw: reason };
|
|
1785
|
+
if (HONEST_ENDINGS.has(subtype) || HONEST_ENDINGS.has(reason)) return null;
|
|
1786
|
+
const failed = result.is_error === true || subtype === "error_during_execution" || reason.startsWith("aborted");
|
|
1787
|
+
if (!failed) return null;
|
|
1788
|
+
const raw = reason && reason !== "completed" ? reason : subtype || reason || "\u043E\u0448\u0438\u0431\u043A\u0430 \u0431\u0435\u0437 \u043C\u0435\u0442\u043A\u0438";
|
|
1789
|
+
return { kind: "other", raw };
|
|
1790
|
+
}
|
|
1791
|
+
var HONEST_ENDINGS;
|
|
1779
1792
|
var init_claudeResult = __esm({
|
|
1780
1793
|
"src/claudeResult.ts"() {
|
|
1781
1794
|
"use strict";
|
|
1782
1795
|
init_pricing();
|
|
1796
|
+
HONEST_ENDINGS = /* @__PURE__ */ new Set(["error_max_turns"]);
|
|
1783
1797
|
}
|
|
1784
1798
|
});
|
|
1785
1799
|
|
|
@@ -1854,6 +1868,9 @@ function writeMcpConfig(spec) {
|
|
|
1854
1868
|
writeFileSync(path, JSON.stringify(cfg, null, 2));
|
|
1855
1869
|
return path;
|
|
1856
1870
|
}
|
|
1871
|
+
function abortField(abort) {
|
|
1872
|
+
return abort ? { aborted: abort } : {};
|
|
1873
|
+
}
|
|
1857
1874
|
var ISOLATION_FLAGS, MCP_CONFIG_FILE, claudeCodeExecutor;
|
|
1858
1875
|
var init_claudeCode = __esm({
|
|
1859
1876
|
"src/executors/claudeCode.ts"() {
|
|
@@ -1892,7 +1909,10 @@ var init_claudeCode = __esm({
|
|
|
1892
1909
|
durationMs: spend.durationMs,
|
|
1893
1910
|
// TASWM-377: «упёрся в потолок» — отдельный факт об этом же итоге, а не отдельный
|
|
1894
1911
|
// разбор файла: у claude он лежит в тех же полях, что деньги и токены.
|
|
1895
|
-
...budgetExhausted(result) ? { stoppedByBudget: true } : {}
|
|
1912
|
+
...budgetExhausted(result) ? { stoppedByBudget: true } : {},
|
|
1913
|
+
// TASWM-487: и «оборвалось» — третий факт об этом же итоге. Порядок важен: потолок
|
|
1914
|
+
// трат sessionAbort отсекает сам, поэтому оба ключа одновременно не появятся.
|
|
1915
|
+
...abortField(sessionAbort(result))
|
|
1896
1916
|
};
|
|
1897
1917
|
},
|
|
1898
1918
|
session: {
|
|
@@ -2373,7 +2393,7 @@ var init_package = __esm({
|
|
|
2373
2393
|
"package.json"() {
|
|
2374
2394
|
package_default = {
|
|
2375
2395
|
name: "@taskless-app/swarm",
|
|
2376
|
-
version: "0.6.
|
|
2396
|
+
version: "0.6.22",
|
|
2377
2397
|
type: "module",
|
|
2378
2398
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
2379
2399
|
keywords: [
|
|
@@ -2423,7 +2443,7 @@ var init_package = __esm({
|
|
|
2423
2443
|
execa: "^10.0.0",
|
|
2424
2444
|
zod: "3.25.76"
|
|
2425
2445
|
},
|
|
2426
|
-
gitHead: "
|
|
2446
|
+
gitHead: "b8eaac4a5562ffcf45a02af338267620e0a7843f"
|
|
2427
2447
|
};
|
|
2428
2448
|
}
|
|
2429
2449
|
});
|
|
@@ -8510,10 +8530,24 @@ async function openPrsForBranch(branch, repoDir, run = realRepoRunner) {
|
|
|
8510
8530
|
}
|
|
8511
8531
|
}
|
|
8512
8532
|
var NO_CHECKS_STDERR = /no checks reported/i;
|
|
8533
|
+
var CiAccessDeniedError = class extends Error {
|
|
8534
|
+
detail;
|
|
8535
|
+
constructor(detail) {
|
|
8536
|
+
super(`\u043D\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u0430 \u043A \u0447\u0435\u043A\u0430\u043C: ${detail}`);
|
|
8537
|
+
this.name = "CiAccessDeniedError";
|
|
8538
|
+
this.detail = detail;
|
|
8539
|
+
}
|
|
8540
|
+
};
|
|
8541
|
+
var DENIED_STDERR = /(?:^|\D)403(?:\D|$)|not accessible by integration|must have admin rights|resource not accessible/i;
|
|
8542
|
+
function firstLine(s) {
|
|
8543
|
+
return s.split("\n").map((l) => l.trim()).find((l) => l.length > 0) ?? "gh \u0432\u0435\u0440\u043D\u0443\u043B 403";
|
|
8544
|
+
}
|
|
8513
8545
|
var realChecksRunner = async (pr) => {
|
|
8514
8546
|
const r = await $4({ reject: false, timeout: 15e3 })`gh pr checks ${pr} --json state,name,bucket,link`;
|
|
8515
8547
|
const stdout = r.stdout ?? "";
|
|
8516
|
-
|
|
8548
|
+
const stderr = r.stderr ?? "";
|
|
8549
|
+
if (!stdout.trim() && NO_CHECKS_STDERR.test(stderr)) return "[]";
|
|
8550
|
+
if (!stdout.trim() && DENIED_STDERR.test(stderr)) throw new CiAccessDeniedError(firstLine(stderr));
|
|
8517
8551
|
return stdout;
|
|
8518
8552
|
};
|
|
8519
8553
|
async function prCheckRows(pr, run) {
|
|
@@ -8522,13 +8556,17 @@ async function prCheckRows(pr, run) {
|
|
|
8522
8556
|
const rows = JSON.parse(out);
|
|
8523
8557
|
if (!Array.isArray(rows)) return null;
|
|
8524
8558
|
return rows.map((r) => ({ name: r.name ?? "?", bucket: (r.bucket ?? "").toLowerCase(), link: r.link ?? "" }));
|
|
8525
|
-
} catch {
|
|
8559
|
+
} catch (e) {
|
|
8560
|
+
if (e instanceof CiAccessDeniedError) return { denied: e.detail };
|
|
8526
8561
|
return null;
|
|
8527
8562
|
}
|
|
8528
8563
|
}
|
|
8564
|
+
function isDenied(rows) {
|
|
8565
|
+
return rows != null && !Array.isArray(rows);
|
|
8566
|
+
}
|
|
8529
8567
|
async function ghChecks(pr, run = realChecksRunner) {
|
|
8530
8568
|
const rows = await prCheckRows(pr, run);
|
|
8531
|
-
if (!rows || rows.length === 0) return null;
|
|
8569
|
+
if (!rows || isDenied(rows) || rows.length === 0) return null;
|
|
8532
8570
|
let pass = 0, fail = 0, pending2 = 0;
|
|
8533
8571
|
for (const r of rows) {
|
|
8534
8572
|
if (r.bucket === "pass") pass++;
|
|
@@ -11084,6 +11122,44 @@ init_config();
|
|
|
11084
11122
|
init_agentToken();
|
|
11085
11123
|
init_linkFailure();
|
|
11086
11124
|
|
|
11125
|
+
// src/toolFailure.ts
|
|
11126
|
+
init_linkFailure();
|
|
11127
|
+
var TOOL_FAILURE = {
|
|
11128
|
+
/** Тул отработал, но искомого в ответе нет: задачи с таким слагом в воркспейсе не существует. */
|
|
11129
|
+
NOT_FOUND: "not_found",
|
|
11130
|
+
/** Объект есть, но токену роя не виден (приватный проект, спейс, чужой воркспейс). */
|
|
11131
|
+
FORBIDDEN: "forbidden",
|
|
11132
|
+
/** Токен роя не состоит в воркспейсе, которым искали. */
|
|
11133
|
+
WORKSPACE_MISMATCH: "workspace_mismatch",
|
|
11134
|
+
/** До прода не достучались: сеть, DNS, таймаут, оборванный сокет. */
|
|
11135
|
+
UNREACHABLE: "unreachable",
|
|
11136
|
+
/** Прод ответил, но токен роя отвергнут (отозван, протух). Сетью это не лечится. */
|
|
11137
|
+
UNAUTHORIZED: "unauthorized",
|
|
11138
|
+
/** Тул ответил ошибкой, которую мы не узнали, — текст кладём в detail как есть. */
|
|
11139
|
+
TOOL_ERROR: "tool_error",
|
|
11140
|
+
/** Успех, но полезной нагрузки в ответе нет (форма ответа разошлась с ожиданием). */
|
|
11141
|
+
EMPTY: "empty"
|
|
11142
|
+
};
|
|
11143
|
+
var TOOL_FAILURE_TEXT = {
|
|
11144
|
+
[TOOL_FAILURE.NOT_FOUND]: "\u0432 \u044D\u0442\u043E\u043C \u0432\u043E\u0440\u043A\u0441\u043F\u0435\u0439\u0441\u0435 \u0442\u0430\u043A\u043E\u0433\u043E \u043D\u0435\u0442 \u2014 \u043F\u0440\u043E\u0432\u0435\u0440\u044C \u0441\u043B\u0430\u0433 \u0438 \u0432\u043E\u0440\u043A\u0441\u043F\u0435\u0439\u0441 \u043F\u0440\u043E\u0433\u043E\u043D\u0430",
|
|
11145
|
+
[TOOL_FAILURE.FORBIDDEN]: "\u0434\u043E\u0441\u0442\u0443\u043F\u0430 \u043D\u0435\u0442: \u043E\u0431\u044A\u0435\u043A\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442, \u043D\u043E \u0442\u043E\u043A\u0435\u043D\u0443 \u0440\u043E\u044F \u043D\u0435 \u0432\u0438\u0434\u0435\u043D \u2014 \u043D\u0443\u0436\u0435\u043D \u0447\u0435\u043B\u043E\u0432\u0435\u043A",
|
|
11146
|
+
[TOOL_FAILURE.WORKSPACE_MISMATCH]: "\u0442\u043E\u043A\u0435\u043D \u0440\u043E\u044F \u043D\u0435 \u0441\u043E\u0441\u0442\u043E\u0438\u0442 \u0432 \u044D\u0442\u043E\u043C \u0432\u043E\u0440\u043A\u0441\u043F\u0435\u0439\u0441\u0435",
|
|
11147
|
+
[TOOL_FAILURE.UNREACHABLE]: "Taskless \u043D\u0435 \u043E\u0442\u0432\u0435\u0442\u0438\u043B \u2014 \u0441\u0435\u0442\u044C, DNS \u0438\u043B\u0438 \u0442\u0430\u0439\u043C\u0430\u0443\u0442",
|
|
11148
|
+
[TOOL_FAILURE.UNAUTHORIZED]: "\u0442\u043E\u043A\u0435\u043D \u0440\u043E\u044F \u043E\u0442\u0432\u0435\u0440\u0433\u043D\u0443\u0442 \u043F\u0440\u043E\u0434\u043E\u043C \u2014 \u043D\u0443\u0436\u0435\u043D swarm login \u043D\u0430 \u044D\u0442\u043E\u0439 \u043C\u0430\u0448\u0438\u043D\u0435",
|
|
11149
|
+
[TOOL_FAILURE.TOOL_ERROR]: "\u0442\u0443\u043B \u043E\u0442\u0432\u0435\u0442\u0438\u043B \u043E\u0448\u0438\u0431\u043A\u043E\u0439",
|
|
11150
|
+
[TOOL_FAILURE.EMPTY]: "\u0442\u0443\u043B \u043E\u0442\u0432\u0435\u0442\u0438\u043B \u0443\u0441\u043F\u0435\u0445\u043E\u043C, \u043D\u043E \u0434\u0430\u043D\u043D\u044B\u0445 \u0432 \u043E\u0442\u0432\u0435\u0442\u0435 \u043D\u0435\u0442"
|
|
11151
|
+
};
|
|
11152
|
+
var TOOL_FAILURE_RETRIABLE = {
|
|
11153
|
+
[TOOL_FAILURE.NOT_FOUND]: false,
|
|
11154
|
+
[TOOL_FAILURE.FORBIDDEN]: false,
|
|
11155
|
+
[TOOL_FAILURE.WORKSPACE_MISMATCH]: false,
|
|
11156
|
+
[TOOL_FAILURE.UNREACHABLE]: true,
|
|
11157
|
+
// Отозванный токен повтором не чинится — его меняет человек (`swarm login`).
|
|
11158
|
+
[TOOL_FAILURE.UNAUTHORIZED]: false,
|
|
11159
|
+
[TOOL_FAILURE.TOOL_ERROR]: false,
|
|
11160
|
+
[TOOL_FAILURE.EMPTY]: false
|
|
11161
|
+
};
|
|
11162
|
+
|
|
11087
11163
|
// src/workspace.ts
|
|
11088
11164
|
init_config();
|
|
11089
11165
|
import { readFileSync as readFileSync9, writeFileSync as writeFileSync8, unlinkSync as unlinkSync4 } from "fs";
|