opencode-swarm 7.26.1 → 7.27.0

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/index.js CHANGED
@@ -34,7 +34,7 @@ var package_default;
34
34
  var init_package = __esm(() => {
35
35
  package_default = {
36
36
  name: "opencode-swarm",
37
- version: "7.26.1",
37
+ version: "7.27.0",
38
38
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
39
39
  main: "dist/index.js",
40
40
  types: "dist/index.d.ts",
@@ -47117,10 +47117,31 @@ function stringHash(str) {
47117
47117
  h2 ^= Math.imul(h1 ^ h1 >>> 13, 3266489909);
47118
47118
  return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(16);
47119
47119
  }
47120
+ function isInfrastructureFailure(currentResult) {
47121
+ const errorMessage = currentResult.errorMessage || "";
47122
+ const stackPrefix = currentResult.stackPrefix || "";
47123
+ if (/\bassertionerror\b/i.test(errorMessage)) {
47124
+ return false;
47125
+ }
47126
+ const combinedText = `${errorMessage}
47127
+ ${stackPrefix}`;
47128
+ return INFRASTRUCTURE_FAILURE_PATTERNS.some((pattern) => pattern.test(combinedText));
47129
+ }
47120
47130
  function classifyFailure(currentResult, history) {
47121
47131
  const normalizedFile = currentResult.testFile.toLowerCase();
47122
47132
  const normalizedName = currentResult.testName.toLowerCase();
47123
47133
  const testHistory = history.filter((r) => r.testFile.toLowerCase() === normalizedFile && r.testName.toLowerCase() === normalizedName).sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
47134
+ if (isInfrastructureFailure(currentResult)) {
47135
+ return {
47136
+ testFile: currentResult.testFile,
47137
+ testName: currentResult.testName,
47138
+ classification: "infrastructure_failure",
47139
+ errorMessage: currentResult.errorMessage,
47140
+ stackPrefix: currentResult.stackPrefix,
47141
+ durationMs: currentResult.durationMs,
47142
+ confidence: computeConfidence2(testHistory.length)
47143
+ };
47144
+ }
47124
47145
  const lastThree = testHistory.slice(0, 3);
47125
47146
  const lastTen = testHistory.slice(0, 10);
47126
47147
  const normalizedTestFile = currentResult.testFile.toLowerCase();
@@ -47220,6 +47241,20 @@ function classifyAndCluster(testResults, history) {
47220
47241
  const clusters = clusterFailures(classified);
47221
47242
  return { classified, clusters };
47222
47243
  }
47244
+ var MAX_INFRA_CONTEXT_CHARS = 80, INFRASTRUCTURE_FAILURE_PATTERNS;
47245
+ var init_failure_classifier = __esm(() => {
47246
+ INFRASTRUCTURE_FAILURE_PATTERNS = [
47247
+ /\boutofmemoryerror\b/i,
47248
+ /(?:^|\n|\bcommand failed:\s*)\s*killed(?:\s*(?:[-:]\s*)?(?:out of memory|oom|by signal|signal|sigkill).*)?\s*(?:\n|$)/i,
47249
+ /(?:^|\n)\s*etimedout\b/i,
47250
+ new RegExp(`\\b(?:connect|connection|request|socket|network)\\b[^\\n]{0,${MAX_INFRA_CONTEXT_CHARS}}\\betimedout\\b`, "i"),
47251
+ /(?:^|\n)\s*econnrefused\b/i,
47252
+ new RegExp(`\\b(?:connect|connection|socket)\\b[^\\n]{0,${MAX_INFRA_CONTEXT_CHARS}}\\beconnrefused\\b`, "i"),
47253
+ /(?:^|\n)\s*enotfound\b/i,
47254
+ new RegExp(`\\b(?:getaddrinfo|dns|lookup)\\b[^\\n]{0,${MAX_INFRA_CONTEXT_CHARS}}\\benotfound\\b`, "i"),
47255
+ /\bexit(?:ed)?(?:\s+with)?(?:\s+code)?\s*[:=]?\s*137\b/i
47256
+ ];
47257
+ });
47223
47258
 
47224
47259
  // src/test-impact/flaky-detector.ts
47225
47260
  function detectFlakyTests(allHistory) {
@@ -48964,6 +48999,7 @@ var init_test_runner = __esm(() => {
48964
48999
  init_zod();
48965
49000
  init_discovery();
48966
49001
  init_analyzer();
49002
+ init_failure_classifier();
48967
49003
  init_history_store();
48968
49004
  init_bun_compat();
48969
49005
  init_path_security();
package/dist/index.js CHANGED
@@ -33,7 +33,7 @@ var package_default;
33
33
  var init_package = __esm(() => {
34
34
  package_default = {
35
35
  name: "opencode-swarm",
36
- version: "7.26.1",
36
+ version: "7.27.0",
37
37
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
38
38
  main: "dist/index.js",
39
39
  types: "dist/index.d.ts",
@@ -57509,10 +57509,31 @@ function stringHash(str) {
57509
57509
  h2 ^= Math.imul(h1 ^ h1 >>> 13, 3266489909);
57510
57510
  return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(16);
57511
57511
  }
57512
+ function isInfrastructureFailure(currentResult) {
57513
+ const errorMessage = currentResult.errorMessage || "";
57514
+ const stackPrefix = currentResult.stackPrefix || "";
57515
+ if (/\bassertionerror\b/i.test(errorMessage)) {
57516
+ return false;
57517
+ }
57518
+ const combinedText = `${errorMessage}
57519
+ ${stackPrefix}`;
57520
+ return INFRASTRUCTURE_FAILURE_PATTERNS.some((pattern) => pattern.test(combinedText));
57521
+ }
57512
57522
  function classifyFailure(currentResult, history) {
57513
57523
  const normalizedFile = currentResult.testFile.toLowerCase();
57514
57524
  const normalizedName = currentResult.testName.toLowerCase();
57515
57525
  const testHistory = history.filter((r) => r.testFile.toLowerCase() === normalizedFile && r.testName.toLowerCase() === normalizedName).sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
57526
+ if (isInfrastructureFailure(currentResult)) {
57527
+ return {
57528
+ testFile: currentResult.testFile,
57529
+ testName: currentResult.testName,
57530
+ classification: "infrastructure_failure",
57531
+ errorMessage: currentResult.errorMessage,
57532
+ stackPrefix: currentResult.stackPrefix,
57533
+ durationMs: currentResult.durationMs,
57534
+ confidence: computeConfidence2(testHistory.length)
57535
+ };
57536
+ }
57516
57537
  const lastThree = testHistory.slice(0, 3);
57517
57538
  const lastTen = testHistory.slice(0, 10);
57518
57539
  const normalizedTestFile = currentResult.testFile.toLowerCase();
@@ -57612,6 +57633,20 @@ function classifyAndCluster(testResults, history) {
57612
57633
  const clusters = clusterFailures(classified);
57613
57634
  return { classified, clusters };
57614
57635
  }
57636
+ var MAX_INFRA_CONTEXT_CHARS = 80, INFRASTRUCTURE_FAILURE_PATTERNS;
57637
+ var init_failure_classifier = __esm(() => {
57638
+ INFRASTRUCTURE_FAILURE_PATTERNS = [
57639
+ /\boutofmemoryerror\b/i,
57640
+ /(?:^|\n|\bcommand failed:\s*)\s*killed(?:\s*(?:[-:]\s*)?(?:out of memory|oom|by signal|signal|sigkill).*)?\s*(?:\n|$)/i,
57641
+ /(?:^|\n)\s*etimedout\b/i,
57642
+ new RegExp(`\\b(?:connect|connection|request|socket|network)\\b[^\\n]{0,${MAX_INFRA_CONTEXT_CHARS}}\\betimedout\\b`, "i"),
57643
+ /(?:^|\n)\s*econnrefused\b/i,
57644
+ new RegExp(`\\b(?:connect|connection|socket)\\b[^\\n]{0,${MAX_INFRA_CONTEXT_CHARS}}\\beconnrefused\\b`, "i"),
57645
+ /(?:^|\n)\s*enotfound\b/i,
57646
+ new RegExp(`\\b(?:getaddrinfo|dns|lookup)\\b[^\\n]{0,${MAX_INFRA_CONTEXT_CHARS}}\\benotfound\\b`, "i"),
57647
+ /\bexit(?:ed)?(?:\s+with)?(?:\s+code)?\s*[:=]?\s*137\b/i
57648
+ ];
57649
+ });
57615
57650
 
57616
57651
  // src/test-impact/flaky-detector.ts
57617
57652
  function detectFlakyTests(allHistory) {
@@ -59356,6 +59391,7 @@ var init_test_runner = __esm(() => {
59356
59391
  init_zod();
59357
59392
  init_discovery();
59358
59393
  init_analyzer();
59394
+ init_failure_classifier();
59359
59395
  init_history_store();
59360
59396
  init_bun_compat();
59361
59397
  init_path_security();
@@ -73572,7 +73608,7 @@ var init_curator_drift = __esm(() => {
73572
73608
  var exports_project_context = {};
73573
73609
  __export(exports_project_context, {
73574
73610
  buildProjectContext: () => buildProjectContext,
73575
- _internals: () => _internals56,
73611
+ _internals: () => _internals57,
73576
73612
  LANG_BACKEND_DETECTION_TIMEOUT_MS: () => LANG_BACKEND_DETECTION_TIMEOUT_MS
73577
73613
  });
73578
73614
  import * as fs112 from "node:fs";
@@ -73656,7 +73692,7 @@ function selectLintCommand(backend, directory) {
73656
73692
  return null;
73657
73693
  }
73658
73694
  async function buildProjectContext(directory) {
73659
- const backend = await _internals56.pickBackend(directory);
73695
+ const backend = await _internals57.pickBackend(directory);
73660
73696
  if (!backend)
73661
73697
  return null;
73662
73698
  const ctx = emptyProjectContext();
@@ -73687,16 +73723,16 @@ async function buildProjectContext(directory) {
73687
73723
  if (backend.prompts.reviewerChecklist.length > 0) {
73688
73724
  ctx.REVIEWER_CHECKLIST = bulletList(backend.prompts.reviewerChecklist);
73689
73725
  }
73690
- const profiles = _internals56.pickedProfiles(directory);
73726
+ const profiles = _internals57.pickedProfiles(directory);
73691
73727
  if (profiles.length > 1) {
73692
73728
  ctx.PROJECT_CONTEXT_SECONDARY_LANGUAGES = profiles.slice(1).map((p) => p.id).join(", ");
73693
73729
  }
73694
73730
  return ctx;
73695
73731
  }
73696
- var LANG_BACKEND_DETECTION_TIMEOUT_MS = 300, _internals56;
73732
+ var LANG_BACKEND_DETECTION_TIMEOUT_MS = 300, _internals57;
73697
73733
  var init_project_context = __esm(() => {
73698
73734
  init_dispatch();
73699
- _internals56 = {
73735
+ _internals57 = {
73700
73736
  pickBackend,
73701
73737
  pickedProfiles
73702
73738
  };
@@ -92261,10 +92297,61 @@ async function writeCheckpoint(directory) {
92261
92297
  fs81.writeFileSync(jsonPath, JSON.stringify(plan, null, 2), "utf8");
92262
92298
  const md = derivePlanMarkdown(plan);
92263
92299
  fs81.writeFileSync(mdPath, md, "utf8");
92300
+ for (const legacyPath of [
92301
+ path108.join(directory, "SWARM_PLAN.json"),
92302
+ path108.join(directory, "SWARM_PLAN.md")
92303
+ ]) {
92304
+ try {
92305
+ if (_internals43.existsSyncForCleanup(legacyPath)) {
92306
+ _internals43.unlinkSyncForCleanup(legacyPath);
92307
+ }
92308
+ } catch {}
92309
+ }
92264
92310
  } catch (error93) {
92265
92311
  console.warn(`[checkpoint] Failed to write SWARM_PLAN checkpoint: ${error93 instanceof Error ? error93.message : String(error93)}`);
92266
92312
  }
92267
92313
  }
92314
+ async function importCheckpoint(directory, source) {
92315
+ try {
92316
+ const swarmDirPath = path108.join(directory, ".swarm", "SWARM_PLAN.json");
92317
+ const rootPath = path108.join(directory, "SWARM_PLAN.json");
92318
+ let checkpointPath;
92319
+ let rawContent;
92320
+ if (fs81.existsSync(swarmDirPath)) {
92321
+ checkpointPath = swarmDirPath;
92322
+ rawContent = fs81.readFileSync(checkpointPath, "utf8");
92323
+ } else if (fs81.existsSync(rootPath)) {
92324
+ checkpointPath = rootPath;
92325
+ rawContent = fs81.readFileSync(checkpointPath, "utf8");
92326
+ console.warn("[checkpoint] importCheckpoint: using legacy root-level SWARM_PLAN.json. Consider running /swarm close to migrate.");
92327
+ } else {
92328
+ return {
92329
+ success: false,
92330
+ error: "SWARM_PLAN.json not found in .swarm/ or project root"
92331
+ };
92332
+ }
92333
+ const parsed = JSON.parse(rawContent);
92334
+ const plan = PlanSchema.parse(parsed);
92335
+ await savePlanWithAutoAcknowledgedRemovals(directory, plan, "import_checkpoint", "import external checkpoint");
92336
+ await appendLedgerEvent(directory, {
92337
+ event_type: "plan_rebuilt",
92338
+ source: source ?? "external_reseed",
92339
+ plan_id: derivePlanId(plan)
92340
+ });
92341
+ return { success: true, plan };
92342
+ } catch (error93) {
92343
+ return {
92344
+ success: false,
92345
+ error: error93 instanceof Error ? error93.message : String(error93)
92346
+ };
92347
+ }
92348
+ }
92349
+ var _internals43 = {
92350
+ writeCheckpoint,
92351
+ importCheckpoint,
92352
+ existsSyncForCleanup: fs81.existsSync,
92353
+ unlinkSyncForCleanup: fs81.unlinkSync
92354
+ };
92268
92355
 
92269
92356
  // src/tools/phase-complete.ts
92270
92357
  init_ledger();
@@ -92467,7 +92554,7 @@ function listLaneEvidenceSync(directory, phase) {
92467
92554
  }
92468
92555
  return laneIds;
92469
92556
  }
92470
- var _internals43 = {
92557
+ var _internals44 = {
92471
92558
  listActiveLocks,
92472
92559
  readPersisted: readPersisted2,
92473
92560
  readPlanJson: defaultReadPlanJson,
@@ -92528,7 +92615,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
92528
92615
  reason: "Lean Turbo state unreadable or missing"
92529
92616
  };
92530
92617
  }
92531
- const persisted = _internals43.readPersisted(directory);
92618
+ const persisted = _internals44.readPersisted(directory);
92532
92619
  if (!persisted) {
92533
92620
  return {
92534
92621
  ok: false,
@@ -92592,7 +92679,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
92592
92679
  }
92593
92680
  }
92594
92681
  if (runState.lanes.length > 0) {
92595
- const evidenceLaneIds = new Set(_internals43.listLaneEvidenceSync(directory, phase));
92682
+ const evidenceLaneIds = new Set(_internals44.listLaneEvidenceSync(directory, phase));
92596
92683
  for (const lane of runState.lanes) {
92597
92684
  if ((lane.status === "completed" || lane.status === "failed") && !evidenceLaneIds.has(lane.laneId)) {
92598
92685
  return {
@@ -92602,7 +92689,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
92602
92689
  }
92603
92690
  }
92604
92691
  }
92605
- const activeLocks = _internals43.listActiveLocks(directory);
92692
+ const activeLocks = _internals44.listActiveLocks(directory);
92606
92693
  const phaseLaneIds = new Set(laneIds);
92607
92694
  for (const lock of activeLocks) {
92608
92695
  if (lock.laneId && phaseLaneIds.has(lock.laneId)) {
@@ -92622,7 +92709,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
92622
92709
  }
92623
92710
  const serialDegradedTasks = runState.degradedTasks.filter((dt) => !laneTaskIds.has(dt.taskId));
92624
92711
  if (serialDegradedTasks.length > 0) {
92625
- const plan = _internals43.readPlanJson(directory);
92712
+ const plan = _internals44.readPlanJson(directory);
92626
92713
  if (!plan) {
92627
92714
  return {
92628
92715
  ok: false,
@@ -92666,7 +92753,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
92666
92753
  }
92667
92754
  const serializedTasks = runState.serializedTasks;
92668
92755
  if (Array.isArray(serializedTasks) && serializedTasks.length > 0) {
92669
- const plan = _internals43.readPlanJson(directory);
92756
+ const plan = _internals44.readPlanJson(directory);
92670
92757
  if (!plan) {
92671
92758
  return {
92672
92759
  ok: false,
@@ -92725,7 +92812,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
92725
92812
  }
92726
92813
  let reviewerVerdict = runState.lastReviewerVerdict;
92727
92814
  if (!reviewerVerdict) {
92728
- const evidence = _internals43.readReviewerEvidence(directory, phase);
92815
+ const evidence = _internals44.readReviewerEvidence(directory, phase);
92729
92816
  reviewerVerdict = evidence?.verdict ?? undefined;
92730
92817
  }
92731
92818
  if (mergedConfig.phase_reviewer) {
@@ -92738,7 +92825,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
92738
92825
  }
92739
92826
  let criticVerdict = runState.lastCriticVerdict;
92740
92827
  if (!criticVerdict) {
92741
- const evidence = _internals43.readCriticEvidence(directory, phase);
92828
+ const evidence = _internals44.readCriticEvidence(directory, phase);
92742
92829
  criticVerdict = evidence?.verdict ?? undefined;
92743
92830
  }
92744
92831
  if (mergedConfig.phase_critic) {
@@ -93661,7 +93748,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
93661
93748
  phase_critic: leanConfig.phase_critic,
93662
93749
  integrated_diff_required: leanConfig.integrated_diff_required
93663
93750
  } : undefined;
93664
- const leanCheck = _internals43.verifyLeanTurboPhaseReady(dir, phase, sessionID, leanPhaseReadyConfig);
93751
+ const leanCheck = _internals44.verifyLeanTurboPhaseReady(dir, phase, sessionID, leanPhaseReadyConfig);
93665
93752
  if (!leanCheck.ok) {
93666
93753
  return JSON.stringify({
93667
93754
  success: false,
@@ -95849,11 +95936,11 @@ var quality_budget = createSwarmTool({
95849
95936
  }).optional().describe("Quality budget thresholds")
95850
95937
  },
95851
95938
  async execute(args2, directory) {
95852
- const result = await _internals44.qualityBudget(args2, directory);
95939
+ const result = await _internals45.qualityBudget(args2, directory);
95853
95940
  return JSON.stringify(result);
95854
95941
  }
95855
95942
  });
95856
- var _internals44 = {
95943
+ var _internals45 = {
95857
95944
  qualityBudget
95858
95945
  };
95859
95946
 
@@ -96582,7 +96669,7 @@ import * as path114 from "node:path";
96582
96669
  var semgrepAvailableCache = null;
96583
96670
  var DEFAULT_RULES_DIR = ".swarm/semgrep-rules";
96584
96671
  var DEFAULT_TIMEOUT_MS3 = 30000;
96585
- var _internals45 = {
96672
+ var _internals46 = {
96586
96673
  isSemgrepAvailable,
96587
96674
  checkSemgrepAvailable,
96588
96675
  resetSemgrepCache,
@@ -96607,7 +96694,7 @@ function isSemgrepAvailable() {
96607
96694
  }
96608
96695
  }
96609
96696
  async function checkSemgrepAvailable() {
96610
- return _internals45.isSemgrepAvailable();
96697
+ return _internals46.isSemgrepAvailable();
96611
96698
  }
96612
96699
  function resetSemgrepCache() {
96613
96700
  semgrepAvailableCache = null;
@@ -96704,12 +96791,12 @@ async function runSemgrep(options) {
96704
96791
  const timeoutMs = options.timeoutMs || DEFAULT_TIMEOUT_MS3;
96705
96792
  if (files.length === 0) {
96706
96793
  return {
96707
- available: _internals45.isSemgrepAvailable(),
96794
+ available: _internals46.isSemgrepAvailable(),
96708
96795
  findings: [],
96709
96796
  engine: "tier_a"
96710
96797
  };
96711
96798
  }
96712
- if (!_internals45.isSemgrepAvailable()) {
96799
+ if (!_internals46.isSemgrepAvailable()) {
96713
96800
  return {
96714
96801
  available: false,
96715
96802
  findings: [],
@@ -96868,7 +96955,7 @@ function assignOccurrenceIndices(findings, directory) {
96868
96955
  }
96869
96956
  const occIdx = countMap.get(baseKey) ?? 0;
96870
96957
  countMap.set(baseKey, occIdx + 1);
96871
- const fp = _internals46.fingerprintFinding(finding, directory, occIdx);
96958
+ const fp = _internals47.fingerprintFinding(finding, directory, occIdx);
96872
96959
  return {
96873
96960
  finding,
96874
96961
  index: occIdx,
@@ -96937,7 +97024,7 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
96937
97024
  }
96938
97025
  } catch {}
96939
97026
  const scannedRelFiles = new Set(scannedFiles.map((f) => normalizeFindingPath(directory, f)));
96940
- const indexed = _internals46.assignOccurrenceIndices(findings, directory);
97027
+ const indexed = _internals47.assignOccurrenceIndices(findings, directory);
96941
97028
  if (existing && !opts?.force) {
96942
97029
  const prunedFingerprints = existing.fingerprints.filter((fp) => {
96943
97030
  const relFile = fp.slice(0, fp.indexOf("|"));
@@ -97077,7 +97164,7 @@ function loadBaseline(directory, phase) {
97077
97164
  };
97078
97165
  }
97079
97166
  }
97080
- var _internals46 = {
97167
+ var _internals47 = {
97081
97168
  fingerprintFinding,
97082
97169
  assignOccurrenceIndices,
97083
97170
  captureOrMergeBaseline,
@@ -97487,11 +97574,11 @@ var sast_scan = createSwarmTool({
97487
97574
  capture_baseline: safeArgs.capture_baseline,
97488
97575
  phase: safeArgs.phase
97489
97576
  };
97490
- const result = await _internals47.sastScan(input, directory);
97577
+ const result = await _internals48.sastScan(input, directory);
97491
97578
  return JSON.stringify(result, null, 2);
97492
97579
  }
97493
97580
  });
97494
- var _internals47 = {
97581
+ var _internals48 = {
97495
97582
  sastScan,
97496
97583
  sast_scan
97497
97584
  };
@@ -101403,7 +101490,7 @@ import {
101403
101490
  mkdirSync as mkdirSync31,
101404
101491
  readFileSync as readFileSync63,
101405
101492
  renameSync as renameSync20,
101406
- unlinkSync as unlinkSync15,
101493
+ unlinkSync as unlinkSync16,
101407
101494
  writeFileSync as writeFileSync25
101408
101495
  } from "node:fs";
101409
101496
  import path125 from "node:path";
@@ -101637,7 +101724,7 @@ function writePhaseCouncilEvidence(workingDir, synthesis) {
101637
101724
  renameSync20(tempFile, evidenceFile);
101638
101725
  } finally {
101639
101726
  if (existsSync72(tempFile)) {
101640
- unlinkSync15(tempFile);
101727
+ unlinkSync16(tempFile);
101641
101728
  }
101642
101729
  }
101643
101730
  }
@@ -102006,6 +102093,10 @@ var suggestPatch = createSwarmTool({
102006
102093
  }, null, 2);
102007
102094
  }
102008
102095
  });
102096
+
102097
+ // src/tools/index.ts
102098
+ init_failure_classifier();
102099
+
102009
102100
  // src/tools/generate-mutants.ts
102010
102101
  init_zod();
102011
102102
 
@@ -102815,7 +102906,7 @@ function resolveDefaultReviewerAgent(generatedAgentNames) {
102815
102906
  }
102816
102907
  async function compileReviewPackage(directory, phase, sessionID, requireDiffSummary) {
102817
102908
  const lanes = await listLaneEvidence(directory, phase);
102818
- const persisted = _internals48.readPersisted?.(directory) ?? null;
102909
+ const persisted = _internals49.readPersisted?.(directory) ?? null;
102819
102910
  if (persisted) {
102820
102911
  let matchingRunState = null;
102821
102912
  for (const sessionState of Object.values(persisted.sessions)) {
@@ -103007,7 +103098,7 @@ Be specific and evidence-based. Do not approve a phase with unresolved degraded
103007
103098
  client.session.delete({ path: { id: sessionId } }).catch(() => {});
103008
103099
  }
103009
103100
  }
103010
- var _internals48 = {
103101
+ var _internals49 = {
103011
103102
  compileReviewPackage,
103012
103103
  parseReviewerVerdict,
103013
103104
  writeReviewerEvidence,
@@ -103024,28 +103115,28 @@ async function dispatchPhaseReviewer(directory, phase, sessionID, config3) {
103024
103115
  };
103025
103116
  const generatedAgentNames = swarmState.generatedAgentNames;
103026
103117
  const agentName = mergedConfig.reviewerAgent || resolveDefaultReviewerAgent(generatedAgentNames);
103027
- const pkg = await _internals48.compileReviewPackage(directory, phase, sessionID, mergedConfig.requireDiffSummary);
103118
+ const pkg = await _internals49.compileReviewPackage(directory, phase, sessionID, mergedConfig.requireDiffSummary);
103028
103119
  let responseText;
103029
103120
  try {
103030
- responseText = await _internals48.dispatchReviewerAgent(directory, pkg, agentName, mergedConfig.timeoutMs);
103121
+ responseText = await _internals49.dispatchReviewerAgent(directory, pkg, agentName, mergedConfig.timeoutMs);
103031
103122
  } catch (error93) {
103032
- const evidencePath2 = await _internals48.writeReviewerEvidence(directory, phase, "REJECTED", error93 instanceof Error ? error93.message : String(error93));
103123
+ const evidencePath2 = await _internals49.writeReviewerEvidence(directory, phase, "REJECTED", error93 instanceof Error ? error93.message : String(error93));
103033
103124
  return {
103034
103125
  verdict: "REJECTED",
103035
103126
  reason: `Reviewer dispatch failed: ${error93 instanceof Error ? error93.message : String(error93)}`,
103036
103127
  evidencePath: evidencePath2
103037
103128
  };
103038
103129
  }
103039
- const parsed = _internals48.parseReviewerVerdict(responseText);
103130
+ const parsed = _internals49.parseReviewerVerdict(responseText);
103040
103131
  if (!parsed) {
103041
- const evidencePath2 = await _internals48.writeReviewerEvidence(directory, phase, "REJECTED", "Reviewer response could not be parsed");
103132
+ const evidencePath2 = await _internals49.writeReviewerEvidence(directory, phase, "REJECTED", "Reviewer response could not be parsed");
103042
103133
  return {
103043
103134
  verdict: "REJECTED",
103044
103135
  reason: "Reviewer response could not be parsed",
103045
103136
  evidencePath: evidencePath2
103046
103137
  };
103047
103138
  }
103048
- const evidencePath = await _internals48.writeReviewerEvidence(directory, phase, parsed.verdict, parsed.reason);
103139
+ const evidencePath = await _internals49.writeReviewerEvidence(directory, phase, parsed.verdict, parsed.reason);
103049
103140
  return {
103050
103141
  verdict: parsed.verdict,
103051
103142
  reason: parsed.reason,
@@ -103551,7 +103642,7 @@ ${fileList}
103551
103642
 
103552
103643
  // src/tools/lean-turbo-run-phase.ts
103553
103644
  init_create_tool();
103554
- var _internals49 = {
103645
+ var _internals50 = {
103555
103646
  LeanTurboRunner,
103556
103647
  loadPluginConfigWithMeta
103557
103648
  };
@@ -103561,9 +103652,9 @@ async function executeLeanTurboRunPhase(args2) {
103561
103652
  let runError = null;
103562
103653
  let runner = null;
103563
103654
  try {
103564
- const { config: config3 } = _internals49.loadPluginConfigWithMeta(directory);
103655
+ const { config: config3 } = _internals50.loadPluginConfigWithMeta(directory);
103565
103656
  const leanConfig = config3.turbo?.strategy === "lean" ? config3.turbo.lean : undefined;
103566
- runner = new _internals49.LeanTurboRunner({
103657
+ runner = new _internals50.LeanTurboRunner({
103567
103658
  directory,
103568
103659
  sessionID,
103569
103660
  opencodeClient: swarmState.opencodeClient ?? null,
@@ -103844,7 +103935,7 @@ import * as path132 from "node:path";
103844
103935
 
103845
103936
  // src/mutation/engine.ts
103846
103937
  import { spawnSync as spawnSync3 } from "node:child_process";
103847
- import { unlinkSync as unlinkSync16, writeFileSync as writeFileSync26 } from "node:fs";
103938
+ import { unlinkSync as unlinkSync17, writeFileSync as writeFileSync26 } from "node:fs";
103848
103939
  import * as path131 from "node:path";
103849
103940
 
103850
103941
  // src/mutation/equivalence.ts
@@ -103917,7 +104008,7 @@ function isStaticallyEquivalent(originalCode, mutatedCode) {
103917
104008
  const strippedMutated = stripCode(mutatedCode);
103918
104009
  return strippedOriginal === strippedMutated;
103919
104010
  }
103920
- var _internals50 = {
104011
+ var _internals51 = {
103921
104012
  isStaticallyEquivalent,
103922
104013
  checkEquivalence,
103923
104014
  batchCheckEquivalence
@@ -103957,7 +104048,7 @@ async function batchCheckEquivalence(patches, llmJudge) {
103957
104048
  const results = [];
103958
104049
  for (const { patch, originalCode, mutatedCode } of patches) {
103959
104050
  try {
103960
- const result = await _internals50.checkEquivalence(patch, originalCode, mutatedCode, llmJudge);
104051
+ const result = await _internals51.checkEquivalence(patch, originalCode, mutatedCode, llmJudge);
103961
104052
  results.push(result);
103962
104053
  } catch (err3) {
103963
104054
  results.push({
@@ -103976,7 +104067,7 @@ async function batchCheckEquivalence(patches, llmJudge) {
103976
104067
  var MUTATION_TIMEOUT_MS = 30000;
103977
104068
  var TOTAL_BUDGET_MS = 300000;
103978
104069
  var GIT_APPLY_TIMEOUT_MS = 5000;
103979
- var _internals51 = {
104070
+ var _internals52 = {
103980
104071
  executeMutation,
103981
104072
  computeReport,
103982
104073
  executeMutationSuite,
@@ -104008,7 +104099,7 @@ async function executeMutation(patch, testCommand, _testFiles, workingDir) {
104008
104099
  };
104009
104100
  }
104010
104101
  try {
104011
- const applyResult = _internals51.spawnSync("git", ["apply", "--", patchFile], {
104102
+ const applyResult = _internals52.spawnSync("git", ["apply", "--", patchFile], {
104012
104103
  cwd: workingDir,
104013
104104
  timeout: GIT_APPLY_TIMEOUT_MS,
104014
104105
  stdio: "pipe"
@@ -104037,7 +104128,7 @@ async function executeMutation(patch, testCommand, _testFiles, workingDir) {
104037
104128
  }
104038
104129
  let testPassed = false;
104039
104130
  try {
104040
- const spawnResult = _internals51.spawnSync(testCommand[0], testCommand.slice(1), {
104131
+ const spawnResult = _internals52.spawnSync(testCommand[0], testCommand.slice(1), {
104041
104132
  cwd: workingDir,
104042
104133
  timeout: MUTATION_TIMEOUT_MS,
104043
104134
  stdio: "pipe"
@@ -104070,7 +104161,7 @@ async function executeMutation(patch, testCommand, _testFiles, workingDir) {
104070
104161
  } finally {
104071
104162
  if (patchFile) {
104072
104163
  try {
104073
- const revertResult = _internals51.spawnSync("git", ["apply", "-R", "--", patchFile], {
104164
+ const revertResult = _internals52.spawnSync("git", ["apply", "-R", "--", patchFile], {
104074
104165
  cwd: workingDir,
104075
104166
  timeout: GIT_APPLY_TIMEOUT_MS,
104076
104167
  stdio: "pipe"
@@ -104089,7 +104180,7 @@ async function executeMutation(patch, testCommand, _testFiles, workingDir) {
104089
104180
  revertError = new Error(`Failed to revert mutation ${patch.id}: ${revertErr}. Working tree may be dirty.`);
104090
104181
  }
104091
104182
  try {
104092
- unlinkSync16(patchFile);
104183
+ unlinkSync17(patchFile);
104093
104184
  } catch (_unlinkErr) {}
104094
104185
  }
104095
104186
  }
@@ -104263,7 +104354,7 @@ async function executeMutationSuite(patches, testCommand, testFiles, workingDir,
104263
104354
  }
104264
104355
 
104265
104356
  // src/mutation/gate.ts
104266
- var _internals52 = {
104357
+ var _internals53 = {
104267
104358
  evaluateMutationGate,
104268
104359
  buildTestImprovementPrompt,
104269
104360
  buildMessage
@@ -104284,8 +104375,8 @@ function evaluateMutationGate(report, passThreshold = PASS_THRESHOLD, warnThresh
104284
104375
  } else {
104285
104376
  verdict = "fail";
104286
104377
  }
104287
- const testImprovementPrompt = _internals52.buildTestImprovementPrompt(report, passThreshold, verdict);
104288
- const message = _internals52.buildMessage(verdict, adjustedKillRate, report.killed, report.totalMutants, report.equivalent, warnThreshold);
104378
+ const testImprovementPrompt = _internals53.buildTestImprovementPrompt(report, passThreshold, verdict);
104379
+ const message = _internals53.buildMessage(verdict, adjustedKillRate, report.killed, report.totalMutants, report.equivalent, warnThreshold);
104289
104380
  return {
104290
104381
  verdict,
104291
104382
  killRate: report.killRate,
@@ -104902,7 +104993,7 @@ import * as path136 from "node:path";
104902
104993
  init_bun_compat();
104903
104994
  import * as fs104 from "node:fs";
104904
104995
  import * as path135 from "node:path";
104905
- var _internals53 = { bunSpawn };
104996
+ var _internals54 = { bunSpawn };
104906
104997
  var _swarmGitExcludedChecked = false;
104907
104998
  function fileCoversSwarm(content) {
104908
104999
  for (const rawLine of content.split(`
@@ -104935,7 +105026,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
104935
105026
  checkIgnoreExitCode
104936
105027
  ] = await Promise.all([
104937
105028
  (async () => {
104938
- const proc = _internals53.bunSpawn(["git", "-C", directory, "rev-parse", "--show-toplevel"], GIT_SPAWN_OPTIONS);
105029
+ const proc = _internals54.bunSpawn(["git", "-C", directory, "rev-parse", "--show-toplevel"], GIT_SPAWN_OPTIONS);
104939
105030
  try {
104940
105031
  return await Promise.all([proc.exited, proc.stdout.text()]);
104941
105032
  } finally {
@@ -104945,7 +105036,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
104945
105036
  }
104946
105037
  })(),
104947
105038
  (async () => {
104948
- const proc = _internals53.bunSpawn(["git", "-C", directory, "rev-parse", "--git-path", "info/exclude"], GIT_SPAWN_OPTIONS);
105039
+ const proc = _internals54.bunSpawn(["git", "-C", directory, "rev-parse", "--git-path", "info/exclude"], GIT_SPAWN_OPTIONS);
104949
105040
  try {
104950
105041
  return await Promise.all([proc.exited, proc.stdout.text()]);
104951
105042
  } finally {
@@ -104955,7 +105046,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
104955
105046
  }
104956
105047
  })(),
104957
105048
  (async () => {
104958
- const proc = _internals53.bunSpawn(["git", "-C", directory, "check-ignore", "-q", ".swarm/.gitkeep"], GIT_SPAWN_OPTIONS);
105049
+ const proc = _internals54.bunSpawn(["git", "-C", directory, "check-ignore", "-q", ".swarm/.gitkeep"], GIT_SPAWN_OPTIONS);
104959
105050
  try {
104960
105051
  return await proc.exited;
104961
105052
  } finally {
@@ -104994,7 +105085,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
104994
105085
  }
104995
105086
  } catch {}
104996
105087
  }
104997
- const trackedProc = _internals53.bunSpawn(["git", "-C", directory, "ls-files", "--", ".swarm"], GIT_SPAWN_OPTIONS);
105088
+ const trackedProc = _internals54.bunSpawn(["git", "-C", directory, "ls-files", "--", ".swarm"], GIT_SPAWN_OPTIONS);
104998
105089
  let trackedExitCode;
104999
105090
  let trackedOutput;
105000
105091
  try {
@@ -105019,7 +105110,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
105019
105110
  }
105020
105111
 
105021
105112
  // src/hooks/diff-scope.ts
105022
- var _internals54 = { bunSpawn };
105113
+ var _internals55 = { bunSpawn };
105023
105114
  function getDeclaredScope(taskId, directory) {
105024
105115
  try {
105025
105116
  const planPath = path136.join(directory, ".swarm", "plan.json");
@@ -105054,7 +105145,7 @@ var GIT_DIFF_SPAWN_OPTIONS = {
105054
105145
  };
105055
105146
  async function getChangedFiles(directory) {
105056
105147
  try {
105057
- const proc = _internals54.bunSpawn(["git", "diff", "--name-only", "HEAD~1"], {
105148
+ const proc = _internals55.bunSpawn(["git", "diff", "--name-only", "HEAD~1"], {
105058
105149
  cwd: directory,
105059
105150
  ...GIT_DIFF_SPAWN_OPTIONS
105060
105151
  });
@@ -105071,7 +105162,7 @@ async function getChangedFiles(directory) {
105071
105162
  return stdout.trim().split(`
105072
105163
  `).map((f) => f.trim()).filter((f) => f.length > 0);
105073
105164
  }
105074
- const proc2 = _internals54.bunSpawn(["git", "diff", "--name-only", "HEAD"], {
105165
+ const proc2 = _internals55.bunSpawn(["git", "diff", "--name-only", "HEAD"], {
105075
105166
  cwd: directory,
105076
105167
  ...GIT_DIFF_SPAWN_OPTIONS
105077
105168
  });
@@ -105129,7 +105220,7 @@ init_telemetry();
105129
105220
  init_file_locks();
105130
105221
  import * as fs106 from "node:fs";
105131
105222
  import * as path137 from "node:path";
105132
- var _internals55 = {
105223
+ var _internals56 = {
105133
105224
  listActiveLocks,
105134
105225
  verifyLeanTurboTaskCompletion
105135
105226
  };
@@ -105271,7 +105362,7 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
105271
105362
  }
105272
105363
  };
105273
105364
  }
105274
- const activeLocks = _internals55.listActiveLocks(directory);
105365
+ const activeLocks = _internals56.listActiveLocks(directory);
105275
105366
  const laneLocks = activeLocks.filter((lock) => lock.laneId === lane.laneId);
105276
105367
  if (laneLocks.length > 0) {
105277
105368
  return {
@@ -1,3 +1,11 @@
1
+ /**
2
+ * Checkpoint artifact writer.
3
+ * Writes SWARM_PLAN.md and SWARM_PLAN.json inside .swarm/.
4
+ * Export-only — not a live runtime source of truth.
5
+ * Called on: save_plan, phase completion, /swarm close.
6
+ * NOT called on every task update.
7
+ */
8
+ import * as fs from 'node:fs';
1
9
  import { type Plan } from '../config/plan-schema';
2
10
  /**
3
11
  * Write SWARM_PLAN.json and SWARM_PLAN.md inside the .swarm/ directory under the project root.
@@ -26,4 +34,6 @@ export declare function importCheckpoint(directory: string, source?: string): Pr
26
34
  export declare const _internals: {
27
35
  writeCheckpoint: typeof writeCheckpoint;
28
36
  importCheckpoint: typeof importCheckpoint;
37
+ existsSyncForCleanup: typeof fs.existsSync;
38
+ unlinkSyncForCleanup: typeof fs.unlinkSync;
29
39
  };
@@ -1,5 +1,5 @@
1
1
  import type { TestRunRecord } from './history-store.js';
2
- export type FailureClassification = 'new_regression' | 'pre_existing' | 'flaky' | 'unknown';
2
+ export type FailureClassification = 'new_regression' | 'pre_existing' | 'flaky' | 'infrastructure_failure' | 'unknown';
3
3
  export interface ClassifiedFailure {
4
4
  testFile: string;
5
5
  testName: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "7.26.1",
3
+ "version": "7.27.0",
4
4
  "description": "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",