opencode-swarm 6.85.2 → 6.85.4

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 (44) hide show
  1. package/dist/cli/index.js +363 -410
  2. package/dist/index.js +1034 -1085
  3. package/dist/services/diagnose-service.d.ts +10 -0
  4. package/dist/tools/batch-symbols.d.ts +1 -1
  5. package/dist/tools/build-check.d.ts +1 -1
  6. package/dist/tools/check-gate-status.d.ts +1 -1
  7. package/dist/tools/checkpoint.d.ts +1 -1
  8. package/dist/tools/co-change-analyzer.d.ts +1 -1
  9. package/dist/tools/completion-verify.d.ts +1 -1
  10. package/dist/tools/complexity-hotspots.d.ts +1 -1
  11. package/dist/tools/convene-council.d.ts +1 -1
  12. package/dist/tools/convene-general-council.d.ts +1 -1
  13. package/dist/tools/create-tool.d.ts +9 -1
  14. package/dist/tools/declare-council-criteria.d.ts +1 -1
  15. package/dist/tools/declare-scope.d.ts +1 -1
  16. package/dist/tools/domain-detector.d.ts +2 -2
  17. package/dist/tools/evidence-check.d.ts +1 -1
  18. package/dist/tools/file-extractor.d.ts +1 -1
  19. package/dist/tools/get-approved-plan.d.ts +1 -1
  20. package/dist/tools/knowledge-query.d.ts +1 -1
  21. package/dist/tools/lint.d.ts +1 -1
  22. package/dist/tools/pkg-audit.d.ts +1 -1
  23. package/dist/tools/placeholder-scan.d.ts +1 -1
  24. package/dist/tools/pre-check-batch.d.ts +1 -1
  25. package/dist/tools/quality-budget.d.ts +1 -1
  26. package/dist/tools/req-coverage.d.ts +1 -1
  27. package/dist/tools/save-plan.d.ts +1 -1
  28. package/dist/tools/sbom-generate.d.ts +1 -1
  29. package/dist/tools/schema-drift.d.ts +1 -1
  30. package/dist/tools/search.d.ts +1 -1
  31. package/dist/tools/set-qa-gates.d.ts +1 -1
  32. package/dist/tools/suggest-patch.d.ts +1 -1
  33. package/dist/tools/symbols.d.ts +1 -1
  34. package/dist/tools/syntax-check.d.ts +1 -1
  35. package/dist/tools/test-runner.d.ts +1 -1
  36. package/dist/tools/todo-extract.d.ts +1 -1
  37. package/dist/tools/update-task-status.d.ts +1 -1
  38. package/dist/tools/web-search.d.ts +1 -1
  39. package/dist/tools/write-drift-evidence.d.ts +1 -1
  40. package/dist/tools/write-hallucination-evidence.d.ts +1 -1
  41. package/dist/tools/write-mutation-evidence.d.ts +1 -1
  42. package/dist/tools/write-retro.d.ts +1 -1
  43. package/package.json +1 -1
  44. package/dist/knowledge/hive-promoter.d.ts +0 -23
package/dist/cli/index.js CHANGED
@@ -17611,13 +17611,13 @@ __export(exports_config_doctor, {
17611
17611
  import * as crypto3 from "crypto";
17612
17612
  import * as fs9 from "fs";
17613
17613
  import * as os5 from "os";
17614
- import * as path18 from "path";
17614
+ import * as path19 from "path";
17615
17615
  function getUserConfigDir3() {
17616
- return process.env.XDG_CONFIG_HOME || path18.join(os5.homedir(), ".config");
17616
+ return process.env.XDG_CONFIG_HOME || path19.join(os5.homedir(), ".config");
17617
17617
  }
17618
17618
  function getConfigPaths(directory) {
17619
- const userConfigPath = path18.join(getUserConfigDir3(), "opencode", "opencode-swarm.json");
17620
- const projectConfigPath = path18.join(directory, ".opencode", "opencode-swarm.json");
17619
+ const userConfigPath = path19.join(getUserConfigDir3(), "opencode", "opencode-swarm.json");
17620
+ const projectConfigPath = path19.join(directory, ".opencode", "opencode-swarm.json");
17621
17621
  return { userConfigPath, projectConfigPath };
17622
17622
  }
17623
17623
  function computeHash(content) {
@@ -17642,9 +17642,9 @@ function isValidConfigPath(configPath, directory) {
17642
17642
  const normalizedUser = userConfigPath.replace(/\\/g, "/");
17643
17643
  const normalizedProject = projectConfigPath.replace(/\\/g, "/");
17644
17644
  try {
17645
- const resolvedConfig = path18.resolve(configPath);
17646
- const resolvedUser = path18.resolve(normalizedUser);
17647
- const resolvedProject = path18.resolve(normalizedProject);
17645
+ const resolvedConfig = path19.resolve(configPath);
17646
+ const resolvedUser = path19.resolve(normalizedUser);
17647
+ const resolvedProject = path19.resolve(normalizedProject);
17648
17648
  return resolvedConfig === resolvedUser || resolvedConfig === resolvedProject;
17649
17649
  } catch {
17650
17650
  return false;
@@ -17684,12 +17684,12 @@ function createConfigBackup(directory) {
17684
17684
  };
17685
17685
  }
17686
17686
  function writeBackupArtifact(directory, backup) {
17687
- const swarmDir = path18.join(directory, ".swarm");
17687
+ const swarmDir = path19.join(directory, ".swarm");
17688
17688
  if (!fs9.existsSync(swarmDir)) {
17689
17689
  fs9.mkdirSync(swarmDir, { recursive: true });
17690
17690
  }
17691
17691
  const backupFilename = `config-backup-${backup.createdAt}.json`;
17692
- const backupPath = path18.join(swarmDir, backupFilename);
17692
+ const backupPath = path19.join(swarmDir, backupFilename);
17693
17693
  const artifact = {
17694
17694
  createdAt: backup.createdAt,
17695
17695
  configPath: backup.configPath,
@@ -17719,7 +17719,7 @@ function restoreFromBackup(backupPath, directory) {
17719
17719
  return null;
17720
17720
  }
17721
17721
  const targetPath = artifact.configPath;
17722
- const targetDir = path18.dirname(targetPath);
17722
+ const targetDir = path19.dirname(targetPath);
17723
17723
  if (!fs9.existsSync(targetDir)) {
17724
17724
  fs9.mkdirSync(targetDir, { recursive: true });
17725
17725
  }
@@ -17750,9 +17750,9 @@ function readConfigFromFile(directory) {
17750
17750
  return null;
17751
17751
  }
17752
17752
  }
17753
- function validateConfigKey(path19, value, _config) {
17753
+ function validateConfigKey(path20, value, _config) {
17754
17754
  const findings = [];
17755
- switch (path19) {
17755
+ switch (path20) {
17756
17756
  case "agents": {
17757
17757
  if (value !== undefined) {
17758
17758
  findings.push({
@@ -17999,27 +17999,27 @@ function validateConfigKey(path19, value, _config) {
17999
17999
  }
18000
18000
  return findings;
18001
18001
  }
18002
- function walkConfigAndValidate(obj, path19, config3, findings) {
18002
+ function walkConfigAndValidate(obj, path20, config3, findings) {
18003
18003
  if (obj === null || obj === undefined) {
18004
18004
  return;
18005
18005
  }
18006
- if (path19 && typeof obj === "object" && !Array.isArray(obj)) {
18007
- const keyFindings = validateConfigKey(path19, obj, config3);
18006
+ if (path20 && typeof obj === "object" && !Array.isArray(obj)) {
18007
+ const keyFindings = validateConfigKey(path20, obj, config3);
18008
18008
  findings.push(...keyFindings);
18009
18009
  }
18010
18010
  if (typeof obj !== "object") {
18011
- const keyFindings = validateConfigKey(path19, obj, config3);
18011
+ const keyFindings = validateConfigKey(path20, obj, config3);
18012
18012
  findings.push(...keyFindings);
18013
18013
  return;
18014
18014
  }
18015
18015
  if (Array.isArray(obj)) {
18016
18016
  obj.forEach((item, index) => {
18017
- walkConfigAndValidate(item, `${path19}[${index}]`, config3, findings);
18017
+ walkConfigAndValidate(item, `${path20}[${index}]`, config3, findings);
18018
18018
  });
18019
18019
  return;
18020
18020
  }
18021
18021
  for (const [key, value] of Object.entries(obj)) {
18022
- const newPath = path19 ? `${path19}.${key}` : key;
18022
+ const newPath = path20 ? `${path20}.${key}` : key;
18023
18023
  walkConfigAndValidate(value, newPath, config3, findings);
18024
18024
  }
18025
18025
  }
@@ -18139,7 +18139,7 @@ function applySafeAutoFixes(directory, result) {
18139
18139
  }
18140
18140
  }
18141
18141
  if (appliedFixes.length > 0) {
18142
- const configDir = path18.dirname(configPath);
18142
+ const configDir = path19.dirname(configPath);
18143
18143
  if (!fs9.existsSync(configDir)) {
18144
18144
  fs9.mkdirSync(configDir, { recursive: true });
18145
18145
  }
@@ -18149,12 +18149,12 @@ function applySafeAutoFixes(directory, result) {
18149
18149
  return { appliedFixes, updatedConfigPath };
18150
18150
  }
18151
18151
  function writeDoctorArtifact(directory, result) {
18152
- const swarmDir = path18.join(directory, ".swarm");
18152
+ const swarmDir = path19.join(directory, ".swarm");
18153
18153
  if (!fs9.existsSync(swarmDir)) {
18154
18154
  fs9.mkdirSync(swarmDir, { recursive: true });
18155
18155
  }
18156
18156
  const artifactFilename = "config-doctor.json";
18157
- const artifactPath = path18.join(swarmDir, artifactFilename);
18157
+ const artifactPath = path19.join(swarmDir, artifactFilename);
18158
18158
  const guiOutput = {
18159
18159
  timestamp: result.timestamp,
18160
18160
  summary: result.summary,
@@ -18515,8 +18515,8 @@ var init_evidence_summary_service = __esm(() => {
18515
18515
  });
18516
18516
 
18517
18517
  // src/cli/index.ts
18518
- import * as fs23 from "fs";
18519
- import * as os7 from "os";
18518
+ import * as fs22 from "fs";
18519
+ import * as os6 from "os";
18520
18520
  import * as path33 from "path";
18521
18521
 
18522
18522
  // src/commands/acknowledge-spec-drift.ts
@@ -20842,6 +20842,7 @@ async function handleBrainstormCommand(_directory, args) {
20842
20842
  init_zod();
20843
20843
 
20844
20844
  // src/tools/checkpoint.ts
20845
+ init_zod();
20845
20846
  import * as child_process from "child_process";
20846
20847
  import * as fs6 from "fs";
20847
20848
  import * as path8 from "path";
@@ -33184,7 +33185,8 @@ function createSwarmTool(opts) {
33184
33185
  execute: async (args, ctx) => {
33185
33186
  const directory = ctx?.directory ?? process.cwd();
33186
33187
  try {
33187
- return await opts.execute(args, directory, ctx);
33188
+ const result = await opts.execute(args, directory, ctx);
33189
+ return result;
33188
33190
  } catch (error93) {
33189
33191
  const message = error93 instanceof Error ? error93.message : String(error93);
33190
33192
  return JSON.stringify({
@@ -33410,8 +33412,8 @@ function handleDelete(label, directory) {
33410
33412
  var checkpoint = createSwarmTool({
33411
33413
  description: "Save, restore, list, and delete git checkpoints. " + "Use save to create a named snapshot, restore to return to a checkpoint (soft reset), " + "list to see all checkpoints, and delete to remove a checkpoint from the log. " + "Git commits are preserved on delete.",
33412
33414
  args: {
33413
- action: tool.schema.string().describe("Action to perform: save, restore, list, or delete"),
33414
- label: tool.schema.string().optional().describe("Checkpoint label (required for save, restore, delete)")
33415
+ action: exports_external.string().describe("Action to perform: save, restore, list, or delete"),
33416
+ label: exports_external.string().optional().describe("Checkpoint label (required for save, restore, delete)")
33415
33417
  },
33416
33418
  execute: async (args, directory) => {
33417
33419
  if (!isGitRepo()) {
@@ -33485,7 +33487,8 @@ var CheckpointResultSchema = exports_external.object({
33485
33487
  checkpoints: exports_external.array(exports_external.unknown()).optional()
33486
33488
  }).passthrough();
33487
33489
  function safeParseResult(result) {
33488
- const parsed = CheckpointResultSchema.safeParse(JSON.parse(result));
33490
+ const jsonStr = typeof result === "string" ? result : result.output;
33491
+ const parsed = CheckpointResultSchema.safeParse(JSON.parse(jsonStr));
33489
33492
  if (!parsed.success) {
33490
33493
  return {
33491
33494
  success: false,
@@ -33671,7 +33674,7 @@ function resolveSwarmRejectedPath(directory) {
33671
33674
  }
33672
33675
  function resolveHiveKnowledgePath() {
33673
33676
  const platform = process.platform;
33674
- const home = os3.homedir();
33677
+ const home = process.env.HOME || os3.homedir();
33675
33678
  let dataDir;
33676
33679
  if (platform === "win32") {
33677
33680
  dataDir = path9.join(process.env.LOCALAPPDATA || path9.join(home, "AppData", "Local"), "opencode-swarm", "Data");
@@ -34429,6 +34432,7 @@ async function flushPendingSnapshot(directory) {
34429
34432
  }
34430
34433
 
34431
34434
  // src/tools/write-retro.ts
34435
+ init_zod();
34432
34436
  init_evidence_schema();
34433
34437
  init_manager2();
34434
34438
  async function executeWriteRetro(args, directory) {
@@ -34734,22 +34738,22 @@ async function executeWriteRetro(args, directory) {
34734
34738
  var write_retro = createSwarmTool({
34735
34739
  description: "Write a retrospective evidence bundle for a completed phase. " + "Accepts flat retro fields and writes a correctly-wrapped EvidenceBundle to " + ".swarm/evidence/retro-{phase}/evidence.json. " + "Use this instead of manually writing retro JSON to avoid schema validation failures in phase_complete.",
34736
34740
  args: {
34737
- phase: tool.schema.number().int().min(1).max(99).describe("The phase number being completed (e.g., 1, 2, 3)"),
34738
- summary: tool.schema.string().describe("Human-readable summary of the phase"),
34739
- task_count: tool.schema.number().int().min(1).max(9999).describe("Count of tasks completed in this phase"),
34740
- task_complexity: tool.schema.enum(["trivial", "simple", "moderate", "complex"]).describe("Complexity level of the completed tasks"),
34741
- total_tool_calls: tool.schema.number().int().min(0).max(9999).describe("Total number of tool calls in this phase"),
34742
- coder_revisions: tool.schema.number().int().min(0).max(999).describe("Number of coder revisions made"),
34743
- reviewer_rejections: tool.schema.number().int().min(0).max(999).describe("Number of reviewer rejections received"),
34744
- loop_detections: tool.schema.number().int().min(0).max(9999).optional().describe("Number of loop detection events in this phase"),
34745
- circuit_breaker_trips: tool.schema.number().int().min(0).max(9999).optional().describe("Number of circuit breaker trips in this phase"),
34746
- test_failures: tool.schema.number().int().min(0).max(9999).describe("Number of test failures encountered"),
34747
- security_findings: tool.schema.number().int().min(0).max(999).describe("Number of security findings"),
34748
- integration_issues: tool.schema.number().int().min(0).max(999).describe("Number of integration issues"),
34749
- lessons_learned: tool.schema.array(tool.schema.string()).max(5).optional().describe("Key lessons learned from this phase (max 5)"),
34750
- top_rejection_reasons: tool.schema.array(tool.schema.string()).optional().describe("Top reasons for reviewer rejections"),
34751
- task_id: tool.schema.string().optional().describe("Optional custom task ID (defaults to retro-{phase})"),
34752
- metadata: tool.schema.record(tool.schema.string(), tool.schema.unknown()).optional().describe("Optional additional metadata")
34741
+ phase: exports_external.number().int().min(1).max(99).describe("The phase number being completed (e.g., 1, 2, 3)"),
34742
+ summary: exports_external.string().describe("Human-readable summary of the phase"),
34743
+ task_count: exports_external.number().int().min(1).max(9999).describe("Count of tasks completed in this phase"),
34744
+ task_complexity: exports_external.enum(["trivial", "simple", "moderate", "complex"]).describe("Complexity level of the completed tasks"),
34745
+ total_tool_calls: exports_external.number().int().min(0).max(9999).describe("Total number of tool calls in this phase"),
34746
+ coder_revisions: exports_external.number().int().min(0).max(999).describe("Number of coder revisions made"),
34747
+ reviewer_rejections: exports_external.number().int().min(0).max(999).describe("Number of reviewer rejections received"),
34748
+ loop_detections: exports_external.number().int().min(0).max(9999).optional().describe("Number of loop detection events in this phase"),
34749
+ circuit_breaker_trips: exports_external.number().int().min(0).max(9999).optional().describe("Number of circuit breaker trips in this phase"),
34750
+ test_failures: exports_external.number().int().min(0).max(9999).describe("Number of test failures encountered"),
34751
+ security_findings: exports_external.number().int().min(0).max(999).describe("Number of security findings"),
34752
+ integration_issues: exports_external.number().int().min(0).max(999).describe("Number of integration issues"),
34753
+ lessons_learned: exports_external.array(exports_external.string()).max(5).optional().describe("Key lessons learned from this phase (max 5)"),
34754
+ top_rejection_reasons: exports_external.array(exports_external.string()).optional().describe("Top reasons for reviewer rejections"),
34755
+ task_id: exports_external.string().optional().describe("Optional custom task ID (defaults to retro-{phase})"),
34756
+ metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional().describe("Optional additional metadata")
34753
34757
  },
34754
34758
  execute: async (args, directory) => {
34755
34759
  const rawPhase = args.phase !== undefined ? Number(args.phase) : 0;
@@ -35346,6 +35350,9 @@ async function handleCouncilCommand(_directory, args) {
35346
35350
  return `[${tokens.join(" ")}] ${question}`;
35347
35351
  }
35348
35352
 
35353
+ // src/hooks/hive-promoter.ts
35354
+ import path15 from "path";
35355
+
35349
35356
  // src/background/event-bus.ts
35350
35357
  init_utils();
35351
35358
 
@@ -35567,6 +35574,86 @@ async function checkHivePromotions(swarmEntries, config3) {
35567
35574
  total_hive_entries: hiveEntries.length
35568
35575
  };
35569
35576
  }
35577
+ async function promoteToHive(directory, lesson, category) {
35578
+ const trimmedLesson = lesson.trim();
35579
+ const hiveEntries = await readKnowledge(resolveHiveKnowledgePath());
35580
+ const validationResult = validateLesson(trimmedLesson, hiveEntries.map((e) => e.lesson), {
35581
+ category: category || "process",
35582
+ scope: "global",
35583
+ confidence: 1
35584
+ });
35585
+ if (validationResult.severity === "error") {
35586
+ throw new Error(`Lesson rejected by validator: ${validationResult.reason}`);
35587
+ }
35588
+ if (findNearDuplicate(trimmedLesson, hiveEntries, 0.6)) {
35589
+ return `Lesson already exists in hive (near-duplicate).`;
35590
+ }
35591
+ const newHiveEntry = {
35592
+ id: crypto.randomUUID(),
35593
+ tier: "hive",
35594
+ lesson: trimmedLesson,
35595
+ category: category || "process",
35596
+ tags: [],
35597
+ scope: "global",
35598
+ confidence: 1,
35599
+ status: "promoted",
35600
+ confirmed_by: [],
35601
+ retrieval_outcomes: {
35602
+ applied_count: 0,
35603
+ succeeded_after_count: 0,
35604
+ failed_after_count: 0
35605
+ },
35606
+ schema_version: 1,
35607
+ created_at: new Date().toISOString(),
35608
+ updated_at: new Date().toISOString(),
35609
+ source_project: path15.basename(directory) || "unknown",
35610
+ encounter_score: 1
35611
+ };
35612
+ await appendKnowledge(resolveHiveKnowledgePath(), newHiveEntry);
35613
+ return `Promoted to hive: "${trimmedLesson.slice(0, 50)}${trimmedLesson.length > 50 ? "..." : ""}" (confidence: 1.0, source: manual)`;
35614
+ }
35615
+ async function promoteFromSwarm(directory, lessonId) {
35616
+ const swarmEntries = await readKnowledge(resolveSwarmKnowledgePath(directory));
35617
+ const swarmEntry = swarmEntries.find((e) => e.id === lessonId);
35618
+ if (!swarmEntry) {
35619
+ throw new Error(`Lesson ${lessonId} not found in .swarm/knowledge.jsonl`);
35620
+ }
35621
+ const hiveEntries = await readKnowledge(resolveHiveKnowledgePath());
35622
+ const validationResult = validateLesson(swarmEntry.lesson, hiveEntries.map((e) => e.lesson), {
35623
+ category: swarmEntry.category,
35624
+ scope: swarmEntry.scope,
35625
+ confidence: swarmEntry.confidence
35626
+ });
35627
+ if (validationResult.severity === "error") {
35628
+ throw new Error(`Lesson rejected by validator: ${validationResult.reason}`);
35629
+ }
35630
+ if (findNearDuplicate(swarmEntry.lesson, hiveEntries, 0.6)) {
35631
+ return `Lesson already exists in hive (near-duplicate).`;
35632
+ }
35633
+ const newHiveEntry = {
35634
+ id: crypto.randomUUID(),
35635
+ tier: "hive",
35636
+ lesson: swarmEntry.lesson,
35637
+ category: swarmEntry.category,
35638
+ tags: swarmEntry.tags,
35639
+ scope: swarmEntry.scope,
35640
+ confidence: 1,
35641
+ status: "promoted",
35642
+ confirmed_by: [],
35643
+ retrieval_outcomes: {
35644
+ applied_count: 0,
35645
+ succeeded_after_count: 0,
35646
+ failed_after_count: 0
35647
+ },
35648
+ schema_version: 1,
35649
+ created_at: new Date().toISOString(),
35650
+ updated_at: new Date().toISOString(),
35651
+ source_project: swarmEntry.project_name,
35652
+ encounter_score: 1
35653
+ };
35654
+ await appendKnowledge(resolveHiveKnowledgePath(), newHiveEntry);
35655
+ return `Promoted lesson ${lessonId} from swarm to hive: "${swarmEntry.lesson.slice(0, 50)}${swarmEntry.lesson.length > 50 ? "..." : ""}"`;
35656
+ }
35570
35657
 
35571
35658
  // src/commands/curate.ts
35572
35659
  async function handleCurateCommand(directory, _args) {
@@ -35597,13 +35684,14 @@ function formatCurationSummary(summary) {
35597
35684
  }
35598
35685
 
35599
35686
  // src/commands/dark-matter.ts
35600
- import path16 from "path";
35687
+ import path17 from "path";
35601
35688
 
35602
35689
  // src/tools/co-change-analyzer.ts
35690
+ init_zod();
35603
35691
  import * as child_process3 from "child_process";
35604
35692
  import { randomUUID } from "crypto";
35605
35693
  import { readdir, readFile as readFile3, stat } from "fs/promises";
35606
- import * as path15 from "path";
35694
+ import * as path16 from "path";
35607
35695
  import { promisify } from "util";
35608
35696
  function getExecFileAsync() {
35609
35697
  return promisify(child_process3.execFile);
@@ -35705,7 +35793,7 @@ async function scanSourceFiles(dir) {
35705
35793
  try {
35706
35794
  const entries = await readdir(dir, { withFileTypes: true });
35707
35795
  for (const entry of entries) {
35708
- const fullPath = path15.join(dir, entry.name);
35796
+ const fullPath = path16.join(dir, entry.name);
35709
35797
  if (entry.isDirectory()) {
35710
35798
  if (skipDirs.has(entry.name)) {
35711
35799
  continue;
@@ -35713,7 +35801,7 @@ async function scanSourceFiles(dir) {
35713
35801
  const subFiles = await scanSourceFiles(fullPath);
35714
35802
  results.push(...subFiles);
35715
35803
  } else if (entry.isFile()) {
35716
- const ext = path15.extname(entry.name);
35804
+ const ext = path16.extname(entry.name);
35717
35805
  if ([".ts", ".tsx", ".js", ".jsx", ".mjs"].includes(ext)) {
35718
35806
  results.push(fullPath);
35719
35807
  }
@@ -35735,8 +35823,8 @@ async function getStaticEdges(directory) {
35735
35823
  continue;
35736
35824
  }
35737
35825
  try {
35738
- const sourceDir = path15.dirname(sourceFile);
35739
- const resolvedPath = path15.resolve(sourceDir, importPath);
35826
+ const sourceDir = path16.dirname(sourceFile);
35827
+ const resolvedPath = path16.resolve(sourceDir, importPath);
35740
35828
  const extensions = [
35741
35829
  "",
35742
35830
  ".ts",
@@ -35761,8 +35849,8 @@ async function getStaticEdges(directory) {
35761
35849
  if (!targetFile) {
35762
35850
  continue;
35763
35851
  }
35764
- const relSource = path15.relative(directory, sourceFile).replace(/\\/g, "/");
35765
- const relTarget = path15.relative(directory, targetFile).replace(/\\/g, "/");
35852
+ const relSource = path16.relative(directory, sourceFile).replace(/\\/g, "/");
35853
+ const relTarget = path16.relative(directory, targetFile).replace(/\\/g, "/");
35766
35854
  const [key] = relSource < relTarget ? [`${relSource}::${relTarget}`, relSource, relTarget] : [`${relTarget}::${relSource}`, relTarget, relSource];
35767
35855
  edges.add(key);
35768
35856
  } catch {}
@@ -35774,7 +35862,7 @@ async function getStaticEdges(directory) {
35774
35862
  function isTestImplementationPair(fileA, fileB) {
35775
35863
  const testPatterns = [".test.ts", ".test.js", ".spec.ts", ".spec.js"];
35776
35864
  const getBaseName = (filePath) => {
35777
- const base = path15.basename(filePath);
35865
+ const base = path16.basename(filePath);
35778
35866
  for (const pattern of testPatterns) {
35779
35867
  if (base.endsWith(pattern)) {
35780
35868
  return base.slice(0, -pattern.length);
@@ -35784,16 +35872,16 @@ function isTestImplementationPair(fileA, fileB) {
35784
35872
  };
35785
35873
  const baseA = getBaseName(fileA);
35786
35874
  const baseB = getBaseName(fileB);
35787
- return baseA === baseB && baseA !== path15.basename(fileA) && baseA !== path15.basename(fileB);
35875
+ return baseA === baseB && baseA !== path16.basename(fileA) && baseA !== path16.basename(fileB);
35788
35876
  }
35789
35877
  function hasSharedPrefix(fileA, fileB) {
35790
- const dirA = path15.dirname(fileA);
35791
- const dirB = path15.dirname(fileB);
35878
+ const dirA = path16.dirname(fileA);
35879
+ const dirB = path16.dirname(fileB);
35792
35880
  if (dirA !== dirB) {
35793
35881
  return false;
35794
35882
  }
35795
- const baseA = path15.basename(fileA).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
35796
- const baseB = path15.basename(fileB).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
35883
+ const baseA = path16.basename(fileA).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
35884
+ const baseB = path16.basename(fileB).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
35797
35885
  if (baseA.startsWith(baseB) || baseB.startsWith(baseA)) {
35798
35886
  return true;
35799
35887
  }
@@ -35847,8 +35935,8 @@ function darkMatterToKnowledgeEntries(pairs, projectName) {
35847
35935
  const entries = [];
35848
35936
  const now = new Date().toISOString();
35849
35937
  for (const pair of pairs.slice(0, 10)) {
35850
- const baseA = path15.basename(pair.fileA);
35851
- const baseB = path15.basename(pair.fileB);
35938
+ const baseA = path16.basename(pair.fileA);
35939
+ const baseB = path16.basename(pair.fileB);
35852
35940
  let lesson = `Files ${pair.fileA} and ${pair.fileB} co-change with NPMI=${pair.npmi.toFixed(3)} but have no import relationship. This hidden coupling suggests a shared architectural concern \u2014 changes to one likely require changes to the other.`;
35853
35941
  if (lesson.length > 280) {
35854
35942
  lesson = `Files ${baseA} and ${baseB} co-change with NPMI=${pair.npmi.toFixed(3)} but have no import relationship. This hidden coupling suggests a shared architectural concern \u2014 changes to one likely require changes to the other.`;
@@ -35906,10 +35994,10 @@ Consider adding explicit documentation or extracting the shared concern.`;
35906
35994
  var co_change_analyzer = createSwarmTool({
35907
35995
  description: "Detects hidden couplings (dark matter) by analyzing git history to find file pairs that frequently co-change but have no import relationship. Useful for identifying architectural concerns that are not explicitly documented.",
35908
35996
  args: {
35909
- min_commits: tool.schema.number().optional().describe("Minimum commit count to analyze (default: 20)"),
35910
- min_co_changes: tool.schema.number().optional().describe("Minimum co-change count to consider (default: 3)"),
35911
- threshold: tool.schema.number().optional().describe("NPMI threshold for filtering (default: 0.5)"),
35912
- max_commits: tool.schema.number().optional().describe("Maximum commits to analyze (default: 500)")
35997
+ min_commits: exports_external.number().optional().describe("Minimum commit count to analyze (default: 20)"),
35998
+ min_co_changes: exports_external.number().optional().describe("Minimum co-change count to consider (default: 3)"),
35999
+ threshold: exports_external.number().optional().describe("NPMI threshold for filtering (default: 0.5)"),
36000
+ max_commits: exports_external.number().optional().describe("Maximum commits to analyze (default: 500)")
35913
36001
  },
35914
36002
  async execute(args, directory) {
35915
36003
  let minCommits;
@@ -35958,7 +36046,7 @@ async function handleDarkMatterCommand(directory, args) {
35958
36046
  const output = formatDarkMatterOutput(pairs);
35959
36047
  if (pairs.length > 0) {
35960
36048
  try {
35961
- const projectName = path16.basename(path16.resolve(directory));
36049
+ const projectName = path17.basename(path17.resolve(directory));
35962
36050
  const entries = darkMatterToKnowledgeEntries(pairs, projectName);
35963
36051
  if (entries.length > 0) {
35964
36052
  const knowledgePath = resolveSwarmKnowledgePath(directory);
@@ -35980,7 +36068,7 @@ async function handleDarkMatterCommand(directory, args) {
35980
36068
  // src/services/diagnose-service.ts
35981
36069
  import * as child_process4 from "child_process";
35982
36070
  import { existsSync as existsSync8, readdirSync as readdirSync4, readFileSync as readFileSync6, statSync as statSync5 } from "fs";
35983
- import path17 from "path";
36071
+ import path18 from "path";
35984
36072
  import { fileURLToPath } from "url";
35985
36073
  init_manager2();
35986
36074
  init_utils2();
@@ -36280,7 +36368,7 @@ async function checkSpecStaleness(directory, plan) {
36280
36368
  };
36281
36369
  }
36282
36370
  async function checkConfigParseability(directory) {
36283
- const configPath = path17.join(directory, ".opencode/opencode-swarm.json");
36371
+ const configPath = path18.join(directory, ".opencode/opencode-swarm.json");
36284
36372
  if (!existsSync8(configPath)) {
36285
36373
  return {
36286
36374
  name: "Config Parseability",
@@ -36305,6 +36393,12 @@ async function checkConfigParseability(directory) {
36305
36393
  };
36306
36394
  }
36307
36395
  }
36396
+ function resolveGrammarDir(thisDir) {
36397
+ const normalized = thisDir.replace(/\\/g, "/");
36398
+ const isSource = normalized.endsWith("/src/services");
36399
+ const isCliBundle = normalized.endsWith("/cli");
36400
+ return isSource || isCliBundle ? path18.join(thisDir, "..", "lang", "grammars") : path18.join(thisDir, "lang", "grammars");
36401
+ }
36308
36402
  async function checkGrammarWasmFiles() {
36309
36403
  const grammarFiles = [
36310
36404
  "tree-sitter-javascript.wasm",
@@ -36327,15 +36421,14 @@ async function checkGrammarWasmFiles() {
36327
36421
  "tree-sitter-ini.wasm",
36328
36422
  "tree-sitter-regex.wasm"
36329
36423
  ];
36330
- const thisDir = path17.dirname(fileURLToPath(import.meta.url));
36331
- const isSource = thisDir.replace(/\\/g, "/").endsWith("/src/services");
36332
- const grammarDir = isSource ? path17.join(thisDir, "..", "lang", "grammars") : path17.join(thisDir, "lang", "grammars");
36424
+ const thisDir = path18.dirname(fileURLToPath(import.meta.url));
36425
+ const grammarDir = resolveGrammarDir(thisDir);
36333
36426
  const missing = [];
36334
- if (!existsSync8(path17.join(grammarDir, "tree-sitter.wasm"))) {
36427
+ if (!existsSync8(path18.join(grammarDir, "tree-sitter.wasm"))) {
36335
36428
  missing.push("tree-sitter.wasm (core runtime)");
36336
36429
  }
36337
36430
  for (const file3 of grammarFiles) {
36338
- if (!existsSync8(path17.join(grammarDir, file3))) {
36431
+ if (!existsSync8(path18.join(grammarDir, file3))) {
36339
36432
  missing.push(file3);
36340
36433
  }
36341
36434
  }
@@ -36353,7 +36446,7 @@ async function checkGrammarWasmFiles() {
36353
36446
  };
36354
36447
  }
36355
36448
  async function checkCheckpointManifest(directory) {
36356
- const manifestPath = path17.join(directory, ".swarm/checkpoints.json");
36449
+ const manifestPath = path18.join(directory, ".swarm/checkpoints.json");
36357
36450
  if (!existsSync8(manifestPath)) {
36358
36451
  return {
36359
36452
  name: "Checkpoint Manifest",
@@ -36405,7 +36498,7 @@ async function checkCheckpointManifest(directory) {
36405
36498
  }
36406
36499
  }
36407
36500
  async function checkEventStreamIntegrity(directory) {
36408
- const eventsPath = path17.join(directory, ".swarm/events.jsonl");
36501
+ const eventsPath = path18.join(directory, ".swarm/events.jsonl");
36409
36502
  if (!existsSync8(eventsPath)) {
36410
36503
  return {
36411
36504
  name: "Event Stream",
@@ -36446,7 +36539,7 @@ async function checkEventStreamIntegrity(directory) {
36446
36539
  }
36447
36540
  }
36448
36541
  async function checkSteeringDirectives(directory) {
36449
- const eventsPath = path17.join(directory, ".swarm/events.jsonl");
36542
+ const eventsPath = path18.join(directory, ".swarm/events.jsonl");
36450
36543
  if (!existsSync8(eventsPath)) {
36451
36544
  return {
36452
36545
  name: "Steering Directives",
@@ -36502,7 +36595,7 @@ async function checkCurator(directory) {
36502
36595
  detail: "Disabled (enable via curator.enabled)"
36503
36596
  };
36504
36597
  }
36505
- const summaryPath = path17.join(directory, ".swarm/curator-summary.json");
36598
+ const summaryPath = path18.join(directory, ".swarm/curator-summary.json");
36506
36599
  if (!existsSync8(summaryPath)) {
36507
36600
  return {
36508
36601
  name: "Curator",
@@ -36650,7 +36743,7 @@ async function getDiagnoseData(directory) {
36650
36743
  checks5.push(await checkSteeringDirectives(directory));
36651
36744
  checks5.push(await checkCurator(directory));
36652
36745
  try {
36653
- const evidenceDir = path17.join(directory, ".swarm", "evidence");
36746
+ const evidenceDir = path18.join(directory, ".swarm", "evidence");
36654
36747
  const snapshotFiles = existsSync8(evidenceDir) ? readdirSync4(evidenceDir).filter((f) => f.startsWith("agent-tools-") && f.endsWith(".json")) : [];
36655
36748
  if (snapshotFiles.length > 0) {
36656
36749
  const latest = snapshotFiles.sort().pop();
@@ -36703,11 +36796,11 @@ init_config_doctor();
36703
36796
 
36704
36797
  // src/services/tool-doctor.ts
36705
36798
  import * as fs11 from "fs";
36706
- import * as path20 from "path";
36799
+ import * as path21 from "path";
36707
36800
 
36708
36801
  // src/build/discovery.ts
36709
36802
  import * as fs10 from "fs";
36710
- import * as path19 from "path";
36803
+ import * as path20 from "path";
36711
36804
 
36712
36805
  // src/lang/detector.ts
36713
36806
  import { access as access2, readdir as readdir2 } from "fs/promises";
@@ -37211,7 +37304,7 @@ LANGUAGE_REGISTRY.register({
37211
37304
  displayName: "C# / .NET",
37212
37305
  tier: 2,
37213
37306
  extensions: [".cs", ".csx"],
37214
- treeSitter: { grammarId: "c_sharp", wasmFile: "tree-sitter-c_sharp.wasm" },
37307
+ treeSitter: { grammarId: "csharp", wasmFile: "tree-sitter-c-sharp.wasm" },
37215
37308
  build: {
37216
37309
  detectFiles: ["*.csproj", "*.sln", "Directory.Build.props"],
37217
37310
  commands: [
@@ -37871,11 +37964,11 @@ function findBuildFiles(workingDir, patterns) {
37871
37964
  const regex = simpleGlobToRegex(pattern);
37872
37965
  const matches = files.filter((f) => regex.test(f));
37873
37966
  if (matches.length > 0) {
37874
- return path19.join(dir, matches[0]);
37967
+ return path20.join(dir, matches[0]);
37875
37968
  }
37876
37969
  } catch {}
37877
37970
  } else {
37878
- const filePath = path19.join(workingDir, pattern);
37971
+ const filePath = path20.join(workingDir, pattern);
37879
37972
  if (fs10.existsSync(filePath)) {
37880
37973
  return filePath;
37881
37974
  }
@@ -37884,7 +37977,7 @@ function findBuildFiles(workingDir, patterns) {
37884
37977
  return null;
37885
37978
  }
37886
37979
  function getRepoDefinedScripts(workingDir, scripts) {
37887
- const packageJsonPath = path19.join(workingDir, "package.json");
37980
+ const packageJsonPath = path20.join(workingDir, "package.json");
37888
37981
  if (!fs10.existsSync(packageJsonPath)) {
37889
37982
  return [];
37890
37983
  }
@@ -37925,7 +38018,7 @@ function findAllBuildFiles(workingDir) {
37925
38018
  const regex = simpleGlobToRegex(pattern);
37926
38019
  findFilesRecursive(workingDir, regex, allBuildFiles);
37927
38020
  } else {
37928
- const filePath = path19.join(workingDir, pattern);
38021
+ const filePath = path20.join(workingDir, pattern);
37929
38022
  if (fs10.existsSync(filePath)) {
37930
38023
  allBuildFiles.add(filePath);
37931
38024
  }
@@ -37938,7 +38031,7 @@ function findFilesRecursive(dir, regex, results) {
37938
38031
  try {
37939
38032
  const entries = fs10.readdirSync(dir, { withFileTypes: true });
37940
38033
  for (const entry of entries) {
37941
- const fullPath = path19.join(dir, entry.name);
38034
+ const fullPath = path20.join(dir, entry.name);
37942
38035
  if (entry.isDirectory() && !["node_modules", ".git", "dist", "build", "target"].includes(entry.name)) {
37943
38036
  findFilesRecursive(fullPath, regex, results);
37944
38037
  } else if (entry.isFile() && regex.test(entry.name)) {
@@ -37961,7 +38054,7 @@ async function discoverBuildCommandsFromProfiles(workingDir) {
37961
38054
  let foundCommand = false;
37962
38055
  for (const cmd of sortedCommands) {
37963
38056
  if (cmd.detectFile) {
37964
- const detectFilePath = path19.join(workingDir, cmd.detectFile);
38057
+ const detectFilePath = path20.join(workingDir, cmd.detectFile);
37965
38058
  if (!fs10.existsSync(detectFilePath)) {
37966
38059
  continue;
37967
38060
  }
@@ -38136,8 +38229,8 @@ function checkBinaryReadiness() {
38136
38229
  }
38137
38230
  function runToolDoctor(_directory, pluginRoot) {
38138
38231
  const findings = [];
38139
- const resolvedPluginRoot = pluginRoot ?? path20.resolve(import.meta.dir, "..", "..");
38140
- const indexPath = path20.join(resolvedPluginRoot, "src", "index.ts");
38232
+ const resolvedPluginRoot = pluginRoot ?? path21.resolve(import.meta.dir, "..", "..");
38233
+ const indexPath = path21.join(resolvedPluginRoot, "src", "index.ts");
38141
38234
  if (!fs11.existsSync(indexPath)) {
38142
38235
  return {
38143
38236
  findings: [
@@ -39060,10 +39153,10 @@ async function handleHistoryCommand(directory, _args) {
39060
39153
  import { randomUUID as randomUUID2 } from "crypto";
39061
39154
  import { existsSync as existsSync12, readFileSync as readFileSync10 } from "fs";
39062
39155
  import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
39063
- import * as path21 from "path";
39156
+ import * as path22 from "path";
39064
39157
  async function migrateContextToKnowledge(directory, config3) {
39065
- const sentinelPath = path21.join(directory, ".swarm", ".knowledge-migrated");
39066
- const contextPath = path21.join(directory, ".swarm", "context.md");
39158
+ const sentinelPath = path22.join(directory, ".swarm", ".knowledge-migrated");
39159
+ const contextPath = path22.join(directory, ".swarm", "context.md");
39067
39160
  const knowledgePath = resolveSwarmKnowledgePath(directory);
39068
39161
  if (existsSync12(sentinelPath)) {
39069
39162
  return {
@@ -39259,7 +39352,7 @@ function truncateLesson(text) {
39259
39352
  return `${text.slice(0, 277)}...`;
39260
39353
  }
39261
39354
  function inferProjectName(directory) {
39262
- const packageJsonPath = path21.join(directory, "package.json");
39355
+ const packageJsonPath = path22.join(directory, "package.json");
39263
39356
  if (existsSync12(packageJsonPath)) {
39264
39357
  try {
39265
39358
  const pkg = JSON.parse(readFileSync10(packageJsonPath, "utf-8"));
@@ -39268,7 +39361,7 @@ function inferProjectName(directory) {
39268
39361
  }
39269
39362
  } catch {}
39270
39363
  }
39271
- return path21.basename(directory);
39364
+ return path22.basename(directory);
39272
39365
  }
39273
39366
  async function writeSentinel(sentinelPath, migrated, dropped) {
39274
39367
  const sentinel = {
@@ -39280,7 +39373,7 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
39280
39373
  schema_version: 1,
39281
39374
  migration_tool: "knowledge-migrator.ts"
39282
39375
  };
39283
- await mkdir3(path21.dirname(sentinelPath), { recursive: true });
39376
+ await mkdir3(path22.dirname(sentinelPath), { recursive: true });
39284
39377
  await writeFile4(sentinelPath, JSON.stringify(sentinel, null, 2), "utf-8");
39285
39378
  }
39286
39379
 
@@ -39517,11 +39610,12 @@ async function handlePlanCommand(directory, args) {
39517
39610
  init_manager2();
39518
39611
  init_manager();
39519
39612
  import * as fs18 from "fs";
39520
- import * as path28 from "path";
39613
+ import * as path29 from "path";
39521
39614
 
39522
39615
  // src/tools/lint.ts
39616
+ init_zod();
39523
39617
  import * as fs12 from "fs";
39524
- import * as path22 from "path";
39618
+ import * as path23 from "path";
39525
39619
  init_utils();
39526
39620
 
39527
39621
  // src/utils/path-security.ts
@@ -39567,9 +39661,9 @@ function validateArgs(args) {
39567
39661
  }
39568
39662
  function getLinterCommand(linter, mode, projectDir) {
39569
39663
  const isWindows = process.platform === "win32";
39570
- const binDir = path22.join(projectDir, "node_modules", ".bin");
39571
- const biomeBin = isWindows ? path22.join(binDir, "biome.EXE") : path22.join(binDir, "biome");
39572
- const eslintBin = isWindows ? path22.join(binDir, "eslint.cmd") : path22.join(binDir, "eslint");
39664
+ const binDir = path23.join(projectDir, "node_modules", ".bin");
39665
+ const biomeBin = isWindows ? path23.join(binDir, "biome.EXE") : path23.join(binDir, "biome");
39666
+ const eslintBin = isWindows ? path23.join(binDir, "eslint.cmd") : path23.join(binDir, "eslint");
39573
39667
  switch (linter) {
39574
39668
  case "biome":
39575
39669
  if (mode === "fix") {
@@ -39585,7 +39679,7 @@ function getLinterCommand(linter, mode, projectDir) {
39585
39679
  }
39586
39680
  function getAdditionalLinterCommand(linter, mode, cwd) {
39587
39681
  const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
39588
- const gradlew = fs12.existsSync(path22.join(cwd, gradlewName)) ? path22.join(cwd, gradlewName) : null;
39682
+ const gradlew = fs12.existsSync(path23.join(cwd, gradlewName)) ? path23.join(cwd, gradlewName) : null;
39589
39683
  switch (linter) {
39590
39684
  case "ruff":
39591
39685
  return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
@@ -39619,10 +39713,10 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
39619
39713
  }
39620
39714
  }
39621
39715
  function detectRuff(cwd) {
39622
- if (fs12.existsSync(path22.join(cwd, "ruff.toml")))
39716
+ if (fs12.existsSync(path23.join(cwd, "ruff.toml")))
39623
39717
  return isCommandAvailable("ruff");
39624
39718
  try {
39625
- const pyproject = path22.join(cwd, "pyproject.toml");
39719
+ const pyproject = path23.join(cwd, "pyproject.toml");
39626
39720
  if (fs12.existsSync(pyproject)) {
39627
39721
  const content = fs12.readFileSync(pyproject, "utf-8");
39628
39722
  if (content.includes("[tool.ruff]"))
@@ -39632,19 +39726,19 @@ function detectRuff(cwd) {
39632
39726
  return false;
39633
39727
  }
39634
39728
  function detectClippy(cwd) {
39635
- return fs12.existsSync(path22.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
39729
+ return fs12.existsSync(path23.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
39636
39730
  }
39637
39731
  function detectGolangciLint(cwd) {
39638
- return fs12.existsSync(path22.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
39732
+ return fs12.existsSync(path23.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
39639
39733
  }
39640
39734
  function detectCheckstyle(cwd) {
39641
- const hasMaven = fs12.existsSync(path22.join(cwd, "pom.xml"));
39642
- const hasGradle = fs12.existsSync(path22.join(cwd, "build.gradle")) || fs12.existsSync(path22.join(cwd, "build.gradle.kts"));
39643
- const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs12.existsSync(path22.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
39735
+ const hasMaven = fs12.existsSync(path23.join(cwd, "pom.xml"));
39736
+ const hasGradle = fs12.existsSync(path23.join(cwd, "build.gradle")) || fs12.existsSync(path23.join(cwd, "build.gradle.kts"));
39737
+ const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs12.existsSync(path23.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
39644
39738
  return (hasMaven || hasGradle) && hasBinary;
39645
39739
  }
39646
39740
  function detectKtlint(cwd) {
39647
- const hasKotlin = fs12.existsSync(path22.join(cwd, "build.gradle.kts")) || fs12.existsSync(path22.join(cwd, "build.gradle")) || (() => {
39741
+ const hasKotlin = fs12.existsSync(path23.join(cwd, "build.gradle.kts")) || fs12.existsSync(path23.join(cwd, "build.gradle")) || (() => {
39648
39742
  try {
39649
39743
  return fs12.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
39650
39744
  } catch {
@@ -39663,11 +39757,11 @@ function detectDotnetFormat(cwd) {
39663
39757
  }
39664
39758
  }
39665
39759
  function detectCppcheck(cwd) {
39666
- if (fs12.existsSync(path22.join(cwd, "CMakeLists.txt"))) {
39760
+ if (fs12.existsSync(path23.join(cwd, "CMakeLists.txt"))) {
39667
39761
  return isCommandAvailable("cppcheck");
39668
39762
  }
39669
39763
  try {
39670
- const dirsToCheck = [cwd, path22.join(cwd, "src")];
39764
+ const dirsToCheck = [cwd, path23.join(cwd, "src")];
39671
39765
  const hasCpp = dirsToCheck.some((dir) => {
39672
39766
  try {
39673
39767
  return fs12.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
@@ -39681,13 +39775,13 @@ function detectCppcheck(cwd) {
39681
39775
  }
39682
39776
  }
39683
39777
  function detectSwiftlint(cwd) {
39684
- return fs12.existsSync(path22.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
39778
+ return fs12.existsSync(path23.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
39685
39779
  }
39686
39780
  function detectDartAnalyze(cwd) {
39687
- return fs12.existsSync(path22.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
39781
+ return fs12.existsSync(path23.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
39688
39782
  }
39689
39783
  function detectRubocop(cwd) {
39690
- return (fs12.existsSync(path22.join(cwd, "Gemfile")) || fs12.existsSync(path22.join(cwd, "gems.rb")) || fs12.existsSync(path22.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
39784
+ return (fs12.existsSync(path23.join(cwd, "Gemfile")) || fs12.existsSync(path23.join(cwd, "gems.rb")) || fs12.existsSync(path23.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
39691
39785
  }
39692
39786
  function detectAdditionalLinter(cwd) {
39693
39787
  if (detectRuff(cwd))
@@ -39715,10 +39809,10 @@ function detectAdditionalLinter(cwd) {
39715
39809
  function findBinInAncestors(startDir, binName) {
39716
39810
  let dir = startDir;
39717
39811
  while (true) {
39718
- const candidate = path22.join(dir, "node_modules", ".bin", binName);
39812
+ const candidate = path23.join(dir, "node_modules", ".bin", binName);
39719
39813
  if (fs12.existsSync(candidate))
39720
39814
  return candidate;
39721
- const parent = path22.dirname(dir);
39815
+ const parent = path23.dirname(dir);
39722
39816
  if (parent === dir)
39723
39817
  break;
39724
39818
  dir = parent;
@@ -39727,10 +39821,10 @@ function findBinInAncestors(startDir, binName) {
39727
39821
  }
39728
39822
  function findBinInEnvPath(binName) {
39729
39823
  const searchPath = process.env.PATH ?? "";
39730
- for (const dir of searchPath.split(path22.delimiter)) {
39824
+ for (const dir of searchPath.split(path23.delimiter)) {
39731
39825
  if (!dir)
39732
39826
  continue;
39733
- const candidate = path22.join(dir, binName);
39827
+ const candidate = path23.join(dir, binName);
39734
39828
  if (fs12.existsSync(candidate))
39735
39829
  return candidate;
39736
39830
  }
@@ -39743,13 +39837,13 @@ async function detectAvailableLinter(directory) {
39743
39837
  return null;
39744
39838
  const projectDir = directory;
39745
39839
  const isWindows = process.platform === "win32";
39746
- const biomeBin = isWindows ? path22.join(projectDir, "node_modules", ".bin", "biome.EXE") : path22.join(projectDir, "node_modules", ".bin", "biome");
39747
- const eslintBin = isWindows ? path22.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path22.join(projectDir, "node_modules", ".bin", "eslint");
39840
+ const biomeBin = isWindows ? path23.join(projectDir, "node_modules", ".bin", "biome.EXE") : path23.join(projectDir, "node_modules", ".bin", "biome");
39841
+ const eslintBin = isWindows ? path23.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path23.join(projectDir, "node_modules", ".bin", "eslint");
39748
39842
  const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
39749
39843
  if (localResult)
39750
39844
  return localResult;
39751
- const biomeAncestor = findBinInAncestors(path22.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
39752
- const eslintAncestor = findBinInAncestors(path22.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
39845
+ const biomeAncestor = findBinInAncestors(path23.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
39846
+ const eslintAncestor = findBinInAncestors(path23.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
39753
39847
  if (biomeAncestor || eslintAncestor) {
39754
39848
  return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
39755
39849
  }
@@ -39911,7 +40005,7 @@ async function runAdditionalLint(linter, mode, cwd) {
39911
40005
  var lint = createSwarmTool({
39912
40006
  description: "Run project linter in check or fix mode. Supports biome, eslint (JS/TS), ruff (Python), clippy (Rust), golangci-lint (Go), checkstyle (Java), ktlint (Kotlin), dotnet-format (C#), cppcheck (C/C++), swiftlint (Swift), dart analyze (Dart), and rubocop (Ruby). Returns JSON with success status, exit code, and output for architect pre-reviewer gate. Use check mode for CI/linting and fix mode to automatically apply fixes.",
39913
40007
  args: {
39914
- mode: tool.schema.enum(["fix", "check"]).describe('Linting mode: "check" for read-only lint check, "fix" to automatically apply fixes')
40008
+ mode: exports_external.enum(["fix", "check"]).describe('Linting mode: "check" for read-only lint check, "fix" to automatically apply fixes')
39915
40009
  },
39916
40010
  async execute(args, directory) {
39917
40011
  if (!validateArgs(args)) {
@@ -39956,8 +40050,9 @@ For Rust: rustup component add clippy`
39956
40050
  });
39957
40051
 
39958
40052
  // src/tools/secretscan.ts
40053
+ init_zod();
39959
40054
  import * as fs13 from "fs";
39960
- import * as path23 from "path";
40055
+ import * as path24 from "path";
39961
40056
  var MAX_FILE_PATH_LENGTH = 500;
39962
40057
  var MAX_FILE_SIZE_BYTES = 512 * 1024;
39963
40058
  var MAX_FILES_SCANNED = 1000;
@@ -40184,7 +40279,7 @@ function isGlobOrPathPattern(pattern) {
40184
40279
  return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
40185
40280
  }
40186
40281
  function loadSecretScanIgnore(scanDir) {
40187
- const ignorePath = path23.join(scanDir, ".secretscanignore");
40282
+ const ignorePath = path24.join(scanDir, ".secretscanignore");
40188
40283
  try {
40189
40284
  if (!fs13.existsSync(ignorePath))
40190
40285
  return [];
@@ -40207,7 +40302,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
40207
40302
  if (exactNames.has(entry))
40208
40303
  return true;
40209
40304
  for (const pattern of globPatterns) {
40210
- if (path23.matchesGlob(relPath, pattern))
40305
+ if (path24.matchesGlob(relPath, pattern))
40211
40306
  return true;
40212
40307
  }
40213
40308
  return false;
@@ -40228,7 +40323,7 @@ function validateDirectoryInput(dir) {
40228
40323
  return null;
40229
40324
  }
40230
40325
  function isBinaryFile(filePath, buffer) {
40231
- const ext = path23.extname(filePath).toLowerCase();
40326
+ const ext = path24.extname(filePath).toLowerCase();
40232
40327
  if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
40233
40328
  return true;
40234
40329
  }
@@ -40365,9 +40460,9 @@ function isSymlinkLoop(realPath, visited) {
40365
40460
  return false;
40366
40461
  }
40367
40462
  function isPathWithinScope(realPath, scanDir) {
40368
- const resolvedScanDir = path23.resolve(scanDir);
40369
- const resolvedRealPath = path23.resolve(realPath);
40370
- return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path23.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
40463
+ const resolvedScanDir = path24.resolve(scanDir);
40464
+ const resolvedRealPath = path24.resolve(realPath);
40465
+ return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path24.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
40371
40466
  }
40372
40467
  function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
40373
40468
  skippedDirs: 0,
@@ -40393,8 +40488,8 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
40393
40488
  return a.localeCompare(b);
40394
40489
  });
40395
40490
  for (const entry of entries) {
40396
- const fullPath = path23.join(dir, entry);
40397
- const relPath = path23.relative(scanDir, fullPath).replace(/\\/g, "/");
40491
+ const fullPath = path24.join(dir, entry);
40492
+ const relPath = path24.relative(scanDir, fullPath).replace(/\\/g, "/");
40398
40493
  if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
40399
40494
  stats.skippedDirs++;
40400
40495
  continue;
@@ -40429,7 +40524,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
40429
40524
  const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
40430
40525
  files.push(...subFiles);
40431
40526
  } else if (lstat.isFile()) {
40432
- const ext = path23.extname(fullPath).toLowerCase();
40527
+ const ext = path24.extname(fullPath).toLowerCase();
40433
40528
  if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
40434
40529
  files.push(fullPath);
40435
40530
  } else {
@@ -40442,8 +40537,8 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
40442
40537
  var secretscan = createSwarmTool({
40443
40538
  description: "Scan directory for potential secrets (API keys, tokens, passwords) using regex patterns and entropy heuristics. Returns metadata-only findings with redacted previews - NEVER returns raw secrets. Excludes common directories (node_modules, .git, dist, etc.) by default. Supports glob patterns (e.g. **/.svelte-kit/**, **/*.test.ts) and reads .secretscanignore at the scan root.",
40444
40539
  args: {
40445
- directory: tool.schema.string().describe('Directory to scan for secrets (e.g., "." or "./src")'),
40446
- exclude: tool.schema.array(tool.schema.string()).optional().describe("Patterns to exclude: plain directory names (e.g. node_modules), relative paths, or globs (e.g. **/.svelte-kit/**, **/*.test.ts). Added to default exclusions.")
40540
+ directory: exports_external.string().describe('Directory to scan for secrets (e.g., "." or "./src")'),
40541
+ exclude: exports_external.array(exports_external.string()).optional().describe("Patterns to exclude: plain directory names (e.g. node_modules), relative paths, or globs (e.g. **/.svelte-kit/**, **/*.test.ts). Added to default exclusions.")
40447
40542
  },
40448
40543
  async execute(args, _directory, _ctx) {
40449
40544
  const typedArgs = args;
@@ -40495,7 +40590,7 @@ var secretscan = createSwarmTool({
40495
40590
  }
40496
40591
  }
40497
40592
  try {
40498
- const _scanDirRaw = path23.resolve(directory);
40593
+ const _scanDirRaw = path24.resolve(directory);
40499
40594
  const scanDir = (() => {
40500
40595
  try {
40501
40596
  return fs13.realpathSync(_scanDirRaw);
@@ -40637,7 +40732,8 @@ var secretscan = createSwarmTool({
40637
40732
  async function runSecretscan(directory) {
40638
40733
  try {
40639
40734
  const result = await secretscan.execute({ directory }, {});
40640
- return JSON.parse(result);
40735
+ const jsonStr = typeof result === "string" ? result : result.output;
40736
+ return JSON.parse(jsonStr);
40641
40737
  } catch (e) {
40642
40738
  const errorResult = {
40643
40739
  error: e instanceof Error ? `scan failed: ${e.message}` : "scan failed: unknown error",
@@ -40652,12 +40748,13 @@ async function runSecretscan(directory) {
40652
40748
  }
40653
40749
 
40654
40750
  // src/tools/test-runner.ts
40751
+ init_zod();
40655
40752
  import * as fs17 from "fs";
40656
- import * as path27 from "path";
40753
+ import * as path28 from "path";
40657
40754
 
40658
40755
  // src/test-impact/analyzer.ts
40659
40756
  import fs14 from "fs";
40660
- import path24 from "path";
40757
+ import path25 from "path";
40661
40758
  var IMPORT_REGEX_ES = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
40662
40759
  var IMPORT_REGEX_REQUIRE = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
40663
40760
  var IMPORT_REGEX_REEXPORT = /export\s+(?:\{[^}]*\}|\*)\s+from\s+['"]([^'"]+)['"]/g;
@@ -40682,8 +40779,8 @@ function resolveRelativeImport(fromDir, importPath) {
40682
40779
  if (!importPath.startsWith(".")) {
40683
40780
  return null;
40684
40781
  }
40685
- const resolved = path24.resolve(fromDir, importPath);
40686
- if (path24.extname(resolved)) {
40782
+ const resolved = path25.resolve(fromDir, importPath);
40783
+ if (path25.extname(resolved)) {
40687
40784
  if (fs14.existsSync(resolved) && fs14.statSync(resolved).isFile()) {
40688
40785
  return normalizePath(resolved);
40689
40786
  }
@@ -40728,12 +40825,12 @@ function findTestFilesSync(cwd) {
40728
40825
  for (const entry of entries) {
40729
40826
  if (entry.isDirectory()) {
40730
40827
  if (!skipDirs.has(entry.name)) {
40731
- walk(path24.join(dir, entry.name), visitedInodes);
40828
+ walk(path25.join(dir, entry.name), visitedInodes);
40732
40829
  }
40733
40830
  } else if (entry.isFile()) {
40734
40831
  const name = entry.name;
40735
40832
  if (/\.(test|spec)\.(ts|tsx|js|jsx)$/.test(name) || dir.includes("__tests__") && /\.(ts|tsx|js|jsx)$/.test(name)) {
40736
- testFiles.push(normalizePath(path24.join(dir, entry.name)));
40833
+ testFiles.push(normalizePath(path25.join(dir, entry.name)));
40737
40834
  }
40738
40835
  }
40739
40836
  }
@@ -40771,7 +40868,7 @@ async function buildImpactMapInternal(cwd) {
40771
40868
  continue;
40772
40869
  }
40773
40870
  const imports = extractImports(content);
40774
- const testDir = path24.dirname(testFile);
40871
+ const testDir = path25.dirname(testFile);
40775
40872
  for (const importPath of imports) {
40776
40873
  const resolvedSource = resolveRelativeImport(testDir, importPath);
40777
40874
  if (resolvedSource === null) {
@@ -40793,7 +40890,7 @@ async function buildImpactMap(cwd) {
40793
40890
  return impactMap;
40794
40891
  }
40795
40892
  async function loadImpactMap(cwd) {
40796
- const cachePath = path24.join(cwd, ".swarm", "cache", "impact-map.json");
40893
+ const cachePath = path25.join(cwd, ".swarm", "cache", "impact-map.json");
40797
40894
  if (fs14.existsSync(cachePath)) {
40798
40895
  try {
40799
40896
  const content = fs14.readFileSync(cachePath, "utf-8");
@@ -40808,8 +40905,8 @@ async function loadImpactMap(cwd) {
40808
40905
  return buildImpactMap(cwd);
40809
40906
  }
40810
40907
  async function saveImpactMap(cwd, impactMap) {
40811
- const cacheDir = path24.join(cwd, ".swarm", "cache");
40812
- const cachePath = path24.join(cacheDir, "impact-map.json");
40908
+ const cacheDir = path25.join(cwd, ".swarm", "cache");
40909
+ const cachePath = path25.join(cacheDir, "impact-map.json");
40813
40910
  if (!fs14.existsSync(cacheDir)) {
40814
40911
  fs14.mkdirSync(cacheDir, { recursive: true });
40815
40912
  }
@@ -40835,7 +40932,7 @@ async function analyzeImpact(changedFiles, cwd) {
40835
40932
  const impactedTestsSet = new Set;
40836
40933
  const untestedFiles = [];
40837
40934
  for (const changedFile of validFiles) {
40838
- const normalizedChanged = normalizePath(path24.resolve(changedFile));
40935
+ const normalizedChanged = normalizePath(path25.resolve(changedFile));
40839
40936
  const tests = impactMap[normalizedChanged];
40840
40937
  if (tests && tests.length > 0) {
40841
40938
  for (const test of tests) {
@@ -41082,13 +41179,13 @@ function detectFlakyTests(allHistory) {
41082
41179
 
41083
41180
  // src/test-impact/history-store.ts
41084
41181
  import fs15 from "fs";
41085
- import path25 from "path";
41182
+ import path26 from "path";
41086
41183
  var MAX_HISTORY_PER_TEST = 20;
41087
41184
  var MAX_ERROR_LENGTH = 500;
41088
41185
  var MAX_STACK_LENGTH = 200;
41089
41186
  var MAX_CHANGED_FILES = 50;
41090
41187
  function getHistoryPath(workingDir) {
41091
- return path25.join(workingDir || process.cwd(), ".swarm", "cache", "test-history.jsonl");
41188
+ return path26.join(workingDir || process.cwd(), ".swarm", "cache", "test-history.jsonl");
41092
41189
  }
41093
41190
  function sanitizeErrorMessage(errorMessage) {
41094
41191
  if (errorMessage === undefined) {
@@ -41148,7 +41245,7 @@ function appendTestRun(record3, workingDir) {
41148
41245
  changedFiles: sanitizeChangedFiles(record3.changedFiles || [])
41149
41246
  };
41150
41247
  const historyPath = getHistoryPath(workingDir);
41151
- const historyDir = path25.dirname(historyPath);
41248
+ const historyDir = path26.dirname(historyPath);
41152
41249
  if (!fs15.existsSync(historyDir)) {
41153
41250
  fs15.mkdirSync(historyDir, { recursive: true });
41154
41251
  }
@@ -41222,7 +41319,7 @@ function getAllHistory(workingDir) {
41222
41319
 
41223
41320
  // src/tools/resolve-working-directory.ts
41224
41321
  import * as fs16 from "fs";
41225
- import * as path26 from "path";
41322
+ import * as path27 from "path";
41226
41323
  function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
41227
41324
  if (workingDirectory == null || workingDirectory === "") {
41228
41325
  return { success: true, directory: fallbackDirectory };
@@ -41242,15 +41339,15 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
41242
41339
  };
41243
41340
  }
41244
41341
  }
41245
- const normalizedDir = path26.normalize(workingDirectory);
41246
- const pathParts = normalizedDir.split(path26.sep);
41342
+ const normalizedDir = path27.normalize(workingDirectory);
41343
+ const pathParts = normalizedDir.split(path27.sep);
41247
41344
  if (pathParts.includes("..")) {
41248
41345
  return {
41249
41346
  success: false,
41250
41347
  message: "Invalid working_directory: path traversal sequences (..) are not allowed"
41251
41348
  };
41252
41349
  }
41253
- const resolvedDir = path26.resolve(normalizedDir);
41350
+ const resolvedDir = path27.resolve(normalizedDir);
41254
41351
  let statResult;
41255
41352
  try {
41256
41353
  statResult = fs16.statSync(resolvedDir);
@@ -41266,7 +41363,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
41266
41363
  message: `Invalid working_directory: path "${resolvedDir}" is not a directory`
41267
41364
  };
41268
41365
  }
41269
- const resolvedFallback = path26.resolve(fallbackDirectory);
41366
+ const resolvedFallback = path27.resolve(fallbackDirectory);
41270
41367
  let fallbackExists = false;
41271
41368
  try {
41272
41369
  fs16.statSync(resolvedFallback);
@@ -41276,7 +41373,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
41276
41373
  }
41277
41374
  if (workingDirectory != null && workingDirectory !== "") {
41278
41375
  if (fallbackExists) {
41279
- const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path26.sep);
41376
+ const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path27.sep);
41280
41377
  if (isSubdirectory) {
41281
41378
  return {
41282
41379
  success: false,
@@ -41366,14 +41463,14 @@ function hasDevDependency(devDeps, ...patterns) {
41366
41463
  return hasPackageJsonDependency(devDeps, ...patterns);
41367
41464
  }
41368
41465
  function detectGoTest(cwd) {
41369
- return fs17.existsSync(path27.join(cwd, "go.mod")) && isCommandAvailable("go");
41466
+ return fs17.existsSync(path28.join(cwd, "go.mod")) && isCommandAvailable("go");
41370
41467
  }
41371
41468
  function detectJavaMaven(cwd) {
41372
- return fs17.existsSync(path27.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
41469
+ return fs17.existsSync(path28.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
41373
41470
  }
41374
41471
  function detectGradle(cwd) {
41375
- const hasBuildFile = fs17.existsSync(path27.join(cwd, "build.gradle")) || fs17.existsSync(path27.join(cwd, "build.gradle.kts"));
41376
- const hasGradlew = fs17.existsSync(path27.join(cwd, "gradlew")) || fs17.existsSync(path27.join(cwd, "gradlew.bat"));
41472
+ const hasBuildFile = fs17.existsSync(path28.join(cwd, "build.gradle")) || fs17.existsSync(path28.join(cwd, "build.gradle.kts"));
41473
+ const hasGradlew = fs17.existsSync(path28.join(cwd, "gradlew")) || fs17.existsSync(path28.join(cwd, "gradlew.bat"));
41377
41474
  return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
41378
41475
  }
41379
41476
  function detectDotnetTest(cwd) {
@@ -41386,30 +41483,30 @@ function detectDotnetTest(cwd) {
41386
41483
  }
41387
41484
  }
41388
41485
  function detectCTest(cwd) {
41389
- const hasSource = fs17.existsSync(path27.join(cwd, "CMakeLists.txt"));
41390
- const hasBuildCache = fs17.existsSync(path27.join(cwd, "CMakeCache.txt")) || fs17.existsSync(path27.join(cwd, "build", "CMakeCache.txt"));
41486
+ const hasSource = fs17.existsSync(path28.join(cwd, "CMakeLists.txt"));
41487
+ const hasBuildCache = fs17.existsSync(path28.join(cwd, "CMakeCache.txt")) || fs17.existsSync(path28.join(cwd, "build", "CMakeCache.txt"));
41391
41488
  return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
41392
41489
  }
41393
41490
  function detectSwiftTest(cwd) {
41394
- return fs17.existsSync(path27.join(cwd, "Package.swift")) && isCommandAvailable("swift");
41491
+ return fs17.existsSync(path28.join(cwd, "Package.swift")) && isCommandAvailable("swift");
41395
41492
  }
41396
41493
  function detectDartTest(cwd) {
41397
- return fs17.existsSync(path27.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
41494
+ return fs17.existsSync(path28.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
41398
41495
  }
41399
41496
  function detectRSpec(cwd) {
41400
- const hasRSpecFile = fs17.existsSync(path27.join(cwd, ".rspec"));
41401
- const hasGemfile = fs17.existsSync(path27.join(cwd, "Gemfile"));
41402
- const hasSpecDir = fs17.existsSync(path27.join(cwd, "spec"));
41497
+ const hasRSpecFile = fs17.existsSync(path28.join(cwd, ".rspec"));
41498
+ const hasGemfile = fs17.existsSync(path28.join(cwd, "Gemfile"));
41499
+ const hasSpecDir = fs17.existsSync(path28.join(cwd, "spec"));
41403
41500
  const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
41404
41501
  return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
41405
41502
  }
41406
41503
  function detectMinitest(cwd) {
41407
- return fs17.existsSync(path27.join(cwd, "test")) && (fs17.existsSync(path27.join(cwd, "Gemfile")) || fs17.existsSync(path27.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
41504
+ return fs17.existsSync(path28.join(cwd, "test")) && (fs17.existsSync(path28.join(cwd, "Gemfile")) || fs17.existsSync(path28.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
41408
41505
  }
41409
41506
  async function detectTestFramework(cwd) {
41410
41507
  const baseDir = cwd;
41411
41508
  try {
41412
- const packageJsonPath = path27.join(baseDir, "package.json");
41509
+ const packageJsonPath = path28.join(baseDir, "package.json");
41413
41510
  if (fs17.existsSync(packageJsonPath)) {
41414
41511
  const content = fs17.readFileSync(packageJsonPath, "utf-8");
41415
41512
  const pkg = JSON.parse(content);
@@ -41430,16 +41527,16 @@ async function detectTestFramework(cwd) {
41430
41527
  return "jest";
41431
41528
  if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
41432
41529
  return "mocha";
41433
- if (fs17.existsSync(path27.join(baseDir, "bun.lockb")) || fs17.existsSync(path27.join(baseDir, "bun.lock"))) {
41530
+ if (fs17.existsSync(path28.join(baseDir, "bun.lockb")) || fs17.existsSync(path28.join(baseDir, "bun.lock"))) {
41434
41531
  if (scripts.test?.includes("bun"))
41435
41532
  return "bun";
41436
41533
  }
41437
41534
  }
41438
41535
  } catch {}
41439
41536
  try {
41440
- const pyprojectTomlPath = path27.join(baseDir, "pyproject.toml");
41441
- const setupCfgPath = path27.join(baseDir, "setup.cfg");
41442
- const requirementsTxtPath = path27.join(baseDir, "requirements.txt");
41537
+ const pyprojectTomlPath = path28.join(baseDir, "pyproject.toml");
41538
+ const setupCfgPath = path28.join(baseDir, "setup.cfg");
41539
+ const requirementsTxtPath = path28.join(baseDir, "requirements.txt");
41443
41540
  if (fs17.existsSync(pyprojectTomlPath)) {
41444
41541
  const content = fs17.readFileSync(pyprojectTomlPath, "utf-8");
41445
41542
  if (content.includes("[tool.pytest"))
@@ -41459,7 +41556,7 @@ async function detectTestFramework(cwd) {
41459
41556
  }
41460
41557
  } catch {}
41461
41558
  try {
41462
- const cargoTomlPath = path27.join(baseDir, "Cargo.toml");
41559
+ const cargoTomlPath = path28.join(baseDir, "Cargo.toml");
41463
41560
  if (fs17.existsSync(cargoTomlPath)) {
41464
41561
  const content = fs17.readFileSync(cargoTomlPath, "utf-8");
41465
41562
  if (content.includes("[dev-dependencies]")) {
@@ -41470,9 +41567,9 @@ async function detectTestFramework(cwd) {
41470
41567
  }
41471
41568
  } catch {}
41472
41569
  try {
41473
- const pesterConfigPath = path27.join(baseDir, "pester.config.ps1");
41474
- const pesterConfigJsonPath = path27.join(baseDir, "pester.config.ps1.json");
41475
- const pesterPs1Path = path27.join(baseDir, "tests.ps1");
41570
+ const pesterConfigPath = path28.join(baseDir, "pester.config.ps1");
41571
+ const pesterConfigJsonPath = path28.join(baseDir, "pester.config.ps1.json");
41572
+ const pesterPs1Path = path28.join(baseDir, "tests.ps1");
41476
41573
  if (fs17.existsSync(pesterConfigPath) || fs17.existsSync(pesterConfigJsonPath) || fs17.existsSync(pesterPs1Path)) {
41477
41574
  return "pester";
41478
41575
  }
@@ -41515,12 +41612,12 @@ function isTestDirectoryPath(normalizedPath) {
41515
41612
  return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
41516
41613
  }
41517
41614
  function resolveWorkspacePath(file3, workingDir) {
41518
- return path27.isAbsolute(file3) ? path27.resolve(file3) : path27.resolve(workingDir, file3);
41615
+ return path28.isAbsolute(file3) ? path28.resolve(file3) : path28.resolve(workingDir, file3);
41519
41616
  }
41520
41617
  function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
41521
41618
  if (!preferRelative)
41522
41619
  return absolutePath;
41523
- return path27.relative(workingDir, absolutePath);
41620
+ return path28.relative(workingDir, absolutePath);
41524
41621
  }
41525
41622
  function dedupePush(target, value) {
41526
41623
  if (!target.includes(value)) {
@@ -41557,18 +41654,18 @@ function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
41557
41654
  }
41558
41655
  }
41559
41656
  function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
41560
- const relativeDir = path27.dirname(relativePath);
41657
+ const relativeDir = path28.dirname(relativePath);
41561
41658
  const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
41562
41659
  const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
41563
- const rootDir = path27.join(workingDir, dirName);
41564
- return nestedRelativeDir ? [rootDir, path27.join(rootDir, nestedRelativeDir)] : [rootDir];
41660
+ const rootDir = path28.join(workingDir, dirName);
41661
+ return nestedRelativeDir ? [rootDir, path28.join(rootDir, nestedRelativeDir)] : [rootDir];
41565
41662
  });
41566
41663
  const normalizedRelativePath = relativePath.replace(/\\/g, "/");
41567
41664
  if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
41568
- directories.push(path27.join(workingDir, "src/test/java", path27.dirname(normalizedRelativePath.slice("src/main/java/".length))));
41665
+ directories.push(path28.join(workingDir, "src/test/java", path28.dirname(normalizedRelativePath.slice("src/main/java/".length))));
41569
41666
  }
41570
41667
  if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
41571
- directories.push(path27.join(workingDir, "src/test/kotlin", path27.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
41668
+ directories.push(path28.join(workingDir, "src/test/kotlin", path28.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
41572
41669
  }
41573
41670
  return [...new Set(directories)];
41574
41671
  }
@@ -41596,23 +41693,23 @@ function isLanguageSpecificTestFile(basename4) {
41596
41693
  }
41597
41694
  function isConventionTestFilePath(filePath) {
41598
41695
  const normalizedPath = filePath.replace(/\\/g, "/");
41599
- const basename4 = path27.basename(filePath);
41696
+ const basename4 = path28.basename(filePath);
41600
41697
  return hasCompoundTestExtension(basename4) || basename4.includes(".spec.") || basename4.includes(".test.") || isLanguageSpecificTestFile(basename4) || isTestDirectoryPath(normalizedPath);
41601
41698
  }
41602
41699
  function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
41603
41700
  const testFiles = [];
41604
41701
  for (const file3 of sourceFiles) {
41605
41702
  const absoluteFile = resolveWorkspacePath(file3, workingDir);
41606
- const relativeFile = path27.relative(workingDir, absoluteFile);
41607
- const basename4 = path27.basename(absoluteFile);
41608
- const dirname11 = path27.dirname(absoluteFile);
41609
- const preferRelativeOutput = !path27.isAbsolute(file3);
41703
+ const relativeFile = path28.relative(workingDir, absoluteFile);
41704
+ const basename4 = path28.basename(absoluteFile);
41705
+ const dirname11 = path28.dirname(absoluteFile);
41706
+ const preferRelativeOutput = !path28.isAbsolute(file3);
41610
41707
  if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file3)) {
41611
41708
  dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
41612
41709
  continue;
41613
41710
  }
41614
41711
  const nameWithoutExt = basename4.replace(/\.[^.]+$/, "");
41615
- const ext = path27.extname(basename4);
41712
+ const ext = path28.extname(basename4);
41616
41713
  const genericTestNames = [
41617
41714
  `${nameWithoutExt}.spec${ext}`,
41618
41715
  `${nameWithoutExt}.test${ext}`
@@ -41621,7 +41718,7 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
41621
41718
  const colocatedCandidates = [
41622
41719
  ...genericTestNames,
41623
41720
  ...languageSpecificTestNames
41624
- ].map((candidateName) => path27.join(dirname11, candidateName));
41721
+ ].map((candidateName) => path28.join(dirname11, candidateName));
41625
41722
  const testDirectoryNames = [
41626
41723
  basename4,
41627
41724
  ...genericTestNames,
@@ -41630,8 +41727,8 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
41630
41727
  const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
41631
41728
  const possibleTestFiles = [
41632
41729
  ...colocatedCandidates,
41633
- ...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path27.join(dirname11, dirName, candidateName))),
41634
- ...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path27.join(candidateDir, candidateName)))
41730
+ ...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path28.join(dirname11, dirName, candidateName))),
41731
+ ...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path28.join(candidateDir, candidateName)))
41635
41732
  ];
41636
41733
  for (const testFile of possibleTestFiles) {
41637
41734
  if (fs17.existsSync(testFile)) {
@@ -41652,7 +41749,7 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
41652
41749
  try {
41653
41750
  const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
41654
41751
  const content = fs17.readFileSync(absoluteTestFile, "utf-8");
41655
- const testDir = path27.dirname(absoluteTestFile);
41752
+ const testDir = path28.dirname(absoluteTestFile);
41656
41753
  const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
41657
41754
  let match;
41658
41755
  match = importRegex.exec(content);
@@ -41660,8 +41757,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
41660
41757
  const importPath = match[1];
41661
41758
  let resolvedImport;
41662
41759
  if (importPath.startsWith(".")) {
41663
- resolvedImport = path27.resolve(testDir, importPath);
41664
- const existingExt = path27.extname(resolvedImport);
41760
+ resolvedImport = path28.resolve(testDir, importPath);
41761
+ const existingExt = path28.extname(resolvedImport);
41665
41762
  if (!existingExt) {
41666
41763
  for (const extToTry of [
41667
41764
  ".ts",
@@ -41681,12 +41778,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
41681
41778
  } else {
41682
41779
  continue;
41683
41780
  }
41684
- const importBasename = path27.basename(resolvedImport, path27.extname(resolvedImport));
41685
- const importDir = path27.dirname(resolvedImport);
41781
+ const importBasename = path28.basename(resolvedImport, path28.extname(resolvedImport));
41782
+ const importDir = path28.dirname(resolvedImport);
41686
41783
  for (const sourceFile of absoluteSourceFiles) {
41687
- const sourceDir = path27.dirname(sourceFile);
41688
- const sourceBasename = path27.basename(sourceFile, path27.extname(sourceFile));
41689
- const isRelatedDir = importDir === sourceDir || importDir === path27.join(sourceDir, "__tests__") || importDir === path27.join(sourceDir, "tests") || importDir === path27.join(sourceDir, "test") || importDir === path27.join(sourceDir, "spec");
41784
+ const sourceDir = path28.dirname(sourceFile);
41785
+ const sourceBasename = path28.basename(sourceFile, path28.extname(sourceFile));
41786
+ const isRelatedDir = importDir === sourceDir || importDir === path28.join(sourceDir, "__tests__") || importDir === path28.join(sourceDir, "tests") || importDir === path28.join(sourceDir, "test") || importDir === path28.join(sourceDir, "spec");
41690
41787
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
41691
41788
  dedupePush(testFiles, testFile);
41692
41789
  break;
@@ -41699,8 +41796,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
41699
41796
  while (match !== null) {
41700
41797
  const importPath = match[1];
41701
41798
  if (importPath.startsWith(".")) {
41702
- let resolvedImport = path27.resolve(testDir, importPath);
41703
- const existingExt = path27.extname(resolvedImport);
41799
+ let resolvedImport = path28.resolve(testDir, importPath);
41800
+ const existingExt = path28.extname(resolvedImport);
41704
41801
  if (!existingExt) {
41705
41802
  for (const extToTry of [
41706
41803
  ".ts",
@@ -41717,12 +41814,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
41717
41814
  }
41718
41815
  }
41719
41816
  }
41720
- const importDir = path27.dirname(resolvedImport);
41721
- const importBasename = path27.basename(resolvedImport, path27.extname(resolvedImport));
41817
+ const importDir = path28.dirname(resolvedImport);
41818
+ const importBasename = path28.basename(resolvedImport, path28.extname(resolvedImport));
41722
41819
  for (const sourceFile of absoluteSourceFiles) {
41723
- const sourceDir = path27.dirname(sourceFile);
41724
- const sourceBasename = path27.basename(sourceFile, path27.extname(sourceFile));
41725
- const isRelatedDir = importDir === sourceDir || importDir === path27.join(sourceDir, "__tests__") || importDir === path27.join(sourceDir, "tests") || importDir === path27.join(sourceDir, "test") || importDir === path27.join(sourceDir, "spec");
41820
+ const sourceDir = path28.dirname(sourceFile);
41821
+ const sourceBasename = path28.basename(sourceFile, path28.extname(sourceFile));
41822
+ const isRelatedDir = importDir === sourceDir || importDir === path28.join(sourceDir, "__tests__") || importDir === path28.join(sourceDir, "tests") || importDir === path28.join(sourceDir, "test") || importDir === path28.join(sourceDir, "spec");
41726
41823
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
41727
41824
  dedupePush(testFiles, testFile);
41728
41825
  break;
@@ -41825,8 +41922,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
41825
41922
  return ["mvn", "test"];
41826
41923
  case "gradle": {
41827
41924
  const isWindows = process.platform === "win32";
41828
- const hasGradlewBat = fs17.existsSync(path27.join(baseDir, "gradlew.bat"));
41829
- const hasGradlew = fs17.existsSync(path27.join(baseDir, "gradlew"));
41925
+ const hasGradlewBat = fs17.existsSync(path28.join(baseDir, "gradlew.bat"));
41926
+ const hasGradlew = fs17.existsSync(path28.join(baseDir, "gradlew"));
41830
41927
  if (hasGradlewBat && isWindows)
41831
41928
  return ["gradlew.bat", "test"];
41832
41929
  if (hasGradlew)
@@ -41843,7 +41940,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
41843
41940
  "cmake-build-release",
41844
41941
  "out"
41845
41942
  ];
41846
- const actualBuildDir = buildDirCandidates.find((d) => fs17.existsSync(path27.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
41943
+ const actualBuildDir = buildDirCandidates.find((d) => fs17.existsSync(path28.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
41847
41944
  return ["ctest", "--test-dir", actualBuildDir];
41848
41945
  }
41849
41946
  case "swift-test":
@@ -42341,12 +42438,12 @@ function analyzeFailures(workingDir) {
42341
42438
  var test_runner = createSwarmTool({
42342
42439
  description: 'Run project tests with framework detection. Supports bun, vitest, jest, mocha, pytest, cargo, pester, go-test, maven, gradle, dotnet-test, ctest, swift-test, dart-test, rspec, and minitest. Returns deterministic normalized JSON with framework, scope, command, totals, coverage, duration, success status, and failures. Use scope "all" for full suite, "convention" to accept direct test files or map source files to test files, "graph" to find related tests via imports from source files, or "impact" to find tests covering changed source files using test-impact analysis.',
42343
42440
  args: {
42344
- scope: tool.schema.enum(["all", "convention", "graph", "impact"]).optional().describe('Test scope: "all" runs full suite, "convention" accepts direct test files or maps source files to tests by naming, "graph" finds related tests via imports from source files, "impact" finds tests covering changed source files via test-impact analysis'),
42345
- files: tool.schema.array(tool.schema.string()).optional().describe('Specific files to test. For "convention", pass source files or direct test files. For "graph" and "impact", pass source files only.'),
42346
- coverage: tool.schema.boolean().optional().describe("Enable coverage reporting if supported"),
42347
- timeout_ms: tool.schema.number().optional().describe("Timeout in milliseconds (default 60000, max 300000)"),
42348
- allow_full_suite: tool.schema.boolean().optional().describe('Explicit opt-in for scope "all". Required because full-suite output can destabilize SSE streaming.'),
42349
- working_directory: tool.schema.string().optional().describe("Explicit project root directory. When provided, tests run relative to this path instead of the plugin context directory. Use this when CWD differs from the actual project root.")
42441
+ scope: exports_external.enum(["all", "convention", "graph", "impact"]).optional().describe('Test scope: "all" runs full suite, "convention" accepts direct test files or maps source files to tests by naming, "graph" finds related tests via imports from source files, "impact" finds tests covering changed source files via test-impact analysis'),
42442
+ files: exports_external.array(exports_external.string()).optional().describe('Specific files to test. For "convention", pass source files or direct test files. For "graph" and "impact", pass source files only.'),
42443
+ coverage: exports_external.boolean().optional().describe("Enable coverage reporting if supported"),
42444
+ timeout_ms: exports_external.number().optional().describe("Timeout in milliseconds (default 60000, max 300000)"),
42445
+ allow_full_suite: exports_external.boolean().optional().describe('Explicit opt-in for scope "all". Required because full-suite output can destabilize SSE streaming.'),
42446
+ working_directory: exports_external.string().optional().describe("Explicit project root directory. When provided, tests run relative to this path instead of the plugin context directory. Use this when CWD differs from the actual project root.")
42350
42447
  },
42351
42448
  async execute(args, directory) {
42352
42449
  let workingDirInput;
@@ -42471,7 +42568,7 @@ var test_runner = createSwarmTool({
42471
42568
  const sourceFiles = args.files.filter((file3) => {
42472
42569
  if (directTestFiles.includes(file3))
42473
42570
  return false;
42474
- const ext = path27.extname(file3).toLowerCase();
42571
+ const ext = path28.extname(file3).toLowerCase();
42475
42572
  return SOURCE_EXTENSIONS.has(ext);
42476
42573
  });
42477
42574
  const invalidFiles = args.files.filter((file3) => !directTestFiles.includes(file3) && !sourceFiles.includes(file3));
@@ -42506,7 +42603,7 @@ var test_runner = createSwarmTool({
42506
42603
  if (isConventionTestFilePath(f)) {
42507
42604
  return false;
42508
42605
  }
42509
- const ext = path27.extname(f).toLowerCase();
42606
+ const ext = path28.extname(f).toLowerCase();
42510
42607
  return SOURCE_EXTENSIONS.has(ext);
42511
42608
  });
42512
42609
  if (sourceFiles.length === 0) {
@@ -42533,7 +42630,7 @@ var test_runner = createSwarmTool({
42533
42630
  if (isConventionTestFilePath(f)) {
42534
42631
  return false;
42535
42632
  }
42536
- const ext = path27.extname(f).toLowerCase();
42633
+ const ext = path28.extname(f).toLowerCase();
42537
42634
  return SOURCE_EXTENSIONS.has(ext);
42538
42635
  });
42539
42636
  if (sourceFiles.length === 0) {
@@ -42551,8 +42648,8 @@ var test_runner = createSwarmTool({
42551
42648
  const impactResult = await analyzeImpact(sourceFiles, workingDir);
42552
42649
  if (impactResult.impactedTests.length > 0) {
42553
42650
  testFiles = impactResult.impactedTests.map((absPath) => {
42554
- const relativePath = path27.relative(workingDir, absPath);
42555
- return path27.isAbsolute(relativePath) ? absPath : relativePath;
42651
+ const relativePath = path28.relative(workingDir, absPath);
42652
+ return path28.isAbsolute(relativePath) ? absPath : relativePath;
42556
42653
  });
42557
42654
  } else {
42558
42655
  graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
@@ -42645,8 +42742,8 @@ function validateDirectoryPath(dir) {
42645
42742
  if (dir.includes("..")) {
42646
42743
  throw new Error("Directory path must not contain path traversal sequences");
42647
42744
  }
42648
- const normalized = path28.normalize(dir);
42649
- const absolutePath = path28.isAbsolute(normalized) ? normalized : path28.resolve(normalized);
42745
+ const normalized = path29.normalize(dir);
42746
+ const absolutePath = path29.isAbsolute(normalized) ? normalized : path29.resolve(normalized);
42650
42747
  return absolutePath;
42651
42748
  }
42652
42749
  function validateTimeout(timeoutMs, defaultValue) {
@@ -42669,7 +42766,7 @@ function validateTimeout(timeoutMs, defaultValue) {
42669
42766
  }
42670
42767
  function getPackageVersion(dir) {
42671
42768
  try {
42672
- const packagePath = path28.join(dir, "package.json");
42769
+ const packagePath = path29.join(dir, "package.json");
42673
42770
  if (fs18.existsSync(packagePath)) {
42674
42771
  const content = fs18.readFileSync(packagePath, "utf-8");
42675
42772
  const pkg = JSON.parse(content);
@@ -42680,7 +42777,7 @@ function getPackageVersion(dir) {
42680
42777
  }
42681
42778
  function getChangelogVersion(dir) {
42682
42779
  try {
42683
- const changelogPath = path28.join(dir, "CHANGELOG.md");
42780
+ const changelogPath = path29.join(dir, "CHANGELOG.md");
42684
42781
  if (fs18.existsSync(changelogPath)) {
42685
42782
  const content = fs18.readFileSync(changelogPath, "utf-8");
42686
42783
  const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
@@ -42694,7 +42791,7 @@ function getChangelogVersion(dir) {
42694
42791
  function getVersionFileVersion(dir) {
42695
42792
  const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
42696
42793
  for (const file3 of possibleFiles) {
42697
- const filePath = path28.join(dir, file3);
42794
+ const filePath = path29.join(dir, file3);
42698
42795
  if (fs18.existsSync(filePath)) {
42699
42796
  try {
42700
42797
  const content = fs18.readFileSync(filePath, "utf-8").trim();
@@ -43021,7 +43118,7 @@ async function runEvidenceCheck(dir) {
43021
43118
  async function runRequirementCoverageCheck(dir, currentPhase) {
43022
43119
  const startTime = Date.now();
43023
43120
  try {
43024
- const specPath = path28.join(dir, ".swarm", "spec.md");
43121
+ const specPath = path29.join(dir, ".swarm", "spec.md");
43025
43122
  if (!fs18.existsSync(specPath)) {
43026
43123
  return {
43027
43124
  type: "req_coverage",
@@ -43234,144 +43331,6 @@ async function handlePreflightCommand(directory, _args) {
43234
43331
  const report = await runPreflight(directory, phase);
43235
43332
  return formatPreflightMarkdown(report);
43236
43333
  }
43237
- // src/knowledge/hive-promoter.ts
43238
- import * as fs19 from "fs";
43239
- import * as os6 from "os";
43240
- import * as path29 from "path";
43241
- var DANGEROUS_PATTERNS = [
43242
- [/rm\s+-rf/, "rm\\s+-rf"],
43243
- [/:\s*!\s*\|/, ":\\s*!\\s*\\|"],
43244
- [/\|\s*sh\b/, "\\|\\s*sh\\b"],
43245
- [/`[^`]*`/, "`[^`]*`"],
43246
- [/\$\(/, "\\$\\("],
43247
- [/;\s*rm\s+\//, ";\\s*rm\\s+\\/"],
43248
- [/>\s*\/dev\//, ">\\s*\\/dev\\/"],
43249
- [/\bmkfs\b/, "\\bmkfs\\b"],
43250
- [/\bdd\s+if=/, "\\bdd\\s+if="],
43251
- [/chmod\s+[0-7]*7[0-7]{2}/, "chmod\\s+[0-7]*7[0-7]\\{2\\}"],
43252
- [/\bchown\s+-R\b/, "\\bchown\\s+-R\\b"],
43253
- [/(?<!\.)\beval\s*\(/, "(?<!\\.)\\beval\\s*\\("],
43254
- [/(?<!\.)\bexec\s*\(/, "(?<!\\.)\\bexec\\s*\\("]
43255
- ];
43256
- var SHELL_COMMAND_START = /^(grep|find|ls|cat|sed|awk|curl|wget|ssh|scp|git|mv|cp|mkdir|touch|echo|printf|python|python3|node|bash|sh|zsh|apt|yum|brew)\s/;
43257
- function validateLesson2(text) {
43258
- if (!text || !text.trim()) {
43259
- return { valid: false, reason: "Lesson text cannot be empty" };
43260
- }
43261
- for (const [pattern, patternSource] of DANGEROUS_PATTERNS) {
43262
- if (pattern.test(text)) {
43263
- return {
43264
- valid: false,
43265
- reason: `Dangerous pattern detected: ${patternSource}`
43266
- };
43267
- }
43268
- }
43269
- const trimmed = text.trim();
43270
- if (SHELL_COMMAND_START.test(trimmed)) {
43271
- const lastChar = trimmed[trimmed.length - 1];
43272
- if (![".", "!", "?", ";"].includes(lastChar)) {
43273
- return {
43274
- valid: false,
43275
- reason: "Lesson appears to contain raw shell commands"
43276
- };
43277
- }
43278
- }
43279
- return { valid: true };
43280
- }
43281
- function getHiveFilePath() {
43282
- const platform = process.platform;
43283
- const home = os6.homedir();
43284
- let dataDir;
43285
- if (platform === "win32") {
43286
- dataDir = path29.join(process.env.LOCALAPPDATA || path29.join(home, "AppData", "Local"), "opencode-swarm", "Data");
43287
- } else if (platform === "darwin") {
43288
- dataDir = path29.join(home, "Library", "Application Support", "opencode-swarm");
43289
- } else {
43290
- dataDir = path29.join(process.env.XDG_DATA_HOME || path29.join(home, ".local", "share"), "opencode-swarm");
43291
- }
43292
- return path29.join(dataDir, "hive-knowledge.jsonl");
43293
- }
43294
- async function promoteToHive(_directory, lesson, category) {
43295
- const trimmed = (lesson ?? "").trim();
43296
- if (!trimmed) {
43297
- throw new Error("Lesson text required");
43298
- }
43299
- const validation = validateLesson2(trimmed);
43300
- if (!validation.valid) {
43301
- throw new Error(`Lesson rejected by validator: ${validation.reason}`);
43302
- }
43303
- const hivePath = getHiveFilePath();
43304
- const hiveDir = path29.dirname(hivePath);
43305
- if (!fs19.existsSync(hiveDir)) {
43306
- fs19.mkdirSync(hiveDir, { recursive: true });
43307
- }
43308
- const now = new Date;
43309
- const entry = {
43310
- id: `hive-manual-${now.getTime()}`,
43311
- lesson: trimmed,
43312
- category: category || "process",
43313
- scope_tag: "global",
43314
- confidence: 1,
43315
- status: "promoted",
43316
- promotion_source: "manual",
43317
- promotedAt: now.toISOString(),
43318
- retrievalOutcomes: { applied: 0, succeededAfter: 0, failedAfter: 0 }
43319
- };
43320
- fs19.appendFileSync(hivePath, `${JSON.stringify(entry)}
43321
- `, "utf-8");
43322
- const preview = `${trimmed.slice(0, 50)}${trimmed.length > 50 ? "..." : ""}`;
43323
- return `Promoted to hive: "${preview}" (confidence: 1.0, source: manual)`;
43324
- }
43325
- async function promoteFromSwarm(directory, lessonId) {
43326
- const knowledgePath = path29.join(directory, ".swarm", "knowledge.jsonl");
43327
- const entries = [];
43328
- if (fs19.existsSync(knowledgePath)) {
43329
- const content = fs19.readFileSync(knowledgePath, "utf-8");
43330
- for (const line of content.split(`
43331
- `)) {
43332
- const t = line.trim();
43333
- if (!t)
43334
- continue;
43335
- try {
43336
- entries.push(JSON.parse(t));
43337
- } catch {}
43338
- }
43339
- }
43340
- const swarmEntry = entries.find((e) => e.id === lessonId);
43341
- if (!swarmEntry) {
43342
- throw new Error(`Lesson ${lessonId} not found in .swarm/knowledge.jsonl`);
43343
- }
43344
- const lessonText = typeof swarmEntry.lesson === "string" ? swarmEntry.lesson.trim() : "";
43345
- if (!lessonText) {
43346
- throw new Error("Lesson text required");
43347
- }
43348
- const validation = validateLesson2(lessonText);
43349
- if (!validation.valid) {
43350
- throw new Error(`Lesson rejected by validator: ${validation.reason}`);
43351
- }
43352
- const hivePath = getHiveFilePath();
43353
- const hiveDir = path29.dirname(hivePath);
43354
- if (!fs19.existsSync(hiveDir)) {
43355
- fs19.mkdirSync(hiveDir, { recursive: true });
43356
- }
43357
- const now = new Date;
43358
- const hiveEntry = {
43359
- id: `hive-manual-${now.getTime()}`,
43360
- lesson: lessonText,
43361
- category: typeof swarmEntry.category === "string" ? swarmEntry.category : "process",
43362
- scope_tag: typeof swarmEntry.scope === "string" ? swarmEntry.scope : "global",
43363
- confidence: 1,
43364
- status: "promoted",
43365
- promotion_source: "manual",
43366
- promotedAt: now.toISOString(),
43367
- retrievalOutcomes: { applied: 0, succeededAfter: 0, failedAfter: 0 }
43368
- };
43369
- fs19.appendFileSync(hivePath, `${JSON.stringify(hiveEntry)}
43370
- `, "utf-8");
43371
- const preview = `${lessonText.slice(0, 50)}${lessonText.length > 50 ? "..." : ""}`;
43372
- return `Promoted to hive: "${preview}" (confidence: 1.0, source: manual)`;
43373
- }
43374
-
43375
43334
  // src/commands/promote.ts
43376
43335
  async function handlePromoteCommand(directory, args) {
43377
43336
  let category;
@@ -43393,12 +43352,6 @@ async function handlePromoteCommand(directory, args) {
43393
43352
  if (!lessonText && !lessonId) {
43394
43353
  return `Usage: /swarm promote "<lesson text>" or /swarm promote --from-swarm <id>`;
43395
43354
  }
43396
- if (lessonText) {
43397
- const validation = validateLesson2(lessonText);
43398
- if (!validation.valid) {
43399
- return `Lesson rejected by validator: ${validation.reason}`;
43400
- }
43401
- }
43402
43355
  if (lessonId) {
43403
43356
  try {
43404
43357
  return await promoteFromSwarm(directory, lessonId);
@@ -43547,7 +43500,7 @@ async function handleQaGatesCommand(directory, args, sessionID) {
43547
43500
  }
43548
43501
 
43549
43502
  // src/commands/reset.ts
43550
- import * as fs20 from "fs";
43503
+ import * as fs19 from "fs";
43551
43504
 
43552
43505
  // src/background/manager.ts
43553
43506
  init_utils();
@@ -44248,8 +44201,8 @@ async function handleResetCommand(directory, args) {
44248
44201
  for (const filename of filesToReset) {
44249
44202
  try {
44250
44203
  const resolvedPath = validateSwarmPath(directory, filename);
44251
- if (fs20.existsSync(resolvedPath)) {
44252
- fs20.unlinkSync(resolvedPath);
44204
+ if (fs19.existsSync(resolvedPath)) {
44205
+ fs19.unlinkSync(resolvedPath);
44253
44206
  results.push(`- \u2705 Deleted ${filename}`);
44254
44207
  } else {
44255
44208
  results.push(`- \u23ED\uFE0F ${filename} not found (skipped)`);
@@ -44266,8 +44219,8 @@ async function handleResetCommand(directory, args) {
44266
44219
  }
44267
44220
  try {
44268
44221
  const summariesPath = validateSwarmPath(directory, "summaries");
44269
- if (fs20.existsSync(summariesPath)) {
44270
- fs20.rmSync(summariesPath, { recursive: true, force: true });
44222
+ if (fs19.existsSync(summariesPath)) {
44223
+ fs19.rmSync(summariesPath, { recursive: true, force: true });
44271
44224
  results.push("- \u2705 Deleted summaries/ directory");
44272
44225
  } else {
44273
44226
  results.push("- \u23ED\uFE0F summaries/ not found (skipped)");
@@ -44287,14 +44240,14 @@ async function handleResetCommand(directory, args) {
44287
44240
 
44288
44241
  // src/commands/reset-session.ts
44289
44242
  init_utils2();
44290
- import * as fs21 from "fs";
44243
+ import * as fs20 from "fs";
44291
44244
  import * as path30 from "path";
44292
44245
  async function handleResetSessionCommand(directory, _args) {
44293
44246
  const results = [];
44294
44247
  try {
44295
44248
  const statePath = validateSwarmPath(directory, "session/state.json");
44296
- if (fs21.existsSync(statePath)) {
44297
- fs21.unlinkSync(statePath);
44249
+ if (fs20.existsSync(statePath)) {
44250
+ fs20.unlinkSync(statePath);
44298
44251
  results.push("\u2705 Deleted .swarm/session/state.json");
44299
44252
  } else {
44300
44253
  results.push("\u23ED\uFE0F state.json not found (already clean)");
@@ -44304,14 +44257,14 @@ async function handleResetSessionCommand(directory, _args) {
44304
44257
  }
44305
44258
  try {
44306
44259
  const sessionDir = path30.dirname(validateSwarmPath(directory, "session/state.json"));
44307
- if (fs21.existsSync(sessionDir)) {
44308
- const files = fs21.readdirSync(sessionDir);
44260
+ if (fs20.existsSync(sessionDir)) {
44261
+ const files = fs20.readdirSync(sessionDir);
44309
44262
  const otherFiles = files.filter((f) => f !== "state.json");
44310
44263
  let deletedCount = 0;
44311
44264
  for (const file3 of otherFiles) {
44312
44265
  const filePath = path30.join(sessionDir, file3);
44313
- if (fs21.lstatSync(filePath).isFile()) {
44314
- fs21.unlinkSync(filePath);
44266
+ if (fs20.lstatSync(filePath).isFile()) {
44267
+ fs20.unlinkSync(filePath);
44315
44268
  deletedCount++;
44316
44269
  }
44317
44270
  }
@@ -44416,18 +44369,18 @@ ${error93 instanceof Error ? error93.message : String(error93)}`;
44416
44369
 
44417
44370
  // src/commands/rollback.ts
44418
44371
  init_utils2();
44419
- import * as fs22 from "fs";
44372
+ import * as fs21 from "fs";
44420
44373
  import * as path32 from "path";
44421
44374
  async function handleRollbackCommand(directory, args) {
44422
44375
  const phaseArg = args[0];
44423
44376
  if (!phaseArg) {
44424
44377
  const manifestPath2 = validateSwarmPath(directory, "checkpoints/manifest.json");
44425
- if (!fs22.existsSync(manifestPath2)) {
44378
+ if (!fs21.existsSync(manifestPath2)) {
44426
44379
  return "No checkpoints found. Use `/swarm checkpoint` to create checkpoints.";
44427
44380
  }
44428
44381
  let manifest2;
44429
44382
  try {
44430
- manifest2 = JSON.parse(fs22.readFileSync(manifestPath2, "utf-8"));
44383
+ manifest2 = JSON.parse(fs21.readFileSync(manifestPath2, "utf-8"));
44431
44384
  } catch {
44432
44385
  return "Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.";
44433
44386
  }
@@ -44449,12 +44402,12 @@ async function handleRollbackCommand(directory, args) {
44449
44402
  return "Error: Phase number must be a positive integer.";
44450
44403
  }
44451
44404
  const manifestPath = validateSwarmPath(directory, "checkpoints/manifest.json");
44452
- if (!fs22.existsSync(manifestPath)) {
44405
+ if (!fs21.existsSync(manifestPath)) {
44453
44406
  return `Error: No checkpoints found. Cannot rollback to phase ${targetPhase}.`;
44454
44407
  }
44455
44408
  let manifest;
44456
44409
  try {
44457
- manifest = JSON.parse(fs22.readFileSync(manifestPath, "utf-8"));
44410
+ manifest = JSON.parse(fs21.readFileSync(manifestPath, "utf-8"));
44458
44411
  } catch {
44459
44412
  return `Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.`;
44460
44413
  }
@@ -44464,10 +44417,10 @@ async function handleRollbackCommand(directory, args) {
44464
44417
  return `Error: Checkpoint for phase ${targetPhase} not found. Available phases: ${available}`;
44465
44418
  }
44466
44419
  const checkpointDir = validateSwarmPath(directory, `checkpoints/phase-${targetPhase}`);
44467
- if (!fs22.existsSync(checkpointDir)) {
44420
+ if (!fs21.existsSync(checkpointDir)) {
44468
44421
  return `Error: Checkpoint directory for phase ${targetPhase} does not exist.`;
44469
44422
  }
44470
- const checkpointFiles = fs22.readdirSync(checkpointDir);
44423
+ const checkpointFiles = fs21.readdirSync(checkpointDir);
44471
44424
  if (checkpointFiles.length === 0) {
44472
44425
  return `Error: Checkpoint for phase ${targetPhase} is empty. Cannot rollback.`;
44473
44426
  }
@@ -44478,7 +44431,7 @@ async function handleRollbackCommand(directory, args) {
44478
44431
  const src = path32.join(checkpointDir, file3);
44479
44432
  const dest = path32.join(swarmDir, file3);
44480
44433
  try {
44481
- fs22.cpSync(src, dest, { recursive: true, force: true });
44434
+ fs21.cpSync(src, dest, { recursive: true, force: true });
44482
44435
  successes.push(file3);
44483
44436
  } catch (error93) {
44484
44437
  failures.push({ file: file3, error: error93.message });
@@ -44495,7 +44448,7 @@ async function handleRollbackCommand(directory, args) {
44495
44448
  timestamp: new Date().toISOString()
44496
44449
  };
44497
44450
  try {
44498
- fs22.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
44451
+ fs21.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
44499
44452
  `);
44500
44453
  } catch (error93) {
44501
44454
  console.error("Failed to write rollback event:", error93 instanceof Error ? error93.message : String(error93));
@@ -44538,11 +44491,11 @@ async function handleSimulateCommand(directory, args) {
44538
44491
  ];
44539
44492
  const report = reportLines.filter(Boolean).join(`
44540
44493
  `);
44541
- const fs23 = await import("fs/promises");
44494
+ const fs22 = await import("fs/promises");
44542
44495
  const path33 = await import("path");
44543
44496
  const reportPath = path33.join(directory, ".swarm", "simulate-report.md");
44544
- await fs23.mkdir(path33.dirname(reportPath), { recursive: true });
44545
- await fs23.writeFile(reportPath, report, "utf-8");
44497
+ await fs22.mkdir(path33.dirname(reportPath), { recursive: true });
44498
+ await fs22.writeFile(reportPath, report, "utf-8");
44546
44499
  return `${darkMatterPairs.length} hidden coupling pairs detected`;
44547
44500
  }
44548
44501
 
@@ -45075,19 +45028,19 @@ function resolveCommand(tokens) {
45075
45028
  }
45076
45029
 
45077
45030
  // src/cli/index.ts
45078
- var CONFIG_DIR = path33.join(process.env.XDG_CONFIG_HOME || path33.join(os7.homedir(), ".config"), "opencode");
45031
+ var CONFIG_DIR = path33.join(process.env.XDG_CONFIG_HOME || path33.join(os6.homedir(), ".config"), "opencode");
45079
45032
  var OPENCODE_CONFIG_PATH = path33.join(CONFIG_DIR, "opencode.json");
45080
45033
  var PLUGIN_CONFIG_PATH = path33.join(CONFIG_DIR, "opencode-swarm.json");
45081
45034
  var PROMPTS_DIR = path33.join(CONFIG_DIR, "opencode-swarm");
45082
- var OPENCODE_PLUGIN_CACHE_PATH = path33.join(process.env.XDG_CACHE_HOME || path33.join(os7.homedir(), ".cache"), "opencode", "packages", "opencode-swarm@latest");
45035
+ var OPENCODE_PLUGIN_CACHE_PATH = path33.join(process.env.XDG_CACHE_HOME || path33.join(os6.homedir(), ".cache"), "opencode", "packages", "opencode-swarm@latest");
45083
45036
  function ensureDir(dir) {
45084
- if (!fs23.existsSync(dir)) {
45085
- fs23.mkdirSync(dir, { recursive: true });
45037
+ if (!fs22.existsSync(dir)) {
45038
+ fs22.mkdirSync(dir, { recursive: true });
45086
45039
  }
45087
45040
  }
45088
45041
  function loadJson(filepath) {
45089
45042
  try {
45090
- const content = fs23.readFileSync(filepath, "utf-8");
45043
+ const content = fs22.readFileSync(filepath, "utf-8");
45091
45044
  const stripped = content.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (match, comment) => comment ? "" : match).replace(/,(\s*[}\]])/g, "$1");
45092
45045
  return JSON.parse(stripped);
45093
45046
  } catch {
@@ -45095,7 +45048,7 @@ function loadJson(filepath) {
45095
45048
  }
45096
45049
  }
45097
45050
  function saveJson(filepath, data) {
45098
- fs23.writeFileSync(filepath, `${JSON.stringify(data, null, 2)}
45051
+ fs22.writeFileSync(filepath, `${JSON.stringify(data, null, 2)}
45099
45052
  `, "utf-8");
45100
45053
  }
45101
45054
  async function install() {
@@ -45135,15 +45088,15 @@ async function install() {
45135
45088
  console.log("\u2713 Added opencode-swarm to OpenCode plugins");
45136
45089
  console.log("\u2713 Disabled default OpenCode agents (explore, general)");
45137
45090
  try {
45138
- if (fs23.existsSync(OPENCODE_PLUGIN_CACHE_PATH)) {
45139
- fs23.rmSync(OPENCODE_PLUGIN_CACHE_PATH, { recursive: true, force: true });
45091
+ if (fs22.existsSync(OPENCODE_PLUGIN_CACHE_PATH)) {
45092
+ fs22.rmSync(OPENCODE_PLUGIN_CACHE_PATH, { recursive: true, force: true });
45140
45093
  console.log("\u2713 Cleared opencode plugin cache (next start will fetch latest)");
45141
45094
  }
45142
45095
  } catch {
45143
45096
  console.warn("\u26A0 Could not clear opencode plugin cache \u2014 you may need to delete it manually:");
45144
45097
  console.warn(` ${OPENCODE_PLUGIN_CACHE_PATH}`);
45145
45098
  }
45146
- if (!fs23.existsSync(PLUGIN_CONFIG_PATH)) {
45099
+ if (!fs22.existsSync(PLUGIN_CONFIG_PATH)) {
45147
45100
  const defaultConfig = {
45148
45101
  agents: {
45149
45102
  coder: {
@@ -45246,7 +45199,7 @@ async function uninstall() {
45246
45199
  `);
45247
45200
  const opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
45248
45201
  if (!opencodeConfig) {
45249
- if (fs23.existsSync(OPENCODE_CONFIG_PATH)) {
45202
+ if (fs22.existsSync(OPENCODE_CONFIG_PATH)) {
45250
45203
  console.log(`\u2717 Could not parse opencode config at: ${OPENCODE_CONFIG_PATH}`);
45251
45204
  return 1;
45252
45205
  } else {
@@ -45278,13 +45231,13 @@ async function uninstall() {
45278
45231
  console.log("\u2713 Re-enabled default OpenCode agents (explore, general)");
45279
45232
  if (process.argv.includes("--clean")) {
45280
45233
  let cleaned = false;
45281
- if (fs23.existsSync(PLUGIN_CONFIG_PATH)) {
45282
- fs23.unlinkSync(PLUGIN_CONFIG_PATH);
45234
+ if (fs22.existsSync(PLUGIN_CONFIG_PATH)) {
45235
+ fs22.unlinkSync(PLUGIN_CONFIG_PATH);
45283
45236
  console.log(`\u2713 Removed plugin config: ${PLUGIN_CONFIG_PATH}`);
45284
45237
  cleaned = true;
45285
45238
  }
45286
- if (fs23.existsSync(PROMPTS_DIR)) {
45287
- fs23.rmSync(PROMPTS_DIR, { recursive: true });
45239
+ if (fs22.existsSync(PROMPTS_DIR)) {
45240
+ fs22.rmSync(PROMPTS_DIR, { recursive: true });
45288
45241
  console.log(`\u2713 Removed custom prompts: ${PROMPTS_DIR}`);
45289
45242
  cleaned = true;
45290
45243
  }