opencode-swarm 7.8.0 → 7.9.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.8.0",
37
+ version: "7.9.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",
@@ -19738,7 +19738,13 @@ async function handleArchiveCommand(directory, args) {
19738
19738
  const wouldArchiveAge = [];
19739
19739
  const remainingBundles = [];
19740
19740
  for (const taskId of beforeTaskIds) {
19741
- const result = await loadEvidence(directory, taskId);
19741
+ let result;
19742
+ try {
19743
+ result = await loadEvidence(directory, taskId);
19744
+ } catch (_evidenceErr) {
19745
+ warn("archive: skipping corrupt or unreadable evidence for task", taskId);
19746
+ continue;
19747
+ }
19742
19748
  if (result.status !== "found") {
19743
19749
  continue;
19744
19750
  }
@@ -19793,6 +19799,7 @@ async function handleArchiveCommand(directory, args) {
19793
19799
  var init_archive = __esm(() => {
19794
19800
  init_loader();
19795
19801
  init_manager2();
19802
+ init_utils();
19796
19803
  });
19797
19804
 
19798
19805
  // src/db/project-db.ts
@@ -20799,7 +20806,13 @@ async function handleBenchmarkCommand(directory, args) {
20799
20806
  let totalTestToCodeRatio = 0;
20800
20807
  let qualityEvidenceCount = 0;
20801
20808
  for (const tid of await listEvidenceTaskIds(directory)) {
20802
- const result = await loadEvidence(directory, tid);
20809
+ let result;
20810
+ try {
20811
+ result = await loadEvidence(directory, tid);
20812
+ } catch (_evidenceErr) {
20813
+ warn("benchmark: skipping corrupt or unreadable evidence for task", tid);
20814
+ continue;
20815
+ }
20803
20816
  if (result.status !== "found")
20804
20817
  continue;
20805
20818
  for (const e of result.bundle.entries) {
@@ -37201,7 +37214,17 @@ async function handleDarkMatterCommand(directory, args) {
37201
37214
  i++;
37202
37215
  }
37203
37216
  }
37204
- const pairs = await detectDarkMatter(directory, options);
37217
+ let pairs;
37218
+ try {
37219
+ pairs = await _internals10.detectDarkMatter(directory, options);
37220
+ } catch (err) {
37221
+ const errMsg = err instanceof Error ? err.message : String(err);
37222
+ return `## Dark Matter Analysis Failed
37223
+
37224
+ Error analyzing git history: ${errMsg}
37225
+
37226
+ Ensure this is a git repository with commit history.`;
37227
+ }
37205
37228
  const output = formatDarkMatterOutput(pairs);
37206
37229
  if (pairs.length > 0) {
37207
37230
  try {
@@ -41607,22 +41630,37 @@ var init_handoff_service = __esm(() => {
41607
41630
 
41608
41631
  // src/commands/handoff.ts
41609
41632
  import crypto4 from "crypto";
41610
- import { renameSync as renameSync7 } from "fs";
41633
+ import { renameSync as renameSync7, unlinkSync as unlinkSync4 } from "fs";
41611
41634
  async function handleHandoffCommand(directory, _args) {
41612
41635
  const handoffData = await getHandoffData(directory);
41613
41636
  const markdown = formatHandoffMarkdown(handoffData);
41614
- const resolvedPath = validateSwarmPath(directory, "handoff.md");
41615
- const tempPath = `${resolvedPath}.tmp.${crypto4.randomUUID()}`;
41616
- await bunWrite(tempPath, markdown);
41617
- renameSync7(tempPath, resolvedPath);
41618
- const continuationPrompt = formatContinuationPrompt(handoffData);
41619
- const promptPath = validateSwarmPath(directory, "handoff-prompt.md");
41620
- const promptTempPath = `${promptPath}.tmp.${crypto4.randomUUID()}`;
41621
- await bunWrite(promptTempPath, continuationPrompt);
41622
- renameSync7(promptTempPath, promptPath);
41623
- await writeSnapshot(directory, swarmState);
41624
- await flushPendingSnapshot(directory);
41625
- return `## Handoff Brief Written
41637
+ try {
41638
+ const resolvedPath = validateSwarmPath(directory, "handoff.md");
41639
+ const tempPath = `${resolvedPath}.tmp.${crypto4.randomUUID()}`;
41640
+ await bunWrite(tempPath, markdown);
41641
+ try {
41642
+ renameSync7(tempPath, resolvedPath);
41643
+ } catch (renameErr) {
41644
+ try {
41645
+ unlinkSync4(tempPath);
41646
+ } catch {}
41647
+ throw renameErr;
41648
+ }
41649
+ const continuationPrompt = formatContinuationPrompt(handoffData);
41650
+ const promptPath = validateSwarmPath(directory, "handoff-prompt.md");
41651
+ const promptTempPath = `${promptPath}.tmp.${crypto4.randomUUID()}`;
41652
+ await bunWrite(promptTempPath, continuationPrompt);
41653
+ try {
41654
+ renameSync7(promptTempPath, promptPath);
41655
+ } catch (renameErr) {
41656
+ try {
41657
+ unlinkSync4(promptTempPath);
41658
+ } catch {}
41659
+ throw renameErr;
41660
+ }
41661
+ await writeSnapshot(directory, swarmState);
41662
+ await flushPendingSnapshot(directory);
41663
+ return `## Handoff Brief Written
41626
41664
 
41627
41665
  Brief written to \`.swarm/handoff.md\`.
41628
41666
  Continuation prompt written to \`.swarm/handoff-prompt.md\`.
@@ -41636,6 +41674,16 @@ ${markdown}
41636
41674
  Copy and paste the block below into your next session to resume cleanly:
41637
41675
 
41638
41676
  ${continuationPrompt}`;
41677
+ } catch (err) {
41678
+ const errMsg = err instanceof Error ? err.message : String(err);
41679
+ return `## Handoff Generated (file write failed)
41680
+
41681
+ Handoff data was generated but could not be written to disk: ${errMsg}
41682
+
41683
+ The handoff content is included below for manual copy:
41684
+
41685
+ ${markdown}`;
41686
+ }
41639
41687
  }
41640
41688
  var init_handoff = __esm(() => {
41641
41689
  init_utils2();
@@ -47722,7 +47770,19 @@ async function handleSimulateCommand(directory, args) {
47722
47770
  options.minCommits = val;
47723
47771
  }
47724
47772
  }
47725
- const darkMatterPairs = await detectDarkMatter(directory, options);
47773
+ let darkMatterPairs;
47774
+ try {
47775
+ darkMatterPairs = await _internals10.detectDarkMatter(directory, options);
47776
+ } catch (err) {
47777
+ const errMsg = err instanceof Error ? err.message : String(err);
47778
+ return `## Simulate Report
47779
+
47780
+ ### Error
47781
+
47782
+ Error analyzing git history: ${errMsg}
47783
+
47784
+ Ensure this is a git repository with commit history.`;
47785
+ }
47726
47786
  const reportLines = [
47727
47787
  "# Simulate Report",
47728
47788
  "",
@@ -47740,15 +47800,21 @@ async function handleSimulateCommand(directory, args) {
47740
47800
  ];
47741
47801
  const report = reportLines.filter(Boolean).join(`
47742
47802
  `);
47743
- const fs22 = await import("fs/promises");
47744
- const path37 = await import("path");
47745
- const reportPath = path37.join(directory, ".swarm", "simulate-report.md");
47746
- await fs22.mkdir(path37.dirname(reportPath), { recursive: true });
47747
- await fs22.writeFile(reportPath, report, "utf-8");
47803
+ try {
47804
+ const fs22 = await import("fs/promises");
47805
+ const path37 = await import("path");
47806
+ const reportPath = path37.join(directory, ".swarm", "simulate-report.md");
47807
+ await fs22.mkdir(path37.dirname(reportPath), { recursive: true });
47808
+ await fs22.writeFile(reportPath, report, "utf-8");
47809
+ } catch (err) {
47810
+ const writeErr = err instanceof Error ? err.message : String(err);
47811
+ warn(`simulate: failed to write report to ${directory}/.swarm/simulate-report.md`, writeErr);
47812
+ }
47748
47813
  return `${darkMatterPairs.length} hidden coupling pairs detected`;
47749
47814
  }
47750
47815
  var init_simulate = __esm(() => {
47751
47816
  init_co_change_analyzer();
47817
+ init_utils();
47752
47818
  });
47753
47819
 
47754
47820
  // src/commands/specify.ts
@@ -48195,12 +48261,6 @@ function buildHelpText() {
48195
48261
  return lines.join(`
48196
48262
  `);
48197
48263
  }
48198
- function getHelpText() {
48199
- if (!_helpText) {
48200
- _helpText = buildHelpText();
48201
- }
48202
- return _helpText;
48203
- }
48204
48264
  function createSwarmCommandHandler(directory, agents) {
48205
48265
  return async (input, output) => {
48206
48266
  if (input.command !== "swarm" && !input.command.startsWith("swarm-")) {
@@ -48226,7 +48286,22 @@ function createSwarmCommandHandler(directory, agents) {
48226
48286
  let text;
48227
48287
  const resolved = resolveCommand(tokens);
48228
48288
  if (!resolved) {
48229
- text = getHelpText();
48289
+ if (tokens.length === 0) {
48290
+ text = buildHelpText();
48291
+ } else {
48292
+ const attemptedCommand = tokens[0] || "";
48293
+ const MAX_DISPLAY = 100;
48294
+ const displayCommand = attemptedCommand.length > MAX_DISPLAY ? `${attemptedCommand.slice(0, MAX_DISPLAY)}...` : attemptedCommand;
48295
+ const similar = _internals19.findSimilarCommands(attemptedCommand);
48296
+ const header = `Command \`/swarm ${displayCommand}\` not found.`;
48297
+ const suggestions = similar.length > 0 ? `Did you mean:
48298
+ ${similar.map((cmd) => ` \u2022 /swarm ${cmd}`).join(`
48299
+ `)}` : "";
48300
+ const footer = "Run `/swarm help` for all commands.";
48301
+ text = [header, suggestions, footer].filter(Boolean).join(`
48302
+
48303
+ `);
48304
+ }
48230
48305
  } else {
48231
48306
  try {
48232
48307
  text = await resolved.entry.handler({
@@ -48258,7 +48333,6 @@ ${text}`;
48258
48333
  ];
48259
48334
  };
48260
48335
  }
48261
- var _helpText;
48262
48336
  var init_commands = __esm(() => {
48263
48337
  init_registry();
48264
48338
  init_acknowledge_spec_drift();
@@ -48318,14 +48392,38 @@ function levenshteinDistance(a, b) {
48318
48392
  }
48319
48393
  function findSimilarCommands(query) {
48320
48394
  const q = query.toLowerCase();
48321
- const scored = VALID_COMMANDS.filter((cmd) => {
48322
- if (cmd.includes(" ") || cmd.includes("-"))
48323
- return false;
48324
- return cmd.toLowerCase().includes(q) || q.includes(cmd.toLowerCase());
48325
- }).map((cmd) => ({
48326
- cmd,
48327
- score: cmd.length < q.length ? q.length - cmd.length : _internals19.levenshteinDistance(q, cmd)
48328
- }));
48395
+ if (q.length > 500) {
48396
+ return [];
48397
+ }
48398
+ const scored = VALID_COMMANDS.map((cmd) => {
48399
+ const cmdLower = cmd.toLowerCase();
48400
+ const fullScore = _internals19.levenshteinDistance(q, cmdLower);
48401
+ let tokenScore = Infinity;
48402
+ if (cmd.includes(" ") || cmd.includes("-")) {
48403
+ const qTokens = q.split(/[\s-]+/);
48404
+ const cmdTokens = cmdLower.split(/[\s-]+/);
48405
+ let totalTokenDist = 0;
48406
+ for (const qt of qTokens) {
48407
+ if (qt.length === 0)
48408
+ continue;
48409
+ let minDist = Infinity;
48410
+ for (const ct of cmdTokens) {
48411
+ if (ct.length === 0)
48412
+ continue;
48413
+ const dist = _internals19.levenshteinDistance(qt, ct);
48414
+ if (dist < minDist)
48415
+ minDist = dist;
48416
+ }
48417
+ totalTokenDist += minDist;
48418
+ }
48419
+ tokenScore = totalTokenDist;
48420
+ }
48421
+ const dashStrippedQ = q.replace(/-/g, "");
48422
+ const dashStrippedCmd = cmdLower.replace(/-/g, "");
48423
+ const dashScore = _internals19.levenshteinDistance(dashStrippedQ, dashStrippedCmd);
48424
+ const score = Math.min(fullScore, tokenScore, dashScore);
48425
+ return { cmd, score };
48426
+ });
48329
48427
  scored.sort((a, b) => a.score - b.score);
48330
48428
  return scored.slice(0, 3).map((s) => s.cmd);
48331
48429
  }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Tests for archive.ts graceful handling of corrupt evidence files (Task 1.6)
3
+ *
4
+ * Verifies that the try/catch in handleArchiveCommand's dry-run loop
5
+ * catches exceptions from loadEvidence and skips corrupt/unreadable files.
6
+ *
7
+ * Uses real filesystem operations like existing archive tests.
8
+ */
9
+ export {};
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Tests for benchmark.ts graceful handling of corrupt evidence files.
3
+ *
4
+ * Verifies that the try/catch in handleBenchmarkCommand's cumulative loop
5
+ * catches exceptions from loadEvidence and skips corrupt/unreadable files.
6
+ */
7
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Adversarial security tests for command-not-found UX in createSwarmCommandHandler.
3
+ *
4
+ * Attack vectors covered:
5
+ * 1. Very long command name (10000+ chars) — does it hang or crash?
6
+ * 2. Command with special characters (script injection, shell injection, template literals)
7
+ * 3. Command with newlines/embedded control chars — does it break output format?
8
+ * 4. Command with unicode/emoji — handled gracefully?
9
+ * 5. Extremely deep tokens array (1000 elements) — does findSimilarCommands handle it?
10
+ * 6. Null bytes in command name
11
+ */
12
+ export {};
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Tests for command-not-found UX improvement in createSwarmCommandHandler.
3
+ *
4
+ * Covers:
5
+ * - Unknown single-word command shows "Command not found" + suggestions + footer
6
+ * - Unknown compound command shows header with command name
7
+ * - Empty tokens (empty array) → returns buildHelpText() output
8
+ * - Command with no similar matches → shows header + footer only (no "Did you mean" section)
9
+ * - Multiple similar commands returned → all shown with bullet format
10
+ */
11
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
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.8.0",
36
+ version: "7.9.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",
@@ -20405,7 +20405,13 @@ async function handleArchiveCommand(directory, args2) {
20405
20405
  const wouldArchiveAge = [];
20406
20406
  const remainingBundles = [];
20407
20407
  for (const taskId of beforeTaskIds) {
20408
- const result = await loadEvidence(directory, taskId);
20408
+ let result;
20409
+ try {
20410
+ result = await loadEvidence(directory, taskId);
20411
+ } catch (_evidenceErr) {
20412
+ warn("archive: skipping corrupt or unreadable evidence for task", taskId);
20413
+ continue;
20414
+ }
20409
20415
  if (result.status !== "found") {
20410
20416
  continue;
20411
20417
  }
@@ -20460,6 +20466,7 @@ async function handleArchiveCommand(directory, args2) {
20460
20466
  var init_archive = __esm(() => {
20461
20467
  init_loader();
20462
20468
  init_manager2();
20469
+ init_utils();
20463
20470
  });
20464
20471
 
20465
20472
  // src/db/project-db.ts
@@ -27228,7 +27235,13 @@ async function handleBenchmarkCommand(directory, args2) {
27228
27235
  let totalTestToCodeRatio = 0;
27229
27236
  let qualityEvidenceCount = 0;
27230
27237
  for (const tid of await listEvidenceTaskIds(directory)) {
27231
- const result = await loadEvidence(directory, tid);
27238
+ let result;
27239
+ try {
27240
+ result = await loadEvidence(directory, tid);
27241
+ } catch (_evidenceErr) {
27242
+ warn("benchmark: skipping corrupt or unreadable evidence for task", tid);
27243
+ continue;
27244
+ }
27232
27245
  if (result.status !== "found")
27233
27246
  continue;
27234
27247
  for (const e of result.bundle.entries) {
@@ -43835,8 +43848,10 @@ async function runCuratorInit(directory, config3, llmDelegate) {
43835
43848
  const timer = setTimeout(() => ac.abort(), timeoutMs);
43836
43849
  let llmOutput;
43837
43850
  try {
43851
+ const delegatePromise = llmDelegate(systemPrompt, userInput, ac.signal);
43852
+ delegatePromise.catch(() => {});
43838
43853
  llmOutput = await Promise.race([
43839
- llmDelegate(systemPrompt, userInput, ac.signal),
43854
+ delegatePromise,
43840
43855
  new Promise((_, reject) => {
43841
43856
  ac.signal.addEventListener("abort", () => reject(new Error("CURATOR_LLM_TIMEOUT")));
43842
43857
  })
@@ -43963,8 +43978,10 @@ async function runCuratorPhase(directory, phase, agentsDispatched, config3, _kno
43963
43978
  const timer = setTimeout(() => ac.abort(), timeoutMs);
43964
43979
  let llmOutput;
43965
43980
  try {
43981
+ const delegatePromise = llmDelegate(systemPrompt, userInput, ac.signal);
43982
+ delegatePromise.catch(() => {});
43966
43983
  llmOutput = await Promise.race([
43967
- llmDelegate(systemPrompt, userInput, ac.signal),
43984
+ delegatePromise,
43968
43985
  new Promise((_, reject) => {
43969
43986
  ac.signal.addEventListener("abort", () => reject(new Error("CURATOR_LLM_TIMEOUT")));
43970
43987
  })
@@ -44900,7 +44917,17 @@ async function handleDarkMatterCommand(directory, args2) {
44900
44917
  i2++;
44901
44918
  }
44902
44919
  }
44903
- const pairs = await detectDarkMatter(directory, options);
44920
+ let pairs;
44921
+ try {
44922
+ pairs = await _internals15.detectDarkMatter(directory, options);
44923
+ } catch (err2) {
44924
+ const errMsg = err2 instanceof Error ? err2.message : String(err2);
44925
+ return `## Dark Matter Analysis Failed
44926
+
44927
+ Error analyzing git history: ${errMsg}
44928
+
44929
+ Ensure this is a git repository with commit history.`;
44930
+ }
44904
44931
  const output = formatDarkMatterOutput(pairs);
44905
44932
  if (pairs.length > 0) {
44906
44933
  try {
@@ -49483,22 +49510,37 @@ var init_handoff_service = __esm(() => {
49483
49510
 
49484
49511
  // src/commands/handoff.ts
49485
49512
  import crypto4 from "node:crypto";
49486
- import { renameSync as renameSync10 } from "node:fs";
49513
+ import { renameSync as renameSync10, unlinkSync as unlinkSync5 } from "node:fs";
49487
49514
  async function handleHandoffCommand(directory, _args) {
49488
49515
  const handoffData = await getHandoffData(directory);
49489
49516
  const markdown = formatHandoffMarkdown(handoffData);
49490
- const resolvedPath = validateSwarmPath(directory, "handoff.md");
49491
- const tempPath = `${resolvedPath}.tmp.${crypto4.randomUUID()}`;
49492
- await bunWrite(tempPath, markdown);
49493
- renameSync10(tempPath, resolvedPath);
49494
- const continuationPrompt = formatContinuationPrompt(handoffData);
49495
- const promptPath = validateSwarmPath(directory, "handoff-prompt.md");
49496
- const promptTempPath = `${promptPath}.tmp.${crypto4.randomUUID()}`;
49497
- await bunWrite(promptTempPath, continuationPrompt);
49498
- renameSync10(promptTempPath, promptPath);
49499
- await writeSnapshot(directory, swarmState);
49500
- await flushPendingSnapshot(directory);
49501
- return `## Handoff Brief Written
49517
+ try {
49518
+ const resolvedPath = validateSwarmPath(directory, "handoff.md");
49519
+ const tempPath = `${resolvedPath}.tmp.${crypto4.randomUUID()}`;
49520
+ await bunWrite(tempPath, markdown);
49521
+ try {
49522
+ renameSync10(tempPath, resolvedPath);
49523
+ } catch (renameErr) {
49524
+ try {
49525
+ unlinkSync5(tempPath);
49526
+ } catch {}
49527
+ throw renameErr;
49528
+ }
49529
+ const continuationPrompt = formatContinuationPrompt(handoffData);
49530
+ const promptPath = validateSwarmPath(directory, "handoff-prompt.md");
49531
+ const promptTempPath = `${promptPath}.tmp.${crypto4.randomUUID()}`;
49532
+ await bunWrite(promptTempPath, continuationPrompt);
49533
+ try {
49534
+ renameSync10(promptTempPath, promptPath);
49535
+ } catch (renameErr) {
49536
+ try {
49537
+ unlinkSync5(promptTempPath);
49538
+ } catch {}
49539
+ throw renameErr;
49540
+ }
49541
+ await writeSnapshot(directory, swarmState);
49542
+ await flushPendingSnapshot(directory);
49543
+ return `## Handoff Brief Written
49502
49544
 
49503
49545
  Brief written to \`.swarm/handoff.md\`.
49504
49546
  Continuation prompt written to \`.swarm/handoff-prompt.md\`.
@@ -49512,6 +49554,16 @@ ${markdown}
49512
49554
  Copy and paste the block below into your next session to resume cleanly:
49513
49555
 
49514
49556
  ${continuationPrompt}`;
49557
+ } catch (err2) {
49558
+ const errMsg = err2 instanceof Error ? err2.message : String(err2);
49559
+ return `## Handoff Generated (file write failed)
49560
+
49561
+ Handoff data was generated but could not be written to disk: ${errMsg}
49562
+
49563
+ The handoff content is included below for manual copy:
49564
+
49565
+ ${markdown}`;
49566
+ }
49515
49567
  }
49516
49568
  var init_handoff = __esm(() => {
49517
49569
  init_utils2();
@@ -55708,7 +55760,19 @@ async function handleSimulateCommand(directory, args2) {
55708
55760
  options.minCommits = val;
55709
55761
  }
55710
55762
  }
55711
- const darkMatterPairs = await detectDarkMatter(directory, options);
55763
+ let darkMatterPairs;
55764
+ try {
55765
+ darkMatterPairs = await _internals15.detectDarkMatter(directory, options);
55766
+ } catch (err2) {
55767
+ const errMsg = err2 instanceof Error ? err2.message : String(err2);
55768
+ return `## Simulate Report
55769
+
55770
+ ### Error
55771
+
55772
+ Error analyzing git history: ${errMsg}
55773
+
55774
+ Ensure this is a git repository with commit history.`;
55775
+ }
55712
55776
  const reportLines = [
55713
55777
  "# Simulate Report",
55714
55778
  "",
@@ -55726,15 +55790,21 @@ async function handleSimulateCommand(directory, args2) {
55726
55790
  ];
55727
55791
  const report = reportLines.filter(Boolean).join(`
55728
55792
  `);
55729
- const fs29 = await import("node:fs/promises");
55730
- const path44 = await import("node:path");
55731
- const reportPath = path44.join(directory, ".swarm", "simulate-report.md");
55732
- await fs29.mkdir(path44.dirname(reportPath), { recursive: true });
55733
- await fs29.writeFile(reportPath, report, "utf-8");
55793
+ try {
55794
+ const fs29 = await import("node:fs/promises");
55795
+ const path44 = await import("node:path");
55796
+ const reportPath = path44.join(directory, ".swarm", "simulate-report.md");
55797
+ await fs29.mkdir(path44.dirname(reportPath), { recursive: true });
55798
+ await fs29.writeFile(reportPath, report, "utf-8");
55799
+ } catch (err2) {
55800
+ const writeErr = err2 instanceof Error ? err2.message : String(err2);
55801
+ warn(`simulate: failed to write report to ${directory}/.swarm/simulate-report.md`, writeErr);
55802
+ }
55734
55803
  return `${darkMatterPairs.length} hidden coupling pairs detected`;
55735
55804
  }
55736
55805
  var init_simulate = __esm(() => {
55737
55806
  init_co_change_analyzer();
55807
+ init_utils();
55738
55808
  });
55739
55809
 
55740
55810
  // src/commands/specify.ts
@@ -56396,12 +56466,6 @@ function buildHelpText() {
56396
56466
  return lines.join(`
56397
56467
  `);
56398
56468
  }
56399
- function getHelpText() {
56400
- if (!_helpText) {
56401
- _helpText = buildHelpText();
56402
- }
56403
- return _helpText;
56404
- }
56405
56469
  function createSwarmCommandHandler(directory, agents) {
56406
56470
  return async (input, output) => {
56407
56471
  if (input.command !== "swarm" && !input.command.startsWith("swarm-")) {
@@ -56427,7 +56491,22 @@ function createSwarmCommandHandler(directory, agents) {
56427
56491
  let text;
56428
56492
  const resolved = resolveCommand(tokens);
56429
56493
  if (!resolved) {
56430
- text = getHelpText();
56494
+ if (tokens.length === 0) {
56495
+ text = buildHelpText();
56496
+ } else {
56497
+ const attemptedCommand = tokens[0] || "";
56498
+ const MAX_DISPLAY = 100;
56499
+ const displayCommand = attemptedCommand.length > MAX_DISPLAY ? `${attemptedCommand.slice(0, MAX_DISPLAY)}...` : attemptedCommand;
56500
+ const similar = _internals24.findSimilarCommands(attemptedCommand);
56501
+ const header = `Command \`/swarm ${displayCommand}\` not found.`;
56502
+ const suggestions = similar.length > 0 ? `Did you mean:
56503
+ ${similar.map((cmd) => ` • /swarm ${cmd}`).join(`
56504
+ `)}` : "";
56505
+ const footer = "Run `/swarm help` for all commands.";
56506
+ text = [header, suggestions, footer].filter(Boolean).join(`
56507
+
56508
+ `);
56509
+ }
56431
56510
  } else {
56432
56511
  try {
56433
56512
  text = await resolved.entry.handler({
@@ -56459,7 +56538,6 @@ ${text}`;
56459
56538
  ];
56460
56539
  };
56461
56540
  }
56462
- var _helpText;
56463
56541
  var init_commands = __esm(() => {
56464
56542
  init_registry();
56465
56543
  init_acknowledge_spec_drift();
@@ -56519,14 +56597,38 @@ function levenshteinDistance(a, b) {
56519
56597
  }
56520
56598
  function findSimilarCommands(query) {
56521
56599
  const q = query.toLowerCase();
56522
- const scored = VALID_COMMANDS.filter((cmd) => {
56523
- if (cmd.includes(" ") || cmd.includes("-"))
56524
- return false;
56525
- return cmd.toLowerCase().includes(q) || q.includes(cmd.toLowerCase());
56526
- }).map((cmd) => ({
56527
- cmd,
56528
- score: cmd.length < q.length ? q.length - cmd.length : _internals24.levenshteinDistance(q, cmd)
56529
- }));
56600
+ if (q.length > 500) {
56601
+ return [];
56602
+ }
56603
+ const scored = VALID_COMMANDS.map((cmd) => {
56604
+ const cmdLower = cmd.toLowerCase();
56605
+ const fullScore = _internals24.levenshteinDistance(q, cmdLower);
56606
+ let tokenScore = Infinity;
56607
+ if (cmd.includes(" ") || cmd.includes("-")) {
56608
+ const qTokens = q.split(/[\s-]+/);
56609
+ const cmdTokens = cmdLower.split(/[\s-]+/);
56610
+ let totalTokenDist = 0;
56611
+ for (const qt of qTokens) {
56612
+ if (qt.length === 0)
56613
+ continue;
56614
+ let minDist = Infinity;
56615
+ for (const ct of cmdTokens) {
56616
+ if (ct.length === 0)
56617
+ continue;
56618
+ const dist = _internals24.levenshteinDistance(qt, ct);
56619
+ if (dist < minDist)
56620
+ minDist = dist;
56621
+ }
56622
+ totalTokenDist += minDist;
56623
+ }
56624
+ tokenScore = totalTokenDist;
56625
+ }
56626
+ const dashStrippedQ = q.replace(/-/g, "");
56627
+ const dashStrippedCmd = cmdLower.replace(/-/g, "");
56628
+ const dashScore = _internals24.levenshteinDistance(dashStrippedQ, dashStrippedCmd);
56629
+ const score = Math.min(fullScore, tokenScore, dashScore);
56630
+ return { cmd, score };
56631
+ });
56530
56632
  scored.sort((a, b) => a.score - b.score);
56531
56633
  return scored.slice(0, 3).map((s) => s.cmd);
56532
56634
  }
@@ -65345,27 +65447,32 @@ __export(exports_runtime, {
65345
65447
  isGrammarAvailable: () => isGrammarAvailable,
65346
65448
  getSupportedLanguages: () => getSupportedLanguages,
65347
65449
  getInitializedLanguages: () => getInitializedLanguages,
65348
- clearParserCache: () => clearParserCache
65450
+ clearParserCache: () => clearParserCache,
65451
+ _internals: () => _internals25
65349
65452
  });
65350
65453
  import * as path67 from "node:path";
65351
65454
  import { fileURLToPath as fileURLToPath2 } from "node:url";
65352
65455
  async function initTreeSitter() {
65353
- if (treeSitterInitialized) {
65354
- return;
65355
- }
65356
- const thisDir = path67.dirname(fileURLToPath2(import.meta.url));
65357
- const isSource = thisDir.replace(/\\/g, "/").endsWith("/src/lang");
65358
- if (isSource) {
65359
- await Parser.init();
65360
- } else {
65361
- const grammarsDir = getGrammarsDirAbsolute();
65362
- await Parser.init({
65363
- locateFile(scriptName) {
65364
- return path67.join(grammarsDir, scriptName);
65456
+ if (!treeSitterInitPromise) {
65457
+ treeSitterInitPromise = (async () => {
65458
+ const thisDir = path67.dirname(fileURLToPath2(import.meta.url));
65459
+ const isSource = thisDir.replace(/\\/g, "/").endsWith("/src/lang");
65460
+ if (isSource) {
65461
+ await _internals25.parserInit();
65462
+ } else {
65463
+ const grammarsDir = getGrammarsDirAbsolute();
65464
+ await _internals25.parserInit({
65465
+ locateFile(scriptName) {
65466
+ return path67.join(grammarsDir, scriptName);
65467
+ }
65468
+ });
65365
65469
  }
65470
+ })().catch((err2) => {
65471
+ treeSitterInitPromise = null;
65472
+ throw err2;
65366
65473
  });
65367
65474
  }
65368
- treeSitterInitialized = true;
65475
+ return treeSitterInitPromise;
65369
65476
  }
65370
65477
  function sanitizeLanguageId(languageId) {
65371
65478
  const normalized = languageId.toLowerCase();
@@ -65448,7 +65555,7 @@ async function isGrammarAvailable(languageId) {
65448
65555
  function clearParserCache() {
65449
65556
  parserCache.clear();
65450
65557
  initializedLanguages.clear();
65451
- treeSitterInitialized = false;
65558
+ treeSitterInitPromise = null;
65452
65559
  }
65453
65560
  function getInitializedLanguages() {
65454
65561
  return Array.from(initializedLanguages);
@@ -65456,11 +65563,14 @@ function getInitializedLanguages() {
65456
65563
  function getSupportedLanguages() {
65457
65564
  return Object.keys(LANGUAGE_WASM_MAP);
65458
65565
  }
65459
- var parserCache, initializedLanguages, treeSitterInitialized = false, LANGUAGE_WASM_MAP;
65566
+ var parserCache, initializedLanguages, treeSitterInitPromise = null, _internals25, LANGUAGE_WASM_MAP;
65460
65567
  var init_runtime = __esm(() => {
65461
65568
  init_tree_sitter();
65462
65569
  parserCache = new Map;
65463
65570
  initializedLanguages = new Set;
65571
+ _internals25 = {
65572
+ parserInit: Parser.init
65573
+ };
65464
65574
  LANGUAGE_WASM_MAP = {
65465
65575
  javascript: "tree-sitter-javascript.wasm",
65466
65576
  typescript: "tree-sitter-typescript.wasm",
@@ -65878,9 +65988,9 @@ var init_doc_scan = __esm(() => {
65878
65988
  var exports_knowledge_recall = {};
65879
65989
  __export(exports_knowledge_recall, {
65880
65990
  knowledge_recall: () => knowledge_recall,
65881
- _internals: () => _internals25
65991
+ _internals: () => _internals26
65882
65992
  });
65883
- var knowledge_recall, _internals25;
65993
+ var knowledge_recall, _internals26;
65884
65994
  var init_knowledge_recall = __esm(() => {
65885
65995
  init_zod();
65886
65996
  init_knowledge_store();
@@ -65966,7 +66076,7 @@ var init_knowledge_recall = __esm(() => {
65966
66076
  return JSON.stringify(result);
65967
66077
  }
65968
66078
  });
65969
- _internals25 = {
66079
+ _internals26 = {
65970
66080
  knowledge_recall
65971
66081
  };
65972
66082
  });
@@ -66021,7 +66131,7 @@ __export(exports_curator_drift, {
66021
66131
  runDeterministicDriftCheck: () => runDeterministicDriftCheck,
66022
66132
  readPriorDriftReports: () => readPriorDriftReports,
66023
66133
  buildDriftInjectionText: () => buildDriftInjectionText,
66024
- _internals: () => _internals27
66134
+ _internals: () => _internals28
66025
66135
  });
66026
66136
  import * as fs54 from "node:fs";
66027
66137
  import * as path73 from "node:path";
@@ -66066,7 +66176,7 @@ async function runDeterministicDriftCheck(directory, phase, curatorResult, confi
66066
66176
  try {
66067
66177
  const planMd = await readSwarmFileAsync(directory, "plan.md");
66068
66178
  const specMd = await readSwarmFileAsync(directory, "spec.md");
66069
- const priorReports = await _internals27.readPriorDriftReports(directory);
66179
+ const priorReports = await _internals28.readPriorDriftReports(directory);
66070
66180
  const complianceCount = curatorResult.compliance.length;
66071
66181
  const warningCompliance = curatorResult.compliance.filter((obs) => obs.severity === "warning");
66072
66182
  let alignment = "ALIGNED";
@@ -66115,7 +66225,7 @@ async function runDeterministicDriftCheck(directory, phase, curatorResult, confi
66115
66225
  scope_additions: [],
66116
66226
  injection_summary: injectionSummary
66117
66227
  };
66118
- const reportPath = await _internals27.writeDriftReport(directory, report);
66228
+ const reportPath = await _internals28.writeDriftReport(directory, report);
66119
66229
  getGlobalEventBus().publish("curator.drift.completed", {
66120
66230
  phase,
66121
66231
  alignment,
@@ -66178,12 +66288,12 @@ function buildDriftInjectionText(report, maxChars) {
66178
66288
  }
66179
66289
  return text.slice(0, maxChars);
66180
66290
  }
66181
- var DRIFT_REPORT_PREFIX = "drift-report-phase-", _internals27;
66291
+ var DRIFT_REPORT_PREFIX = "drift-report-phase-", _internals28;
66182
66292
  var init_curator_drift = __esm(() => {
66183
66293
  init_event_bus();
66184
66294
  init_logger();
66185
66295
  init_utils2();
66186
- _internals27 = {
66296
+ _internals28 = {
66187
66297
  readPriorDriftReports,
66188
66298
  writeDriftReport,
66189
66299
  runDeterministicDriftCheck,
@@ -67078,7 +67188,7 @@ init_state();
67078
67188
  init_utils();
67079
67189
  init_bun_compat();
67080
67190
  init_utils2();
67081
- import { renameSync as renameSync12, unlinkSync as unlinkSync8 } from "node:fs";
67191
+ import { renameSync as renameSync12, unlinkSync as unlinkSync9 } from "node:fs";
67082
67192
  import * as nodePath2 from "node:path";
67083
67193
  function createAgentActivityHooks(config3, directory) {
67084
67194
  if (config3.hooks?.agent_activity === false) {
@@ -67156,7 +67266,7 @@ async function doFlush(directory) {
67156
67266
  renameSync12(tempPath, path52);
67157
67267
  } catch (writeError) {
67158
67268
  try {
67159
- unlinkSync8(tempPath);
67269
+ unlinkSync9(tempPath);
67160
67270
  } catch {}
67161
67271
  throw writeError;
67162
67272
  }
@@ -67903,14 +68013,22 @@ function createCuratorLLMDelegate(directory, mode = "init", sessionId) {
67903
68013
  throw new Error("CURATOR_LLM_TIMEOUT");
67904
68014
  }
67905
68015
  const agentName = resolveCuratorAgentName(mode, sessionId);
67906
- const promptResult = await client.session.prompt({
67907
- path: { id: ephemeralSessionId },
67908
- body: {
67909
- agent: agentName,
67910
- tools: { write: false, edit: false, patch: false },
67911
- parts: [{ type: "text", text: userInput }]
68016
+ let promptResult;
68017
+ try {
68018
+ promptResult = await client.session.prompt({
68019
+ path: { id: ephemeralSessionId },
68020
+ body: {
68021
+ agent: agentName,
68022
+ tools: { write: false, edit: false, patch: false },
68023
+ parts: [{ type: "text", text: userInput }]
68024
+ }
68025
+ });
68026
+ } catch (promptErr) {
68027
+ if (signal?.aborted) {
68028
+ throw new Error("CURATOR_LLM_TIMEOUT");
67912
68029
  }
67913
- });
68030
+ throw promptErr;
68031
+ }
67914
68032
  if (!promptResult.data) {
67915
68033
  throw new Error(`Curator LLM prompt failed: ${JSON.stringify(promptResult.error)}`);
67916
68034
  }
@@ -76307,10 +76425,10 @@ async function getRunMemorySummary(directory) {
76307
76425
  if (entries.length === 0) {
76308
76426
  return null;
76309
76427
  }
76310
- const groups = _internals26.groupByTaskId(entries);
76428
+ const groups = _internals27.groupByTaskId(entries);
76311
76429
  const summaries = [];
76312
76430
  for (const [taskId, taskEntries] of groups) {
76313
- const summary = _internals26.summarizeTask(taskId, taskEntries);
76431
+ const summary = _internals27.summarizeTask(taskId, taskEntries);
76314
76432
  if (summary) {
76315
76433
  summaries.push(summary);
76316
76434
  }
@@ -76343,7 +76461,7 @@ Use this data to avoid repeating known failure patterns.`;
76343
76461
  }
76344
76462
  return prefix + summaryText + suffix;
76345
76463
  }
76346
- var _internals26 = {
76464
+ var _internals27 = {
76347
76465
  generateTaskFingerprint,
76348
76466
  recordOutcome,
76349
76467
  getTaskHistory,
@@ -86442,11 +86560,11 @@ var quality_budget = createSwarmTool({
86442
86560
  }).optional().describe("Quality budget thresholds")
86443
86561
  },
86444
86562
  async execute(args2, directory) {
86445
- const result = await _internals28.qualityBudget(args2, directory);
86563
+ const result = await _internals29.qualityBudget(args2, directory);
86446
86564
  return JSON.stringify(result);
86447
86565
  }
86448
86566
  });
86449
- var _internals28 = {
86567
+ var _internals29 = {
86450
86568
  qualityBudget
86451
86569
  };
86452
86570
 
@@ -87175,7 +87293,7 @@ import * as path97 from "node:path";
87175
87293
  var semgrepAvailableCache = null;
87176
87294
  var DEFAULT_RULES_DIR = ".swarm/semgrep-rules";
87177
87295
  var DEFAULT_TIMEOUT_MS3 = 30000;
87178
- var _internals29 = {
87296
+ var _internals30 = {
87179
87297
  isSemgrepAvailable,
87180
87298
  checkSemgrepAvailable,
87181
87299
  resetSemgrepCache,
@@ -87200,7 +87318,7 @@ function isSemgrepAvailable() {
87200
87318
  }
87201
87319
  }
87202
87320
  async function checkSemgrepAvailable() {
87203
- return _internals29.isSemgrepAvailable();
87321
+ return _internals30.isSemgrepAvailable();
87204
87322
  }
87205
87323
  function resetSemgrepCache() {
87206
87324
  semgrepAvailableCache = null;
@@ -87297,12 +87415,12 @@ async function runSemgrep(options) {
87297
87415
  const timeoutMs = options.timeoutMs || DEFAULT_TIMEOUT_MS3;
87298
87416
  if (files.length === 0) {
87299
87417
  return {
87300
- available: _internals29.isSemgrepAvailable(),
87418
+ available: _internals30.isSemgrepAvailable(),
87301
87419
  findings: [],
87302
87420
  engine: "tier_a"
87303
87421
  };
87304
87422
  }
87305
- if (!_internals29.isSemgrepAvailable()) {
87423
+ if (!_internals30.isSemgrepAvailable()) {
87306
87424
  return {
87307
87425
  available: false,
87308
87426
  findings: [],
@@ -87461,7 +87579,7 @@ function assignOccurrenceIndices(findings, directory) {
87461
87579
  }
87462
87580
  const occIdx = countMap.get(baseKey) ?? 0;
87463
87581
  countMap.set(baseKey, occIdx + 1);
87464
- const fp = _internals30.fingerprintFinding(finding, directory, occIdx);
87582
+ const fp = _internals31.fingerprintFinding(finding, directory, occIdx);
87465
87583
  return {
87466
87584
  finding,
87467
87585
  index: occIdx,
@@ -87530,7 +87648,7 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
87530
87648
  }
87531
87649
  } catch {}
87532
87650
  const scannedRelFiles = new Set(scannedFiles.map((f) => normalizeFindingPath(directory, f)));
87533
- const indexed = _internals30.assignOccurrenceIndices(findings, directory);
87651
+ const indexed = _internals31.assignOccurrenceIndices(findings, directory);
87534
87652
  if (existing && !opts?.force) {
87535
87653
  const prunedFingerprints = existing.fingerprints.filter((fp) => {
87536
87654
  const relFile = fp.slice(0, fp.indexOf("|"));
@@ -87670,7 +87788,7 @@ function loadBaseline(directory, phase) {
87670
87788
  };
87671
87789
  }
87672
87790
  }
87673
- var _internals30 = {
87791
+ var _internals31 = {
87674
87792
  fingerprintFinding,
87675
87793
  assignOccurrenceIndices,
87676
87794
  captureOrMergeBaseline,
@@ -88080,11 +88198,11 @@ var sast_scan = createSwarmTool({
88080
88198
  capture_baseline: safeArgs.capture_baseline,
88081
88199
  phase: safeArgs.phase
88082
88200
  };
88083
- const result = await _internals31.sastScan(input, directory);
88201
+ const result = await _internals32.sastScan(input, directory);
88084
88202
  return JSON.stringify(result, null, 2);
88085
88203
  }
88086
88204
  });
88087
- var _internals31 = {
88205
+ var _internals32 = {
88088
88206
  sastScan,
88089
88207
  sast_scan
88090
88208
  };
@@ -92438,7 +92556,7 @@ import * as path110 from "node:path";
92438
92556
 
92439
92557
  // src/mutation/engine.ts
92440
92558
  import { spawnSync as spawnSync3 } from "node:child_process";
92441
- import { unlinkSync as unlinkSync13, writeFileSync as writeFileSync22 } from "node:fs";
92559
+ import { unlinkSync as unlinkSync14, writeFileSync as writeFileSync22 } from "node:fs";
92442
92560
  import * as path109 from "node:path";
92443
92561
 
92444
92562
  // src/mutation/equivalence.ts
@@ -92511,7 +92629,7 @@ function isStaticallyEquivalent(originalCode, mutatedCode) {
92511
92629
  const strippedMutated = stripCode(mutatedCode);
92512
92630
  return strippedOriginal === strippedMutated;
92513
92631
  }
92514
- var _internals32 = {
92632
+ var _internals33 = {
92515
92633
  isStaticallyEquivalent,
92516
92634
  checkEquivalence,
92517
92635
  batchCheckEquivalence
@@ -92551,7 +92669,7 @@ async function batchCheckEquivalence(patches, llmJudge) {
92551
92669
  const results = [];
92552
92670
  for (const { patch, originalCode, mutatedCode } of patches) {
92553
92671
  try {
92554
- const result = await _internals32.checkEquivalence(patch, originalCode, mutatedCode, llmJudge);
92672
+ const result = await _internals33.checkEquivalence(patch, originalCode, mutatedCode, llmJudge);
92555
92673
  results.push(result);
92556
92674
  } catch (err3) {
92557
92675
  results.push({
@@ -92677,7 +92795,7 @@ async function executeMutation(patch, testCommand, _testFiles, workingDir) {
92677
92795
  revertError = new Error(`Failed to revert mutation ${patch.id}: ${revertErr}. Working tree may be dirty.`);
92678
92796
  }
92679
92797
  try {
92680
- unlinkSync13(patchFile);
92798
+ unlinkSync14(patchFile);
92681
92799
  } catch (_unlinkErr) {}
92682
92800
  }
92683
92801
  }
@@ -92851,7 +92969,7 @@ async function executeMutationSuite(patches, testCommand, testFiles, workingDir,
92851
92969
  }
92852
92970
 
92853
92971
  // src/mutation/gate.ts
92854
- var _internals33 = {
92972
+ var _internals34 = {
92855
92973
  evaluateMutationGate,
92856
92974
  buildTestImprovementPrompt,
92857
92975
  buildMessage
@@ -92872,8 +92990,8 @@ function evaluateMutationGate(report, passThreshold = PASS_THRESHOLD, warnThresh
92872
92990
  } else {
92873
92991
  verdict = "fail";
92874
92992
  }
92875
- const testImprovementPrompt = _internals33.buildTestImprovementPrompt(report, passThreshold, verdict);
92876
- const message = _internals33.buildMessage(verdict, adjustedKillRate, report.killed, report.totalMutants, report.equivalent, warnThreshold);
92993
+ const testImprovementPrompt = _internals34.buildTestImprovementPrompt(report, passThreshold, verdict);
92994
+ const message = _internals34.buildMessage(verdict, adjustedKillRate, report.killed, report.totalMutants, report.equivalent, warnThreshold);
92877
92995
  return {
92878
92996
  verdict,
92879
92997
  killRate: report.killRate,
@@ -93490,7 +93608,7 @@ import * as path114 from "node:path";
93490
93608
  init_bun_compat();
93491
93609
  import * as fs92 from "node:fs";
93492
93610
  import * as path113 from "node:path";
93493
- var _internals34 = { bunSpawn };
93611
+ var _internals35 = { bunSpawn };
93494
93612
  var _swarmGitExcludedChecked = false;
93495
93613
  function fileCoversSwarm(content) {
93496
93614
  for (const rawLine of content.split(`
@@ -93523,7 +93641,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
93523
93641
  checkIgnoreExitCode
93524
93642
  ] = await Promise.all([
93525
93643
  (async () => {
93526
- const proc = _internals34.bunSpawn(["git", "-C", directory, "rev-parse", "--show-toplevel"], GIT_SPAWN_OPTIONS);
93644
+ const proc = _internals35.bunSpawn(["git", "-C", directory, "rev-parse", "--show-toplevel"], GIT_SPAWN_OPTIONS);
93527
93645
  try {
93528
93646
  return await Promise.all([proc.exited, proc.stdout.text()]);
93529
93647
  } finally {
@@ -93533,7 +93651,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
93533
93651
  }
93534
93652
  })(),
93535
93653
  (async () => {
93536
- const proc = _internals34.bunSpawn(["git", "-C", directory, "rev-parse", "--git-path", "info/exclude"], GIT_SPAWN_OPTIONS);
93654
+ const proc = _internals35.bunSpawn(["git", "-C", directory, "rev-parse", "--git-path", "info/exclude"], GIT_SPAWN_OPTIONS);
93537
93655
  try {
93538
93656
  return await Promise.all([proc.exited, proc.stdout.text()]);
93539
93657
  } finally {
@@ -93543,7 +93661,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
93543
93661
  }
93544
93662
  })(),
93545
93663
  (async () => {
93546
- const proc = _internals34.bunSpawn(["git", "-C", directory, "check-ignore", "-q", ".swarm/.gitkeep"], GIT_SPAWN_OPTIONS);
93664
+ const proc = _internals35.bunSpawn(["git", "-C", directory, "check-ignore", "-q", ".swarm/.gitkeep"], GIT_SPAWN_OPTIONS);
93547
93665
  try {
93548
93666
  return await proc.exited;
93549
93667
  } finally {
@@ -93582,7 +93700,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
93582
93700
  }
93583
93701
  } catch {}
93584
93702
  }
93585
- const trackedProc = _internals34.bunSpawn(["git", "-C", directory, "ls-files", "--", ".swarm"], GIT_SPAWN_OPTIONS);
93703
+ const trackedProc = _internals35.bunSpawn(["git", "-C", directory, "ls-files", "--", ".swarm"], GIT_SPAWN_OPTIONS);
93586
93704
  let trackedExitCode;
93587
93705
  let trackedOutput;
93588
93706
  try {
@@ -93607,7 +93725,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
93607
93725
  }
93608
93726
 
93609
93727
  // src/hooks/diff-scope.ts
93610
- var _internals35 = { bunSpawn };
93728
+ var _internals36 = { bunSpawn };
93611
93729
  function getDeclaredScope(taskId, directory) {
93612
93730
  try {
93613
93731
  const planPath = path114.join(directory, ".swarm", "plan.json");
@@ -93642,7 +93760,7 @@ var GIT_DIFF_SPAWN_OPTIONS = {
93642
93760
  };
93643
93761
  async function getChangedFiles(directory) {
93644
93762
  try {
93645
- const proc = _internals35.bunSpawn(["git", "diff", "--name-only", "HEAD~1"], {
93763
+ const proc = _internals36.bunSpawn(["git", "diff", "--name-only", "HEAD~1"], {
93646
93764
  cwd: directory,
93647
93765
  ...GIT_DIFF_SPAWN_OPTIONS
93648
93766
  });
@@ -93659,7 +93777,7 @@ async function getChangedFiles(directory) {
93659
93777
  return stdout.trim().split(`
93660
93778
  `).map((f) => f.trim()).filter((f) => f.length > 0);
93661
93779
  }
93662
- const proc2 = _internals35.bunSpawn(["git", "diff", "--name-only", "HEAD"], {
93780
+ const proc2 = _internals36.bunSpawn(["git", "diff", "--name-only", "HEAD"], {
93663
93781
  cwd: directory,
93664
93782
  ...GIT_DIFF_SPAWN_OPTIONS
93665
93783
  });
@@ -95346,7 +95464,7 @@ async function initializeOpenCodeSwarm(ctx) {
95346
95464
  ...opencodeConfig.command || {},
95347
95465
  swarm: {
95348
95466
  template: "/swarm $ARGUMENTS",
95349
- description: "Swarm management commands: /swarm [status|plan|agents|history|config|evidence|handoff|archive|diagnose|diagnosis|preflight|sync-plan|benchmark|export|reset|rollback|retrieve|clarify|analyze|specify|brainstorm|council|qa-gates|dark-matter|knowledge|curate|turbo|full-auto|write-retro|reset-session|simulate|promote|checkpoint|acknowledge-spec-drift|doctor-tools|close]"
95467
+ description: "Swarm management commands: /swarm [status|plan|agents|history|config|evidence|handoff|archive|diagnose|diagnosis|preflight|sync-plan|benchmark|export|reset|rollback|retrieve|clarify|analyze|specify|brainstorm|council|pr-review|issue|qa-gates|dark-matter|knowledge|curate|turbo|full-auto|write-retro|reset-session|simulate|promote|checkpoint|acknowledge-spec-drift|doctor-tools|close]"
95350
95468
  },
95351
95469
  "swarm-status": {
95352
95470
  template: "/swarm status",
@@ -95436,6 +95554,14 @@ async function initializeOpenCodeSwarm(ctx) {
95436
95554
  template: "/swarm council $ARGUMENTS",
95437
95555
  description: "Use /swarm council <question> to convene a multi-model General Council deliberation (generalist / skeptic / domain expert) [--spec-review]"
95438
95556
  },
95557
+ "swarm-pr-review": {
95558
+ template: "/swarm pr-review $ARGUMENTS",
95559
+ description: "Use /swarm pr-review to launch deep PR review with multi-lane analysis"
95560
+ },
95561
+ "swarm-issue": {
95562
+ template: "/swarm issue $ARGUMENTS",
95563
+ description: "Use /swarm issue to ingest a GitHub issue into the swarm workflow"
95564
+ },
95439
95565
  "swarm-qa-gates": {
95440
95566
  template: "/swarm qa-gates $ARGUMENTS",
95441
95567
  description: "Use /swarm qa-gates to view or modify QA gate profile for the current plan"
@@ -95457,7 +95583,7 @@ async function initializeOpenCodeSwarm(ctx) {
95457
95583
  description: "Use /swarm turbo to enable turbo mode for faster execution"
95458
95584
  },
95459
95585
  "swarm-full-auto": {
95460
- template: "/swarm-full-auto $ARGUMENTS",
95586
+ template: "/swarm full-auto $ARGUMENTS",
95461
95587
  description: "Toggle Full-Auto Mode for the active session [on|off]"
95462
95588
  },
95463
95589
  "swarm-write-retro": {
@@ -4,6 +4,16 @@ export type Parser = ParserType;
4
4
  * Parser cache to avoid reloading grammars multiple times per session
5
5
  */
6
6
  export declare const parserCache: Map<string, ParserType>;
7
+ /**
8
+ * DI seam for testing — overridable reference to TreeSitterParser.init.
9
+ * Tests can replace this with a spy/mock to observe init calls without
10
+ * mock.module leakage. Restore the original reference in afterEach.
11
+ */
12
+ export declare const _internals: {
13
+ parserInit: (opts?: {
14
+ locateFile: (scriptName: string) => string;
15
+ }) => Promise<void>;
16
+ };
7
17
  /**
8
18
  * Initialize a parser for the given language
9
19
  * Loads WASM from dist/lang/grammars/ (copied during build)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "7.8.0",
3
+ "version": "7.9.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",