@taskless-app/swarm 0.6.38 → 0.6.39
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 +265 -148
- package/dist/overmind.js +613 -252
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -2018,10 +2018,94 @@ var init_claudeResult = __esm({
|
|
|
2018
2018
|
}
|
|
2019
2019
|
});
|
|
2020
2020
|
|
|
2021
|
-
// src/
|
|
2022
|
-
import { readdirSync as readdirSync2, statSync
|
|
2021
|
+
// src/transcriptSpend.ts
|
|
2022
|
+
import { readFileSync as readFileSync2, readdirSync as readdirSync2, statSync } from "fs";
|
|
2023
2023
|
import { homedir as homedir2 } from "os";
|
|
2024
2024
|
import { join as join2 } from "path";
|
|
2025
|
+
function transcriptDir(worktree, projectsDir) {
|
|
2026
|
+
return join2(projectsDir, worktree.replace(/[/.]/g, "-"));
|
|
2027
|
+
}
|
|
2028
|
+
function transcriptSpendInWindow(worktree, fromMs, toMs, opts = {}) {
|
|
2029
|
+
const projectsDir = opts.projectsDir ?? join2(homedir2(), ".claude", "projects");
|
|
2030
|
+
const empty = { costUsd: 0, tokensIn: 0, tokensOut: 0, durationMs: 0, replies: 0, unpriced: 0, unpricedModel: null };
|
|
2031
|
+
const dir = transcriptDir(worktree, projectsDir);
|
|
2032
|
+
let files;
|
|
2033
|
+
try {
|
|
2034
|
+
files = readdirSync2(dir).filter((f) => f.endsWith(".jsonl"));
|
|
2035
|
+
} catch {
|
|
2036
|
+
return empty;
|
|
2037
|
+
}
|
|
2038
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2039
|
+
let costUsd = 0;
|
|
2040
|
+
let tokensIn = 0;
|
|
2041
|
+
let tokensOut = 0;
|
|
2042
|
+
let firstAt = null;
|
|
2043
|
+
let lastAt = null;
|
|
2044
|
+
let replies = 0;
|
|
2045
|
+
let unpriced = 0;
|
|
2046
|
+
let unpricedModel = null;
|
|
2047
|
+
for (const f of files) {
|
|
2048
|
+
const path = join2(dir, f);
|
|
2049
|
+
let raw;
|
|
2050
|
+
try {
|
|
2051
|
+
if (statSync(path).mtimeMs < fromMs) continue;
|
|
2052
|
+
raw = readFileSync2(path, "utf8");
|
|
2053
|
+
} catch {
|
|
2054
|
+
continue;
|
|
2055
|
+
}
|
|
2056
|
+
for (const line of raw.split("\n")) {
|
|
2057
|
+
if (!line.startsWith("{") || !line.includes('"usage"')) continue;
|
|
2058
|
+
let entry;
|
|
2059
|
+
try {
|
|
2060
|
+
entry = JSON.parse(line);
|
|
2061
|
+
} catch {
|
|
2062
|
+
continue;
|
|
2063
|
+
}
|
|
2064
|
+
if (entry.type !== "assistant") continue;
|
|
2065
|
+
const usage2 = entry.message?.usage;
|
|
2066
|
+
if (!usage2) continue;
|
|
2067
|
+
const at = entry.timestamp ? Date.parse(entry.timestamp) : NaN;
|
|
2068
|
+
if (!Number.isFinite(at) || at < fromMs || at >= toMs) continue;
|
|
2069
|
+
const key = entry.requestId ?? entry.message?.id ?? entry.uuid;
|
|
2070
|
+
if (!key || seen.has(key)) continue;
|
|
2071
|
+
seen.add(key);
|
|
2072
|
+
const model = entry.message?.model ?? null;
|
|
2073
|
+
const est = costFromUsage(usage2, model, opts.table);
|
|
2074
|
+
costUsd += est.costUsd;
|
|
2075
|
+
if (est.warning) {
|
|
2076
|
+
unpriced += 1;
|
|
2077
|
+
unpricedModel ??= model;
|
|
2078
|
+
}
|
|
2079
|
+
const num = (v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? v : 0;
|
|
2080
|
+
tokensIn += num(usage2.input_tokens) + num(usage2.cache_creation_input_tokens) + num(usage2.cache_read_input_tokens);
|
|
2081
|
+
tokensOut += num(usage2.output_tokens);
|
|
2082
|
+
if (firstAt === null || at < firstAt) firstAt = at;
|
|
2083
|
+
if (lastAt === null || at > lastAt) lastAt = at;
|
|
2084
|
+
replies += 1;
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
if (replies === 0) return empty;
|
|
2088
|
+
return {
|
|
2089
|
+
costUsd,
|
|
2090
|
+
tokensIn,
|
|
2091
|
+
tokensOut,
|
|
2092
|
+
durationMs: firstAt !== null && lastAt !== null ? lastAt - firstAt : 0,
|
|
2093
|
+
replies,
|
|
2094
|
+
unpriced,
|
|
2095
|
+
unpricedModel
|
|
2096
|
+
};
|
|
2097
|
+
}
|
|
2098
|
+
var init_transcriptSpend = __esm({
|
|
2099
|
+
"src/transcriptSpend.ts"() {
|
|
2100
|
+
"use strict";
|
|
2101
|
+
init_pricing();
|
|
2102
|
+
}
|
|
2103
|
+
});
|
|
2104
|
+
|
|
2105
|
+
// src/executors/claudeCode.ts
|
|
2106
|
+
import { readdirSync as readdirSync3, statSync as statSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
2107
|
+
import { homedir as homedir3 } from "os";
|
|
2108
|
+
import { join as join3 } from "path";
|
|
2025
2109
|
function claudeArgs(cfgPath, prompt, continueSession = false, model, pluginDirs = [], settings, maxBudgetUsd, effort) {
|
|
2026
2110
|
const pluginFlags = pluginDirs.flatMap((dir) => ["--plugin-dir", dir]);
|
|
2027
2111
|
const budgetFlags = typeof maxBudgetUsd === "number" && maxBudgetUsd > 0 ? ["--max-budget-usd", String(maxBudgetUsd)] : [];
|
|
@@ -2053,21 +2137,21 @@ function droneSettingsJson(paths, mergeGateHook = null) {
|
|
|
2053
2137
|
if (mergeGateHook) settings.hooks = { PreToolUse: [{ matcher: "Bash", hooks: [{ type: "command", command: mergeGateHook }] }] };
|
|
2054
2138
|
return JSON.stringify(settings);
|
|
2055
2139
|
}
|
|
2056
|
-
function
|
|
2057
|
-
return
|
|
2140
|
+
function transcriptDir2(worktree, projectsDir) {
|
|
2141
|
+
return join3(projectsDir, worktree.replace(/[/.]/g, "-"));
|
|
2058
2142
|
}
|
|
2059
|
-
function sessionTranscriptExists(worktree, projectsDir =
|
|
2143
|
+
function sessionTranscriptExists(worktree, projectsDir = join3(homedir3(), ".claude", "projects")) {
|
|
2060
2144
|
try {
|
|
2061
|
-
return
|
|
2145
|
+
return readdirSync3(transcriptDir2(worktree, projectsDir)).some((f) => f.endsWith(".jsonl"));
|
|
2062
2146
|
} catch {
|
|
2063
2147
|
return false;
|
|
2064
2148
|
}
|
|
2065
2149
|
}
|
|
2066
|
-
function transcriptMtimeMs(worktree, projectsDir =
|
|
2067
|
-
const dir =
|
|
2150
|
+
function transcriptMtimeMs(worktree, projectsDir = join3(homedir3(), ".claude", "projects")) {
|
|
2151
|
+
const dir = transcriptDir2(worktree, projectsDir);
|
|
2068
2152
|
let files;
|
|
2069
2153
|
try {
|
|
2070
|
-
files =
|
|
2154
|
+
files = readdirSync3(dir);
|
|
2071
2155
|
} catch {
|
|
2072
2156
|
return null;
|
|
2073
2157
|
}
|
|
@@ -2075,7 +2159,7 @@ function transcriptMtimeMs(worktree, projectsDir = join2(homedir2(), ".claude",
|
|
|
2075
2159
|
for (const f of files) {
|
|
2076
2160
|
if (!f.endsWith(".jsonl")) continue;
|
|
2077
2161
|
try {
|
|
2078
|
-
const mtime2 =
|
|
2162
|
+
const mtime2 = statSync2(join3(dir, f)).mtimeMs;
|
|
2079
2163
|
if (latest === null || mtime2 > latest) latest = mtime2;
|
|
2080
2164
|
} catch {
|
|
2081
2165
|
}
|
|
@@ -2088,7 +2172,7 @@ function writeMcpConfig(spec) {
|
|
|
2088
2172
|
[spec.mcp.name]: { command: spec.mcp.command, args: spec.mcp.args, env: spec.mcp.env }
|
|
2089
2173
|
}
|
|
2090
2174
|
};
|
|
2091
|
-
const path =
|
|
2175
|
+
const path = join3(spec.worktree, MCP_CONFIG_FILE);
|
|
2092
2176
|
writeFileSync2(path, JSON.stringify(cfg, null, 2));
|
|
2093
2177
|
return path;
|
|
2094
2178
|
}
|
|
@@ -2103,6 +2187,7 @@ var init_claudeCode = __esm({
|
|
|
2103
2187
|
init_swarmFiles();
|
|
2104
2188
|
init_mergeGateHook();
|
|
2105
2189
|
init_claudeResult();
|
|
2190
|
+
init_transcriptSpend();
|
|
2106
2191
|
ISOLATION_FLAGS = ["--setting-sources", "project", "--strict-mcp-config"];
|
|
2107
2192
|
MCP_CONFIG_FILE = SWARM_MCP_CONFIG_FILE;
|
|
2108
2193
|
claudeCodeExecutor = {
|
|
@@ -2141,6 +2226,26 @@ var init_claudeCode = __esm({
|
|
|
2141
2226
|
...abortField(sessionAbort(result))
|
|
2142
2227
|
};
|
|
2143
2228
|
},
|
|
2229
|
+
// TASWM-548: итога нет — берём трату из транскрипта сессии. Тот пишется по ходу работы и
|
|
2230
|
+
// переживает SIGTERM разгрузки, из-за которого итог и не был напечатан; формат usage там
|
|
2231
|
+
// тот же, что в итоге, поэтому цена считается тем же прайсингом (см. transcriptSpend.ts).
|
|
2232
|
+
rescueSpend(worktree, fromMs, toMs) {
|
|
2233
|
+
const spend = transcriptSpendInWindow(worktree, fromMs, toMs);
|
|
2234
|
+
if (spend.replies === 0) return null;
|
|
2235
|
+
return {
|
|
2236
|
+
costUsd: spend.costUsd,
|
|
2237
|
+
tokensIn: spend.tokensIn,
|
|
2238
|
+
tokensOut: spend.tokensOut,
|
|
2239
|
+
durationMs: spend.durationMs,
|
|
2240
|
+
// Часть ответов не по чему было тарифицировать (модели нет в MODEL_PRICING) — их
|
|
2241
|
+
// токены в трату вошли, а деньги НЕТ. Тот же канал, что и у warning штатного итога
|
|
2242
|
+
// (cost.accountRunCost его печатает): иначе спасённые $0 при сожжённых токенах
|
|
2243
|
+
// выглядели бы как честный ноль.
|
|
2244
|
+
...spend.unpriced > 0 ? {
|
|
2245
|
+
warning: `\u0437\u0430\u043F\u0438\u0441\u044C \u0441\u0435\u0441\u0441\u0438\u0438: ${spend.unpriced} \u0438\u0437 ${spend.replies} \u043E\u0442\u0432\u0435\u0442\u043E\u0432 \u0431\u0435\u0437 \u0441\u0442\u0440\u043E\u043A\u0438 \u0432 \u043F\u0440\u0430\u0439\u0441\u0438\u043D\u0433\u0435 (\u043C\u043E\u0434\u0435\u043B\u044C "${spend.unpricedModel ?? ""}") \u2014 \u0438\u0445 \u0446\u0435\u043D\u0430 \u0432 \u0441\u043F\u0430\u0441\u0451\u043D\u043D\u0443\u044E \u0442\u0440\u0430\u0442\u0443 \u041D\u0415 \u0432\u043E\u0448\u043B\u0430`
|
|
2246
|
+
} : {}
|
|
2247
|
+
};
|
|
2248
|
+
},
|
|
2144
2249
|
session: {
|
|
2145
2250
|
exists: (worktree) => sessionTranscriptExists(worktree),
|
|
2146
2251
|
mtimeMs: (worktree) => transcriptMtimeMs(worktree)
|
|
@@ -2158,34 +2263,34 @@ var init_claudeCode = __esm({
|
|
|
2158
2263
|
});
|
|
2159
2264
|
|
|
2160
2265
|
// src/swarmHome.ts
|
|
2161
|
-
import { homedir as
|
|
2162
|
-
import { join as
|
|
2266
|
+
import { homedir as homedir4 } from "os";
|
|
2267
|
+
import { join as join4 } from "path";
|
|
2163
2268
|
import { mkdirSync as mkdirSync2 } from "fs";
|
|
2164
2269
|
var SWARM_HOME;
|
|
2165
2270
|
var init_swarmHome = __esm({
|
|
2166
2271
|
"src/swarmHome.ts"() {
|
|
2167
2272
|
"use strict";
|
|
2168
|
-
SWARM_HOME = process.env.SWARM_HOME ||
|
|
2273
|
+
SWARM_HOME = process.env.SWARM_HOME || join4(homedir4(), ".taskless-swarm");
|
|
2169
2274
|
mkdirSync2(SWARM_HOME, { recursive: true });
|
|
2170
2275
|
}
|
|
2171
2276
|
});
|
|
2172
2277
|
|
|
2173
2278
|
// src/executors/codex.ts
|
|
2174
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readdirSync as
|
|
2175
|
-
import { join as
|
|
2279
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readdirSync as readdirSync4, statSync as statSync3, symlinkSync } from "fs";
|
|
2280
|
+
import { join as join5 } from "path";
|
|
2176
2281
|
function resolveCodexBin(env = process.env) {
|
|
2177
2282
|
return (env.SWARM_CODEX_BIN ?? "").trim() || "codex";
|
|
2178
2283
|
}
|
|
2179
2284
|
function codexHomePath(worktree, swarmHome = SWARM_HOME) {
|
|
2180
|
-
return
|
|
2285
|
+
return join5(swarmHome, "executor-state", "codex", worktree.replace(/[/.]/g, "-"));
|
|
2181
2286
|
}
|
|
2182
2287
|
function ensureCodexHome(worktree, realHome, env = process.env, swarmHome = SWARM_HOME) {
|
|
2183
2288
|
const home = codexHomePath(worktree, swarmHome);
|
|
2184
2289
|
mkdirSync3(home, { recursive: true });
|
|
2185
|
-
const real = (env.CODEX_HOME ?? "").trim() ||
|
|
2290
|
+
const real = (env.CODEX_HOME ?? "").trim() || join5(realHome, ".codex");
|
|
2186
2291
|
for (const file of ["auth.json", "config.toml"]) {
|
|
2187
|
-
const target =
|
|
2188
|
-
const link =
|
|
2292
|
+
const target = join5(real, file);
|
|
2293
|
+
const link = join5(home, file);
|
|
2189
2294
|
if (!existsSync3(target) || existsSync3(link)) continue;
|
|
2190
2295
|
try {
|
|
2191
2296
|
symlinkSync(target, link);
|
|
@@ -2244,16 +2349,16 @@ function parseCodexStream(raw) {
|
|
|
2244
2349
|
function newestRolloutMtime(dir, depth = 4) {
|
|
2245
2350
|
let entries;
|
|
2246
2351
|
try {
|
|
2247
|
-
entries =
|
|
2352
|
+
entries = readdirSync4(dir);
|
|
2248
2353
|
} catch {
|
|
2249
2354
|
return null;
|
|
2250
2355
|
}
|
|
2251
2356
|
let latest = null;
|
|
2252
2357
|
for (const name of entries) {
|
|
2253
|
-
const full =
|
|
2358
|
+
const full = join5(dir, name);
|
|
2254
2359
|
let st;
|
|
2255
2360
|
try {
|
|
2256
|
-
st =
|
|
2361
|
+
st = statSync3(full);
|
|
2257
2362
|
} catch {
|
|
2258
2363
|
continue;
|
|
2259
2364
|
}
|
|
@@ -2324,8 +2429,8 @@ ${notice}` : spec.prompt;
|
|
|
2324
2429
|
return est.warning ? { costUsd: est.costUsd, warning: est.warning } : { costUsd: est.costUsd };
|
|
2325
2430
|
},
|
|
2326
2431
|
session: {
|
|
2327
|
-
exists: (worktree) => newestRolloutMtime(
|
|
2328
|
-
mtimeMs: (worktree) => newestRolloutMtime(
|
|
2432
|
+
exists: (worktree) => newestRolloutMtime(join5(codexHomePath(worktree), "sessions")) !== null,
|
|
2433
|
+
mtimeMs: (worktree) => newestRolloutMtime(join5(codexHomePath(worktree), "sessions"))
|
|
2329
2434
|
},
|
|
2330
2435
|
probe: {
|
|
2331
2436
|
// Тот же принцип, что у claude: дешёвый реальный прогон — он проверяет и auth, и живость
|
|
@@ -2372,8 +2477,8 @@ var init_executors = __esm({
|
|
|
2372
2477
|
});
|
|
2373
2478
|
|
|
2374
2479
|
// src/config.ts
|
|
2375
|
-
import { basename, join as
|
|
2376
|
-
import { readFileSync as
|
|
2480
|
+
import { basename, join as join6, resolve } from "path";
|
|
2481
|
+
import { readFileSync as readFileSync3, realpathSync, renameSync, writeFileSync as writeFileSync3 } from "fs";
|
|
2377
2482
|
function normalizeRepo(repo) {
|
|
2378
2483
|
const r = (repo ?? "").trim();
|
|
2379
2484
|
if (!r) return "";
|
|
@@ -2387,10 +2492,10 @@ function effectiveRepoOf(repo, fallback) {
|
|
|
2387
2492
|
return normalizeRepo(repo || fallback || "");
|
|
2388
2493
|
}
|
|
2389
2494
|
function droneWorktreePath(worktreesDir, repo, slug) {
|
|
2390
|
-
return
|
|
2495
|
+
return join6(droneWorktreeRoot(worktreesDir, repo), slug);
|
|
2391
2496
|
}
|
|
2392
2497
|
function droneWorktreeRoot(worktreesDir, repo) {
|
|
2393
|
-
return
|
|
2498
|
+
return join6(worktreesDir, basename(normalizeRepo(repo)));
|
|
2394
2499
|
}
|
|
2395
2500
|
function resolveEffectiveWorktreesDir(deps) {
|
|
2396
2501
|
if (deps.envOverride) return deps.envOverride;
|
|
@@ -2417,7 +2522,7 @@ function mcpEndpoint(api, path = TASKLESS_MCP_PATH) {
|
|
|
2417
2522
|
}
|
|
2418
2523
|
function tokenFromFile() {
|
|
2419
2524
|
try {
|
|
2420
|
-
return
|
|
2525
|
+
return readFileSync3(join6(SWARM_HOME, "token"), "utf8").trim();
|
|
2421
2526
|
} catch {
|
|
2422
2527
|
return "";
|
|
2423
2528
|
}
|
|
@@ -2430,25 +2535,25 @@ var init_config = __esm({
|
|
|
2430
2535
|
init_executors();
|
|
2431
2536
|
init_swarmHome();
|
|
2432
2537
|
init_swarmHome();
|
|
2433
|
-
DB_PATH = process.env.SWARM_DB ||
|
|
2538
|
+
DB_PATH = process.env.SWARM_DB || join6(SWARM_HOME, "swarm.db");
|
|
2434
2539
|
EXECUTOR = resolveExecutor(process.env.SWARM_EXECUTOR);
|
|
2435
|
-
DRONE_HOME = process.env.SWARM_DRONE_HOME ||
|
|
2540
|
+
DRONE_HOME = process.env.SWARM_DRONE_HOME || join6(SWARM_HOME, "drone-home");
|
|
2436
2541
|
DRONE_HOME_ISOLATION = process.env.SWARM_DRONE_ISOLATE_HOME !== "0" && process.platform !== "win32";
|
|
2437
2542
|
DRONE_ISOLATION = DRONE_HOME_ISOLATION ? { home: DRONE_HOME, swarmHome: SWARM_HOME } : void 0;
|
|
2438
|
-
WORKTREES_NOINDEX_DIR =
|
|
2439
|
-
WORKTREES_LEGACY_DIR =
|
|
2543
|
+
WORKTREES_NOINDEX_DIR = join6(SWARM_HOME, "worktrees.noindex");
|
|
2544
|
+
WORKTREES_LEGACY_DIR = join6(SWARM_HOME, "worktrees");
|
|
2440
2545
|
WORKTREES_DIR = process.env.SWARM_WORKTREES || WORKTREES_NOINDEX_DIR;
|
|
2441
|
-
RUN_LOGS_DIR = process.env.SWARM_RUN_LOGS ||
|
|
2442
|
-
DAEMON_LOG_PATH = process.env.SWARM_DAEMON_LOG ||
|
|
2546
|
+
RUN_LOGS_DIR = process.env.SWARM_RUN_LOGS || join6(SWARM_HOME, "run-logs");
|
|
2547
|
+
DAEMON_LOG_PATH = process.env.SWARM_DAEMON_LOG || join6(SWARM_HOME, "overmind.log");
|
|
2443
2548
|
DAEMON_LOG_MAX_BYTES = envNum("SWARM_DAEMON_LOG_MAX_BYTES", 16 * 1024 * 1024);
|
|
2444
2549
|
DAEMON_LOG_KEEP = envNum("SWARM_DAEMON_LOG_KEEP", 2);
|
|
2445
2550
|
DAEMON_LOG_CHECK_MS = envNum("SWARM_DAEMON_LOG_CHECK_MS", 6e4);
|
|
2446
2551
|
DIST_BUILD = true;
|
|
2447
2552
|
SWARM_BACKEND = process.env.SWARM_BACKEND === "client" ? "client" : process.env.SWARM_BACKEND === "sqlite" ? "sqlite" : DIST_BUILD ? "client" : "sqlite";
|
|
2448
|
-
SWARM_OUTBOX = process.env.SWARM_OUTBOX ||
|
|
2553
|
+
SWARM_OUTBOX = process.env.SWARM_OUTBOX || join6(SWARM_HOME, "outbox.jsonl");
|
|
2449
2554
|
SWARM_MAX_IN_FLIGHT = Math.trunc(envNum("SWARM_MAX_IN_FLIGHT", 3));
|
|
2450
2555
|
SWARM_CLAIM_INTERVAL_MS = envNum("SWARM_CLAIM_INTERVAL_MS", 6e4);
|
|
2451
|
-
ENV_CACHE_DIR = process.env.SWARM_ENV_CACHE_DIR ||
|
|
2556
|
+
ENV_CACHE_DIR = process.env.SWARM_ENV_CACHE_DIR || join6(SWARM_HOME, "env-cache");
|
|
2452
2557
|
ENV_CACHE_ENABLED = process.env.SWARM_ENV_CACHE !== "0";
|
|
2453
2558
|
ENV_CACHE_KEEP = Math.trunc(envNum("SWARM_ENV_CACHE_KEEP", 4));
|
|
2454
2559
|
SWARM_MAX_LOAD_FACTOR = envNum("SWARM_MAX_LOAD_FACTOR", 0.9);
|
|
@@ -2478,15 +2583,15 @@ var init_config = __esm({
|
|
|
2478
2583
|
DRONE_CHANNEL_ENABLED = process.env.SWARM_DRONE_CHANNEL !== "0";
|
|
2479
2584
|
DRONE_CHANNEL_PORT = Number(process.env.SWARM_DRONE_CHANNEL_PORT) || 7421;
|
|
2480
2585
|
DRONE_CHANNEL_URL = process.env.SWARM_DRONE_CHANNEL_URL || `http://127.0.0.1:${DRONE_CHANNEL_PORT}`;
|
|
2481
|
-
DRONE_CHANNEL_SECRET_PATH = process.env.SWARM_DRONE_CHANNEL_SECRET ||
|
|
2586
|
+
DRONE_CHANNEL_SECRET_PATH = process.env.SWARM_DRONE_CHANNEL_SECRET || join6(SWARM_HOME, "drone-channel.key");
|
|
2482
2587
|
DRONE_CHANNEL_GRACE_MS = envNum("SWARM_DRONE_CHANNEL_GRACE_MS", 12e4);
|
|
2483
|
-
HEARTBEAT_PATH = process.env.SWARM_HEARTBEAT ||
|
|
2588
|
+
HEARTBEAT_PATH = process.env.SWARM_HEARTBEAT || join6(SWARM_HOME, "overmind.heartbeat");
|
|
2484
2589
|
HEARTBEAT_STALE_MS = Number(process.env.SWARM_HEARTBEAT_STALE_MS) || 3e4;
|
|
2485
2590
|
SWARM_REPO = process.env.SWARM_REPO || "";
|
|
2486
2591
|
SWARM_SCAN_DEPTH = Number(process.env.SWARM_SCAN_DEPTH) || 3;
|
|
2487
2592
|
SWARM_REPO_PATHS = (process.env.SWARM_REPOS || SWARM_REPO).split(",").map((s) => s.trim()).filter(Boolean);
|
|
2488
2593
|
SWARM_SCAN_ROOTS_RAW = process.env.SWARM_SCAN_ROOTS || "";
|
|
2489
|
-
REPO_MAP_PATH = process.env.SWARM_REPO_MAP ||
|
|
2594
|
+
REPO_MAP_PATH = process.env.SWARM_REPO_MAP || join6(SWARM_HOME, "repo-map.json");
|
|
2490
2595
|
SWARM_REPO_MAP_MS = envNum("SWARM_REPO_MAP_MS", 15 * 6e4);
|
|
2491
2596
|
SWARM_REPO_SCAN_TTL_MS = envNum("SWARM_REPO_SCAN_TTL_MS", 24 * 60 * 6e4);
|
|
2492
2597
|
TASKLESS_API = process.env.TASKLESS_API || "https://taskless.ru";
|
|
@@ -2501,7 +2606,7 @@ var init_config = __esm({
|
|
|
2501
2606
|
SWARM_AUTO_REVIEW = process.env.SWARM_AUTO_REVIEW !== "0";
|
|
2502
2607
|
SWARM_AUTO_VERIFY = process.env.SWARM_AUTO_VERIFY !== "0";
|
|
2503
2608
|
SWARM_MERGE_QUEUE = process.env.SWARM_MERGE_QUEUE !== "0";
|
|
2504
|
-
REVIEW_CUTOFF_PATH = process.env.SWARM_REVIEW_CUTOFF ||
|
|
2609
|
+
REVIEW_CUTOFF_PATH = process.env.SWARM_REVIEW_CUTOFF || join6(SWARM_HOME, "review-cutoff.json");
|
|
2505
2610
|
SWARM_REVIEW_CAP = Math.trunc(envNum("SWARM_REVIEW_CAP", 1));
|
|
2506
2611
|
SWARM_STORM_URL = process.env.SWARM_STORM_URL || "";
|
|
2507
2612
|
WEB_PORT = Number(process.env.SWARM_WEB_PORT) || 7420;
|
|
@@ -2541,7 +2646,7 @@ var init_quietExec = __esm({
|
|
|
2541
2646
|
|
|
2542
2647
|
// src/resources.ts
|
|
2543
2648
|
import os from "os";
|
|
2544
|
-
import { readFileSync as
|
|
2649
|
+
import { readFileSync as readFileSync4, statfsSync } from "fs";
|
|
2545
2650
|
function isTransientResourceError(e) {
|
|
2546
2651
|
const code = e?.code;
|
|
2547
2652
|
return code === "ENFILE" || code === "EMFILE" || code === "EAGAIN";
|
|
@@ -2593,7 +2698,7 @@ function fileDescriptorLoadRatio() {
|
|
|
2593
2698
|
}
|
|
2594
2699
|
if (process.platform === "linux") {
|
|
2595
2700
|
try {
|
|
2596
|
-
const [allocated, , max] =
|
|
2701
|
+
const [allocated, , max] = readFileSync4("/proc/sys/fs/file-nr", "utf8").trim().split(/\s+/).map(Number);
|
|
2597
2702
|
if (Number.isFinite(allocated ?? NaN) && Number.isFinite(max ?? NaN) && max) return allocated / max;
|
|
2598
2703
|
} catch {
|
|
2599
2704
|
}
|
|
@@ -2817,11 +2922,11 @@ var init_zoneNotes = __esm({
|
|
|
2817
2922
|
});
|
|
2818
2923
|
|
|
2819
2924
|
// src/agentToken.ts
|
|
2820
|
-
import { readFileSync as
|
|
2821
|
-
import { join as
|
|
2925
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, unlinkSync } from "fs";
|
|
2926
|
+
import { join as join7 } from "path";
|
|
2822
2927
|
function loadAgentToken() {
|
|
2823
2928
|
try {
|
|
2824
|
-
const s = JSON.parse(
|
|
2929
|
+
const s = JSON.parse(readFileSync5(STORE_PATH, "utf8"));
|
|
2825
2930
|
return s.token ? s : null;
|
|
2826
2931
|
} catch {
|
|
2827
2932
|
return null;
|
|
@@ -2899,7 +3004,7 @@ var init_agentToken = __esm({
|
|
|
2899
3004
|
"src/agentToken.ts"() {
|
|
2900
3005
|
"use strict";
|
|
2901
3006
|
init_config();
|
|
2902
|
-
STORE_PATH =
|
|
3007
|
+
STORE_PATH = join7(SWARM_HOME, "agent.json");
|
|
2903
3008
|
base = (api) => api.replace(/\/$/, "");
|
|
2904
3009
|
TOKEN_PROBE_TIMEOUT_MS = 8e3;
|
|
2905
3010
|
}
|
|
@@ -3285,7 +3390,7 @@ var init_package = __esm({
|
|
|
3285
3390
|
"package.json"() {
|
|
3286
3391
|
package_default = {
|
|
3287
3392
|
name: "@taskless-app/swarm",
|
|
3288
|
-
version: "0.6.
|
|
3393
|
+
version: "0.6.39",
|
|
3289
3394
|
type: "module",
|
|
3290
3395
|
description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
|
|
3291
3396
|
keywords: [
|
|
@@ -3336,7 +3441,7 @@ var init_package = __esm({
|
|
|
3336
3441
|
execa: "^10.0.0",
|
|
3337
3442
|
zod: "3.25.76"
|
|
3338
3443
|
},
|
|
3339
|
-
gitHead: "
|
|
3444
|
+
gitHead: "0c0b1bc0ee05add0d2b5b5d503a05ed7b7834dd8"
|
|
3340
3445
|
};
|
|
3341
3446
|
}
|
|
3342
3447
|
});
|
|
@@ -3502,12 +3607,12 @@ var init_netTimeout = __esm({
|
|
|
3502
3607
|
|
|
3503
3608
|
// src/droneChannel.ts
|
|
3504
3609
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
3505
|
-
import { chmodSync as chmodSync2, mkdirSync as mkdirSync7, readFileSync as
|
|
3610
|
+
import { chmodSync as chmodSync2, mkdirSync as mkdirSync7, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
|
|
3506
3611
|
import { dirname as dirname3 } from "path";
|
|
3507
3612
|
import { serve } from "@hono/node-server";
|
|
3508
3613
|
function loadChannelSecret(path) {
|
|
3509
3614
|
try {
|
|
3510
|
-
const s =
|
|
3615
|
+
const s = readFileSync9(path, "utf8").trim();
|
|
3511
3616
|
if (s.length >= 32) return s;
|
|
3512
3617
|
} catch {
|
|
3513
3618
|
}
|
|
@@ -3590,8 +3695,8 @@ var init_authState = __esm({
|
|
|
3590
3695
|
|
|
3591
3696
|
// src/oauth.ts
|
|
3592
3697
|
import { createHash, randomBytes as randomBytes2 } from "crypto";
|
|
3593
|
-
import { readFileSync as
|
|
3594
|
-
import { join as
|
|
3698
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync8, unlinkSync as unlinkSync3 } from "fs";
|
|
3699
|
+
import { join as join12 } from "path";
|
|
3595
3700
|
function makePkce() {
|
|
3596
3701
|
const verifier = randomBytes2(48).toString("base64url");
|
|
3597
3702
|
const challenge = createHash("sha256").update(verifier).digest("base64url");
|
|
@@ -3675,7 +3780,7 @@ function toStore(clientId, t, now) {
|
|
|
3675
3780
|
}
|
|
3676
3781
|
function loadStore() {
|
|
3677
3782
|
try {
|
|
3678
|
-
return JSON.parse(
|
|
3783
|
+
return JSON.parse(readFileSync10(STORE_PATH2, "utf8"));
|
|
3679
3784
|
} catch {
|
|
3680
3785
|
return null;
|
|
3681
3786
|
}
|
|
@@ -3691,7 +3796,7 @@ function clearStore() {
|
|
|
3691
3796
|
}
|
|
3692
3797
|
function loadClientId() {
|
|
3693
3798
|
try {
|
|
3694
|
-
return JSON.parse(
|
|
3799
|
+
return JSON.parse(readFileSync10(CLIENT_PATH, "utf8")).clientId;
|
|
3695
3800
|
} catch {
|
|
3696
3801
|
return null;
|
|
3697
3802
|
}
|
|
@@ -3726,16 +3831,16 @@ var init_oauth = __esm({
|
|
|
3726
3831
|
AUTHORIZE = "/api/oauth/authorize";
|
|
3727
3832
|
TOKEN = "/api/oauth/token";
|
|
3728
3833
|
SCOPE = "openid profile email taskless:full";
|
|
3729
|
-
STORE_PATH2 =
|
|
3730
|
-
CLIENT_PATH =
|
|
3834
|
+
STORE_PATH2 = join12(SWARM_HOME, "oauth.json");
|
|
3835
|
+
CLIENT_PATH = join12(SWARM_HOME, "oauth-client.json");
|
|
3731
3836
|
base2 = (api) => api.replace(/\/$/, "");
|
|
3732
3837
|
}
|
|
3733
3838
|
});
|
|
3734
3839
|
|
|
3735
3840
|
// src/git.ts
|
|
3736
|
-
import { existsSync as existsSync10, readdirSync as
|
|
3841
|
+
import { existsSync as existsSync10, readdirSync as readdirSync9, statSync as statSync9 } from "fs";
|
|
3737
3842
|
import { appendFile, chmod, mkdir, readFile, rm, writeFile } from "fs/promises";
|
|
3738
|
-
import { isAbsolute, join as
|
|
3843
|
+
import { isAbsolute, join as join15, sep as sep2 } from "path";
|
|
3739
3844
|
import { $ as $5 } from "execa";
|
|
3740
3845
|
function gitNet(repo, args, timeoutMs) {
|
|
3741
3846
|
return withHardTimeout(
|
|
@@ -3750,7 +3855,7 @@ async function reclaimStaleWorktree(repo, worktree) {
|
|
|
3750
3855
|
}
|
|
3751
3856
|
function isLinkedWorktree(dir) {
|
|
3752
3857
|
try {
|
|
3753
|
-
return
|
|
3858
|
+
return statSync9(join15(dir, ".git")).isFile();
|
|
3754
3859
|
} catch {
|
|
3755
3860
|
return false;
|
|
3756
3861
|
}
|
|
@@ -3855,8 +3960,8 @@ async function ensureGitExcluded(worktree, pattern) {
|
|
|
3855
3960
|
try {
|
|
3856
3961
|
const commonDir = await gitPath(worktree, "--git-common-dir");
|
|
3857
3962
|
if (!commonDir) return false;
|
|
3858
|
-
const infoDir =
|
|
3859
|
-
const excludeFile =
|
|
3963
|
+
const infoDir = join15(commonDir, "info");
|
|
3964
|
+
const excludeFile = join15(infoDir, "exclude");
|
|
3860
3965
|
let current = "";
|
|
3861
3966
|
try {
|
|
3862
3967
|
current = await readFile(excludeFile, "utf8");
|
|
@@ -3876,7 +3981,7 @@ async function gitPath(worktree, flag) {
|
|
|
3876
3981
|
const out = await $5({ reject: false })`git -C ${worktree} rev-parse ${flag}`;
|
|
3877
3982
|
const raw = out.stdout.trim();
|
|
3878
3983
|
if (out.exitCode !== 0 || !raw) return null;
|
|
3879
|
-
return isAbsolute(raw) ? raw :
|
|
3984
|
+
return isAbsolute(raw) ? raw : join15(worktree, raw);
|
|
3880
3985
|
}
|
|
3881
3986
|
async function ensureWorktreeHygiene(worktree) {
|
|
3882
3987
|
for (const pattern of SWARM_EXCLUDE_PATTERNS) await ensureGitExcluded(worktree, pattern);
|
|
@@ -3886,12 +3991,12 @@ async function installGuardHooks(worktree) {
|
|
|
3886
3991
|
try {
|
|
3887
3992
|
const gitDir = await gitPath(worktree, "--git-dir");
|
|
3888
3993
|
if (!gitDir) return false;
|
|
3889
|
-
const hooksDir =
|
|
3994
|
+
const hooksDir = join15(gitDir, "swarm-hooks");
|
|
3890
3995
|
const prev = await previousHooksPath(worktree);
|
|
3891
3996
|
await mkdir(hooksDir, { recursive: true });
|
|
3892
3997
|
for (const hook of GUARD_HOOKS) {
|
|
3893
|
-
await writeFile(
|
|
3894
|
-
await chmod(
|
|
3998
|
+
await writeFile(join15(hooksDir, hook), guardHookScript(hook, prev ? `${posix(prev)}/${hook}` : null));
|
|
3999
|
+
await chmod(join15(hooksDir, hook), 493);
|
|
3895
4000
|
}
|
|
3896
4001
|
await $5`git -C ${worktree} config extensions.worktreeConfig true`;
|
|
3897
4002
|
await $5`git -C ${worktree} config --worktree core.hooksPath ${posix(hooksDir)}`;
|
|
@@ -3910,7 +4015,7 @@ async function previousHooksPath(worktree) {
|
|
|
3910
4015
|
if (out.exitCode === 0 && value) return value;
|
|
3911
4016
|
}
|
|
3912
4017
|
const commonDir = await gitPath(worktree, "--git-common-dir");
|
|
3913
|
-
return commonDir ?
|
|
4018
|
+
return commonDir ? join15(commonDir, "hooks") : null;
|
|
3914
4019
|
}
|
|
3915
4020
|
async function removeWorktree(repo, path) {
|
|
3916
4021
|
const branch = (await $5({ reject: false })`git -C ${path} symbolic-ref --quiet --short HEAD`).stdout.trim();
|
|
@@ -3967,7 +4072,7 @@ var init_git = __esm({
|
|
|
3967
4072
|
|
|
3968
4073
|
// src/attachments.ts
|
|
3969
4074
|
import { mkdir as mkdir2, rm as rm2, writeFile as writeFile2 } from "fs/promises";
|
|
3970
|
-
import { join as
|
|
4075
|
+
import { join as join16 } from "path";
|
|
3971
4076
|
var ATTACHMENTS_DIR, ATTACH_MAX_TOTAL_BYTES, ATTACH_MAX_FILE_BYTES, IMAGE_EXT, DOC_EXT, TEXT_EXT, KNOWN_EXT;
|
|
3972
4077
|
var init_attachments = __esm({
|
|
3973
4078
|
"src/attachments.ts"() {
|
|
@@ -3986,7 +4091,7 @@ var init_attachments = __esm({
|
|
|
3986
4091
|
|
|
3987
4092
|
// src/shotUpload.ts
|
|
3988
4093
|
import { readFile as fsReadFile } from "fs/promises";
|
|
3989
|
-
import { basename as basename5, isAbsolute as isAbsolute2, join as
|
|
4094
|
+
import { basename as basename5, isAbsolute as isAbsolute2, join as join17 } from "path";
|
|
3990
4095
|
var SHOT_MAX_FILE_BYTES;
|
|
3991
4096
|
var init_shotUpload = __esm({
|
|
3992
4097
|
"src/shotUpload.ts"() {
|
|
@@ -3996,11 +4101,11 @@ var init_shotUpload = __esm({
|
|
|
3996
4101
|
});
|
|
3997
4102
|
|
|
3998
4103
|
// src/workspace.ts
|
|
3999
|
-
import { readFileSync as
|
|
4000
|
-
import { join as
|
|
4104
|
+
import { readFileSync as readFileSync11, writeFileSync as writeFileSync9, unlinkSync as unlinkSync4 } from "fs";
|
|
4105
|
+
import { join as join18 } from "path";
|
|
4001
4106
|
function loadWorkspace() {
|
|
4002
4107
|
try {
|
|
4003
|
-
const w = JSON.parse(
|
|
4108
|
+
const w = JSON.parse(readFileSync11(WORKSPACE_PATH, "utf8"));
|
|
4004
4109
|
return w && typeof w.id === "string" && w.id ? w : null;
|
|
4005
4110
|
} catch {
|
|
4006
4111
|
return null;
|
|
@@ -4023,7 +4128,7 @@ var init_workspace = __esm({
|
|
|
4023
4128
|
"src/workspace.ts"() {
|
|
4024
4129
|
"use strict";
|
|
4025
4130
|
init_config();
|
|
4026
|
-
WORKSPACE_PATH =
|
|
4131
|
+
WORKSPACE_PATH = join18(SWARM_HOME, "workspace.json");
|
|
4027
4132
|
}
|
|
4028
4133
|
});
|
|
4029
4134
|
|
|
@@ -4441,14 +4546,14 @@ var init_daemonLink = __esm({
|
|
|
4441
4546
|
});
|
|
4442
4547
|
|
|
4443
4548
|
// src/pauseState.ts
|
|
4444
|
-
import { existsSync as existsSync11, readFileSync as
|
|
4445
|
-
import { join as
|
|
4549
|
+
import { existsSync as existsSync11, readFileSync as readFileSync12, renameSync as renameSync5, unlinkSync as unlinkSync5, writeFileSync as writeFileSync10 } from "fs";
|
|
4550
|
+
import { join as join19 } from "path";
|
|
4446
4551
|
function pauseStatePath(home) {
|
|
4447
|
-
return
|
|
4552
|
+
return join19(home, "pause.json");
|
|
4448
4553
|
}
|
|
4449
4554
|
function loadPauseState(home, io = {}) {
|
|
4450
4555
|
const exists = io.exists ?? existsSync11;
|
|
4451
|
-
const readFile2 = io.readFile ?? ((p) =>
|
|
4556
|
+
const readFile2 = io.readFile ?? ((p) => readFileSync12(p, "utf8"));
|
|
4452
4557
|
const path = pauseStatePath(home);
|
|
4453
4558
|
if (!exists(path)) return ACTIVE;
|
|
4454
4559
|
try {
|
|
@@ -4509,10 +4614,10 @@ var init_pauseState = __esm({
|
|
|
4509
4614
|
});
|
|
4510
4615
|
|
|
4511
4616
|
// src/heartbeat.ts
|
|
4512
|
-
import { readFileSync as
|
|
4617
|
+
import { readFileSync as readFileSync13, renameSync as renameSync6, writeFileSync as writeFileSync11 } from "fs";
|
|
4513
4618
|
function readHeartbeat(path) {
|
|
4514
4619
|
try {
|
|
4515
|
-
const ms = Number(
|
|
4620
|
+
const ms = Number(readFileSync13(path, "utf8").trim());
|
|
4516
4621
|
return Number.isFinite(ms) ? ms : null;
|
|
4517
4622
|
} catch {
|
|
4518
4623
|
return null;
|
|
@@ -4574,6 +4679,7 @@ function rowToRun(row) {
|
|
|
4574
4679
|
tokens_in: row.tokens_in ?? 0,
|
|
4575
4680
|
tokens_out: row.tokens_out ?? 0,
|
|
4576
4681
|
duration_ms: row.duration_ms ?? 0,
|
|
4682
|
+
cost_unmeasured: row.cost_unmeasured ?? 0,
|
|
4577
4683
|
pr_url: row.pr_url ?? null,
|
|
4578
4684
|
// TASWM-506: файлы, занятые прогоном с открытым PR — JSON-массив, как depends_on.
|
|
4579
4685
|
changed_paths: row.changed_paths ? JSON.parse(row.changed_paths) : [],
|
|
@@ -4654,6 +4760,7 @@ CREATE TABLE IF NOT EXISTS runs (
|
|
|
4654
4760
|
tokens_in INTEGER NOT NULL DEFAULT 0,
|
|
4655
4761
|
tokens_out INTEGER NOT NULL DEFAULT 0,
|
|
4656
4762
|
duration_ms INTEGER NOT NULL DEFAULT 0,
|
|
4763
|
+
cost_unmeasured INTEGER NOT NULL DEFAULT 0,
|
|
4657
4764
|
pr_url TEXT,
|
|
4658
4765
|
superseded_by INTEGER,
|
|
4659
4766
|
decision TEXT,
|
|
@@ -4769,6 +4876,10 @@ CREATE TABLE IF NOT EXISTS imports (
|
|
|
4769
4876
|
"ALTER TABLE runs ADD COLUMN tokens_in INTEGER NOT NULL DEFAULT 0",
|
|
4770
4877
|
"ALTER TABLE runs ADD COLUMN tokens_out INTEGER NOT NULL DEFAULT 0",
|
|
4771
4878
|
"ALTER TABLE runs ADD COLUMN duration_ms INTEGER NOT NULL DEFAULT 0",
|
|
4879
|
+
// TASWM-548: сколько запусков прогона остались без снятой цены — отличает «бесплатно»
|
|
4880
|
+
// от «не измерено». Прогоны до фичи получают 0: их нули мы перепроверить уже не можем,
|
|
4881
|
+
// а задним числом объявлять их неизмеренными значило бы утверждать непроверенное.
|
|
4882
|
+
"ALTER TABLE runs ADD COLUMN cost_unmeasured INTEGER NOT NULL DEFAULT 0",
|
|
4772
4883
|
// TASWM-395: усилие рассуждения прогона (`claude --effort`). Nullable без DEFAULT —
|
|
4773
4884
|
// NULL это и все прогоны до фичи, и прогоны на дефолте харнесса.
|
|
4774
4885
|
"ALTER TABLE runs ADD COLUMN effort TEXT",
|
|
@@ -5486,8 +5597,8 @@ CREATE TABLE IF NOT EXISTS imports (
|
|
|
5486
5597
|
});
|
|
5487
5598
|
|
|
5488
5599
|
// src/repoScan.ts
|
|
5489
|
-
import { readdirSync as
|
|
5490
|
-
import { join as
|
|
5600
|
+
import { readdirSync as readdirSync10, readFileSync as readFileSync14, statSync as statSync10 } from "fs";
|
|
5601
|
+
import { join as join20 } from "path";
|
|
5491
5602
|
var init_repoScan = __esm({
|
|
5492
5603
|
"src/repoScan.ts"() {
|
|
5493
5604
|
"use strict";
|
|
@@ -5496,9 +5607,9 @@ var init_repoScan = __esm({
|
|
|
5496
5607
|
});
|
|
5497
5608
|
|
|
5498
5609
|
// src/repoDiscovery.ts
|
|
5499
|
-
import { homedir as
|
|
5500
|
-
import { readFileSync as
|
|
5501
|
-
import { isAbsolute as isAbsolute3, join as
|
|
5610
|
+
import { homedir as homedir6 } from "os";
|
|
5611
|
+
import { readFileSync as readFileSync15, renameSync as renameSync7, writeFileSync as writeFileSync12 } from "fs";
|
|
5612
|
+
import { isAbsolute as isAbsolute3, join as join21, resolve as resolve3 } from "path";
|
|
5502
5613
|
function repoMapLines(rows) {
|
|
5503
5614
|
if (!rows?.length) return [];
|
|
5504
5615
|
const missing = rows.filter((r) => !r.path).length;
|
|
@@ -5513,7 +5624,7 @@ function repoMapLines(rows) {
|
|
|
5513
5624
|
}
|
|
5514
5625
|
function loadRepoMapCache(path) {
|
|
5515
5626
|
try {
|
|
5516
|
-
const raw = JSON.parse(
|
|
5627
|
+
const raw = JSON.parse(readFileSync15(path, "utf8"));
|
|
5517
5628
|
if (!Array.isArray(raw?.entries)) return { scannedAt: null, entries: [] };
|
|
5518
5629
|
return {
|
|
5519
5630
|
scannedAt: typeof raw.scannedAt === "string" && raw.scannedAt ? raw.scannedAt : null,
|
|
@@ -5882,11 +5993,11 @@ __export(statusCli_exports, {
|
|
|
5882
5993
|
probeLink: () => probeLink,
|
|
5883
5994
|
runStatusCli: () => runStatusCli
|
|
5884
5995
|
});
|
|
5885
|
-
import { existsSync as existsSync13, readFileSync as
|
|
5996
|
+
import { existsSync as existsSync13, readFileSync as readFileSync16 } from "fs";
|
|
5886
5997
|
function outboxPending(path) {
|
|
5887
5998
|
try {
|
|
5888
5999
|
if (!existsSync13(path)) return 0;
|
|
5889
|
-
return
|
|
6000
|
+
return readFileSync16(path, "utf8").split("\n").filter((l) => l.trim()).length;
|
|
5890
6001
|
} catch {
|
|
5891
6002
|
return null;
|
|
5892
6003
|
}
|
|
@@ -6093,11 +6204,11 @@ var init_prodMergeGate = __esm({
|
|
|
6093
6204
|
});
|
|
6094
6205
|
|
|
6095
6206
|
// src/platform.ts
|
|
6096
|
-
import { existsSync as existsSync14, readFileSync as
|
|
6097
|
-
import { delimiter, join as
|
|
6207
|
+
import { existsSync as existsSync14, readFileSync as readFileSync17 } from "fs";
|
|
6208
|
+
import { delimiter, join as join22 } from "path";
|
|
6098
6209
|
function safeReadText(path) {
|
|
6099
6210
|
try {
|
|
6100
|
-
return
|
|
6211
|
+
return readFileSync17(path, "utf8");
|
|
6101
6212
|
} catch {
|
|
6102
6213
|
return null;
|
|
6103
6214
|
}
|
|
@@ -6108,7 +6219,7 @@ function resolveCommandPath(name, env = process.env, platform = process.platform
|
|
|
6108
6219
|
const exts = platform === "win32" ? (env.PATHEXT ?? ".EXE;.CMD;.BAT").split(";").filter(Boolean) : [""];
|
|
6109
6220
|
for (const dir of dirs) {
|
|
6110
6221
|
for (const ext of exts) {
|
|
6111
|
-
const candidate =
|
|
6222
|
+
const candidate = join22(dir, name + ext);
|
|
6112
6223
|
if (existsSync14(candidate)) return candidate;
|
|
6113
6224
|
}
|
|
6114
6225
|
}
|
|
@@ -6213,12 +6324,12 @@ var init_platform = __esm({
|
|
|
6213
6324
|
|
|
6214
6325
|
// src/envGate.ts
|
|
6215
6326
|
import { existsSync as existsSync15 } from "fs";
|
|
6216
|
-
import { join as
|
|
6327
|
+
import { join as join23 } from "path";
|
|
6217
6328
|
import { createConnection } from "net";
|
|
6218
6329
|
import { execa as execa3 } from "execa";
|
|
6219
6330
|
function detectRequirements(repo, io = {}) {
|
|
6220
6331
|
const exists = io.exists ?? existsSync15;
|
|
6221
|
-
const marker = COMPOSE_MARKERS.find((f) => exists(
|
|
6332
|
+
const marker = COMPOSE_MARKERS.find((f) => exists(join23(repo, f)));
|
|
6222
6333
|
return marker ? [{ kind: "docker", raw: `docker (\u0434\u0435\u0442\u0435\u043A\u0442: ${marker})` }] : [];
|
|
6223
6334
|
}
|
|
6224
6335
|
async function dockerAlive() {
|
|
@@ -6250,7 +6361,7 @@ var init_envGate = __esm({
|
|
|
6250
6361
|
});
|
|
6251
6362
|
|
|
6252
6363
|
// src/doctor.ts
|
|
6253
|
-
import { isAbsolute as isAbsolute4, join as
|
|
6364
|
+
import { isAbsolute as isAbsolute4, join as join24 } from "path";
|
|
6254
6365
|
function ok(id, title, detail) {
|
|
6255
6366
|
return { id, title, status: "ok", detail, remedies: [], critical: false };
|
|
6256
6367
|
}
|
|
@@ -6457,7 +6568,7 @@ function checkRepos(io, snap) {
|
|
|
6457
6568
|
critical: true
|
|
6458
6569
|
};
|
|
6459
6570
|
}
|
|
6460
|
-
if (env && !io.exists(
|
|
6571
|
+
if (env && !io.exists(join24(env, ".git"))) {
|
|
6461
6572
|
return {
|
|
6462
6573
|
id: "repos",
|
|
6463
6574
|
title,
|
|
@@ -6467,7 +6578,7 @@ function checkRepos(io, snap) {
|
|
|
6467
6578
|
critical: true
|
|
6468
6579
|
};
|
|
6469
6580
|
}
|
|
6470
|
-
const broken = snap.paths.filter((p) => !io.exists(
|
|
6581
|
+
const broken = snap.paths.filter((p) => !io.exists(join24(p, ".git")));
|
|
6471
6582
|
if (broken.length) {
|
|
6472
6583
|
return {
|
|
6473
6584
|
id: "repos",
|
|
@@ -6657,12 +6768,12 @@ var init_doctor = __esm({
|
|
|
6657
6768
|
});
|
|
6658
6769
|
|
|
6659
6770
|
// src/repoMemory.ts
|
|
6660
|
-
import { readFileSync as
|
|
6661
|
-
import { join as
|
|
6771
|
+
import { readFileSync as readFileSync18, writeFileSync as writeFileSync13 } from "fs";
|
|
6772
|
+
import { join as join25 } from "path";
|
|
6662
6773
|
function loadRememberedRepos(home) {
|
|
6663
6774
|
let raw;
|
|
6664
6775
|
try {
|
|
6665
|
-
raw =
|
|
6776
|
+
raw = readFileSync18(join25(home, FILE), "utf8");
|
|
6666
6777
|
} catch {
|
|
6667
6778
|
return [];
|
|
6668
6779
|
}
|
|
@@ -6981,8 +7092,8 @@ var init_updateCli = __esm({
|
|
|
6981
7092
|
|
|
6982
7093
|
// src/cli.ts
|
|
6983
7094
|
init_cliIo();
|
|
6984
|
-
import { basename as basename6, dirname as dirname5, join as
|
|
6985
|
-
import { existsSync as existsSync17, readFileSync as
|
|
7095
|
+
import { basename as basename6, dirname as dirname5, join as join26 } from "path";
|
|
7096
|
+
import { existsSync as existsSync17, readFileSync as readFileSync19, writeFileSync as writeFileSync14, mkdirSync as mkdirSync10, readdirSync as readdirSync11, statSync as statSync11, openSync as openSync4, readSync as readSync2, closeSync as closeSync4 } from "fs";
|
|
6986
7097
|
import { setTimeout as sleep2 } from "timers/promises";
|
|
6987
7098
|
|
|
6988
7099
|
// src/swarmClient.ts
|
|
@@ -6990,7 +7101,7 @@ init_config();
|
|
|
6990
7101
|
init_resources();
|
|
6991
7102
|
init_names2();
|
|
6992
7103
|
init_storm();
|
|
6993
|
-
import { appendFileSync, existsSync as existsSync6, mkdirSync as mkdirSync6, readFileSync as
|
|
7104
|
+
import { appendFileSync, existsSync as existsSync6, mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
6994
7105
|
import { dirname as dirname2 } from "path";
|
|
6995
7106
|
import { randomUUID } from "crypto";
|
|
6996
7107
|
|
|
@@ -7022,19 +7133,19 @@ init_zoneNotes();
|
|
|
7022
7133
|
init_toolFailure();
|
|
7023
7134
|
|
|
7024
7135
|
// src/logTail.ts
|
|
7025
|
-
import { closeSync, existsSync as existsSync5, openSync, readSync, readdirSync as
|
|
7026
|
-
import { join as
|
|
7136
|
+
import { closeSync, existsSync as existsSync5, openSync, readSync, readdirSync as readdirSync6, statSync as statSync5 } from "fs";
|
|
7137
|
+
import { join as join9 } from "path";
|
|
7027
7138
|
|
|
7028
7139
|
// src/runLogDir.ts
|
|
7029
|
-
import { existsSync as existsSync4, mkdirSync as mkdirSync5, readdirSync as
|
|
7030
|
-
import { join as
|
|
7140
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync5, readdirSync as readdirSync5, renameSync as renameSync2, statSync as statSync4 } from "fs";
|
|
7141
|
+
import { join as join8 } from "path";
|
|
7031
7142
|
function runLogDirName(runLogKey) {
|
|
7032
7143
|
const safe = runLogKey.replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^[-_]+|[-_]+$/g, "");
|
|
7033
7144
|
if (!safe) throw new Error(`\u043A\u043B\u044E\u0447 \u043F\u0440\u043E\u0433\u043E\u043D\u0430 \u043D\u0435 \u0433\u043E\u0434\u0438\u0442\u0441\u044F \u0432 \u0438\u043C\u044F \u043A\u0430\u0442\u0430\u043B\u043E\u0433\u0430 run-log'\u043E\u0432: ${JSON.stringify(runLogKey)}`);
|
|
7034
7145
|
return /^\d+$/.test(safe) ? `k-${safe}` : safe;
|
|
7035
7146
|
}
|
|
7036
7147
|
function runLogDirPath(runLogsDir, runLogKey) {
|
|
7037
|
-
return
|
|
7148
|
+
return join8(runLogsDir, runLogDirName(runLogKey));
|
|
7038
7149
|
}
|
|
7039
7150
|
function findRunLogDir(runLogsDir, keys) {
|
|
7040
7151
|
for (const key of keys) {
|
|
@@ -7246,13 +7357,13 @@ var SwarmClient = class _SwarmClient {
|
|
|
7246
7357
|
recover() {
|
|
7247
7358
|
if (existsSync6(this.mapPath)) {
|
|
7248
7359
|
try {
|
|
7249
|
-
const obj = JSON.parse(
|
|
7360
|
+
const obj = JSON.parse(readFileSync6(this.mapPath, "utf8"));
|
|
7250
7361
|
for (const [k, v] of Object.entries(obj)) this.prodIdByKey.set(k, v);
|
|
7251
7362
|
} catch {
|
|
7252
7363
|
}
|
|
7253
7364
|
}
|
|
7254
7365
|
if (existsSync6(this.outboxPath)) {
|
|
7255
|
-
const txt =
|
|
7366
|
+
const txt = readFileSync6(this.outboxPath, "utf8");
|
|
7256
7367
|
for (const line of txt.split("\n")) {
|
|
7257
7368
|
const s = line.trim();
|
|
7258
7369
|
if (!s) continue;
|
|
@@ -7275,7 +7386,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
7275
7386
|
if (!existsSync6(this.stormPath)) return;
|
|
7276
7387
|
let txt;
|
|
7277
7388
|
try {
|
|
7278
|
-
txt =
|
|
7389
|
+
txt = readFileSync6(this.stormPath, "utf8");
|
|
7279
7390
|
} catch {
|
|
7280
7391
|
return;
|
|
7281
7392
|
}
|
|
@@ -7359,6 +7470,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
7359
7470
|
if ("tokens_in" in patch && patch.tokens_in !== void 0) out.tokensIn = patch.tokens_in;
|
|
7360
7471
|
if ("tokens_out" in patch && patch.tokens_out !== void 0) out.tokensOut = patch.tokens_out;
|
|
7361
7472
|
if ("duration_ms" in patch && patch.duration_ms !== void 0) out.durationMs = patch.duration_ms;
|
|
7473
|
+
if ("cost_unmeasured" in patch && patch.cost_unmeasured !== void 0) out.costUnmeasured = patch.cost_unmeasured;
|
|
7362
7474
|
if ("respawns" in patch && patch.respawns !== void 0) out.respawns = patch.respawns;
|
|
7363
7475
|
if ("pr_url" in patch) out.prUrl = patch.pr_url ?? null;
|
|
7364
7476
|
if ("changed_paths" in patch && patch.changed_paths) out.changedPaths = patch.changed_paths;
|
|
@@ -7441,6 +7553,8 @@ var SwarmClient = class _SwarmClient {
|
|
|
7441
7553
|
// копятся учётом запусков claude (cost.ts), как cost_usd — TASWM-353
|
|
7442
7554
|
tokens_out: 0,
|
|
7443
7555
|
duration_ms: 0,
|
|
7556
|
+
cost_unmeasured: 0,
|
|
7557
|
+
// запусков без снятой цены (TASWM-548) — копится тем же учётом
|
|
7444
7558
|
pr_url: null,
|
|
7445
7559
|
changed_paths: [],
|
|
7446
7560
|
// файлы прогона снимаются при открытии PR (TASWM-506)
|
|
@@ -9061,6 +9175,8 @@ var SwarmClient = class _SwarmClient {
|
|
|
9061
9175
|
// токены и время работы (TASWM-353) — прод-поля, заполняются ниже
|
|
9062
9176
|
tokens_out: 0,
|
|
9063
9177
|
duration_ms: 0,
|
|
9178
|
+
cost_unmeasured: 0,
|
|
9179
|
+
// запусков без снятой цены (TASWM-548) — прод-поле, заполняется ниже
|
|
9064
9180
|
pr_url: null,
|
|
9065
9181
|
changed_paths: [],
|
|
9066
9182
|
// занятые файлы (TASWM-506) — прод-поле, заполняется ниже
|
|
@@ -9142,6 +9258,7 @@ var SwarmClient = class _SwarmClient {
|
|
|
9142
9258
|
local.tokens_in = typeof pr.tokensIn === "number" ? pr.tokensIn : 0;
|
|
9143
9259
|
local.tokens_out = typeof pr.tokensOut === "number" ? pr.tokensOut : 0;
|
|
9144
9260
|
local.duration_ms = typeof pr.durationMs === "number" ? pr.durationMs : 0;
|
|
9261
|
+
local.cost_unmeasured = typeof pr.costUnmeasured === "number" ? pr.costUnmeasured : 0;
|
|
9145
9262
|
local.pr_url = pr.prUrl ?? null;
|
|
9146
9263
|
local.changed_paths = Array.isArray(pr.changedPaths) ? pr.changedPaths : local.changed_paths ?? [];
|
|
9147
9264
|
local.stop_reason = pr.stopReason ?? null;
|
|
@@ -9539,7 +9656,7 @@ init_config();
|
|
|
9539
9656
|
import { $ as $6 } from "execa";
|
|
9540
9657
|
|
|
9541
9658
|
// src/daemonLaunch.ts
|
|
9542
|
-
import { openSync as openSync2, closeSync as closeSync2, readFileSync as
|
|
9659
|
+
import { openSync as openSync2, closeSync as closeSync2, readFileSync as readFileSync7 } from "fs";
|
|
9543
9660
|
import { spawn } from "child_process";
|
|
9544
9661
|
var FOREGROUND_FLAGS = /* @__PURE__ */ new Set(["--foreground", "-f", "--attach"]);
|
|
9545
9662
|
function parseStartMode(argv) {
|
|
@@ -9599,18 +9716,18 @@ function launchDetached(opts) {
|
|
|
9599
9716
|
}
|
|
9600
9717
|
function tailFile(path, lines) {
|
|
9601
9718
|
try {
|
|
9602
|
-
return tailText(
|
|
9719
|
+
return tailText(readFileSync7(path, "utf8"), lines);
|
|
9603
9720
|
} catch {
|
|
9604
9721
|
return "";
|
|
9605
9722
|
}
|
|
9606
9723
|
}
|
|
9607
9724
|
|
|
9608
9725
|
// src/logRotate.ts
|
|
9609
|
-
import { copyFileSync as copyFileSync2, renameSync as renameSync3, statSync as
|
|
9726
|
+
import { copyFileSync as copyFileSync2, renameSync as renameSync3, statSync as statSync6, fstatSync, truncateSync, unlinkSync as unlinkSync2, existsSync as existsSync7 } from "fs";
|
|
9610
9727
|
var realIo = {
|
|
9611
9728
|
size: (path) => {
|
|
9612
9729
|
try {
|
|
9613
|
-
return
|
|
9730
|
+
return statSync6(path).size;
|
|
9614
9731
|
} catch {
|
|
9615
9732
|
return null;
|
|
9616
9733
|
}
|
|
@@ -9647,15 +9764,15 @@ init_repoRegistry();
|
|
|
9647
9764
|
|
|
9648
9765
|
// src/hostIdentity.ts
|
|
9649
9766
|
import { hostname } from "os";
|
|
9650
|
-
import { existsSync as existsSync8, readFileSync as
|
|
9651
|
-
import { join as
|
|
9767
|
+
import { existsSync as existsSync8, readFileSync as readFileSync8, renameSync as renameSync4, writeFileSync as writeFileSync6 } from "fs";
|
|
9768
|
+
import { join as join10 } from "path";
|
|
9652
9769
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
9653
9770
|
function hostIdentityPath(home) {
|
|
9654
|
-
return
|
|
9771
|
+
return join10(home, "host.json");
|
|
9655
9772
|
}
|
|
9656
9773
|
function loadHostIdentity(deps) {
|
|
9657
9774
|
const exists = deps.exists ?? existsSync8;
|
|
9658
|
-
const readFile2 = deps.readFile ?? ((p) =>
|
|
9775
|
+
const readFile2 = deps.readFile ?? ((p) => readFileSync8(p, "utf8"));
|
|
9659
9776
|
const writeFile3 = deps.writeFile ?? ((p, data) => {
|
|
9660
9777
|
writeFileSync6(`${p}.tmp`, data);
|
|
9661
9778
|
renameSync4(`${p}.tmp`, p);
|
|
@@ -9772,8 +9889,8 @@ import { basename as basename4 } from "path";
|
|
|
9772
9889
|
import { serve as serve2 } from "@hono/node-server";
|
|
9773
9890
|
|
|
9774
9891
|
// src/diff.ts
|
|
9775
|
-
import { statSync as
|
|
9776
|
-
import { join as
|
|
9892
|
+
import { statSync as statSync7 } from "fs";
|
|
9893
|
+
import { join as join11 } from "path";
|
|
9777
9894
|
import { $ as $3 } from "execa";
|
|
9778
9895
|
var MAX_FILES = 200;
|
|
9779
9896
|
var MAX_LINES_PER_FILE = 1500;
|
|
@@ -9916,7 +10033,7 @@ async function resolveBase(wt, baseBranch) {
|
|
|
9916
10033
|
}
|
|
9917
10034
|
function mtime(path) {
|
|
9918
10035
|
try {
|
|
9919
|
-
return
|
|
10036
|
+
return statSync7(path).mtimeMs;
|
|
9920
10037
|
} catch {
|
|
9921
10038
|
return 0;
|
|
9922
10039
|
}
|
|
@@ -9941,7 +10058,7 @@ async function collectRunDiff(worktree, opts = {}) {
|
|
|
9941
10058
|
files.push(pf);
|
|
9942
10059
|
}
|
|
9943
10060
|
}
|
|
9944
|
-
files.sort((a, b) => mtime(
|
|
10061
|
+
files.sort((a, b) => mtime(join11(worktree, b.path)) - mtime(join11(worktree, a.path)));
|
|
9945
10062
|
const truncatedFiles = files.length > MAX_FILES;
|
|
9946
10063
|
if (truncatedFiles) files = files.slice(0, MAX_FILES);
|
|
9947
10064
|
const added = files.reduce((s, f) => s + f.added, 0);
|
|
@@ -11832,15 +11949,15 @@ import { cancelRun, respawnRun, runDaemon, wakeRun, OVERMIND_ENTRY, listDronePro
|
|
|
11832
11949
|
|
|
11833
11950
|
// src/launcher.ts
|
|
11834
11951
|
import { spawn as spawn2 } from "child_process";
|
|
11835
|
-
import { closeSync as closeSync3, existsSync as existsSync9, mkdirSync as mkdirSync9, openSync as openSync3, readdirSync as
|
|
11952
|
+
import { closeSync as closeSync3, existsSync as existsSync9, mkdirSync as mkdirSync9, openSync as openSync3, readdirSync as readdirSync8 } from "fs";
|
|
11836
11953
|
import { createRequire } from "module";
|
|
11837
|
-
import { homedir as
|
|
11838
|
-
import { dirname as dirname4, join as
|
|
11954
|
+
import { homedir as homedir5 } from "os";
|
|
11955
|
+
import { dirname as dirname4, join as join14 } from "path";
|
|
11839
11956
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
11840
11957
|
|
|
11841
11958
|
// src/droneHome.ts
|
|
11842
|
-
import { lstatSync, mkdirSync as mkdirSync8, readdirSync as
|
|
11843
|
-
import { join as
|
|
11959
|
+
import { lstatSync, mkdirSync as mkdirSync8, readdirSync as readdirSync7, rmSync, statSync as statSync8, symlinkSync as symlinkSync2 } from "fs";
|
|
11960
|
+
import { join as join13, relative, sep } from "path";
|
|
11844
11961
|
var DRONE_HOME_DENY_DEFAULT = [".taskless-swarm", ".bash_history", ".zsh_history"];
|
|
11845
11962
|
function droneHomeDeny(env = process.env) {
|
|
11846
11963
|
const extra = (env.SWARM_DRONE_HOME_DENY || "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
@@ -11859,28 +11976,28 @@ function buildDroneHome(opts) {
|
|
|
11859
11976
|
const deny = opts.deny ?? droneHomeDeny();
|
|
11860
11977
|
const platform = opts.platform ?? process.platform;
|
|
11861
11978
|
mkdirSync8(droneHome, { recursive: true, mode: 448 });
|
|
11862
|
-
const wanted = new Set(mirroredEntries(
|
|
11979
|
+
const wanted = new Set(mirroredEntries(readdirSync7(realHome), deny, platform));
|
|
11863
11980
|
const rel = relative(realHome, droneHome);
|
|
11864
11981
|
if (rel && !rel.startsWith("..") && !rel.includes(sep)) wanted.delete(rel);
|
|
11865
|
-
for (const existing of
|
|
11982
|
+
for (const existing of readdirSync7(droneHome)) {
|
|
11866
11983
|
if (wanted.has(existing)) continue;
|
|
11867
|
-
const p =
|
|
11984
|
+
const p = join13(droneHome, existing);
|
|
11868
11985
|
try {
|
|
11869
11986
|
if (lstatSync(p).isSymbolicLink()) rmSync(p);
|
|
11870
11987
|
} catch {
|
|
11871
11988
|
}
|
|
11872
11989
|
}
|
|
11873
11990
|
for (const name of wanted) {
|
|
11874
|
-
const link =
|
|
11991
|
+
const link = join13(droneHome, name);
|
|
11875
11992
|
try {
|
|
11876
11993
|
lstatSync(link);
|
|
11877
11994
|
continue;
|
|
11878
11995
|
} catch {
|
|
11879
11996
|
}
|
|
11880
|
-
const target =
|
|
11997
|
+
const target = join13(realHome, name);
|
|
11881
11998
|
let isDir;
|
|
11882
11999
|
try {
|
|
11883
|
-
isDir =
|
|
12000
|
+
isDir = statSync8(target).isDirectory();
|
|
11884
12001
|
} catch {
|
|
11885
12002
|
continue;
|
|
11886
12003
|
}
|
|
@@ -11898,7 +12015,7 @@ var REAL_PATH_ENV_PINS = [
|
|
|
11898
12015
|
{ env: "YARN_GLOBAL_FOLDER", segments: [".yarn", "berry"] }
|
|
11899
12016
|
];
|
|
11900
12017
|
function realPathEnvPins(realHome) {
|
|
11901
|
-
return Object.fromEntries(REAL_PATH_ENV_PINS.map(({ env, segments }) => [env,
|
|
12018
|
+
return Object.fromEntries(REAL_PATH_ENV_PINS.map(({ env, segments }) => [env, join13(realHome, ...segments)]));
|
|
11902
12019
|
}
|
|
11903
12020
|
function dronePrivatePaths(realHome, swarmHome) {
|
|
11904
12021
|
return [
|
|
@@ -12010,7 +12127,7 @@ function droneEnv(worktree, base3 = process.env, isolation, droneCap = null) {
|
|
|
12010
12127
|
const env = { ...base3 };
|
|
12011
12128
|
const isolate = base3.SWARM_TURBO_ISOLATE !== "0";
|
|
12012
12129
|
if (isolate && !base3.TURBO_CACHE_DIR) {
|
|
12013
|
-
env.TURBO_CACHE_DIR =
|
|
12130
|
+
env.TURBO_CACHE_DIR = join14(worktree, ".turbo", "cache");
|
|
12014
12131
|
}
|
|
12015
12132
|
Object.assign(env, droneTestEnv(droneCap, base3));
|
|
12016
12133
|
for (const key of DAEMON_STATE_ENV) delete env[key];
|
|
@@ -12038,10 +12155,10 @@ var DAEMON_STATE_ENV = [
|
|
|
12038
12155
|
"TASKLESS_TOKEN"
|
|
12039
12156
|
];
|
|
12040
12157
|
function bundledRoleDir(kind) {
|
|
12041
|
-
return
|
|
12158
|
+
return join14(dirname4(fileURLToPath2(import.meta.url)), "..", "roles", kind);
|
|
12042
12159
|
}
|
|
12043
12160
|
function roleDir(worktree, kind) {
|
|
12044
|
-
return
|
|
12161
|
+
return join14(worktree, ".claude", "roles", kind);
|
|
12045
12162
|
}
|
|
12046
12163
|
function roleDirs(worktree, kind) {
|
|
12047
12164
|
return [bundledRoleDir(kind), roleDir(worktree, kind)].filter((dir) => existsSync9(dir));
|
|
@@ -12052,7 +12169,7 @@ function nextRunLogPath(runLogsDir, runLogKeys) {
|
|
|
12052
12169
|
mkdirSync9(dir, { recursive: true });
|
|
12053
12170
|
let files = [];
|
|
12054
12171
|
try {
|
|
12055
|
-
files =
|
|
12172
|
+
files = readdirSync8(dir);
|
|
12056
12173
|
} catch {
|
|
12057
12174
|
}
|
|
12058
12175
|
let next = 0;
|
|
@@ -12060,7 +12177,7 @@ function nextRunLogPath(runLogsDir, runLogKeys) {
|
|
|
12060
12177
|
const m = /^(\d+)\.json/.exec(f);
|
|
12061
12178
|
if (m) next = Math.max(next, Number(m[1]) + 1);
|
|
12062
12179
|
}
|
|
12063
|
-
return
|
|
12180
|
+
return join14(dir, `${next}.json`);
|
|
12064
12181
|
}
|
|
12065
12182
|
function openNextRunLog(runLogsDir, runLogKeys) {
|
|
12066
12183
|
for (let attempt = 0; attempt < 50; attempt++) {
|
|
@@ -12141,11 +12258,11 @@ function makeLauncher(cfg) {
|
|
|
12141
12258
|
} catch (e) {
|
|
12142
12259
|
console.error(`[launcher] \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u043F\u0438\u0441\u0430\u0442\u044C \u0443\u0441\u0438\u043B\u0438\u0435 \u043F\u0440\u043E\u0433\u043E\u043D\u0430 #${run.id}: ${String(e)}`);
|
|
12143
12260
|
}
|
|
12144
|
-
const realHome = cfg.droneIsolation?.realHome ??
|
|
12261
|
+
const realHome = cfg.droneIsolation?.realHome ?? homedir5();
|
|
12145
12262
|
const home = cfg.droneIsolation ? buildDroneHome({ realHome, droneHome: cfg.droneIsolation.home }) : void 0;
|
|
12146
|
-
if (cfg.droneIsolation && process.env.TASKLESS_TOKEN && !existsSync9(
|
|
12263
|
+
if (cfg.droneIsolation && process.env.TASKLESS_TOKEN && !existsSync9(join14(cfg.droneIsolation.swarmHome, "token"))) {
|
|
12147
12264
|
console.error(
|
|
12148
|
-
`[launcher] TASKLESS_TOKEN \u0437\u0430\u0434\u0430\u043D \u0442\u043E\u043B\u044C\u043A\u043E \u0432 env \u0434\u0435\u043C\u043E\u043D\u0430 \u2014 \u0434\u0440\u043E\u043D\u0443 \u043E\u043D \u043D\u0435 \u043D\u0430\u0441\u043B\u0435\u0434\u0443\u0435\u0442\u0441\u044F (TASWM-289), \u0430 \u0444\u0430\u0439\u043B\u0430 ${
|
|
12265
|
+
`[launcher] TASKLESS_TOKEN \u0437\u0430\u0434\u0430\u043D \u0442\u043E\u043B\u044C\u043A\u043E \u0432 env \u0434\u0435\u043C\u043E\u043D\u0430 \u2014 \u0434\u0440\u043E\u043D\u0443 \u043E\u043D \u043D\u0435 \u043D\u0430\u0441\u043B\u0435\u0434\u0443\u0435\u0442\u0441\u044F (TASWM-289), \u0430 \u0444\u0430\u0439\u043B\u0430 ${join14(cfg.droneIsolation.swarmHome, "token")} \u043D\u0435\u0442. read_task \u0434\u0440\u043E\u043D\u0430 \u0431\u0443\u0434\u0435\u0442 slug-only. \u041F\u043E\u0447\u0438\u043D\u0438: \`swarm login\` (oauth.json) \u0438\u043B\u0438 \u043F\u043E\u043B\u043E\u0436\u0438 \u0442\u043E\u043A\u0435\u043D \u0432 \u044D\u0442\u043E\u0442 \u0444\u0430\u0439\u043B.`
|
|
12149
12266
|
);
|
|
12150
12267
|
}
|
|
12151
12268
|
const executor = cfg.executor ?? resolveExecutor();
|
|
@@ -13051,12 +13168,12 @@ async function runDaemonLogs(argv) {
|
|
|
13051
13168
|
const head = tailFile(DAEMON_LOG_PATH, lines);
|
|
13052
13169
|
if (head) console.log(head);
|
|
13053
13170
|
if (!follow) return 0;
|
|
13054
|
-
let pos =
|
|
13171
|
+
let pos = statSync11(DAEMON_LOG_PATH).size;
|
|
13055
13172
|
for (; ; ) {
|
|
13056
13173
|
await sleep2(500);
|
|
13057
13174
|
let size;
|
|
13058
13175
|
try {
|
|
13059
|
-
size =
|
|
13176
|
+
size = statSync11(DAEMON_LOG_PATH).size;
|
|
13060
13177
|
} catch {
|
|
13061
13178
|
continue;
|
|
13062
13179
|
}
|
|
@@ -13328,7 +13445,7 @@ function effectiveWorktreesDir() {
|
|
|
13328
13445
|
exists: (d) => existsSync17(d),
|
|
13329
13446
|
isNonEmptyDir: (d) => {
|
|
13330
13447
|
try {
|
|
13331
|
-
return
|
|
13448
|
+
return readdirSync11(d).length > 0;
|
|
13332
13449
|
} catch {
|
|
13333
13450
|
return false;
|
|
13334
13451
|
}
|
|
@@ -13384,12 +13501,12 @@ async function scoutRepo(repo) {
|
|
|
13384
13501
|
await $6({ reject: false })`git -C ${worktree} reset --hard ${baseRef}`;
|
|
13385
13502
|
}
|
|
13386
13503
|
await setWorktreeIdentity(worktree, name);
|
|
13387
|
-
const abs = (rel) =>
|
|
13504
|
+
const abs = (rel) => join26(worktree, rel);
|
|
13388
13505
|
const code = await runRepoScout({
|
|
13389
13506
|
repoFullName,
|
|
13390
13507
|
repoPath: worktree,
|
|
13391
13508
|
name,
|
|
13392
|
-
readFile: (rel) => existsSync17(abs(rel)) ?
|
|
13509
|
+
readFile: (rel) => existsSync17(abs(rel)) ? readFileSync19(abs(rel), "utf8") : null,
|
|
13393
13510
|
writeFile: (rel, text) => {
|
|
13394
13511
|
mkdirSync10(dirname5(abs(rel)), { recursive: true });
|
|
13395
13512
|
writeFileSync14(abs(rel), text);
|