@taskless-app/swarm 0.6.25 → 0.6.27

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.
Files changed (3) hide show
  1. package/dist/cli.js +84 -25
  2. package/dist/overmind.js +776 -419
  3. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -51,10 +51,12 @@ function isMilestoneKind(kind) {
51
51
  function toRunKind(role) {
52
52
  return role === "hero" || role === "reviewer" || role === "verifier" ? role : "drone";
53
53
  }
54
- var EVENT_KINDS, MILESTONE_KINDS, MILESTONE_KIND_SET;
54
+ var ACTIVE_DRONE_STATUSES, FILE_HOLDING_STATUSES, EVENT_KINDS, MILESTONE_KINDS, MILESTONE_KIND_SET;
55
55
  var init_types = __esm({
56
56
  "../swarm-core/src/types.ts"() {
57
57
  "use strict";
58
+ ACTIVE_DRONE_STATUSES = /* @__PURE__ */ new Set(["running", "blocked"]);
59
+ FILE_HOLDING_STATUSES = /* @__PURE__ */ new Set([...ACTIVE_DRONE_STATUSES, "review"]);
58
60
  EVENT_KINDS = [
59
61
  "spawned",
60
62
  "step",
@@ -338,26 +340,6 @@ var init_timeline = __esm({
338
340
  }
339
341
  });
340
342
 
341
- // ../swarm-core/src/reviewPhase.ts
342
- var REVIEW_PHASE_TEXT, PHASE_BY_LENGTH;
343
- var init_reviewPhase = __esm({
344
- "../swarm-core/src/reviewPhase.ts"() {
345
- "use strict";
346
- REVIEW_PHASE_TEXT = {
347
- checks: "\u0418\u0434\u0443\u0442 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438",
348
- awaiting_reviewer: "\u0417\u0435\u043B\u0451\u043D\u044B\u0439 \u2014 \u0436\u0434\u0451\u0442 \u0440\u0435\u0432\u044C\u044E\u0435\u0440\u0430",
349
- ci_fixing: "CI \u043A\u0440\u0430\u0441\u043D\u044B\u0439 \u2014 \u0434\u0440\u043E\u043D \u0447\u0438\u043D\u0438\u0442",
350
- in_review: "\u041D\u0430 \u0440\u0435\u0432\u044C\u044E",
351
- changes: "\u041D\u0443\u0436\u043D\u044B \u043F\u0440\u0430\u0432\u043A\u0438 \u2014 \u0434\u0440\u043E\u043D \u043F\u0440\u0430\u0432\u0438\u0442",
352
- ready: "\u0417\u0435\u043B\u0451\u043D\u044B\u0439 \u2014 \u0433\u043E\u0442\u043E\u0432 \u043A \u043C\u0435\u0440\u0436\u0443",
353
- reviewer_dead: "\u0420\u0435\u0432\u044C\u044E\u0435\u0440 \u0443\u043C\u0435\u0440 \u2014 \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u0430 \u043D\u0435\u0442, \u043D\u0443\u0436\u0435\u043D \u0447\u0435\u043B\u043E\u0432\u0435\u043A"
354
- };
355
- PHASE_BY_LENGTH = Object.keys(REVIEW_PHASE_TEXT).sort(
356
- (a, b) => REVIEW_PHASE_TEXT[b].length - REVIEW_PHASE_TEXT[a].length
357
- );
358
- }
359
- });
360
-
361
343
  // ../swarm-core/src/verifyVerdict.ts
362
344
  function isVerifyVerdict(v) {
363
345
  return typeof v === "string" && VERIFY_VERDICT_SET.has(v);
@@ -426,6 +408,31 @@ var init_verifyVerdict = __esm({
426
408
  }
427
409
  });
428
410
 
411
+ // ../swarm-core/src/reviewPhase.ts
412
+ var REVIEW_PHASE_TEXT, PHASE_BY_LENGTH;
413
+ var init_reviewPhase = __esm({
414
+ "../swarm-core/src/reviewPhase.ts"() {
415
+ "use strict";
416
+ init_verifyVerdict();
417
+ REVIEW_PHASE_TEXT = {
418
+ checks: "\u0418\u0434\u0443\u0442 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438",
419
+ awaiting_reviewer: "\u0417\u0435\u043B\u0451\u043D\u044B\u0439 \u2014 \u0436\u0434\u0451\u0442 \u0440\u0435\u0432\u044C\u044E\u0435\u0440\u0430",
420
+ ci_fixing: "CI \u043A\u0440\u0430\u0441\u043D\u044B\u0439 \u2014 \u0434\u0440\u043E\u043D \u0447\u0438\u043D\u0438\u0442",
421
+ in_review: "\u041D\u0430 \u0440\u0435\u0432\u044C\u044E",
422
+ changes: "\u041D\u0443\u0436\u043D\u044B \u043F\u0440\u0430\u0432\u043A\u0438 \u2014 \u0434\u0440\u043E\u043D \u043F\u0440\u0430\u0432\u0438\u0442",
423
+ verify_found: "\u0412\u0435\u0440\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u043D\u0430\u0448\u0451\u043B \u2014 \u043D\u0443\u0436\u043D\u044B \u043F\u0440\u0430\u0432\u043A\u0438",
424
+ verify_not_reproduced: "\u0412\u0435\u0440\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u043D\u0435 \u0432\u043E\u0441\u043F\u0440\u043E\u0438\u0437\u0432\u0451\u043B \u2014 \u043D\u0443\u0436\u043D\u044B \u043F\u0440\u0430\u0432\u043A\u0438",
425
+ awaiting_verify: "\u0417\u0435\u043B\u0451\u043D\u044B\u0439 \u2014 \u0436\u0434\u0451\u043C \u0432\u0435\u0440\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u044E",
426
+ verify_dead: "\u0412\u0435\u0440\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u043D\u0435 \u0434\u0430\u043B \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u0430 \u2014 \u043D\u0443\u0436\u0435\u043D \u0447\u0435\u043B\u043E\u0432\u0435\u043A",
427
+ ready: "\u0417\u0435\u043B\u0451\u043D\u044B\u0439 \u2014 \u0433\u043E\u0442\u043E\u0432 \u043A \u043C\u0435\u0440\u0436\u0443",
428
+ reviewer_dead: "\u0420\u0435\u0432\u044C\u044E\u0435\u0440 \u0443\u043C\u0435\u0440 \u2014 \u0432\u0435\u0440\u0434\u0438\u043A\u0442\u0430 \u043D\u0435\u0442, \u043D\u0443\u0436\u0435\u043D \u0447\u0435\u043B\u043E\u0432\u0435\u043A"
429
+ };
430
+ PHASE_BY_LENGTH = Object.keys(REVIEW_PHASE_TEXT).sort(
431
+ (a, b) => REVIEW_PHASE_TEXT[b].length - REVIEW_PHASE_TEXT[a].length
432
+ );
433
+ }
434
+ });
435
+
429
436
  // ../swarm-core/src/mergeGate.ts
430
437
  function computeMergeGate(input) {
431
438
  if (!input.hasRun) {
@@ -608,6 +615,24 @@ var init_prRef = __esm({
608
615
  }
609
616
  });
610
617
 
618
+ // ../swarm-core/src/returnReason.ts
619
+ function isReturnReason(v) {
620
+ return typeof v === "string" && RETURN_REASON_SET.has(v);
621
+ }
622
+ function toReturnReason(v) {
623
+ return isReturnReason(v) ? v : null;
624
+ }
625
+ var RETURN_REASONS, RETURN_REASON_SET, UNRETURNED_FAILURE_STATUSES, UNRETURNED_FAILURE_SET;
626
+ var init_returnReason = __esm({
627
+ "../swarm-core/src/returnReason.ts"() {
628
+ "use strict";
629
+ RETURN_REASONS = ["unclear_goal", "no_acceptance", "too_big", "contradiction"];
630
+ RETURN_REASON_SET = new Set(RETURN_REASONS);
631
+ UNRETURNED_FAILURE_STATUSES = ["failed", "blocked"];
632
+ UNRETURNED_FAILURE_SET = new Set(UNRETURNED_FAILURE_STATUSES);
633
+ }
634
+ });
635
+
611
636
  // ../swarm-core/src/modelPolicy.ts
612
637
  function findProvider(id) {
613
638
  const key = typeof id === "string" ? id.trim().toLowerCase() : "";
@@ -1599,6 +1624,13 @@ var init_zoneMemory = __esm({
1599
1624
  }
1600
1625
  });
1601
1626
 
1627
+ // ../swarm-core/src/taskPrs.ts
1628
+ var init_taskPrs = __esm({
1629
+ "../swarm-core/src/taskPrs.ts"() {
1630
+ "use strict";
1631
+ }
1632
+ });
1633
+
1602
1634
  // ../swarm-core/src/index.ts
1603
1635
  var init_src = __esm({
1604
1636
  "../swarm-core/src/index.ts"() {
@@ -1610,6 +1642,7 @@ var init_src = __esm({
1610
1642
  init_mergeQueue();
1611
1643
  init_prRef();
1612
1644
  init_verifyVerdict();
1645
+ init_returnReason();
1613
1646
  init_modelPolicy();
1614
1647
  init_status();
1615
1648
  init_deps();
@@ -1632,6 +1665,7 @@ var init_src = __esm({
1632
1665
  init_effort();
1633
1666
  init_queuePlan();
1634
1667
  init_zoneMemory();
1668
+ init_taskPrs();
1635
1669
  }
1636
1670
  });
1637
1671
 
@@ -3019,7 +3053,7 @@ var init_package = __esm({
3019
3053
  "package.json"() {
3020
3054
  package_default = {
3021
3055
  name: "@taskless-app/swarm",
3022
- version: "0.6.25",
3056
+ version: "0.6.27",
3023
3057
  type: "module",
3024
3058
  description: "Local control plane for a fleet of AI coding agents (drones), coordinating through Taskless. The overmind runs the swarm.",
3025
3059
  keywords: [
@@ -3070,7 +3104,7 @@ var init_package = __esm({
3070
3104
  execa: "^10.0.0",
3071
3105
  zod: "3.25.76"
3072
3106
  },
3073
- gitHead: "36aaed0414a46ea272ad762b81e051fecec40eaa"
3107
+ gitHead: "2e1ed83014422ae577be60271adc79e291b9e2ab"
3074
3108
  };
3075
3109
  }
3076
3110
  });
@@ -4435,9 +4469,14 @@ function rowToRun(row) {
4435
4469
  tokens_out: row.tokens_out ?? 0,
4436
4470
  duration_ms: row.duration_ms ?? 0,
4437
4471
  pr_url: row.pr_url ?? null,
4472
+ // TASWM-506: файлы, занятые прогоном с открытым PR — JSON-массив, как depends_on.
4473
+ changed_paths: row.changed_paths ? JSON.parse(row.changed_paths) : [],
4438
4474
  superseded_by: row.superseded_by ?? null,
4439
4475
  decision: row.decision ? JSON.parse(row.decision) : null,
4440
4476
  stop_reason: row.stop_reason ?? null,
4477
+ // TASWM-505: через узкий парсер, как verify_verdict ниже — в базе может лежать код,
4478
+ // записанный демоном другой версии; непонятное здесь значит «кода нет».
4479
+ return_reason: toReturnReason(row.return_reason),
4441
4480
  respawns: row.respawns ?? 0,
4442
4481
  // старые прогоны без колонки → 0
4443
4482
  resolves_run_id: row.resolves_run_id ?? null,
@@ -4512,6 +4551,7 @@ CREATE TABLE IF NOT EXISTS runs (
4512
4551
  superseded_by INTEGER,
4513
4552
  decision TEXT,
4514
4553
  stop_reason TEXT,
4554
+ return_reason TEXT,
4515
4555
  respawns INTEGER NOT NULL DEFAULT 0,
4516
4556
  resolves_run_id INTEGER,
4517
4557
  reviews_run_id INTEGER,
@@ -4628,7 +4668,16 @@ CREATE TABLE IF NOT EXISTS imports (
4628
4668
  // TASWM-451: чем проверять работу этого прогона — модель ревью, приехавшая с задачи.
4629
4669
  // Живёт на прогоне ИСПОЛНИТЕЛЯ: ревьюер и верификатор заводятся локально и читают её
4630
4670
  // оттуда, а не ходят за задачей в прод в момент спавна.
4631
- "ALTER TABLE runs ADD COLUMN review_model TEXT"
4671
+ "ALTER TABLE runs ADD COLUMN review_model TEXT",
4672
+ // TASWM-505: КОД причины возврата задачи автору (unclear_goal|no_acceptance|too_big|
4673
+ // contradiction) рядом с прозой в stop_reason — из него складывается распределение
4674
+ // «чего в постановках не хватает чаще всего». NULL — прогон не возвращали либо
4675
+ // возврат сделан демоном до этой фичи.
4676
+ "ALTER TABLE runs ADD COLUMN return_reason TEXT",
4677
+ // TASWM-506: файлы, которые держит прогон с открытым PR (JSON-массив, как depends_on).
4678
+ // Снимается в момент сдачи с PR: worktree сносится на мерже, и пересчитать список
4679
+ // потом неоткуда.
4680
+ "ALTER TABLE runs ADD COLUMN changed_paths TEXT"
4632
4681
  ]) {
4633
4682
  try {
4634
4683
  this.db.exec(alter);
@@ -4774,7 +4823,7 @@ CREATE TABLE IF NOT EXISTS imports (
4774
4823
  const set = fields.map((f) => `${f} = ?`).join(", ");
4775
4824
  const vals = fields.map((f) => {
4776
4825
  const v = patch[f];
4777
- if (f === "depends_on") {
4826
+ if (f === "depends_on" || f === "changed_paths") {
4778
4827
  const arr = v;
4779
4828
  return arr && arr.length ? JSON.stringify(arr) : null;
4780
4829
  }
@@ -7180,9 +7229,11 @@ var SwarmClient = class _SwarmClient {
7180
7229
  if ("duration_ms" in patch && patch.duration_ms !== void 0) out.durationMs = patch.duration_ms;
7181
7230
  if ("respawns" in patch && patch.respawns !== void 0) out.respawns = patch.respawns;
7182
7231
  if ("pr_url" in patch) out.prUrl = patch.pr_url ?? null;
7232
+ if ("changed_paths" in patch && patch.changed_paths) out.changedPaths = patch.changed_paths;
7183
7233
  if ("branch" in patch) out.branch = patch.branch ?? null;
7184
7234
  if ("repo" in patch) out.repo = patch.repo ?? null;
7185
7235
  if ("stop_reason" in patch) out.stopReason = patch.stop_reason ?? null;
7236
+ if ("return_reason" in patch) out.returnReason = patch.return_reason ?? null;
7186
7237
  if ("depends_on" in patch && patch.depends_on) out.dependsOn = patch.depends_on;
7187
7238
  if ("decision" in patch) out.decision = patch.decision ? JSON.stringify(patch.decision) : null;
7188
7239
  if ("kind" in patch && patch.kind !== void 0) out.role = patch.kind;
@@ -7258,9 +7309,12 @@ var SwarmClient = class _SwarmClient {
7258
7309
  tokens_out: 0,
7259
7310
  duration_ms: 0,
7260
7311
  pr_url: null,
7312
+ changed_paths: [],
7313
+ // файлы прогона снимаются при открытии PR (TASWM-506)
7261
7314
  superseded_by: null,
7262
7315
  decision: input.decision ?? null,
7263
7316
  stop_reason: null,
7317
+ return_reason: null,
7264
7318
  respawns: 0,
7265
7319
  resolves_run_id: input.resolves_run_id ?? null,
7266
7320
  reviews_run_id: input.reviews_run_id ?? null,
@@ -8862,9 +8916,12 @@ var SwarmClient = class _SwarmClient {
8862
8916
  tokens_out: 0,
8863
8917
  duration_ms: 0,
8864
8918
  pr_url: null,
8919
+ changed_paths: [],
8920
+ // занятые файлы (TASWM-506) — прод-поле, заполняется ниже
8865
8921
  superseded_by: null,
8866
8922
  decision: null,
8867
8923
  stop_reason: null,
8924
+ return_reason: null,
8868
8925
  respawns: 0,
8869
8926
  resolves_run_id: null,
8870
8927
  reviews_run_id: null,
@@ -8920,6 +8977,7 @@ var SwarmClient = class _SwarmClient {
8920
8977
  const verProd = pr.verifiesRunId ?? null;
8921
8978
  if (verProd) local.verifies_run_id = this.localIdForProdId(verProd) ?? local.verifies_run_id;
8922
8979
  local.verify_verdict = toVerifyVerdict(pr.verifyVerdict) ?? local.verify_verdict;
8980
+ local.return_reason = toReturnReason(pr.returnReason) ?? local.return_reason;
8923
8981
  local.review_phase = pr.reviewPhase ?? local.review_phase;
8924
8982
  local.repo = this.resolveRepo(pr.repo ?? null);
8925
8983
  local.host_id = pr.hostId ?? null;
@@ -8939,6 +8997,7 @@ var SwarmClient = class _SwarmClient {
8939
8997
  local.tokens_out = typeof pr.tokensOut === "number" ? pr.tokensOut : 0;
8940
8998
  local.duration_ms = typeof pr.durationMs === "number" ? pr.durationMs : 0;
8941
8999
  local.pr_url = pr.prUrl ?? null;
9000
+ local.changed_paths = Array.isArray(pr.changedPaths) ? pr.changedPaths : local.changed_paths ?? [];
8942
9001
  local.stop_reason = pr.stopReason ?? null;
8943
9002
  local.respawns = typeof pr.respawns === "number" ? pr.respawns : 0;
8944
9003
  local.decision = parseDecision(pr.decision);