@taskless-app/swarm 0.6.61 → 0.6.62

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 CHANGED
@@ -3616,7 +3616,7 @@ var init_package = __esm({
3616
3616
  "package.json"() {
3617
3617
  package_default = {
3618
3618
  name: "@taskless-app/swarm",
3619
- version: "0.6.61",
3619
+ version: "0.6.62",
3620
3620
  type: "module",
3621
3621
  description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
3622
3622
  keywords: [
@@ -3667,7 +3667,7 @@ var init_package = __esm({
3667
3667
  execa: "^10.0.0",
3668
3668
  zod: "3.25.76"
3669
3669
  },
3670
- gitHead: "97838ed30c3fef4cc868c38d8fd9373635a3b48c"
3670
+ gitHead: "e999630218010a25c03a6024e1b71ef34b2359ec"
3671
3671
  };
3672
3672
  }
3673
3673
  });
@@ -5018,6 +5018,8 @@ function rowToRun(row) {
5018
5018
  // базовая ветка PR (TASWM-285); null → дефолтная
5019
5019
  workspace_id: row.workspace_id ?? null,
5020
5020
  // воркспейс задачи прогона (TASWM-288); null → глобальный пин
5021
+ // TASWM-597: repoless-прогон (офлайн-проект, без worktree/PR). null/0 → код-конвейер.
5022
+ repoless: row.repoless === 1,
5021
5023
  created_at: row.created_at,
5022
5024
  updated_at: row.updated_at
5023
5025
  };
@@ -5089,6 +5091,7 @@ CREATE TABLE IF NOT EXISTS runs (
5089
5091
  priority INTEGER NOT NULL DEFAULT 0,
5090
5092
  base_branch TEXT,
5091
5093
  workspace_id TEXT,
5094
+ repoless INTEGER,
5092
5095
  created_at TEXT NOT NULL DEFAULT (datetime('now')),
5093
5096
  updated_at TEXT NOT NULL DEFAULT (datetime('now'))
5094
5097
  );
@@ -5186,6 +5189,8 @@ CREATE TABLE IF NOT EXISTS imports (
5186
5189
  "ALTER TABLE runs ADD COLUMN base_branch TEXT",
5187
5190
  // Воркспейс задачи прогона (TASWM-288): им пинятся задачные MCP-вызовы прогона.
5188
5191
  "ALTER TABLE runs ADD COLUMN workspace_id TEXT",
5192
+ // TASWM-597: repoless-прогон — задача офлайн-проекта, спавн без worktree/ветки/PR.
5193
+ "ALTER TABLE runs ADD COLUMN repoless INTEGER",
5189
5194
  // Чем обошёлся прогон, кроме денег (TASWM-353): токены вход/выход и время работы.
5190
5195
  "ALTER TABLE runs ADD COLUMN tokens_in INTEGER NOT NULL DEFAULT 0",
5191
5196
  "ALTER TABLE runs ADD COLUMN tokens_out INTEGER NOT NULL DEFAULT 0",
@@ -5362,6 +5367,7 @@ CREATE TABLE IF NOT EXISTS imports (
5362
5367
  const arr = v;
5363
5368
  return arr && arr.length ? JSON.stringify(arr) : null;
5364
5369
  }
5370
+ if (f === "repoless") return v === true ? 1 : v === false ? 0 : null;
5365
5371
  if (f === "area" && typeof v === "string") return normalizeZoneLabel(v) || null;
5366
5372
  return v;
5367
5373
  });
@@ -9669,6 +9675,7 @@ var SwarmClient = class _SwarmClient {
9669
9675
  local.return_reason = toReturnReason(pr.returnReason) ?? local.return_reason;
9670
9676
  local.review_phase = pr.reviewPhase ?? local.review_phase;
9671
9677
  local.repo = this.resolveRepo(pr.repo ?? null);
9678
+ if (typeof pr.repoless === "boolean") local.repoless = pr.repoless;
9672
9679
  local.host_id = pr.hostId ?? null;
9673
9680
  local.host_name = pr.hostName ?? null;
9674
9681
  local.host_pinned = pr.hostPinned === true;
@@ -12799,6 +12806,10 @@ function makeLauncher(cfg) {
12799
12806
  SWARM_RUN_KIND: run.kind,
12800
12807
  SWARM_RUN_NAME: run.name,
12801
12808
  ...run.workspace_id ? { SWARM_WORKSPACE_ID: run.workspace_id } : {},
12809
+ // TASWM-598: repoless-прогон той же спавн-фиксацией — гейт done() («сдача отчётом,
12810
+ // не PR») обязан срабатывать и по данным СПАВНА, а не только по строке прогона от
12811
+ // демона (тот же класс граблей, что у SWARM_REVIEWS_RUN_ID в TASWM-375).
12812
+ ...run.repoless ? { SWARM_RUN_REPOLESS: "1" } : {},
12802
12813
  ...run.reviews_run_id != null ? { SWARM_REVIEWS_RUN_ID: String(run.reviews_run_id) } : {},
12803
12814
  // TASWM-344: та же роль, что у SWARM_REVIEWS_RUN_ID выше, для верификатора — без неё
12804
12815
  // его done() в client-режиме пошёл бы веткой обычной сдачи PR, и вердикт пропал бы.
package/dist/overmind.js CHANGED
@@ -4787,8 +4787,8 @@ __export(droneChannel_exports, {
4787
4787
  verifyLocalCliToken: () => verifyLocalCliToken
4788
4788
  });
4789
4789
  import { createHmac, randomBytes, timingSafeEqual } from "crypto";
4790
- import { chmodSync as chmodSync2, mkdirSync as mkdirSync9, readFileSync as readFileSync19, writeFileSync as writeFileSync12 } from "fs";
4791
- import { dirname as dirname4 } from "path";
4790
+ import { chmodSync as chmodSync2, mkdirSync as mkdirSync10, readFileSync as readFileSync19, writeFileSync as writeFileSync12 } from "fs";
4791
+ import { dirname as dirname5 } from "path";
4792
4792
  import { serve } from "@hono/node-server";
4793
4793
  function loadChannelSecret(path) {
4794
4794
  try {
@@ -4797,7 +4797,7 @@ function loadChannelSecret(path) {
4797
4797
  } catch {
4798
4798
  }
4799
4799
  const secret = randomBytes(32).toString("hex");
4800
- mkdirSync9(dirname4(path), { recursive: true });
4800
+ mkdirSync10(dirname5(path), { recursive: true });
4801
4801
  writeFileSync12(path, secret, { mode: 384 });
4802
4802
  try {
4803
4803
  chmodSync2(path, 384);
@@ -5188,7 +5188,7 @@ var init_droneChannel = __esm({
5188
5188
 
5189
5189
  // src/attachments.ts
5190
5190
  import { mkdir as mkdir3, rm as rm3, writeFile as writeFile3 } from "fs/promises";
5191
- import { join as join25 } from "path";
5191
+ import { join as join26 } from "path";
5192
5192
  function attachmentsFromDoc(doc, origin) {
5193
5193
  const out = [];
5194
5194
  const walk2 = (node) => {
@@ -5279,7 +5279,7 @@ async function materializeAttachments(opts) {
5279
5279
  };
5280
5280
  const result = { files: [], skipped: [] };
5281
5281
  if (opts.refs.length === 0) return result;
5282
- const dir = join25(opts.worktree, ATTACHMENTS_DIR);
5282
+ const dir = join26(opts.worktree, ATTACHMENTS_DIR);
5283
5283
  await io.removeDir(dir);
5284
5284
  let dirReady = false;
5285
5285
  let total = 0;
@@ -5325,7 +5325,7 @@ async function materializeAttachments(opts) {
5325
5325
  await io.mkdir(dir);
5326
5326
  dirReady = true;
5327
5327
  }
5328
- await io.writeFile(join25(dir, name), file.bytes);
5328
+ await io.writeFile(join26(dir, name), file.bytes);
5329
5329
  } catch (e) {
5330
5330
  result.skipped.push(`${label2} \u2014 \u043D\u0435 \u0437\u0430\u043F\u0438\u0441\u0430\u043B\u043E\u0441\u044C \u043D\u0430 \u0434\u0438\u0441\u043A (${errText2(e)})`);
5331
5331
  continue;
@@ -5478,7 +5478,7 @@ var init_attachments = __esm({
5478
5478
 
5479
5479
  // src/shotUpload.ts
5480
5480
  import { readFile as fsReadFile } from "fs/promises";
5481
- import { basename as basename4, isAbsolute as isAbsolute4, join as join26 } from "path";
5481
+ import { basename as basename4, isAbsolute as isAbsolute4, join as join27 } from "path";
5482
5482
  function shotMimetype(path) {
5483
5483
  const dot = path.lastIndexOf(".");
5484
5484
  if (dot < 0) return null;
@@ -5504,7 +5504,7 @@ async function readShots(paths, opts) {
5504
5504
  }
5505
5505
  let bytes;
5506
5506
  try {
5507
- bytes = await read(isAbsolute4(path) ? path : join26(opts.worktree, path));
5507
+ bytes = await read(isAbsolute4(path) ? path : join27(opts.worktree, path));
5508
5508
  } catch (e) {
5509
5509
  skipped.push({ path, reason: `\u043D\u0435 \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u043D: ${e instanceof Error ? e.message : String(e)}` });
5510
5510
  continue;
@@ -5586,7 +5586,7 @@ var init_shotUpload = __esm({
5586
5586
  // src/oauth.ts
5587
5587
  import { createHash as createHash3, randomBytes as randomBytes2 } from "crypto";
5588
5588
  import { readFileSync as readFileSync20, writeFileSync as writeFileSync13, unlinkSync as unlinkSync4 } from "fs";
5589
- import { join as join27 } from "path";
5589
+ import { join as join28 } from "path";
5590
5590
  function makePkce() {
5591
5591
  const verifier = randomBytes2(48).toString("base64url");
5592
5592
  const challenge = createHash3("sha256").update(verifier).digest("base64url");
@@ -5721,8 +5721,8 @@ var init_oauth = __esm({
5721
5721
  AUTHORIZE = "/api/oauth/authorize";
5722
5722
  TOKEN = "/api/oauth/token";
5723
5723
  SCOPE = "openid profile email taskless:full";
5724
- STORE_PATH2 = join27(SWARM_HOME, "oauth.json");
5725
- CLIENT_PATH = join27(SWARM_HOME, "oauth-client.json");
5724
+ STORE_PATH2 = join28(SWARM_HOME, "oauth.json");
5725
+ CLIENT_PATH = join28(SWARM_HOME, "oauth-client.json");
5726
5726
  base2 = (api) => api.replace(/\/$/, "");
5727
5727
  }
5728
5728
  });
@@ -5769,7 +5769,7 @@ var init_authState = __esm({
5769
5769
 
5770
5770
  // src/workspace.ts
5771
5771
  import { readFileSync as readFileSync21, writeFileSync as writeFileSync14, unlinkSync as unlinkSync5 } from "fs";
5772
- import { join as join28 } from "path";
5772
+ import { join as join29 } from "path";
5773
5773
  function loadWorkspace() {
5774
5774
  try {
5775
5775
  const w = JSON.parse(readFileSync21(WORKSPACE_PATH, "utf8"));
@@ -5786,7 +5786,7 @@ var init_workspace = __esm({
5786
5786
  "src/workspace.ts"() {
5787
5787
  "use strict";
5788
5788
  init_config();
5789
- WORKSPACE_PATH = join28(SWARM_HOME, "workspace.json");
5789
+ WORKSPACE_PATH = join29(SWARM_HOME, "workspace.json");
5790
5790
  }
5791
5791
  });
5792
5792
 
@@ -6389,7 +6389,7 @@ __export(db_exports, {
6389
6389
  });
6390
6390
  import { createRequire as createRequire2 } from "module";
6391
6391
  import { randomUUID as randomUUID3 } from "crypto";
6392
- import { existsSync as existsSync15 } from "fs";
6392
+ import { existsSync as existsSync16 } from "fs";
6393
6393
  import { resolve as resolve4 } from "path";
6394
6394
  function rowToQuestion(row) {
6395
6395
  return {
@@ -6471,6 +6471,8 @@ function rowToRun(row) {
6471
6471
  // базовая ветка PR (TASWM-285); null → дефолтная
6472
6472
  workspace_id: row.workspace_id ?? null,
6473
6473
  // воркспейс задачи прогона (TASWM-288); null → глобальный пин
6474
+ // TASWM-597: repoless-прогон (офлайн-проект, без worktree/PR). null/0 → код-конвейер.
6475
+ repoless: row.repoless === 1,
6474
6476
  created_at: row.created_at,
6475
6477
  updated_at: row.updated_at
6476
6478
  };
@@ -6542,6 +6544,7 @@ CREATE TABLE IF NOT EXISTS runs (
6542
6544
  priority INTEGER NOT NULL DEFAULT 0,
6543
6545
  base_branch TEXT,
6544
6546
  workspace_id TEXT,
6547
+ repoless INTEGER,
6545
6548
  created_at TEXT NOT NULL DEFAULT (datetime('now')),
6546
6549
  updated_at TEXT NOT NULL DEFAULT (datetime('now'))
6547
6550
  );
@@ -6639,6 +6642,8 @@ CREATE TABLE IF NOT EXISTS imports (
6639
6642
  "ALTER TABLE runs ADD COLUMN base_branch TEXT",
6640
6643
  // Воркспейс задачи прогона (TASWM-288): им пинятся задачные MCP-вызовы прогона.
6641
6644
  "ALTER TABLE runs ADD COLUMN workspace_id TEXT",
6645
+ // TASWM-597: repoless-прогон — задача офлайн-проекта, спавн без worktree/ветки/PR.
6646
+ "ALTER TABLE runs ADD COLUMN repoless INTEGER",
6642
6647
  // Чем обошёлся прогон, кроме денег (TASWM-353): токены вход/выход и время работы.
6643
6648
  "ALTER TABLE runs ADD COLUMN tokens_in INTEGER NOT NULL DEFAULT 0",
6644
6649
  "ALTER TABLE runs ADD COLUMN tokens_out INTEGER NOT NULL DEFAULT 0",
@@ -6815,6 +6820,7 @@ CREATE TABLE IF NOT EXISTS imports (
6815
6820
  const arr = v;
6816
6821
  return arr && arr.length ? JSON.stringify(arr) : null;
6817
6822
  }
6823
+ if (f === "repoless") return v === true ? 1 : v === false ? 0 : null;
6818
6824
  if (f === "area" && typeof v === "string") return normalizeZoneLabel(v) || null;
6819
6825
  return v;
6820
6826
  });
@@ -7047,7 +7053,7 @@ CREATE TABLE IF NOT EXISTS imports (
7047
7053
  const repoN = normalizeRepo(repo);
7048
7054
  const already = this.db.prepare("SELECT run_count FROM imports WHERE source = ?").get(abs);
7049
7055
  if (already) return { imported: false, runs: already.run_count };
7050
- if (!existsSync15(abs)) throw new Error(`import-db: \u0444\u0430\u0439\u043B\u0430 \u043D\u0435\u0442: ${abs}`);
7056
+ if (!existsSync16(abs)) throw new Error(`import-db: \u0444\u0430\u0439\u043B\u0430 \u043D\u0435\u0442: ${abs}`);
7051
7057
  const src = new this.databaseCtor(abs);
7052
7058
  try {
7053
7059
  const runs = src.prepare("SELECT * FROM runs ORDER BY id").all();
@@ -7417,8 +7423,8 @@ var init_droneStore = __esm({
7417
7423
 
7418
7424
  // src/overmind.ts
7419
7425
  import { homedir as homedir7 } from "os";
7420
- import { existsSync as existsSync20, readFileSync as readFileSync25, readdirSync as readdirSync14, renameSync as renameSync12, statSync as statSync13 } from "fs";
7421
- import { basename as basename6, dirname as dirname5, join as join35 } from "path";
7426
+ import { existsSync as existsSync21, readFileSync as readFileSync25, readdirSync as readdirSync14, renameSync as renameSync12, statSync as statSync13 } from "fs";
7427
+ import { basename as basename6, dirname as dirname6, join as join36 } from "path";
7422
7428
  import { fileURLToPath as fileURLToPath3, pathToFileURL } from "url";
7423
7429
  import { spawn as spawn4 } from "child_process";
7424
7430
 
@@ -9917,6 +9923,7 @@ var SwarmClient = class _SwarmClient {
9917
9923
  local.return_reason = toReturnReason(pr.returnReason) ?? local.return_reason;
9918
9924
  local.review_phase = pr.reviewPhase ?? local.review_phase;
9919
9925
  local.repo = this.resolveRepo(pr.repo ?? null);
9926
+ if (typeof pr.repoless === "boolean") local.repoless = pr.repoless;
9920
9927
  local.host_id = pr.hostId ?? null;
9921
9928
  local.host_name = pr.hostName ?? null;
9922
9929
  local.host_pinned = pr.hostPinned === true;
@@ -11425,6 +11432,10 @@ function makeLauncher(cfg) {
11425
11432
  SWARM_RUN_KIND: run.kind,
11426
11433
  SWARM_RUN_NAME: run.name,
11427
11434
  ...run.workspace_id ? { SWARM_WORKSPACE_ID: run.workspace_id } : {},
11435
+ // TASWM-598: repoless-прогон той же спавн-фиксацией — гейт done() («сдача отчётом,
11436
+ // не PR») обязан срабатывать и по данным СПАВНА, а не только по строке прогона от
11437
+ // демона (тот же класс граблей, что у SWARM_REVIEWS_RUN_ID в TASWM-375).
11438
+ ...run.repoless ? { SWARM_RUN_REPOLESS: "1" } : {},
11428
11439
  ...run.reviews_run_id != null ? { SWARM_REVIEWS_RUN_ID: String(run.reviews_run_id) } : {},
11429
11440
  // TASWM-344: та же роль, что у SWARM_REVIEWS_RUN_ID выше, для верификатора — без неё
11430
11441
  // его done() в client-режиме пошёл бы веткой обычной сдачи PR, и вердикт пропал бы.
@@ -12482,6 +12493,11 @@ function depsPromptNotice(report) {
12482
12493
 
12483
12494
  // src/orchestrator.ts
12484
12495
  init_config();
12496
+ import { existsSync as existsSync15, mkdirSync as mkdirSync9, rmSync as rmSync3 } from "fs";
12497
+ import { join as join25, dirname as dirname4 } from "path";
12498
+ function repolessRunDir(worktreesDir, taskSlug) {
12499
+ return join25(dirname4(worktreesDir), "runs", taskSlug);
12500
+ }
12485
12501
  var WORKTREE_HELD_STATUSES = /* @__PURE__ */ new Set(["running", "blocked", "review", "paused", "storm_dead"]);
12486
12502
  function worktreePathHeldLive(db, path, exceptRunId) {
12487
12503
  return db.listRuns().some((r) => r.id !== exceptRunId && r.worktree_path === path && WORKTREE_HELD_STATUSES.has(r.status));
@@ -12523,6 +12539,24 @@ function healTaskSlug(db, run, task) {
12523
12539
  return db.updateRun(run.id, { task_slug: slug }) ?? run;
12524
12540
  }
12525
12541
  async function spawnDrone(deps, run) {
12542
+ if (run.repoless) {
12543
+ const workdir = repolessRunDir(deps.worktreesDir, run.task_slug);
12544
+ if (existsSync15(workdir)) {
12545
+ rmSync3(workdir, { recursive: true, force: true });
12546
+ deps.db.addEvent(run.id, "step", `\u0440\u0435\u043A\u043B\u0435\u0439\u043C \u043E\u0441\u0438\u0440\u043E\u0442\u0435\u0432\u0448\u0435\u0433\u043E \u0441\u043A\u0440\u0430\u0442\u0447-\u043A\u0430\u0442\u0430\u043B\u043E\u0433\u0430 ${workdir} (\u0434\u0435\u0440\u0436\u0430\u043B \u043C\u0451\u0440\u0442\u0432\u044B\u0439 \u043F\u0440\u043E\u0433\u043E\u043D)`);
12547
+ }
12548
+ mkdirSync9(workdir, { recursive: true });
12549
+ if (run.area && deps.db.runningAreas("").includes(run.area)) throw new AreaBusyError(run.area);
12550
+ deps.db.addEvent(run.id, "step", `repoless-\u043F\u0440\u043E\u0433\u043E\u043D: \u0441\u043A\u0440\u0430\u0442\u0447-\u043A\u0430\u0442\u0430\u043B\u043E\u0433 ${workdir} (\u0431\u0435\u0437 worktree/\u0432\u0435\u0442\u043A\u0438/PR \u2014 TASWM-595)`);
12551
+ const built2 = await deps.buildPrompt(run, workdir);
12552
+ const pid2 = deps.launch({ worktree: workdir, run, prompt: built2 });
12553
+ deps.db.addEvent(run.id, "step", `\u0434\u0440\u043E\u043D \u0437\u0430\u043F\u0443\u0449\u0435\u043D \u0432 ${workdir} (pid ${pid2})`);
12554
+ return deps.db.updateRun(run.id, {
12555
+ status: "running",
12556
+ worktree_path: workdir,
12557
+ pid: pid2
12558
+ });
12559
+ }
12526
12560
  const repo = normalizeRepo(run.repo || deps.repo || "");
12527
12561
  if (!repo) throw new Error(`\u0443 \u043F\u0440\u043E\u0433\u043E\u043D\u0430 #${run.id} (${run.task_slug}) \u043D\u0435\u0442 repo \u0438 \u043D\u0435\u0442 \u0434\u0435\u0444\u043E\u043B\u0442\u0430 SWARM_REPO`);
12528
12562
  const conflict = deps.conflicts ? await deps.conflicts(run, repo) : { kind: "unknown" };
@@ -12726,7 +12760,7 @@ function parkReasonUnretriable(reason) {
12726
12760
  // package.json
12727
12761
  var package_default = {
12728
12762
  name: "@taskless-app/swarm",
12729
- version: "0.6.61",
12763
+ version: "0.6.62",
12730
12764
  type: "module",
12731
12765
  description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
12732
12766
  keywords: [
@@ -12777,7 +12811,7 @@ var package_default = {
12777
12811
  execa: "^10.0.0",
12778
12812
  zod: "3.25.76"
12779
12813
  },
12780
- gitHead: "97838ed30c3fef4cc868c38d8fd9373635a3b48c"
12814
+ gitHead: "e999630218010a25c03a6024e1b71ef34b2359ec"
12781
12815
  };
12782
12816
 
12783
12817
  // src/version.ts
@@ -13566,7 +13600,7 @@ init_git();
13566
13600
 
13567
13601
  // src/diff.ts
13568
13602
  import { statSync as statSync12 } from "fs";
13569
- import { join as join29 } from "path";
13603
+ import { join as join30 } from "path";
13570
13604
  import { $ as $4 } from "execa";
13571
13605
  var MAX_FILES = 200;
13572
13606
  var MAX_LINES_PER_FILE = 1500;
@@ -13734,7 +13768,7 @@ async function collectRunDiff(worktree, opts = {}) {
13734
13768
  files.push(pf);
13735
13769
  }
13736
13770
  }
13737
- files.sort((a, b) => mtime(join29(worktree, b.path)) - mtime(join29(worktree, a.path)));
13771
+ files.sort((a, b) => mtime(join30(worktree, b.path)) - mtime(join30(worktree, a.path)));
13738
13772
  const truncatedFiles = files.length > MAX_FILES;
13739
13773
  if (truncatedFiles) files = files.slice(0, MAX_FILES);
13740
13774
  const added = files.reduce((s, f) => s + f.added, 0);
@@ -14486,6 +14520,45 @@ ${(summary ?? "").trim()}${shots.warning}`,
14486
14520
  \u26A0\uFE0F \u0412\u0435\u0440\u0434\u0438\u043A\u0442-\u043A\u043E\u043C\u043C\u0435\u043D\u0442 \u0432 \u0437\u0430\u0434\u0430\u0447\u0443 \u041D\u0415 \u0443\u0435\u0445\u0430\u043B (${commentWarning}) \u2014 \u0432\u0435\u0440\u0434\u0438\u043A\u0442 \u0435\u0441\u0442\u044C \u0442\u043E\u043B\u044C\u043A\u043E \u043D\u0430 \u043F\u0440\u043E\u0433\u043E\u043D\u0435. \u041F\u0440\u043E\u0434\u0443\u0431\u043B\u0438\u0440\u0443\u0439 \u0435\u0433\u043E \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u043E\u043C \u0432 PR: \`gh pr comment ${trustedPrUrl} --body "${verdictText} \u2026"\`.` : "";
14487
14521
  return { content: [{ type: "text", text: `\u0432\u0435\u0440\u0434\u0438\u043A\u0442 \u0432\u0435\u0440\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u0437\u0430\u043F\u0438\u0441\u0430\u043D (${verdictText})${shotsNote(shots)}${commentNote}` }] };
14488
14522
  }
14523
+ if (run?.repoless || opts.repoless) {
14524
+ const report = (summary ?? "").trim();
14525
+ if (!report) {
14526
+ return {
14527
+ content: [
14528
+ {
14529
+ type: "text",
14530
+ text: "done() repoless-\u043F\u0440\u043E\u0433\u043E\u043D\u0430 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 summary \u2014 \u043E\u043D \u0443\u0445\u043E\u0434\u0438\u0442 \u041E\u0422\u0427\u0401\u0422\u041E\u041C \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u043E\u043C \u0432 \u0437\u0430\u0434\u0430\u0447\u0443: \u0447\u0442\u043E \u0441\u0434\u0435\u043B\u0430\u043D\u043E, \u0447\u0435\u043C \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u043E (\u043F\u043E \u043A\u0440\u0438\u0442\u0435\u0440\u0438\u044F\u043C \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438), \u043A\u0430\u043A\u0438\u0435 \u0440\u0435\u0448\u0435\u043D\u0438\u044F \u043F\u0440\u0438\u043D\u044F\u043B \u0438 \u0447\u0442\u043E \u043E\u0441\u0442\u0430\u043B\u043E\u0441\u044C \u0437\u0430 \u0441\u043A\u043E\u0431\u043A\u0430\u043C\u0438. PR \u0443 \u044D\u0442\u043E\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u043D\u0435\u0442 \u2014 \u043E\u0442\u0447\u0451\u0442 \u0438 \u0435\u0441\u0442\u044C \u0441\u0434\u0430\u0447\u0430."
14531
+ }
14532
+ ],
14533
+ isError: true
14534
+ };
14535
+ }
14536
+ const shots = await uploadShots();
14537
+ const slug = run && reportSlug(run.task_slug) || opts.expectedTaskSlug;
14538
+ if (slug && opts.taskless) {
14539
+ try {
14540
+ await opts.taskless.addComment(
14541
+ slug,
14542
+ `\u041E\u0442\u0447\u0451\u0442 (\u0437\u0430\u0434\u0430\u0447\u0430 \u0431\u0435\u0437 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F \u2014 \u0440\u0430\u0431\u043E\u0442\u044B \u0432 git \u043D\u0435\u0442):
14543
+
14544
+ ${report}${shots.warning}`,
14545
+ {
14546
+ swarmKind: "report",
14547
+ // TASWM-265: имени взять неоткуда при тонкой строке — честная заглушка.
14548
+ swarmDroneName: run?.name ?? "(\u0438\u043C\u044F \u043D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u043E)"
14549
+ },
14550
+ shots.attachments
14551
+ );
14552
+ } catch (e) {
14553
+ await store.addEvent(null, "step", `\u043E\u0442\u0447\u0451\u0442 \u0432 \u0437\u0430\u0434\u0430\u0447\u0443 ${slug} \u043D\u0435 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D: ${e instanceof Error ? e.message : String(e)}`);
14554
+ }
14555
+ } else {
14556
+ await store.addEvent(null, "step", `\u043E\u0442\u0447\u0451\u0442 \u0434\u0440\u043E\u043D\u0430 (Taskless \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D${slug ? "" : ", \u0441\u043B\u0430\u0433 \u043D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043D"}): ${report}`);
14557
+ }
14558
+ await store.updateRun(null, { status: "done" });
14559
+ await store.addEvent(null, "done", "repoless-\u0441\u0434\u0430\u0447\u0430: \u043E\u0442\u0447\u0451\u0442 \u0432 \u0437\u0430\u0434\u0430\u0447\u0435, \u043F\u0440\u0438\u0451\u043C\u043A\u0430 \u0437\u0430 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u043E\u043C (\u0431\u0435\u0437 PR/CI/mergeGate)");
14560
+ return { content: [{ type: "text", text: `\u043F\u0440\u0438\u043D\u044F\u0442\u043E: \u043E\u0442\u0447\u0451\u0442 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D \u0432 \u0437\u0430\u0434\u0430\u0447\u0443${shotsNote(shots)}, \u043F\u0440\u043E\u0433\u043E\u043D \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043D. \u041F\u0440\u0438\u0451\u043C\u043A\u0443 \u0434\u0435\u043B\u0430\u0435\u0442 \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u043F\u043E \u043A\u0440\u0438\u0442\u0435\u0440\u0438\u044F\u043C \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438.` }] };
14561
+ }
14489
14562
  if (isGithubPrUrl(pr_url)) {
14490
14563
  const report = (summary ?? "").trim();
14491
14564
  if (!report) {
@@ -14717,13 +14790,15 @@ async function runDroneServer(runId) {
14717
14790
  const expectedKind = toRunKind(process.env.SWARM_RUN_KIND);
14718
14791
  const spawnReviewsRunId = Number(process.env.SWARM_REVIEWS_RUN_ID);
14719
14792
  const spawnVerifiesRunId = Number(process.env.SWARM_VERIFIES_RUN_ID);
14793
+ const spawnRepoless = process.env.SWARM_RUN_REPOLESS === "1";
14720
14794
  const common = {
14721
14795
  taskless,
14722
14796
  runKind: expectedKind,
14723
14797
  prHeadBranch,
14724
14798
  ...expectedTaskSlug ? { expectedTaskSlug } : {},
14725
14799
  ...Number.isInteger(spawnReviewsRunId) && spawnReviewsRunId > 0 ? { reviewsRunId: spawnReviewsRunId } : {},
14726
- ...Number.isInteger(spawnVerifiesRunId) && spawnVerifiesRunId > 0 ? { verifiesRunId: spawnVerifiesRunId } : {}
14800
+ ...Number.isInteger(spawnVerifiesRunId) && spawnVerifiesRunId > 0 ? { verifiesRunId: spawnVerifiesRunId } : {},
14801
+ ...spawnRepoless ? { repoless: true } : {}
14727
14802
  };
14728
14803
  const channelUrl = process.env.SWARM_DRONE_CHANNEL_URL;
14729
14804
  const channelToken = process.env.SWARM_DRONE_CHANNEL_TOKEN;
@@ -15987,22 +16062,22 @@ async function prodClearMergeIntent(runId, deps = {}) {
15987
16062
  }
15988
16063
 
15989
16064
  // src/envGate.ts
15990
- import { existsSync as existsSync17 } from "fs";
15991
- import { join as join31 } from "path";
16065
+ import { existsSync as existsSync18 } from "fs";
16066
+ import { join as join32 } from "path";
15992
16067
  import { createConnection } from "net";
15993
16068
  import { execa as execa2 } from "execa";
15994
16069
 
15995
16070
  // src/platform.ts
15996
- import { existsSync as existsSync16, readFileSync as readFileSync22 } from "fs";
15997
- import { delimiter as delimiter2, join as join30 } from "path";
16071
+ import { existsSync as existsSync17, readFileSync as readFileSync22 } from "fs";
16072
+ import { delimiter as delimiter2, join as join31 } from "path";
15998
16073
  function resolveCommandPath(name, env = process.env, platform = process.platform) {
15999
- if (name.includes("/") || name.includes("\\")) return existsSync16(name) ? name : null;
16074
+ if (name.includes("/") || name.includes("\\")) return existsSync17(name) ? name : null;
16000
16075
  const dirs = (env.PATH ?? env.Path ?? "").split(delimiter2).filter(Boolean);
16001
16076
  const exts = platform === "win32" ? (env.PATHEXT ?? ".EXE;.CMD;.BAT").split(";").filter(Boolean) : [""];
16002
16077
  for (const dir of dirs) {
16003
16078
  for (const ext of exts) {
16004
- const candidate = join30(dir, name + ext);
16005
- if (existsSync16(candidate)) return candidate;
16079
+ const candidate = join31(dir, name + ext);
16080
+ if (existsSync17(candidate)) return candidate;
16006
16081
  }
16007
16082
  }
16008
16083
  return null;
@@ -16085,8 +16160,8 @@ var COMPOSE_MARKERS = [
16085
16160
  "compose.yaml"
16086
16161
  ];
16087
16162
  function detectRequirements(repo, io = {}) {
16088
- const exists = io.exists ?? existsSync17;
16089
- const marker = COMPOSE_MARKERS.find((f) => exists(join31(repo, f)));
16163
+ const exists = io.exists ?? existsSync18;
16164
+ const marker = COMPOSE_MARKERS.find((f) => exists(join32(repo, f)));
16090
16165
  return marker ? [{ kind: "docker", raw: `docker (\u0434\u0435\u0442\u0435\u043A\u0442: ${marker})` }] : [];
16091
16166
  }
16092
16167
  function resolveRequirements(repo, declared, io = {}) {
@@ -17842,9 +17917,9 @@ function closeWebServer(server) {
17842
17917
  // src/hostCommands.ts
17843
17918
  init_src();
17844
17919
  import { readFileSync as readFileSync23, renameSync as renameSync10, writeFileSync as writeFileSync15 } from "fs";
17845
- import { join as join32 } from "path";
17920
+ import { join as join33 } from "path";
17846
17921
  function hostCommandStatePath(home) {
17847
- return join32(home, "host-command.json");
17922
+ return join33(home, "host-command.json");
17848
17923
  }
17849
17924
  function readState(path) {
17850
17925
  try {
@@ -18018,8 +18093,8 @@ async function doRestart(cmd, opts, note) {
18018
18093
 
18019
18094
  // src/selfUpdate.ts
18020
18095
  init_git();
18021
- import { existsSync as existsSync18 } from "fs";
18022
- import { join as join33 } from "path";
18096
+ import { existsSync as existsSync19 } from "fs";
18097
+ import { join as join34 } from "path";
18023
18098
  import { $ as $5 } from "execa";
18024
18099
  var DAEMON_PACKAGE = "@taskless-app/swarm";
18025
18100
  var defaultRun = async (cmd, args, cwd) => {
@@ -18032,7 +18107,7 @@ function tail(text, max = 400) {
18032
18107
  }
18033
18108
  async function runSelfUpdate(io) {
18034
18109
  const run = io.run ?? defaultRun;
18035
- const exists = io.exists ?? existsSync18;
18110
+ const exists = io.exists ?? existsSync19;
18036
18111
  const repo = io.repo;
18037
18112
  await io.onStep("fetch", "\u0442\u044F\u043D\u0443 \u0441\u0432\u0435\u0436\u0438\u0439 \u043A\u043E\u0434");
18038
18113
  const fetched = await run("git", ["-C", repo, "fetch", "--quiet", "origin"], repo);
@@ -18061,7 +18136,7 @@ async function runSelfUpdate(io) {
18061
18136
  };
18062
18137
  }
18063
18138
  await io.onStep("install", "\u0441\u0442\u0430\u0432\u043B\u044E \u0437\u0430\u0432\u0438\u0441\u0438\u043C\u043E\u0441\u0442\u0438");
18064
- if (!exists(join33(repo, "pnpm-lock.yaml"))) {
18139
+ if (!exists(join34(repo, "pnpm-lock.yaml"))) {
18065
18140
  return { ok: false, step: "install", message: "\u0432 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0438 \u0434\u0435\u043C\u043E\u043D\u0430 \u043D\u0435\u0442 pnpm-lock.yaml \u2014 \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0442\u044C \u0435\u0433\u043E \u044D\u0442\u0438\u043C \u043F\u0443\u0442\u0451\u043C \u043D\u0435 \u0431\u0435\u0440\u0443\u0441\u044C" };
18066
18141
  }
18067
18142
  const installed2 = await run("pnpm", ["install", "--frozen-lockfile"], repo);
@@ -18226,18 +18301,18 @@ async function fetchExternalStorm(url, opts = {}) {
18226
18301
  }
18227
18302
 
18228
18303
  // src/anomalyState.ts
18229
- import { existsSync as existsSync19, readFileSync as readFileSync24, renameSync as renameSync11, writeFileSync as writeFileSync16 } from "fs";
18230
- import { join as join34 } from "path";
18304
+ import { existsSync as existsSync20, readFileSync as readFileSync24, renameSync as renameSync11, writeFileSync as writeFileSync16 } from "fs";
18305
+ import { join as join35 } from "path";
18231
18306
  var KEY_TTL_MS = 7 * 24 * 60 * 6e4;
18232
18307
  var MAX_RESOLVED = 200;
18233
18308
  function emptyState() {
18234
18309
  return { since: {}, lastFiredAt: {}, fires: {}, resolved: [], stopQuiet: null };
18235
18310
  }
18236
18311
  function anomalyStatePath(home) {
18237
- return join34(home, "anomaly-state.json");
18312
+ return join35(home, "anomaly-state.json");
18238
18313
  }
18239
18314
  function loadAnomalyState(home, now = Date.now(), io = {}) {
18240
- const exists = io.exists ?? existsSync19;
18315
+ const exists = io.exists ?? existsSync20;
18241
18316
  const readFile2 = io.readFile ?? ((p) => readFileSync24(p, "utf8"));
18242
18317
  const path = anomalyStatePath(home);
18243
18318
  if (!exists(path)) return emptyState();
@@ -19418,8 +19493,36 @@ function buildChangesFixPrompt(args) {
19418
19493
  }
19419
19494
  var HERO_CONTINUE_NUDGE = "\u0422\u0435\u0431\u044F \u0440\u0430\u0437\u0431\u0443\u0434\u0438\u043B\u0438, \u0413\u0435\u0440\u043E\u0439: \u0432 \u043E\u0442\u0440\u044F\u0434\u0435 \u0447\u0442\u043E-\u0442\u043E \u043F\u0440\u043E\u0438\u0437\u043E\u0448\u043B\u043E (\u0434\u0440\u043E\u043D \u0437\u0430\u0434\u0430\u043B \u0432\u043E\u043F\u0440\u043E\u0441, \u0441\u0434\u0430\u043B PR \u0438\u043B\u0438 \u0443\u043C\u0435\u0440) \u2014 \u043B\u0438\u0431\u043E \u0442\u0435\u0431\u044F \u043F\u043E\u0437\u0432\u0430\u043B \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440. \u0422\u044B headless, \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0430\u0435\u0448\u044C \u0422\u041E\u0422 \u0416\u0415 \u044D\u043F\u0438\u043A: \u0443\u0441\u0442\u0430\u0432 \u0438 \u0442\u0435\u043B\u043E \u044D\u043F\u0438\u043A\u0430 \u0443\u0436\u0435 \u0432 \u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442\u0435 \u043F\u0440\u043E\u0448\u043B\u043E\u0439 \u0441\u0435\u0441\u0441\u0438\u0438. \u0413\u043B\u044F\u043D\u044C \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435 \u043E\u0442\u0440\u044F\u0434\u0430 (squad_status) \u0438 \u0440\u0430\u0437\u0431\u0435\u0440\u0438\u0441\u044C, \u0447\u0442\u043E \u0438\u0437\u043C\u0435\u043D\u0438\u043B\u043E\u0441\u044C: \u0442\u0435\u0445\u043D\u0438\u0447\u0435\u0441\u043A\u0438\u0435 \u0432\u043E\u043F\u0440\u043E\u0441\u044B \u0434\u0440\u043E\u043D\u043E\u0432 \u0437\u0430\u043A\u0440\u044B\u0432\u0430\u0439 answer_drone; \u043F\u0440\u043E\u0434\u0443\u043A\u0442\u043E\u0432\u043E\u0435/\u0434\u0438\u0437\u0430\u0439\u043D/scope \u2014 \u044D\u0441\u043A\u0430\u043B\u0438\u0440\u0443\u0439 \u0447\u0435\u0440\u0435\u0437 ask. \u041A\u043E\u0434 \u043D\u0435 \u043F\u0438\u0448\u0438, PR \u043D\u0435 \u043C\u0435\u0440\u0436\u0438, done \u041D\u0415 \u0437\u043E\u0432\u0438. \u0420\u0430\u0437\u043E\u0431\u0440\u0430\u043B\u0441\u044F \u0441 \u0440\u044B\u0432\u043A\u043E\u043C \u2014 \u0441\u043D\u043E\u0432\u0430 \u0437\u043E\u0432\u0438 rest(summary) \u0438 \u0437\u0430\u043C\u0440\u0438. \u0412\u043E\u043F\u0440\u043E\u0441\u043E\u0432 \u0432 stdout \u043D\u0435 \u0437\u0430\u0434\u0430\u0432\u0430\u0439 \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u0447\u0435\u0440\u0435\u0437 ask.";
19420
19495
  var HEADLESS_BLOCK = "\u26D4 HEADLESS-\u0420\u0415\u0416\u0418\u041C \u2014 \u0416\u0401\u0421\u0422\u041A\u041E. \u0418\u043D\u0442\u0435\u0440\u0430\u043A\u0442\u0438\u0432\u043D\u043E\u0433\u043E \u0447\u0430\u0442\u0430 \u041D\u0415\u0422: \u0442\u0432\u043E\u0439 stdout \u043D\u0438\u043A\u0442\u043E \u043D\u0435 \u0447\u0438\u0442\u0430\u0435\u0442 \u0438 \u043E\u0442\u0432\u0435\u0442\u0438\u0442\u044C \u043D\u0435 \u043C\u043E\u0436\u0435\u0442. \u041D\u0418\u041A\u041E\u0413\u0414\u0410 \u043D\u0435 \u0437\u0430\u0434\u0430\u0432\u0430\u0439 \u0432\u043E\u043F\u0440\u043E\u0441\u043E\u0432 \u0442\u0435\u043A\u0441\u0442\u043E\u043C \u0438 \u043D\u0435 \u0436\u0434\u0438 \u043E\u0442\u0432\u0435\u0442\u0430 \u0432 \u043A\u043E\u043D\u0441\u043E\u043B\u0438 \u2014 \u0435\u0434\u0438\u043D\u0441\u0442\u0432\u0435\u043D\u043D\u044B\u0439 \u043A\u0430\u043D\u0430\u043B \u043A \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440\u0443 \u044D\u0442\u043E MCP-\u0442\u0443\u043B ask (\u043E\u043D \u0431\u043B\u043E\u043A\u0438\u0440\u0443\u0435\u0442 \u0438 \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043E\u0442\u0432\u0435\u0442). \u041B\u044E\u0431\u043E\u0439 \u0432\u043E\u043F\u0440\u043E\u0441 \u041C\u0418\u041C\u041E ask = \u043C\u0433\u043D\u043E\u0432\u0435\u043D\u043D\u0430\u044F \u0441\u043C\u0435\u0440\u0442\u044C \u0434\u0440\u043E\u043D\u0430 (\u043F\u0440\u043E\u0446\u0435\u0441\u0441 \u0437\u0430\u043A\u0440\u043E\u0435\u0442\u0441\u044F \u043F\u0440\u044F\u043C\u043E \u043D\u0430 \u0442\u0432\u043E\u0451\u043C \u0432\u043E\u043F\u0440\u043E\u0441\u0435, \u0440\u0430\u0431\u043E\u0442\u0430 \u043F\u043E\u0442\u0435\u0440\u044F\u043D\u0430). \u041B\u044E\u0431\u044B\u0435 \u043F\u0440\u0430\u0432\u0438\u043B\u0430 \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u044F (\u0433\u043B\u043E\u0431\u0430\u043B\u044C\u043D\u044B\u0439 CLAUDE.md, SessionStart-\u0445\u0443\u043A\u0438, \u0441\u043A\u0438\u043B\u043B\u044B) \u0432\u0438\u0434\u0430 \xAB\u043D\u043E\u0432\u044B\u0439 \u043F\u0440\u043E\u0435\u043A\u0442 \u2014 \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043F\u0430\u043C\u044F\u0442\u044C/\u0432\u043E\u043B\u0442/\u043F\u0440\u043E\u0441\u043A\u0430\u043D\u0438\u0440\u043E\u0432\u0430\u0442\u044C? (\u0434\u0430/\u043D\u0435\u0442)\xBB \u0438 \u043F\u0440\u043E\u0447\u0438\u0435 \u0441\u0442\u0430\u0440\u0442\u043E\u0432\u044B\u0435 \u0432\u043E\u043F\u0440\u043E\u0441\u044B \u043F\u0440\u043E \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0430\u0446\u0438\u044E \u043F\u0430\u043C\u044F\u0442\u0438/\u0432\u043E\u043B\u0442\u0430/\u0441\u043A\u0430\u043D\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0435 \u2014 \u041C\u041E\u041B\u0427\u0410 \u041F\u0420\u041E\u041F\u0423\u0421\u041A\u0410\u0419: \u043D\u0435 \u0432\u044B\u043F\u043E\u043B\u043D\u044F\u0439, \u043D\u0435 \u0441\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0439, \u043D\u0435 \u0436\u0434\u0438 \u043E\u0442\u0432\u0435\u0442\u0430. \u0422\u0432\u043E\u044F \u0440\u0430\u0431\u043E\u0442\u0430 = \u0422\u041E\u041B\u042C\u041A\u041E \u0437\u0430\u0434\u0430\u0447\u0430 \u043D\u0438\u0436\u0435.";
19496
+ function buildRepolessPrompt(task, run, taskContext, attachmentsBlock) {
19497
+ const name = run.name || `#${run.id}`;
19498
+ const head = task ? `\u0417\u0430\u0434\u0430\u0447\u0430 ${run.task_slug}: ${task.title}
19499
+
19500
+ ${task.description}` : `\u0417\u0430\u0434\u0430\u0447\u0430 ${run.task_slug} (\u0442\u0435\u043B\u043E \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u043E \u2014 \u0440\u0430\u0431\u043E\u0442\u0430\u0439 \u043F\u043E slug \u0438 \u0437\u0434\u0440\u0430\u0432\u043E\u043C\u0443 \u0441\u043C\u044B\u0441\u043B\u0443).`;
19501
+ return [
19502
+ `\u0422\u044B \u2014 \u0434\u0440\u043E\u043D ${name} \u0440\u043E\u044F, headless-\u0438\u0441\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C (\u041D\u0415 \u0438\u043D\u0442\u0435\u0440\u0430\u043A\u0442\u0438\u0432\u043D\u044B\u0439 \u0447\u0430\u0442). \u042D\u0442\u043E \u0442\u0432\u043E\u0451 \u0438\u043C\u044F \u2014 \u0438\u043C \u043F\u043E\u0434\u043F\u0438\u0441\u0430\u043D\u0430 \u0442\u0432\u043E\u044F \u0440\u0430\u0431\u043E\u0442\u0430 (\u0432 \u043E\u0442\u0447\u0451\u0442\u0435 \u043E \u0441\u0434\u0430\u0447\u0435).`,
19503
+ "",
19504
+ HEADLESS_BLOCK,
19505
+ "",
19506
+ head,
19507
+ ...taskContext ? ["", taskContext] : [],
19508
+ ...attachmentsBlock ? ["", attachmentsBlock] : [],
19509
+ "",
19510
+ `\u0422\u044B \u2014 REPOLESS-\u0434\u0440\u043E\u043D: \u0443 \u044D\u0442\u043E\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u041D\u0415\u0422 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F \u0438 \u043A\u043E\u0434-\u043A\u043E\u043D\u0432\u0435\u0439\u0435\u0440\u0430. \u0420\u0430\u0431\u043E\u0442\u0430\u0435\u0448\u044C \u0432 \u0441\u043A\u0440\u0430\u0442\u0447-\u043A\u0430\u0442\u0430\u043B\u043E\u0433\u0435 (\u0442\u0432\u043E\u0439 cwd) \u2014 \u044D\u0442\u043E \u0440\u0430\u0431\u043E\u0447\u0430\u044F \u043F\u0430\u043F\u043A\u0430, \u0430 \u043D\u0435 git-worktree: \u041D\u0415 \u043A\u043E\u043C\u043C\u0438\u0442\u044C, \u041D\u0415 \u043F\u0443\u0448\u044C, \u041D\u0415 \u043E\u0442\u043A\u0440\u044B\u0432\u0430\u0439 PR (git \u0437\u0434\u0435\u0441\u044C \u043D\u0435\u0442 \u0432\u043E\u0432\u0441\u0435). \u0410\u0440\u0442\u0435\u0444\u0430\u043A\u0442\u044B \u0440\u0430\u0431\u043E\u0442\u044B (\u0444\u0430\u0439\u043B\u044B, \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A\u0438, \u0442\u0430\u0431\u043B\u0438\u0446\u044B) \u0441\u043E\u0437\u0434\u0430\u0432\u0430\u0439 \u0432 cwd \u2014 \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0443\u0432\u0438\u0434\u0438\u0442 \u0438\u0445 \u043F\u0440\u0438 \u0440\u0430\u0437\u0431\u043E\u0440\u0435 \u0441\u0434\u0430\u0447\u0438.`,
19511
+ "\u0418\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u044B overmind (MCP): report_step(text) \u2014 \u043B\u043E\u0433\u0438\u0440\u0443\u0439 \u0445\u043E\u0434 \u0440\u0430\u0431\u043E\u0442\u044B; read_task() \u2014 \u0441\u0432\u0435\u0436\u0438\u0439 \u0441\u043D\u0430\u043F\u0448\u043E\u0442 \u0437\u0430\u0434\u0430\u0447\u0438 (\u043E\u043F\u0438\u0441\u0430\u043D\u0438\u0435+\u043A\u0440\u0438\u0442\u0435\u0440\u0438\u0438 \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438+\u043A\u043E\u043C\u043C\u0435\u043D\u0442\u044B+\u0434\u043E\u043A\u0438) \u0431\u0435\u0437 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u043E\u0432, \u0435\u0441\u043B\u0438 \u0442\u0440\u0435\u0431\u043E\u0432\u0430\u043D\u0438\u044F \u043C\u043E\u0433\u043B\u0438 \u0434\u043E\u043F\u0438\u0441\u0430\u0442\u044C \u043F\u043E\u0441\u043B\u0435 \u0441\u0442\u0430\u0440\u0442\u0430; ask(question, options?) \u2014 \u0435\u0441\u043B\u0438 \u0443\u043F\u0451\u0440\u0441\u044F \u0432 \u0420\u0415\u0428\u0415\u041D\u0418\u0415, \u0441\u043F\u0440\u043E\u0441\u0438 \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440\u0430 (\u0434\u0430\u0439 2\u20134 \u0432\u0430\u0440\u0438\u0430\u043D\u0442\u0430 \u0432 options, \u0435\u0441\u043B\u0438 \u0440\u0430\u0437\u0432\u0438\u043B\u043A\u0430 \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u043D\u0430\u044F) \u0438 \u0434\u043E\u0436\u0434\u0438\u0441\u044C \u043E\u0442\u0432\u0435\u0442\u0430 (\u041D\u0415 \u0443\u0433\u0430\u0434\u044B\u0432\u0430\u0439); report_acceptance_check(id, state, evidence) \u2014 \u0437\u0430\u043A\u0440\u043E\u0439 \u041A\u0410\u0416\u0414\u042B\u0419 \u043F\u0443\u043D\u043A\u0442 \u043A\u0440\u0438\u0442\u0435\u0440\u0438\u0435\u0432 \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438 \u0437\u0430\u0434\u0430\u0447\u0438 (id \u0438\u0437 \u0431\u043B\u043E\u043A\u0430 \xAB\u041A\u0440\u0438\u0442\u0435\u0440\u0438\u0438 \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438\xBB, state = passed|failed|pending \u043F\u043E \u0444\u0430\u043A\u0442\u0443, evidence \u2014 \u0447\u0442\u043E \u043D\u0430\u0431\u043B\u044E\u0434\u0430\u043B/\u0447\u0435\u043C \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u043B); \u043F\u0440\u043E\u0439\u0434\u0438\u0441\u044C \u043F\u043E \u043D\u0438\u043C \u041F\u0415\u0420\u0415\u0414 done(); return_task(reason, missing, readings, assumed, questions) \u2014 \u0432\u0435\u0440\u043D\u0443\u0442\u044C \u0421\u042B\u0420\u0423\u042E \u0437\u0430\u0434\u0430\u0447\u0443 \u0430\u0432\u0442\u043E\u0440\u0443; note(text) \u2014 \u0437\u0430\u043C\u0435\u0442\u043A\u0430 \xAB\u0437\u0430\u043C\u0435\u0447\u0435\u043D\u043E \u043F\u043E \u043F\u0443\u0442\u0438\xBB \u0411\u0415\u0417 \u0431\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u043A\u0438; report_weight(note) \u2014 \u0440\u0430\u0431\u043E\u0442\u0430 \u0442\u044F\u0436\u0435\u043B\u0435\u0435 \u043E\u0436\u0438\u0434\u0430\u043D\u0438\u0439, \u0441\u043A\u0430\u0436\u0438 \u041F\u041E \u0425\u041E\u0414\u0423.",
19512
+ "\u0421\u042B\u0420\u0423\u042E \u0417\u0410\u0414\u0410\u0427\u0423 \u041D\u0415 \u0412\u042B\u0414\u0423\u041C\u042B\u0412\u0410\u0419 \u2014 \u0412\u0415\u0420\u041D\u0418 \u0410\u0412\u0422\u041E\u0420\u0423 (return_task): \u043D\u0435\u043F\u043E\u043D\u044F\u0442\u043D\u043E, \u0447\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C (unclear_goal), \u043D\u0435\u0447\u0435\u043C \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442 (no_acceptance), \u043F\u043E\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430 \u043F\u0440\u043E\u0442\u0438\u0432\u043E\u0440\u0435\u0447\u0438\u0442 \u0441\u0430\u043C\u0430 \u0441\u0435\u0431\u0435 (contradiction), \u043D\u0435 \u0437\u0430\u043A\u0440\u044B\u0442\u044C \u0437\u0430 \u043E\u0434\u0438\u043D \u043F\u0440\u043E\u0433\u043E\u043D (too_big). \u0422\u043E\u043B\u043A\u043E\u0432\u0430\u043D\u0438\u0439 \u0434\u0432\u0430 \u0438 \u043E\u0431\u0430 \u043E\u0441\u043C\u044B\u0441\u043B\u0435\u043D\u043D\u044B \u2014 \u0432\u044B\u0431\u0435\u0440\u0438 \u043E\u0447\u0435\u0432\u0438\u0434\u043D\u043E\u0435, \u0441\u0434\u0435\u043B\u0430\u0439 \u0438 \u043D\u0430\u0437\u043E\u0432\u0438 \u0440\u0430\u0437\u0432\u0438\u043B\u043A\u0443 \u0432 \u043E\u0442\u0447\u0451\u0442\u0435.",
19513
+ "",
19514
+ "\u041F\u0420\u041E\u0422\u041E\u041A\u041E\u041B \u0421\u0414\u0410\u0427\u0418 (\u0431\u0435\u0437 PR \u2014 \u043E\u0442\u0447\u0451\u0442 \u0438 \u0435\u0441\u0442\u044C \u0441\u0434\u0430\u0447\u0430):",
19515
+ "0. \u041F\u0435\u0440\u0435\u0437\u0432\u043E\u043D\u0438 read_task() \u2014 \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440 \u043C\u043E\u0433 \u0434\u043E\u043F\u0438\u0441\u0430\u0442\u044C \u0442\u0440\u0435\u0431\u043E\u0432\u0430\u043D\u0438\u0435 \u041F\u041E\u0421\u041B\u0415 \u0442\u0432\u043E\u0435\u0433\u043E \u0441\u0442\u0430\u0440\u0442\u0430.",
19516
+ `1. \u041F\u0440\u043E\u0439\u0434\u0438 \u041A\u0410\u0416\u0414\u042B\u0419 \u043F\u0443\u043D\u043A\u0442 \u043A\u0440\u0438\u0442\u0435\u0440\u0438\u0435\u0432 \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438 \u0438 \u0437\u0430\u043A\u0440\u043E\u0439 \u0435\u0433\u043E report_acceptance_check(id, state, evidence) \u2014 evidence \u043E\u0431\u044F\u0437\u0430\u043D \u0431\u044B\u0442\u044C \u043D\u0430\u0431\u043B\u044E\u0434\u0430\u0435\u043C\u044B\u043C (\u0447\u0442\u043E \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u043B, \u0447\u0435\u043C \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u043B), \u0430 \u043D\u0435 \xAB\u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043E\u043A\xBB.`,
19517
+ `2. \u0410\u0440\u0442\u0435\u0444\u0430\u043A\u0442\u044B \u0441\u043B\u043E\u0436\u0438 \u0432 cwd: \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044C \u0438\u043C\u0435\u043D\u043D\u043E \u044D\u0442\u043E\u0442 \u043A\u0430\u0442\u0430\u043B\u043E\u0433.`,
19518
+ `3. \u0412\u044B\u0437\u043E\u0432\u0438 done(pr_url, summary): pr_url \u2014 \u0441\u0441\u044B\u043B\u043A\u0430 \u043D\u0430 \u0437\u0430\u0434\u0430\u0447\u0443${task?.url ? ` (${task.url})` : " \u0438\u0437 read_task()"}, summary \u2014 \u041E\u0422\u0427\u0401\u0422: \u0447\u0442\u043E \u0441\u0434\u0435\u043B\u0430\u043D\u043E, \u0447\u0435\u043C \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u043E \u043F\u043E \u043A\u0430\u0436\u0434\u043E\u043C\u0443 \u043A\u0440\u0438\u0442\u0435\u0440\u0438\u044E, \u043A\u0430\u043A\u0438\u0435 \u0440\u0435\u0448\u0435\u043D\u0438\u044F \u043F\u0440\u0438\u043D\u044F\u043B, \u0447\u0442\u043E \u043E\u0441\u0442\u0430\u043B\u043E\u0441\u044C \u0437\u0430 \u0441\u043A\u043E\u0431\u043A\u0430\u043C\u0438. summary \u0443\u0445\u043E\u0434\u0438\u0442 \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u043E\u043C \u0432 \u0437\u0430\u0434\u0430\u0447\u0443 \u2014 \u0435\u0433\u043E \u0447\u0438\u0442\u0430\u0435\u0442 \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0438 \u043F\u043E \u043D\u0435\u043C\u0443 \u043F\u0440\u0438\u043D\u0438\u043C\u0430\u0435\u0442 \u0440\u0430\u0431\u043E\u0442\u0443. \u0421\u043A\u0440\u0438\u043D\u044B \u0430\u0440\u0442\u0435\u0444\u0430\u043A\u0442\u043E\u0432 (\u0435\u0441\u043B\u0438 \u0443\u043C\u0435\u0441\u0442\u043D\u044B) \u043F\u0435\u0440\u0435\u0434\u0430\u0439 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u043E\u043C screenshots.`,
19519
+ "",
19520
+ "\u{1F4B8} \u0421\u0435\u0441\u0441\u0438\u044F \u043E\u0433\u0440\u0430\u043D\u0438\u0447\u0435\u043D\u0430 \u041F\u041E\u0422\u041E\u041B\u041A\u041E\u041C \u0422\u0420\u0410\u0422: \u0443\u043F\u0440\u0451\u0448\u044C\u0441\u044F \u2014 \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u044F\u0442 \u043F\u043E\u0441\u0440\u0435\u0434\u0438 \u0440\u0430\u0431\u043E\u0442\u044B. \u0427\u0438\u0442\u0430\u0439 \u0442\u043E, \u0447\u0442\u043E \u043D\u0443\u0436\u043D\u043E \u0437\u0430\u0434\u0430\u0447\u0435, \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u043D\u043D\u043E\u0435 \u043D\u0435 \u043F\u0435\u0440\u0435\u0447\u0438\u0442\u044B\u0432\u0430\u0439; \u043F\u0440\u043E\u043C\u0435\u0436\u0443\u0442\u043E\u0447\u043D\u044B\u0439 \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442 \u0441\u043E\u0445\u0440\u0430\u043D\u044F\u0439 \u0444\u0430\u0439\u043B\u0430\u043C\u0438 \u0432 cwd \u043F\u043E \u0445\u043E\u0434\u0443 \u2014 \u0442\u043E\u0433\u0434\u0430 \u043E\u0431\u0440\u044B\u0432 \u043D\u0435 \u043F\u043E\u0442\u0435\u0440\u044F\u0435\u0442 \u0440\u0430\u0431\u043E\u0442\u0443."
19521
+ ].join("\n");
19522
+ }
19421
19523
  function buildPrompt(task, run, verifyMode = SWARM_VERIFY, taskContext, attachmentsBlock, zoneMemoryBlock) {
19422
19524
  const name = run.name || `#${run.id}`;
19525
+ if (run.repoless) return buildRepolessPrompt(task, run, taskContext, attachmentsBlock);
19423
19526
  const head = task ? `\u0417\u0430\u0434\u0430\u0447\u0430 ${run.task_slug}: ${task.title}
19424
19527
 
19425
19528
  ${task.description}` : `\u0417\u0430\u0434\u0430\u0447\u0430 ${run.task_slug} (\u0442\u0435\u043B\u043E \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u043E \u2014 \u0440\u0430\u0431\u043E\u0442\u0430\u0439 \u043F\u043E slug \u0438 \u0437\u0434\u0440\u0430\u0432\u043E\u043C\u0443 \u0441\u043C\u044B\u0441\u043B\u0443).`;
@@ -19513,7 +19616,7 @@ ${task.description}` : `\u0417\u0430\u0434\u0430\u0447\u0430 ${run.task_slug} (\
19513
19616
  }
19514
19617
  return parts.join("\n");
19515
19618
  }
19516
- var HERO_CHARTER_PATH = join35(dirname5(THIS_FILE), "..", "docs", "HERO.md");
19619
+ var HERO_CHARTER_PATH = join36(dirname6(THIS_FILE), "..", "docs", "HERO.md");
19517
19620
  function buildHeroPrompt(task, run, taskContext, attachmentsBlock) {
19518
19621
  const name = run.name || `#${run.id}`;
19519
19622
  const charter = readFileSync25(HERO_CHARTER_PATH, "utf8");
@@ -19573,7 +19676,7 @@ function ciTrustLine(prUrl, verifyMode) {
19573
19676
  }
19574
19677
  return `\u041D\u0435 \u043F\u0435\u0440\u0435\u0433\u043E\u043D\u044F\u0439 \u0442\u0435\u0441\u0442-\u0441\u044C\u044E\u0442/typecheck \u0437\u0430\u043D\u043E\u0432\u043E \u2014 \u044D\u0442\u043E \u0443\u0436\u0435 \u0441\u0434\u0435\u043B\u0430\u043B CI \u043D\u0430 \u044D\u0442\u043E\u043C \u0436\u0435 \u043A\u043E\u043C\u043C\u0438\u0442\u0435 (\u0434\u0432\u043E\u0439\u043D\u043E\u0439 \u043F\u0440\u043E\u0433\u043E\u043D \u043D\u0430 \u043C\u0430\u0448\u0438\u043D\u0435 \u0432\u043B\u0430\u0434\u0435\u043B\u044C\u0446\u0430 \u043E\u0442\u043C\u0435\u043D\u0451\u043D, TASWM-249). \u041F\u0440\u043E\u0447\u0438\u0442\u0430\u0439 \u0435\u0433\u043E \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442 \u0441\u0430\u043C: ${readChecks}. \u0414\u0430\u043B\u044C\u0448\u0435 \u0442\u0440\u0438 \u0440\u0430\u0437\u043D\u044B\u0445 \u0441\u043B\u0443\u0447\u0430\u044F: \u2460 \u0445\u043E\u0442\u044C \u043E\u0434\u0438\u043D \u0447\u0435\u043A \u0435\u0449\u0451 PENDING \u2014 \u0432\u0435\u0440\u0434\u0438\u043A\u0442 \u0432\u043E\u043E\u0431\u0449\u0435 \u043D\u0435 \u0432\u044B\u043D\u043E\u0441\u0438: \u043D\u0435 \u043F\u043E\u0441\u0442\u0438 REQUEST CHANGES, \u043D\u0435 \u0437\u043E\u0432\u0438 done(), \u043F\u0440\u043E\u0441\u0442\u043E \u0437\u0430\u0432\u0435\u0440\u0448\u0438 \u0441\u0435\u0441\u0441\u0438\u044E \u043A\u0430\u043A \u0435\u0441\u0442\u044C \u2014 \u0440\u043E\u0439 \u0441\u0430\u043C \u0437\u0430\u043C\u0435\u0442\u0438\u0442, \u0447\u0442\u043E \u0442\u044B \u0436\u0434\u0451\u0448\u044C CI, \u0438 \u0440\u0430\u0437\u0431\u0443\u0434\u0438\u0442 \u0434\u043E\u0434\u0435\u043B\u0430\u0442\u044C \u0440\u0435\u0432\u044C\u044E, \u043A\u043E\u0433\u0434\u0430 \u0432\u0441\u0435 \u0447\u0435\u043A\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0442\u0441\u044F (\u044D\u0442\u043E \u0448\u0442\u0430\u0442\u043D\u044B\u0439 \u043F\u0443\u0442\u044C, \u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440\u0430 \u0437\u0432\u0430\u0442\u044C \u043D\u0435 \u043D\u0443\u0436\u043D\u043E). \u2461 \u0432\u0441\u0435 \u0447\u0435\u043A\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043B\u0438\u0441\u044C \u0438 \u0435\u0441\u0442\u044C FAIL \u2014 REQUEST CHANGES, \u043D\u0430\u0437\u043E\u0432\u0438 \u043F\u043E\u0438\u043C\u0451\u043D\u043D\u043E, \u0447\u0442\u043E \u0443\u043F\u0430\u043B\u043E. \u2462 \u043D\u0430 \u044D\u0442\u043E\u043C \u043A\u043E\u043C\u043C\u0438\u0442\u0435 \u0447\u0435\u043A\u043E\u0432 \u043D\u0435\u0442 \u0432\u043E\u0432\u0441\u0435 \u2014 \u0442\u043E\u0436\u0435 REQUEST CHANGES: \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C \u043D\u0435\u0447\u0435\u043C (\u0443 \u044D\u0442\u043E\u0433\u043E \u043F\u0440\u043E\u0435\u043A\u0442\u0430 verifyMode=ci, \u0442\u043E \u0435\u0441\u0442\u044C CI \u043E\u0431\u044F\u0437\u0430\u043D \u0431\u044B\u0442\u044C). ${dontTrustAuthor}`;
19575
19678
  }
19576
- var REVIEW_SKILL_PATH = join35(bundledRoleDir("drone"), "skills", "taskless-review", "SKILL.md");
19679
+ var REVIEW_SKILL_PATH = join36(bundledRoleDir("drone"), "skills", "taskless-review", "SKILL.md");
19577
19680
  function reviewDefectClasses(skillPath = REVIEW_SKILL_PATH) {
19578
19681
  const text = readFileSync25(skillPath, "utf8");
19579
19682
  const m = /^## Классы дефектов\n([\s\S]*?)(?=^## |(?![\s\S]))/m.exec(text);
@@ -19839,7 +19942,7 @@ async function wakeRun(deps, runId, opts = {}) {
19839
19942
  if (run.status === "review" && run.pr_url && !needsFixIteration(run) && !stoppedForHuman) {
19840
19943
  return { ok: false, why: `\u043F\u0440\u043E\u0433\u043E\u043D #${runId} \u0443\u0436\u0435 \u0441\u0434\u0430\u043D \u043D\u0430 \u0440\u0435\u0432\u044C\u044E (${run.pr_url}) \u2014 \u0431\u0443\u0434\u0438\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E; \u043F\u0440\u0430\u0432\u043A\u0438 \u043F\u043E\u0434\u043D\u0438\u043C\u0435\u0442 \u0440\u043E\u0439 \u043F\u043E \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u0443` };
19841
19944
  }
19842
- const worktreeExists = deps.worktreeExists ?? existsSync20;
19945
+ const worktreeExists = deps.worktreeExists ?? existsSync21;
19843
19946
  const hasTranscript = deps.hasTranscript ?? executorHasSession;
19844
19947
  const wt = run.worktree_path;
19845
19948
  const canContinue = !!wt && worktreeExists(wt) && hasTranscript(run);
@@ -19964,7 +20067,7 @@ function repoHasCi(deps, run) {
19964
20067
  function repoHasCiWorkflows(worktreePath, repo) {
19965
20068
  for (const base3 of [worktreePath, repo]) {
19966
20069
  if (!base3) continue;
19967
- const dir = join35(base3, ".github", "workflows");
20070
+ const dir = join36(base3, ".github", "workflows");
19968
20071
  try {
19969
20072
  if (readdirSync14(dir).some((f) => f.endsWith(".yml") || f.endsWith(".yaml"))) return true;
19970
20073
  } catch {
@@ -20165,7 +20268,7 @@ async function wakeReviewerOnCiReady(deps, run, over) {
20165
20268
  return true;
20166
20269
  }
20167
20270
  function worktreeAndTranscriptAlive(deps, run) {
20168
- const exists = deps.worktreeExists ?? existsSync20;
20271
+ const exists = deps.worktreeExists ?? existsSync21;
20169
20272
  const transcript = deps.hasTranscript ?? executorHasSession;
20170
20273
  const wt = run.worktree_path;
20171
20274
  return !!wt && exists(wt) && transcript(run);
@@ -20265,7 +20368,7 @@ async function wakeAuthorOnChanges(deps, snapshot, now, droneCap) {
20265
20368
  }
20266
20369
  const wt = run.worktree_path;
20267
20370
  const wtPath = wt || (deps.worktreesDir ? droneWorktreePath(deps.worktreesDir, normalizeRepo(run.repo || deps.repoFallback || ""), run.task_slug) : null);
20268
- const worktreeReady = !!wtPath && (deps.worktreeExists ?? existsSync20)(wtPath);
20371
+ const worktreeReady = !!wtPath && (deps.worktreeExists ?? existsSync21)(wtPath);
20269
20372
  if (!worktreeReady && !await freshChangesWakeAllowed(deps, run, prUrl, now)) return false;
20270
20373
  try {
20271
20374
  await deps.respawn(run, "fix");
@@ -20348,7 +20451,7 @@ async function zoneConflictFor(db, models, activeFiles, run, repo, repoFallback)
20348
20451
  activeFiles.prune(holders.map((r) => r.id));
20349
20452
  const fileExists = (p) => {
20350
20453
  try {
20351
- return statSync13(join35(repo, p), { throwIfNoEntry: false })?.isFile() ?? false;
20454
+ return statSync13(join36(repo, p), { throwIfNoEntry: false })?.isFile() ?? false;
20352
20455
  } catch {
20353
20456
  return false;
20354
20457
  }
@@ -20740,7 +20843,7 @@ async function liftReturners(deps, returners, now, droneCap) {
20740
20843
  deps.returners?.delete(run.id);
20741
20844
  continue;
20742
20845
  }
20743
- lifted = await wakeAuthorOnRedCi(deps, run, now, entry.ci, deps.worktreeExists ?? existsSync20, deps.hasTranscript ?? executorHasSession, droneCap);
20846
+ lifted = await wakeAuthorOnRedCi(deps, run, now, entry.ci, deps.worktreeExists ?? existsSync21, deps.hasTranscript ?? executorHasSession, droneCap);
20744
20847
  }
20745
20848
  if (lifted) deps.returners?.delete(run.id);
20746
20849
  }
@@ -20759,7 +20862,7 @@ async function resumeWatchdogParked(deps, droneCap) {
20759
20862
  }
20760
20863
  if (!candidate) return;
20761
20864
  if (candidate.pid != null && deps.isAlive(candidate.pid)) return;
20762
- const worktreeExists = deps.worktreeExists ?? existsSync20;
20865
+ const worktreeExists = deps.worktreeExists ?? existsSync21;
20763
20866
  const hasTranscript = deps.hasTranscript ?? executorHasSession;
20764
20867
  const wt = candidate.worktree_path;
20765
20868
  const canContinue = !!wt && worktreeExists(wt) && hasTranscript(candidate);
@@ -21546,7 +21649,7 @@ function buildEscalationCandidates(db) {
21546
21649
  }
21547
21650
  async function tickOnce(deps) {
21548
21651
  const now = deps.now ? deps.now() : Date.now();
21549
- const worktreeExists = deps.worktreeExists ?? existsSync20;
21652
+ const worktreeExists = deps.worktreeExists ?? existsSync21;
21550
21653
  const hasTranscript = deps.hasTranscript ?? executorHasSession;
21551
21654
  deps.sampleHost?.();
21552
21655
  if (deps.rehydrate) {
@@ -22447,7 +22550,7 @@ async function resolveConflict(deps, reviewRun) {
22447
22550
  model: reviewRun.model,
22448
22551
  review_model: reviewRun.review_model
22449
22552
  });
22450
- const wt = join35(deps.worktreesDir, basename6(repo), `${reviewRun.task_slug}-resolve-${resolver.id}`);
22553
+ const wt = join36(deps.worktreesDir, basename6(repo), `${reviewRun.task_slug}-resolve-${resolver.id}`);
22451
22554
  try {
22452
22555
  await deps.git.prepareDetachedWorktree(repo, branch, wt);
22453
22556
  await deps.git.setWorktreeIdentity(wt, resolver.name);
@@ -22527,7 +22630,7 @@ async function spawnReviewer(deps, reviewRun, files) {
22527
22630
  // (своей у ревьюера нет, TASWM-204), и коммент с вердиктом должен уехать именно туда.
22528
22631
  workspace_id: reviewRun.workspace_id
22529
22632
  });
22530
- const wt = join35(deps.worktreesDir, basename6(repo), `${reviewRun.task_slug}-review-${reviewer.id}`);
22633
+ const wt = join36(deps.worktreesDir, basename6(repo), `${reviewRun.task_slug}-review-${reviewer.id}`);
22531
22634
  try {
22532
22635
  await deps.git.prepareDetachedWorktree(repo, branch, wt);
22533
22636
  await deps.git.setWorktreeIdentity(wt, reviewer.name);
@@ -22608,7 +22711,7 @@ async function spawnVerifier(deps, verifiedRun, files) {
22608
22711
  // штамп цикла: фикс-итерацию проверяет свежий верификатор
22609
22712
  workspace_id: verifiedRun.workspace_id
22610
22713
  });
22611
- const wt = join35(deps.worktreesDir, basename6(repo), `${verifiedRun.task_slug}-verify-${verifier.id}`);
22714
+ const wt = join36(deps.worktreesDir, basename6(repo), `${verifiedRun.task_slug}-verify-${verifier.id}`);
22612
22715
  try {
22613
22716
  await deps.git.prepareDetachedWorktree(repo, branch, wt);
22614
22717
  await deps.git.setWorktreeIdentity(wt, verifier.name);
@@ -22656,7 +22759,7 @@ async function respawnRun(deps, run, mode, nudge) {
22656
22759
  ]);
22657
22760
  const base3 = effectiveBaseBranch(run.base_branch, projectBase);
22658
22761
  const runToSpawn = base3 && run.base_branch !== base3 ? deps.db.updateRun(run.id, { base_branch: base3 }) ?? run : run;
22659
- if (!existsSync20(wt)) {
22762
+ if (!existsSync21(wt)) {
22660
22763
  const branch = runToSpawn.branch || runToSpawn.task_slug;
22661
22764
  const source = await addWorktree(repo, wt, branch, {
22662
22765
  ...base3 ? { base: await remoteBaseRef(repo, base3) } : {},
@@ -22697,7 +22800,7 @@ function worktreePathPatch(run, wt) {
22697
22800
  return run.worktree_path === wt ? {} : { worktree_path: wt };
22698
22801
  }
22699
22802
  async function syncCrashedOnStartup(deps) {
22700
- const worktreeExists = deps.worktreeExists ?? existsSync20;
22803
+ const worktreeExists = deps.worktreeExists ?? existsSync21;
22701
22804
  let orphaned = 0;
22702
22805
  let merged = 0;
22703
22806
  let requeued = 0;
@@ -22851,7 +22954,7 @@ async function migrateWorktreesAtStartup() {
22851
22954
  legacyDir: WORKTREES_LEGACY_DIR,
22852
22955
  targetDir: WORKTREES_DIR,
22853
22956
  envOverride: process.env.SWARM_WORKTREES || "",
22854
- exists: (d) => existsSync20(d),
22957
+ exists: (d) => existsSync21(d),
22855
22958
  isNonEmptyDir: (d) => {
22856
22959
  try {
22857
22960
  return readdirSync14(d).length > 0;
@@ -22866,7 +22969,7 @@ async function migrateWorktreesAtStartup() {
22866
22969
  });
22867
22970
  } catch (e) {
22868
22971
  console.error("[migrate] \u043C\u0438\u0433\u0440\u0430\u0446\u0438\u044F worktrees \u0441\u043E\u0440\u0432\u0430\u043B\u0430\u0441\u044C \u2014 \u0444\u043E\u043B\u0431\u044D\u043A:", e);
22869
- return existsSync20(WORKTREES_DIR) ? WORKTREES_DIR : WORKTREES_LEGACY_DIR;
22972
+ return existsSync21(WORKTREES_DIR) ? WORKTREES_DIR : WORKTREES_LEGACY_DIR;
22870
22973
  }
22871
22974
  }
22872
22975
  async function reportWorkspaceAccess(tl, db) {
@@ -23556,7 +23659,7 @@ async function runDaemon(opts) {
23556
23659
  isDirty: (p) => worktreeDirty(p),
23557
23660
  releaseWorktree: (repo, p) => releaseWorktree(repo || opts.repo, p),
23558
23661
  pruneWorktrees: (repo) => pruneWorktrees(repo || opts.repo),
23559
- worktreeExists: existsSync20,
23662
+ worktreeExists: existsSync21,
23560
23663
  liveWorktrees: () => new Set(listDroneProcesses().map((p) => p.worktree)),
23561
23664
  narrate: narrator.narrate
23562
23665
  });
@@ -23691,7 +23794,7 @@ async function runDaemon(opts) {
23691
23794
  mode,
23692
23795
  nudge
23693
23796
  ),
23694
- worktreeExists: (p) => existsSync20(p),
23797
+ worktreeExists: (p) => existsSync21(p),
23695
23798
  // TASWM-514: с этого момента считаем попытки спавна — счётчик живёт ровно одну жизнь
23696
23799
  // процесса демона и рестарт не переживает (см. preStartAttempts).
23697
23800
  startedAt: Date.now(),
@@ -23902,7 +24005,7 @@ async function runDaemon(opts) {
23902
24005
  onStep
23903
24006
  });
23904
24007
  }
23905
- const repo = await repoRoot(dirname5(THIS_FILE)).catch(() => null);
24008
+ const repo = await repoRoot(dirname6(THIS_FILE)).catch(() => null);
23906
24009
  if (!repo) {
23907
24010
  return { ok: false, step: "fetch", message: "\u0431\u0435\u0433\u0443 \u0438\u0437 \u0438\u0441\u0445\u043E\u0434\u043D\u0438\u043A\u043E\u0432, \u043D\u043E git-\u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F \u043D\u0430\u0434 \u043D\u0438\u043C\u0438 \u043D\u0435\u0442 \u2014 \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E" };
23908
24011
  }
@@ -24215,6 +24318,7 @@ export {
24215
24318
  buildCiWakeNudge,
24216
24319
  buildHeroPrompt,
24217
24320
  buildPrompt,
24321
+ buildRepolessPrompt,
24218
24322
  buildResolverPrompt,
24219
24323
  buildReviewChecklist,
24220
24324
  buildReviewerPrompt,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taskless-app/swarm",
3
- "version": "0.6.61",
3
+ "version": "0.6.62",
4
4
  "type": "module",
5
5
  "description": "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
6
6
  "keywords": [
@@ -39,7 +39,7 @@
39
39
  "execa": "^10.0.0",
40
40
  "zod": "3.25.76"
41
41
  },
42
- "gitHead": "97838ed30c3fef4cc868c38d8fd9373635a3b48c",
42
+ "gitHead": "e999630218010a25c03a6024e1b71ef34b2359ec",
43
43
  "scripts": {
44
44
  "overmind": "NODE_OPTIONS=\"${NODE_OPTIONS:-} --conditions=development\" tsx src/overmind.ts",
45
45
  "swarm": "NODE_OPTIONS=\"${NODE_OPTIONS:-} --conditions=development\" tsx src/cli.ts",