opencode-swarm 6.85.3 → 6.86.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/cli/index.js +357 -408
  2. package/dist/config/schema.d.ts +4 -0
  3. package/dist/index.js +1040 -1081
  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
@@ -18973,6 +18973,7 @@ for (const [agentName, tools] of Object.entries(AGENT_TOOL_MAP)) {
18973
18973
  // src/config/schema.ts
18974
18974
  var AgentOverrideConfigSchema = exports_external.object({
18975
18975
  model: exports_external.string().optional(),
18976
+ variant: exports_external.string().min(1).optional(),
18976
18977
  temperature: exports_external.number().min(0).max(2).optional(),
18977
18978
  disabled: exports_external.boolean().optional(),
18978
18979
  fallback_models: exports_external.array(exports_external.string()).max(3).optional()
@@ -20842,6 +20843,7 @@ async function handleBrainstormCommand(_directory, args) {
20842
20843
  init_zod();
20843
20844
 
20844
20845
  // src/tools/checkpoint.ts
20846
+ init_zod();
20845
20847
  import * as child_process from "child_process";
20846
20848
  import * as fs6 from "fs";
20847
20849
  import * as path8 from "path";
@@ -33184,7 +33186,8 @@ function createSwarmTool(opts) {
33184
33186
  execute: async (args, ctx) => {
33185
33187
  const directory = ctx?.directory ?? process.cwd();
33186
33188
  try {
33187
- return await opts.execute(args, directory, ctx);
33189
+ const result = await opts.execute(args, directory, ctx);
33190
+ return result;
33188
33191
  } catch (error93) {
33189
33192
  const message = error93 instanceof Error ? error93.message : String(error93);
33190
33193
  return JSON.stringify({
@@ -33410,8 +33413,8 @@ function handleDelete(label, directory) {
33410
33413
  var checkpoint = createSwarmTool({
33411
33414
  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
33415
  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)")
33416
+ action: exports_external.string().describe("Action to perform: save, restore, list, or delete"),
33417
+ label: exports_external.string().optional().describe("Checkpoint label (required for save, restore, delete)")
33415
33418
  },
33416
33419
  execute: async (args, directory) => {
33417
33420
  if (!isGitRepo()) {
@@ -33485,7 +33488,8 @@ var CheckpointResultSchema = exports_external.object({
33485
33488
  checkpoints: exports_external.array(exports_external.unknown()).optional()
33486
33489
  }).passthrough();
33487
33490
  function safeParseResult(result) {
33488
- const parsed = CheckpointResultSchema.safeParse(JSON.parse(result));
33491
+ const jsonStr = typeof result === "string" ? result : result.output;
33492
+ const parsed = CheckpointResultSchema.safeParse(JSON.parse(jsonStr));
33489
33493
  if (!parsed.success) {
33490
33494
  return {
33491
33495
  success: false,
@@ -33671,7 +33675,7 @@ function resolveSwarmRejectedPath(directory) {
33671
33675
  }
33672
33676
  function resolveHiveKnowledgePath() {
33673
33677
  const platform = process.platform;
33674
- const home = os3.homedir();
33678
+ const home = process.env.HOME || os3.homedir();
33675
33679
  let dataDir;
33676
33680
  if (platform === "win32") {
33677
33681
  dataDir = path9.join(process.env.LOCALAPPDATA || path9.join(home, "AppData", "Local"), "opencode-swarm", "Data");
@@ -34429,6 +34433,7 @@ async function flushPendingSnapshot(directory) {
34429
34433
  }
34430
34434
 
34431
34435
  // src/tools/write-retro.ts
34436
+ init_zod();
34432
34437
  init_evidence_schema();
34433
34438
  init_manager2();
34434
34439
  async function executeWriteRetro(args, directory) {
@@ -34734,22 +34739,22 @@ async function executeWriteRetro(args, directory) {
34734
34739
  var write_retro = createSwarmTool({
34735
34740
  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
34741
  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")
34742
+ phase: exports_external.number().int().min(1).max(99).describe("The phase number being completed (e.g., 1, 2, 3)"),
34743
+ summary: exports_external.string().describe("Human-readable summary of the phase"),
34744
+ task_count: exports_external.number().int().min(1).max(9999).describe("Count of tasks completed in this phase"),
34745
+ task_complexity: exports_external.enum(["trivial", "simple", "moderate", "complex"]).describe("Complexity level of the completed tasks"),
34746
+ total_tool_calls: exports_external.number().int().min(0).max(9999).describe("Total number of tool calls in this phase"),
34747
+ coder_revisions: exports_external.number().int().min(0).max(999).describe("Number of coder revisions made"),
34748
+ reviewer_rejections: exports_external.number().int().min(0).max(999).describe("Number of reviewer rejections received"),
34749
+ loop_detections: exports_external.number().int().min(0).max(9999).optional().describe("Number of loop detection events in this phase"),
34750
+ circuit_breaker_trips: exports_external.number().int().min(0).max(9999).optional().describe("Number of circuit breaker trips in this phase"),
34751
+ test_failures: exports_external.number().int().min(0).max(9999).describe("Number of test failures encountered"),
34752
+ security_findings: exports_external.number().int().min(0).max(999).describe("Number of security findings"),
34753
+ integration_issues: exports_external.number().int().min(0).max(999).describe("Number of integration issues"),
34754
+ lessons_learned: exports_external.array(exports_external.string()).max(5).optional().describe("Key lessons learned from this phase (max 5)"),
34755
+ top_rejection_reasons: exports_external.array(exports_external.string()).optional().describe("Top reasons for reviewer rejections"),
34756
+ task_id: exports_external.string().optional().describe("Optional custom task ID (defaults to retro-{phase})"),
34757
+ metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional().describe("Optional additional metadata")
34753
34758
  },
34754
34759
  execute: async (args, directory) => {
34755
34760
  const rawPhase = args.phase !== undefined ? Number(args.phase) : 0;
@@ -35346,6 +35351,9 @@ async function handleCouncilCommand(_directory, args) {
35346
35351
  return `[${tokens.join(" ")}] ${question}`;
35347
35352
  }
35348
35353
 
35354
+ // src/hooks/hive-promoter.ts
35355
+ import path15 from "path";
35356
+
35349
35357
  // src/background/event-bus.ts
35350
35358
  init_utils();
35351
35359
 
@@ -35567,6 +35575,86 @@ async function checkHivePromotions(swarmEntries, config3) {
35567
35575
  total_hive_entries: hiveEntries.length
35568
35576
  };
35569
35577
  }
35578
+ async function promoteToHive(directory, lesson, category) {
35579
+ const trimmedLesson = lesson.trim();
35580
+ const hiveEntries = await readKnowledge(resolveHiveKnowledgePath());
35581
+ const validationResult = validateLesson(trimmedLesson, hiveEntries.map((e) => e.lesson), {
35582
+ category: category || "process",
35583
+ scope: "global",
35584
+ confidence: 1
35585
+ });
35586
+ if (validationResult.severity === "error") {
35587
+ throw new Error(`Lesson rejected by validator: ${validationResult.reason}`);
35588
+ }
35589
+ if (findNearDuplicate(trimmedLesson, hiveEntries, 0.6)) {
35590
+ return `Lesson already exists in hive (near-duplicate).`;
35591
+ }
35592
+ const newHiveEntry = {
35593
+ id: crypto.randomUUID(),
35594
+ tier: "hive",
35595
+ lesson: trimmedLesson,
35596
+ category: category || "process",
35597
+ tags: [],
35598
+ scope: "global",
35599
+ confidence: 1,
35600
+ status: "promoted",
35601
+ confirmed_by: [],
35602
+ retrieval_outcomes: {
35603
+ applied_count: 0,
35604
+ succeeded_after_count: 0,
35605
+ failed_after_count: 0
35606
+ },
35607
+ schema_version: 1,
35608
+ created_at: new Date().toISOString(),
35609
+ updated_at: new Date().toISOString(),
35610
+ source_project: path15.basename(directory) || "unknown",
35611
+ encounter_score: 1
35612
+ };
35613
+ await appendKnowledge(resolveHiveKnowledgePath(), newHiveEntry);
35614
+ return `Promoted to hive: "${trimmedLesson.slice(0, 50)}${trimmedLesson.length > 50 ? "..." : ""}" (confidence: 1.0, source: manual)`;
35615
+ }
35616
+ async function promoteFromSwarm(directory, lessonId) {
35617
+ const swarmEntries = await readKnowledge(resolveSwarmKnowledgePath(directory));
35618
+ const swarmEntry = swarmEntries.find((e) => e.id === lessonId);
35619
+ if (!swarmEntry) {
35620
+ throw new Error(`Lesson ${lessonId} not found in .swarm/knowledge.jsonl`);
35621
+ }
35622
+ const hiveEntries = await readKnowledge(resolveHiveKnowledgePath());
35623
+ const validationResult = validateLesson(swarmEntry.lesson, hiveEntries.map((e) => e.lesson), {
35624
+ category: swarmEntry.category,
35625
+ scope: swarmEntry.scope,
35626
+ confidence: swarmEntry.confidence
35627
+ });
35628
+ if (validationResult.severity === "error") {
35629
+ throw new Error(`Lesson rejected by validator: ${validationResult.reason}`);
35630
+ }
35631
+ if (findNearDuplicate(swarmEntry.lesson, hiveEntries, 0.6)) {
35632
+ return `Lesson already exists in hive (near-duplicate).`;
35633
+ }
35634
+ const newHiveEntry = {
35635
+ id: crypto.randomUUID(),
35636
+ tier: "hive",
35637
+ lesson: swarmEntry.lesson,
35638
+ category: swarmEntry.category,
35639
+ tags: swarmEntry.tags,
35640
+ scope: swarmEntry.scope,
35641
+ confidence: 1,
35642
+ status: "promoted",
35643
+ confirmed_by: [],
35644
+ retrieval_outcomes: {
35645
+ applied_count: 0,
35646
+ succeeded_after_count: 0,
35647
+ failed_after_count: 0
35648
+ },
35649
+ schema_version: 1,
35650
+ created_at: new Date().toISOString(),
35651
+ updated_at: new Date().toISOString(),
35652
+ source_project: swarmEntry.project_name,
35653
+ encounter_score: 1
35654
+ };
35655
+ await appendKnowledge(resolveHiveKnowledgePath(), newHiveEntry);
35656
+ return `Promoted lesson ${lessonId} from swarm to hive: "${swarmEntry.lesson.slice(0, 50)}${swarmEntry.lesson.length > 50 ? "..." : ""}"`;
35657
+ }
35570
35658
 
35571
35659
  // src/commands/curate.ts
35572
35660
  async function handleCurateCommand(directory, _args) {
@@ -35597,13 +35685,14 @@ function formatCurationSummary(summary) {
35597
35685
  }
35598
35686
 
35599
35687
  // src/commands/dark-matter.ts
35600
- import path16 from "path";
35688
+ import path17 from "path";
35601
35689
 
35602
35690
  // src/tools/co-change-analyzer.ts
35691
+ init_zod();
35603
35692
  import * as child_process3 from "child_process";
35604
35693
  import { randomUUID } from "crypto";
35605
35694
  import { readdir, readFile as readFile3, stat } from "fs/promises";
35606
- import * as path15 from "path";
35695
+ import * as path16 from "path";
35607
35696
  import { promisify } from "util";
35608
35697
  function getExecFileAsync() {
35609
35698
  return promisify(child_process3.execFile);
@@ -35705,7 +35794,7 @@ async function scanSourceFiles(dir) {
35705
35794
  try {
35706
35795
  const entries = await readdir(dir, { withFileTypes: true });
35707
35796
  for (const entry of entries) {
35708
- const fullPath = path15.join(dir, entry.name);
35797
+ const fullPath = path16.join(dir, entry.name);
35709
35798
  if (entry.isDirectory()) {
35710
35799
  if (skipDirs.has(entry.name)) {
35711
35800
  continue;
@@ -35713,7 +35802,7 @@ async function scanSourceFiles(dir) {
35713
35802
  const subFiles = await scanSourceFiles(fullPath);
35714
35803
  results.push(...subFiles);
35715
35804
  } else if (entry.isFile()) {
35716
- const ext = path15.extname(entry.name);
35805
+ const ext = path16.extname(entry.name);
35717
35806
  if ([".ts", ".tsx", ".js", ".jsx", ".mjs"].includes(ext)) {
35718
35807
  results.push(fullPath);
35719
35808
  }
@@ -35735,8 +35824,8 @@ async function getStaticEdges(directory) {
35735
35824
  continue;
35736
35825
  }
35737
35826
  try {
35738
- const sourceDir = path15.dirname(sourceFile);
35739
- const resolvedPath = path15.resolve(sourceDir, importPath);
35827
+ const sourceDir = path16.dirname(sourceFile);
35828
+ const resolvedPath = path16.resolve(sourceDir, importPath);
35740
35829
  const extensions = [
35741
35830
  "",
35742
35831
  ".ts",
@@ -35761,8 +35850,8 @@ async function getStaticEdges(directory) {
35761
35850
  if (!targetFile) {
35762
35851
  continue;
35763
35852
  }
35764
- const relSource = path15.relative(directory, sourceFile).replace(/\\/g, "/");
35765
- const relTarget = path15.relative(directory, targetFile).replace(/\\/g, "/");
35853
+ const relSource = path16.relative(directory, sourceFile).replace(/\\/g, "/");
35854
+ const relTarget = path16.relative(directory, targetFile).replace(/\\/g, "/");
35766
35855
  const [key] = relSource < relTarget ? [`${relSource}::${relTarget}`, relSource, relTarget] : [`${relTarget}::${relSource}`, relTarget, relSource];
35767
35856
  edges.add(key);
35768
35857
  } catch {}
@@ -35774,7 +35863,7 @@ async function getStaticEdges(directory) {
35774
35863
  function isTestImplementationPair(fileA, fileB) {
35775
35864
  const testPatterns = [".test.ts", ".test.js", ".spec.ts", ".spec.js"];
35776
35865
  const getBaseName = (filePath) => {
35777
- const base = path15.basename(filePath);
35866
+ const base = path16.basename(filePath);
35778
35867
  for (const pattern of testPatterns) {
35779
35868
  if (base.endsWith(pattern)) {
35780
35869
  return base.slice(0, -pattern.length);
@@ -35784,16 +35873,16 @@ function isTestImplementationPair(fileA, fileB) {
35784
35873
  };
35785
35874
  const baseA = getBaseName(fileA);
35786
35875
  const baseB = getBaseName(fileB);
35787
- return baseA === baseB && baseA !== path15.basename(fileA) && baseA !== path15.basename(fileB);
35876
+ return baseA === baseB && baseA !== path16.basename(fileA) && baseA !== path16.basename(fileB);
35788
35877
  }
35789
35878
  function hasSharedPrefix(fileA, fileB) {
35790
- const dirA = path15.dirname(fileA);
35791
- const dirB = path15.dirname(fileB);
35879
+ const dirA = path16.dirname(fileA);
35880
+ const dirB = path16.dirname(fileB);
35792
35881
  if (dirA !== dirB) {
35793
35882
  return false;
35794
35883
  }
35795
- const baseA = path15.basename(fileA).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
35796
- const baseB = path15.basename(fileB).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
35884
+ const baseA = path16.basename(fileA).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
35885
+ const baseB = path16.basename(fileB).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
35797
35886
  if (baseA.startsWith(baseB) || baseB.startsWith(baseA)) {
35798
35887
  return true;
35799
35888
  }
@@ -35847,8 +35936,8 @@ function darkMatterToKnowledgeEntries(pairs, projectName) {
35847
35936
  const entries = [];
35848
35937
  const now = new Date().toISOString();
35849
35938
  for (const pair of pairs.slice(0, 10)) {
35850
- const baseA = path15.basename(pair.fileA);
35851
- const baseB = path15.basename(pair.fileB);
35939
+ const baseA = path16.basename(pair.fileA);
35940
+ const baseB = path16.basename(pair.fileB);
35852
35941
  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
35942
  if (lesson.length > 280) {
35854
35943
  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 +35995,10 @@ Consider adding explicit documentation or extracting the shared concern.`;
35906
35995
  var co_change_analyzer = createSwarmTool({
35907
35996
  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
35997
  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)")
35998
+ min_commits: exports_external.number().optional().describe("Minimum commit count to analyze (default: 20)"),
35999
+ min_co_changes: exports_external.number().optional().describe("Minimum co-change count to consider (default: 3)"),
36000
+ threshold: exports_external.number().optional().describe("NPMI threshold for filtering (default: 0.5)"),
36001
+ max_commits: exports_external.number().optional().describe("Maximum commits to analyze (default: 500)")
35913
36002
  },
35914
36003
  async execute(args, directory) {
35915
36004
  let minCommits;
@@ -35958,7 +36047,7 @@ async function handleDarkMatterCommand(directory, args) {
35958
36047
  const output = formatDarkMatterOutput(pairs);
35959
36048
  if (pairs.length > 0) {
35960
36049
  try {
35961
- const projectName = path16.basename(path16.resolve(directory));
36050
+ const projectName = path17.basename(path17.resolve(directory));
35962
36051
  const entries = darkMatterToKnowledgeEntries(pairs, projectName);
35963
36052
  if (entries.length > 0) {
35964
36053
  const knowledgePath = resolveSwarmKnowledgePath(directory);
@@ -35980,7 +36069,7 @@ async function handleDarkMatterCommand(directory, args) {
35980
36069
  // src/services/diagnose-service.ts
35981
36070
  import * as child_process4 from "child_process";
35982
36071
  import { existsSync as existsSync8, readdirSync as readdirSync4, readFileSync as readFileSync6, statSync as statSync5 } from "fs";
35983
- import path17 from "path";
36072
+ import path18 from "path";
35984
36073
  import { fileURLToPath } from "url";
35985
36074
  init_manager2();
35986
36075
  init_utils2();
@@ -36280,7 +36369,7 @@ async function checkSpecStaleness(directory, plan) {
36280
36369
  };
36281
36370
  }
36282
36371
  async function checkConfigParseability(directory) {
36283
- const configPath = path17.join(directory, ".opencode/opencode-swarm.json");
36372
+ const configPath = path18.join(directory, ".opencode/opencode-swarm.json");
36284
36373
  if (!existsSync8(configPath)) {
36285
36374
  return {
36286
36375
  name: "Config Parseability",
@@ -36309,7 +36398,7 @@ function resolveGrammarDir(thisDir) {
36309
36398
  const normalized = thisDir.replace(/\\/g, "/");
36310
36399
  const isSource = normalized.endsWith("/src/services");
36311
36400
  const isCliBundle = normalized.endsWith("/cli");
36312
- return isSource || isCliBundle ? path17.join(thisDir, "..", "lang", "grammars") : path17.join(thisDir, "lang", "grammars");
36401
+ return isSource || isCliBundle ? path18.join(thisDir, "..", "lang", "grammars") : path18.join(thisDir, "lang", "grammars");
36313
36402
  }
36314
36403
  async function checkGrammarWasmFiles() {
36315
36404
  const grammarFiles = [
@@ -36333,14 +36422,14 @@ async function checkGrammarWasmFiles() {
36333
36422
  "tree-sitter-ini.wasm",
36334
36423
  "tree-sitter-regex.wasm"
36335
36424
  ];
36336
- const thisDir = path17.dirname(fileURLToPath(import.meta.url));
36425
+ const thisDir = path18.dirname(fileURLToPath(import.meta.url));
36337
36426
  const grammarDir = resolveGrammarDir(thisDir);
36338
36427
  const missing = [];
36339
- if (!existsSync8(path17.join(grammarDir, "tree-sitter.wasm"))) {
36428
+ if (!existsSync8(path18.join(grammarDir, "tree-sitter.wasm"))) {
36340
36429
  missing.push("tree-sitter.wasm (core runtime)");
36341
36430
  }
36342
36431
  for (const file3 of grammarFiles) {
36343
- if (!existsSync8(path17.join(grammarDir, file3))) {
36432
+ if (!existsSync8(path18.join(grammarDir, file3))) {
36344
36433
  missing.push(file3);
36345
36434
  }
36346
36435
  }
@@ -36358,7 +36447,7 @@ async function checkGrammarWasmFiles() {
36358
36447
  };
36359
36448
  }
36360
36449
  async function checkCheckpointManifest(directory) {
36361
- const manifestPath = path17.join(directory, ".swarm/checkpoints.json");
36450
+ const manifestPath = path18.join(directory, ".swarm/checkpoints.json");
36362
36451
  if (!existsSync8(manifestPath)) {
36363
36452
  return {
36364
36453
  name: "Checkpoint Manifest",
@@ -36410,7 +36499,7 @@ async function checkCheckpointManifest(directory) {
36410
36499
  }
36411
36500
  }
36412
36501
  async function checkEventStreamIntegrity(directory) {
36413
- const eventsPath = path17.join(directory, ".swarm/events.jsonl");
36502
+ const eventsPath = path18.join(directory, ".swarm/events.jsonl");
36414
36503
  if (!existsSync8(eventsPath)) {
36415
36504
  return {
36416
36505
  name: "Event Stream",
@@ -36451,7 +36540,7 @@ async function checkEventStreamIntegrity(directory) {
36451
36540
  }
36452
36541
  }
36453
36542
  async function checkSteeringDirectives(directory) {
36454
- const eventsPath = path17.join(directory, ".swarm/events.jsonl");
36543
+ const eventsPath = path18.join(directory, ".swarm/events.jsonl");
36455
36544
  if (!existsSync8(eventsPath)) {
36456
36545
  return {
36457
36546
  name: "Steering Directives",
@@ -36507,7 +36596,7 @@ async function checkCurator(directory) {
36507
36596
  detail: "Disabled (enable via curator.enabled)"
36508
36597
  };
36509
36598
  }
36510
- const summaryPath = path17.join(directory, ".swarm/curator-summary.json");
36599
+ const summaryPath = path18.join(directory, ".swarm/curator-summary.json");
36511
36600
  if (!existsSync8(summaryPath)) {
36512
36601
  return {
36513
36602
  name: "Curator",
@@ -36655,7 +36744,7 @@ async function getDiagnoseData(directory) {
36655
36744
  checks5.push(await checkSteeringDirectives(directory));
36656
36745
  checks5.push(await checkCurator(directory));
36657
36746
  try {
36658
- const evidenceDir = path17.join(directory, ".swarm", "evidence");
36747
+ const evidenceDir = path18.join(directory, ".swarm", "evidence");
36659
36748
  const snapshotFiles = existsSync8(evidenceDir) ? readdirSync4(evidenceDir).filter((f) => f.startsWith("agent-tools-") && f.endsWith(".json")) : [];
36660
36749
  if (snapshotFiles.length > 0) {
36661
36750
  const latest = snapshotFiles.sort().pop();
@@ -36708,11 +36797,11 @@ init_config_doctor();
36708
36797
 
36709
36798
  // src/services/tool-doctor.ts
36710
36799
  import * as fs11 from "fs";
36711
- import * as path20 from "path";
36800
+ import * as path21 from "path";
36712
36801
 
36713
36802
  // src/build/discovery.ts
36714
36803
  import * as fs10 from "fs";
36715
- import * as path19 from "path";
36804
+ import * as path20 from "path";
36716
36805
 
36717
36806
  // src/lang/detector.ts
36718
36807
  import { access as access2, readdir as readdir2 } from "fs/promises";
@@ -37876,11 +37965,11 @@ function findBuildFiles(workingDir, patterns) {
37876
37965
  const regex = simpleGlobToRegex(pattern);
37877
37966
  const matches = files.filter((f) => regex.test(f));
37878
37967
  if (matches.length > 0) {
37879
- return path19.join(dir, matches[0]);
37968
+ return path20.join(dir, matches[0]);
37880
37969
  }
37881
37970
  } catch {}
37882
37971
  } else {
37883
- const filePath = path19.join(workingDir, pattern);
37972
+ const filePath = path20.join(workingDir, pattern);
37884
37973
  if (fs10.existsSync(filePath)) {
37885
37974
  return filePath;
37886
37975
  }
@@ -37889,7 +37978,7 @@ function findBuildFiles(workingDir, patterns) {
37889
37978
  return null;
37890
37979
  }
37891
37980
  function getRepoDefinedScripts(workingDir, scripts) {
37892
- const packageJsonPath = path19.join(workingDir, "package.json");
37981
+ const packageJsonPath = path20.join(workingDir, "package.json");
37893
37982
  if (!fs10.existsSync(packageJsonPath)) {
37894
37983
  return [];
37895
37984
  }
@@ -37930,7 +38019,7 @@ function findAllBuildFiles(workingDir) {
37930
38019
  const regex = simpleGlobToRegex(pattern);
37931
38020
  findFilesRecursive(workingDir, regex, allBuildFiles);
37932
38021
  } else {
37933
- const filePath = path19.join(workingDir, pattern);
38022
+ const filePath = path20.join(workingDir, pattern);
37934
38023
  if (fs10.existsSync(filePath)) {
37935
38024
  allBuildFiles.add(filePath);
37936
38025
  }
@@ -37943,7 +38032,7 @@ function findFilesRecursive(dir, regex, results) {
37943
38032
  try {
37944
38033
  const entries = fs10.readdirSync(dir, { withFileTypes: true });
37945
38034
  for (const entry of entries) {
37946
- const fullPath = path19.join(dir, entry.name);
38035
+ const fullPath = path20.join(dir, entry.name);
37947
38036
  if (entry.isDirectory() && !["node_modules", ".git", "dist", "build", "target"].includes(entry.name)) {
37948
38037
  findFilesRecursive(fullPath, regex, results);
37949
38038
  } else if (entry.isFile() && regex.test(entry.name)) {
@@ -37966,7 +38055,7 @@ async function discoverBuildCommandsFromProfiles(workingDir) {
37966
38055
  let foundCommand = false;
37967
38056
  for (const cmd of sortedCommands) {
37968
38057
  if (cmd.detectFile) {
37969
- const detectFilePath = path19.join(workingDir, cmd.detectFile);
38058
+ const detectFilePath = path20.join(workingDir, cmd.detectFile);
37970
38059
  if (!fs10.existsSync(detectFilePath)) {
37971
38060
  continue;
37972
38061
  }
@@ -38141,8 +38230,8 @@ function checkBinaryReadiness() {
38141
38230
  }
38142
38231
  function runToolDoctor(_directory, pluginRoot) {
38143
38232
  const findings = [];
38144
- const resolvedPluginRoot = pluginRoot ?? path20.resolve(import.meta.dir, "..", "..");
38145
- const indexPath = path20.join(resolvedPluginRoot, "src", "index.ts");
38233
+ const resolvedPluginRoot = pluginRoot ?? path21.resolve(import.meta.dir, "..", "..");
38234
+ const indexPath = path21.join(resolvedPluginRoot, "src", "index.ts");
38146
38235
  if (!fs11.existsSync(indexPath)) {
38147
38236
  return {
38148
38237
  findings: [
@@ -39065,10 +39154,10 @@ async function handleHistoryCommand(directory, _args) {
39065
39154
  import { randomUUID as randomUUID2 } from "crypto";
39066
39155
  import { existsSync as existsSync12, readFileSync as readFileSync10 } from "fs";
39067
39156
  import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
39068
- import * as path21 from "path";
39157
+ import * as path22 from "path";
39069
39158
  async function migrateContextToKnowledge(directory, config3) {
39070
- const sentinelPath = path21.join(directory, ".swarm", ".knowledge-migrated");
39071
- const contextPath = path21.join(directory, ".swarm", "context.md");
39159
+ const sentinelPath = path22.join(directory, ".swarm", ".knowledge-migrated");
39160
+ const contextPath = path22.join(directory, ".swarm", "context.md");
39072
39161
  const knowledgePath = resolveSwarmKnowledgePath(directory);
39073
39162
  if (existsSync12(sentinelPath)) {
39074
39163
  return {
@@ -39264,7 +39353,7 @@ function truncateLesson(text) {
39264
39353
  return `${text.slice(0, 277)}...`;
39265
39354
  }
39266
39355
  function inferProjectName(directory) {
39267
- const packageJsonPath = path21.join(directory, "package.json");
39356
+ const packageJsonPath = path22.join(directory, "package.json");
39268
39357
  if (existsSync12(packageJsonPath)) {
39269
39358
  try {
39270
39359
  const pkg = JSON.parse(readFileSync10(packageJsonPath, "utf-8"));
@@ -39273,7 +39362,7 @@ function inferProjectName(directory) {
39273
39362
  }
39274
39363
  } catch {}
39275
39364
  }
39276
- return path21.basename(directory);
39365
+ return path22.basename(directory);
39277
39366
  }
39278
39367
  async function writeSentinel(sentinelPath, migrated, dropped) {
39279
39368
  const sentinel = {
@@ -39285,7 +39374,7 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
39285
39374
  schema_version: 1,
39286
39375
  migration_tool: "knowledge-migrator.ts"
39287
39376
  };
39288
- await mkdir3(path21.dirname(sentinelPath), { recursive: true });
39377
+ await mkdir3(path22.dirname(sentinelPath), { recursive: true });
39289
39378
  await writeFile4(sentinelPath, JSON.stringify(sentinel, null, 2), "utf-8");
39290
39379
  }
39291
39380
 
@@ -39522,11 +39611,12 @@ async function handlePlanCommand(directory, args) {
39522
39611
  init_manager2();
39523
39612
  init_manager();
39524
39613
  import * as fs18 from "fs";
39525
- import * as path28 from "path";
39614
+ import * as path29 from "path";
39526
39615
 
39527
39616
  // src/tools/lint.ts
39617
+ init_zod();
39528
39618
  import * as fs12 from "fs";
39529
- import * as path22 from "path";
39619
+ import * as path23 from "path";
39530
39620
  init_utils();
39531
39621
 
39532
39622
  // src/utils/path-security.ts
@@ -39572,9 +39662,9 @@ function validateArgs(args) {
39572
39662
  }
39573
39663
  function getLinterCommand(linter, mode, projectDir) {
39574
39664
  const isWindows = process.platform === "win32";
39575
- const binDir = path22.join(projectDir, "node_modules", ".bin");
39576
- const biomeBin = isWindows ? path22.join(binDir, "biome.EXE") : path22.join(binDir, "biome");
39577
- const eslintBin = isWindows ? path22.join(binDir, "eslint.cmd") : path22.join(binDir, "eslint");
39665
+ const binDir = path23.join(projectDir, "node_modules", ".bin");
39666
+ const biomeBin = isWindows ? path23.join(binDir, "biome.EXE") : path23.join(binDir, "biome");
39667
+ const eslintBin = isWindows ? path23.join(binDir, "eslint.cmd") : path23.join(binDir, "eslint");
39578
39668
  switch (linter) {
39579
39669
  case "biome":
39580
39670
  if (mode === "fix") {
@@ -39590,7 +39680,7 @@ function getLinterCommand(linter, mode, projectDir) {
39590
39680
  }
39591
39681
  function getAdditionalLinterCommand(linter, mode, cwd) {
39592
39682
  const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
39593
- const gradlew = fs12.existsSync(path22.join(cwd, gradlewName)) ? path22.join(cwd, gradlewName) : null;
39683
+ const gradlew = fs12.existsSync(path23.join(cwd, gradlewName)) ? path23.join(cwd, gradlewName) : null;
39594
39684
  switch (linter) {
39595
39685
  case "ruff":
39596
39686
  return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
@@ -39624,10 +39714,10 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
39624
39714
  }
39625
39715
  }
39626
39716
  function detectRuff(cwd) {
39627
- if (fs12.existsSync(path22.join(cwd, "ruff.toml")))
39717
+ if (fs12.existsSync(path23.join(cwd, "ruff.toml")))
39628
39718
  return isCommandAvailable("ruff");
39629
39719
  try {
39630
- const pyproject = path22.join(cwd, "pyproject.toml");
39720
+ const pyproject = path23.join(cwd, "pyproject.toml");
39631
39721
  if (fs12.existsSync(pyproject)) {
39632
39722
  const content = fs12.readFileSync(pyproject, "utf-8");
39633
39723
  if (content.includes("[tool.ruff]"))
@@ -39637,19 +39727,19 @@ function detectRuff(cwd) {
39637
39727
  return false;
39638
39728
  }
39639
39729
  function detectClippy(cwd) {
39640
- return fs12.existsSync(path22.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
39730
+ return fs12.existsSync(path23.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
39641
39731
  }
39642
39732
  function detectGolangciLint(cwd) {
39643
- return fs12.existsSync(path22.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
39733
+ return fs12.existsSync(path23.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
39644
39734
  }
39645
39735
  function detectCheckstyle(cwd) {
39646
- const hasMaven = fs12.existsSync(path22.join(cwd, "pom.xml"));
39647
- const hasGradle = fs12.existsSync(path22.join(cwd, "build.gradle")) || fs12.existsSync(path22.join(cwd, "build.gradle.kts"));
39648
- const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs12.existsSync(path22.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
39736
+ const hasMaven = fs12.existsSync(path23.join(cwd, "pom.xml"));
39737
+ const hasGradle = fs12.existsSync(path23.join(cwd, "build.gradle")) || fs12.existsSync(path23.join(cwd, "build.gradle.kts"));
39738
+ const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs12.existsSync(path23.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
39649
39739
  return (hasMaven || hasGradle) && hasBinary;
39650
39740
  }
39651
39741
  function detectKtlint(cwd) {
39652
- const hasKotlin = fs12.existsSync(path22.join(cwd, "build.gradle.kts")) || fs12.existsSync(path22.join(cwd, "build.gradle")) || (() => {
39742
+ const hasKotlin = fs12.existsSync(path23.join(cwd, "build.gradle.kts")) || fs12.existsSync(path23.join(cwd, "build.gradle")) || (() => {
39653
39743
  try {
39654
39744
  return fs12.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
39655
39745
  } catch {
@@ -39668,11 +39758,11 @@ function detectDotnetFormat(cwd) {
39668
39758
  }
39669
39759
  }
39670
39760
  function detectCppcheck(cwd) {
39671
- if (fs12.existsSync(path22.join(cwd, "CMakeLists.txt"))) {
39761
+ if (fs12.existsSync(path23.join(cwd, "CMakeLists.txt"))) {
39672
39762
  return isCommandAvailable("cppcheck");
39673
39763
  }
39674
39764
  try {
39675
- const dirsToCheck = [cwd, path22.join(cwd, "src")];
39765
+ const dirsToCheck = [cwd, path23.join(cwd, "src")];
39676
39766
  const hasCpp = dirsToCheck.some((dir) => {
39677
39767
  try {
39678
39768
  return fs12.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
@@ -39686,13 +39776,13 @@ function detectCppcheck(cwd) {
39686
39776
  }
39687
39777
  }
39688
39778
  function detectSwiftlint(cwd) {
39689
- return fs12.existsSync(path22.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
39779
+ return fs12.existsSync(path23.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
39690
39780
  }
39691
39781
  function detectDartAnalyze(cwd) {
39692
- return fs12.existsSync(path22.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
39782
+ return fs12.existsSync(path23.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
39693
39783
  }
39694
39784
  function detectRubocop(cwd) {
39695
- 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"));
39785
+ 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"));
39696
39786
  }
39697
39787
  function detectAdditionalLinter(cwd) {
39698
39788
  if (detectRuff(cwd))
@@ -39720,10 +39810,10 @@ function detectAdditionalLinter(cwd) {
39720
39810
  function findBinInAncestors(startDir, binName) {
39721
39811
  let dir = startDir;
39722
39812
  while (true) {
39723
- const candidate = path22.join(dir, "node_modules", ".bin", binName);
39813
+ const candidate = path23.join(dir, "node_modules", ".bin", binName);
39724
39814
  if (fs12.existsSync(candidate))
39725
39815
  return candidate;
39726
- const parent = path22.dirname(dir);
39816
+ const parent = path23.dirname(dir);
39727
39817
  if (parent === dir)
39728
39818
  break;
39729
39819
  dir = parent;
@@ -39732,10 +39822,10 @@ function findBinInAncestors(startDir, binName) {
39732
39822
  }
39733
39823
  function findBinInEnvPath(binName) {
39734
39824
  const searchPath = process.env.PATH ?? "";
39735
- for (const dir of searchPath.split(path22.delimiter)) {
39825
+ for (const dir of searchPath.split(path23.delimiter)) {
39736
39826
  if (!dir)
39737
39827
  continue;
39738
- const candidate = path22.join(dir, binName);
39828
+ const candidate = path23.join(dir, binName);
39739
39829
  if (fs12.existsSync(candidate))
39740
39830
  return candidate;
39741
39831
  }
@@ -39748,13 +39838,13 @@ async function detectAvailableLinter(directory) {
39748
39838
  return null;
39749
39839
  const projectDir = directory;
39750
39840
  const isWindows = process.platform === "win32";
39751
- const biomeBin = isWindows ? path22.join(projectDir, "node_modules", ".bin", "biome.EXE") : path22.join(projectDir, "node_modules", ".bin", "biome");
39752
- const eslintBin = isWindows ? path22.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path22.join(projectDir, "node_modules", ".bin", "eslint");
39841
+ const biomeBin = isWindows ? path23.join(projectDir, "node_modules", ".bin", "biome.EXE") : path23.join(projectDir, "node_modules", ".bin", "biome");
39842
+ const eslintBin = isWindows ? path23.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path23.join(projectDir, "node_modules", ".bin", "eslint");
39753
39843
  const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
39754
39844
  if (localResult)
39755
39845
  return localResult;
39756
- const biomeAncestor = findBinInAncestors(path22.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
39757
- const eslintAncestor = findBinInAncestors(path22.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
39846
+ const biomeAncestor = findBinInAncestors(path23.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
39847
+ const eslintAncestor = findBinInAncestors(path23.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
39758
39848
  if (biomeAncestor || eslintAncestor) {
39759
39849
  return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
39760
39850
  }
@@ -39916,7 +40006,7 @@ async function runAdditionalLint(linter, mode, cwd) {
39916
40006
  var lint = createSwarmTool({
39917
40007
  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.",
39918
40008
  args: {
39919
- mode: tool.schema.enum(["fix", "check"]).describe('Linting mode: "check" for read-only lint check, "fix" to automatically apply fixes')
40009
+ mode: exports_external.enum(["fix", "check"]).describe('Linting mode: "check" for read-only lint check, "fix" to automatically apply fixes')
39920
40010
  },
39921
40011
  async execute(args, directory) {
39922
40012
  if (!validateArgs(args)) {
@@ -39961,8 +40051,9 @@ For Rust: rustup component add clippy`
39961
40051
  });
39962
40052
 
39963
40053
  // src/tools/secretscan.ts
40054
+ init_zod();
39964
40055
  import * as fs13 from "fs";
39965
- import * as path23 from "path";
40056
+ import * as path24 from "path";
39966
40057
  var MAX_FILE_PATH_LENGTH = 500;
39967
40058
  var MAX_FILE_SIZE_BYTES = 512 * 1024;
39968
40059
  var MAX_FILES_SCANNED = 1000;
@@ -40189,7 +40280,7 @@ function isGlobOrPathPattern(pattern) {
40189
40280
  return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
40190
40281
  }
40191
40282
  function loadSecretScanIgnore(scanDir) {
40192
- const ignorePath = path23.join(scanDir, ".secretscanignore");
40283
+ const ignorePath = path24.join(scanDir, ".secretscanignore");
40193
40284
  try {
40194
40285
  if (!fs13.existsSync(ignorePath))
40195
40286
  return [];
@@ -40212,7 +40303,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
40212
40303
  if (exactNames.has(entry))
40213
40304
  return true;
40214
40305
  for (const pattern of globPatterns) {
40215
- if (path23.matchesGlob(relPath, pattern))
40306
+ if (path24.matchesGlob(relPath, pattern))
40216
40307
  return true;
40217
40308
  }
40218
40309
  return false;
@@ -40233,7 +40324,7 @@ function validateDirectoryInput(dir) {
40233
40324
  return null;
40234
40325
  }
40235
40326
  function isBinaryFile(filePath, buffer) {
40236
- const ext = path23.extname(filePath).toLowerCase();
40327
+ const ext = path24.extname(filePath).toLowerCase();
40237
40328
  if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
40238
40329
  return true;
40239
40330
  }
@@ -40370,9 +40461,9 @@ function isSymlinkLoop(realPath, visited) {
40370
40461
  return false;
40371
40462
  }
40372
40463
  function isPathWithinScope(realPath, scanDir) {
40373
- const resolvedScanDir = path23.resolve(scanDir);
40374
- const resolvedRealPath = path23.resolve(realPath);
40375
- return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path23.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
40464
+ const resolvedScanDir = path24.resolve(scanDir);
40465
+ const resolvedRealPath = path24.resolve(realPath);
40466
+ return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path24.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
40376
40467
  }
40377
40468
  function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
40378
40469
  skippedDirs: 0,
@@ -40398,8 +40489,8 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
40398
40489
  return a.localeCompare(b);
40399
40490
  });
40400
40491
  for (const entry of entries) {
40401
- const fullPath = path23.join(dir, entry);
40402
- const relPath = path23.relative(scanDir, fullPath).replace(/\\/g, "/");
40492
+ const fullPath = path24.join(dir, entry);
40493
+ const relPath = path24.relative(scanDir, fullPath).replace(/\\/g, "/");
40403
40494
  if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
40404
40495
  stats.skippedDirs++;
40405
40496
  continue;
@@ -40434,7 +40525,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
40434
40525
  const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
40435
40526
  files.push(...subFiles);
40436
40527
  } else if (lstat.isFile()) {
40437
- const ext = path23.extname(fullPath).toLowerCase();
40528
+ const ext = path24.extname(fullPath).toLowerCase();
40438
40529
  if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
40439
40530
  files.push(fullPath);
40440
40531
  } else {
@@ -40447,8 +40538,8 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
40447
40538
  var secretscan = createSwarmTool({
40448
40539
  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.",
40449
40540
  args: {
40450
- directory: tool.schema.string().describe('Directory to scan for secrets (e.g., "." or "./src")'),
40451
- 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.")
40541
+ directory: exports_external.string().describe('Directory to scan for secrets (e.g., "." or "./src")'),
40542
+ 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.")
40452
40543
  },
40453
40544
  async execute(args, _directory, _ctx) {
40454
40545
  const typedArgs = args;
@@ -40500,7 +40591,7 @@ var secretscan = createSwarmTool({
40500
40591
  }
40501
40592
  }
40502
40593
  try {
40503
- const _scanDirRaw = path23.resolve(directory);
40594
+ const _scanDirRaw = path24.resolve(directory);
40504
40595
  const scanDir = (() => {
40505
40596
  try {
40506
40597
  return fs13.realpathSync(_scanDirRaw);
@@ -40642,7 +40733,8 @@ var secretscan = createSwarmTool({
40642
40733
  async function runSecretscan(directory) {
40643
40734
  try {
40644
40735
  const result = await secretscan.execute({ directory }, {});
40645
- return JSON.parse(result);
40736
+ const jsonStr = typeof result === "string" ? result : result.output;
40737
+ return JSON.parse(jsonStr);
40646
40738
  } catch (e) {
40647
40739
  const errorResult = {
40648
40740
  error: e instanceof Error ? `scan failed: ${e.message}` : "scan failed: unknown error",
@@ -40657,12 +40749,13 @@ async function runSecretscan(directory) {
40657
40749
  }
40658
40750
 
40659
40751
  // src/tools/test-runner.ts
40752
+ init_zod();
40660
40753
  import * as fs17 from "fs";
40661
- import * as path27 from "path";
40754
+ import * as path28 from "path";
40662
40755
 
40663
40756
  // src/test-impact/analyzer.ts
40664
40757
  import fs14 from "fs";
40665
- import path24 from "path";
40758
+ import path25 from "path";
40666
40759
  var IMPORT_REGEX_ES = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
40667
40760
  var IMPORT_REGEX_REQUIRE = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
40668
40761
  var IMPORT_REGEX_REEXPORT = /export\s+(?:\{[^}]*\}|\*)\s+from\s+['"]([^'"]+)['"]/g;
@@ -40687,8 +40780,8 @@ function resolveRelativeImport(fromDir, importPath) {
40687
40780
  if (!importPath.startsWith(".")) {
40688
40781
  return null;
40689
40782
  }
40690
- const resolved = path24.resolve(fromDir, importPath);
40691
- if (path24.extname(resolved)) {
40783
+ const resolved = path25.resolve(fromDir, importPath);
40784
+ if (path25.extname(resolved)) {
40692
40785
  if (fs14.existsSync(resolved) && fs14.statSync(resolved).isFile()) {
40693
40786
  return normalizePath(resolved);
40694
40787
  }
@@ -40733,12 +40826,12 @@ function findTestFilesSync(cwd) {
40733
40826
  for (const entry of entries) {
40734
40827
  if (entry.isDirectory()) {
40735
40828
  if (!skipDirs.has(entry.name)) {
40736
- walk(path24.join(dir, entry.name), visitedInodes);
40829
+ walk(path25.join(dir, entry.name), visitedInodes);
40737
40830
  }
40738
40831
  } else if (entry.isFile()) {
40739
40832
  const name = entry.name;
40740
40833
  if (/\.(test|spec)\.(ts|tsx|js|jsx)$/.test(name) || dir.includes("__tests__") && /\.(ts|tsx|js|jsx)$/.test(name)) {
40741
- testFiles.push(normalizePath(path24.join(dir, entry.name)));
40834
+ testFiles.push(normalizePath(path25.join(dir, entry.name)));
40742
40835
  }
40743
40836
  }
40744
40837
  }
@@ -40776,7 +40869,7 @@ async function buildImpactMapInternal(cwd) {
40776
40869
  continue;
40777
40870
  }
40778
40871
  const imports = extractImports(content);
40779
- const testDir = path24.dirname(testFile);
40872
+ const testDir = path25.dirname(testFile);
40780
40873
  for (const importPath of imports) {
40781
40874
  const resolvedSource = resolveRelativeImport(testDir, importPath);
40782
40875
  if (resolvedSource === null) {
@@ -40798,7 +40891,7 @@ async function buildImpactMap(cwd) {
40798
40891
  return impactMap;
40799
40892
  }
40800
40893
  async function loadImpactMap(cwd) {
40801
- const cachePath = path24.join(cwd, ".swarm", "cache", "impact-map.json");
40894
+ const cachePath = path25.join(cwd, ".swarm", "cache", "impact-map.json");
40802
40895
  if (fs14.existsSync(cachePath)) {
40803
40896
  try {
40804
40897
  const content = fs14.readFileSync(cachePath, "utf-8");
@@ -40813,8 +40906,8 @@ async function loadImpactMap(cwd) {
40813
40906
  return buildImpactMap(cwd);
40814
40907
  }
40815
40908
  async function saveImpactMap(cwd, impactMap) {
40816
- const cacheDir = path24.join(cwd, ".swarm", "cache");
40817
- const cachePath = path24.join(cacheDir, "impact-map.json");
40909
+ const cacheDir = path25.join(cwd, ".swarm", "cache");
40910
+ const cachePath = path25.join(cacheDir, "impact-map.json");
40818
40911
  if (!fs14.existsSync(cacheDir)) {
40819
40912
  fs14.mkdirSync(cacheDir, { recursive: true });
40820
40913
  }
@@ -40840,7 +40933,7 @@ async function analyzeImpact(changedFiles, cwd) {
40840
40933
  const impactedTestsSet = new Set;
40841
40934
  const untestedFiles = [];
40842
40935
  for (const changedFile of validFiles) {
40843
- const normalizedChanged = normalizePath(path24.resolve(changedFile));
40936
+ const normalizedChanged = normalizePath(path25.resolve(changedFile));
40844
40937
  const tests = impactMap[normalizedChanged];
40845
40938
  if (tests && tests.length > 0) {
40846
40939
  for (const test of tests) {
@@ -41087,13 +41180,13 @@ function detectFlakyTests(allHistory) {
41087
41180
 
41088
41181
  // src/test-impact/history-store.ts
41089
41182
  import fs15 from "fs";
41090
- import path25 from "path";
41183
+ import path26 from "path";
41091
41184
  var MAX_HISTORY_PER_TEST = 20;
41092
41185
  var MAX_ERROR_LENGTH = 500;
41093
41186
  var MAX_STACK_LENGTH = 200;
41094
41187
  var MAX_CHANGED_FILES = 50;
41095
41188
  function getHistoryPath(workingDir) {
41096
- return path25.join(workingDir || process.cwd(), ".swarm", "cache", "test-history.jsonl");
41189
+ return path26.join(workingDir || process.cwd(), ".swarm", "cache", "test-history.jsonl");
41097
41190
  }
41098
41191
  function sanitizeErrorMessage(errorMessage) {
41099
41192
  if (errorMessage === undefined) {
@@ -41153,7 +41246,7 @@ function appendTestRun(record3, workingDir) {
41153
41246
  changedFiles: sanitizeChangedFiles(record3.changedFiles || [])
41154
41247
  };
41155
41248
  const historyPath = getHistoryPath(workingDir);
41156
- const historyDir = path25.dirname(historyPath);
41249
+ const historyDir = path26.dirname(historyPath);
41157
41250
  if (!fs15.existsSync(historyDir)) {
41158
41251
  fs15.mkdirSync(historyDir, { recursive: true });
41159
41252
  }
@@ -41227,7 +41320,7 @@ function getAllHistory(workingDir) {
41227
41320
 
41228
41321
  // src/tools/resolve-working-directory.ts
41229
41322
  import * as fs16 from "fs";
41230
- import * as path26 from "path";
41323
+ import * as path27 from "path";
41231
41324
  function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
41232
41325
  if (workingDirectory == null || workingDirectory === "") {
41233
41326
  return { success: true, directory: fallbackDirectory };
@@ -41247,15 +41340,15 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
41247
41340
  };
41248
41341
  }
41249
41342
  }
41250
- const normalizedDir = path26.normalize(workingDirectory);
41251
- const pathParts = normalizedDir.split(path26.sep);
41343
+ const normalizedDir = path27.normalize(workingDirectory);
41344
+ const pathParts = normalizedDir.split(path27.sep);
41252
41345
  if (pathParts.includes("..")) {
41253
41346
  return {
41254
41347
  success: false,
41255
41348
  message: "Invalid working_directory: path traversal sequences (..) are not allowed"
41256
41349
  };
41257
41350
  }
41258
- const resolvedDir = path26.resolve(normalizedDir);
41351
+ const resolvedDir = path27.resolve(normalizedDir);
41259
41352
  let statResult;
41260
41353
  try {
41261
41354
  statResult = fs16.statSync(resolvedDir);
@@ -41271,7 +41364,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
41271
41364
  message: `Invalid working_directory: path "${resolvedDir}" is not a directory`
41272
41365
  };
41273
41366
  }
41274
- const resolvedFallback = path26.resolve(fallbackDirectory);
41367
+ const resolvedFallback = path27.resolve(fallbackDirectory);
41275
41368
  let fallbackExists = false;
41276
41369
  try {
41277
41370
  fs16.statSync(resolvedFallback);
@@ -41281,7 +41374,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
41281
41374
  }
41282
41375
  if (workingDirectory != null && workingDirectory !== "") {
41283
41376
  if (fallbackExists) {
41284
- const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path26.sep);
41377
+ const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path27.sep);
41285
41378
  if (isSubdirectory) {
41286
41379
  return {
41287
41380
  success: false,
@@ -41371,14 +41464,14 @@ function hasDevDependency(devDeps, ...patterns) {
41371
41464
  return hasPackageJsonDependency(devDeps, ...patterns);
41372
41465
  }
41373
41466
  function detectGoTest(cwd) {
41374
- return fs17.existsSync(path27.join(cwd, "go.mod")) && isCommandAvailable("go");
41467
+ return fs17.existsSync(path28.join(cwd, "go.mod")) && isCommandAvailable("go");
41375
41468
  }
41376
41469
  function detectJavaMaven(cwd) {
41377
- return fs17.existsSync(path27.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
41470
+ return fs17.existsSync(path28.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
41378
41471
  }
41379
41472
  function detectGradle(cwd) {
41380
- const hasBuildFile = fs17.existsSync(path27.join(cwd, "build.gradle")) || fs17.existsSync(path27.join(cwd, "build.gradle.kts"));
41381
- const hasGradlew = fs17.existsSync(path27.join(cwd, "gradlew")) || fs17.existsSync(path27.join(cwd, "gradlew.bat"));
41473
+ const hasBuildFile = fs17.existsSync(path28.join(cwd, "build.gradle")) || fs17.existsSync(path28.join(cwd, "build.gradle.kts"));
41474
+ const hasGradlew = fs17.existsSync(path28.join(cwd, "gradlew")) || fs17.existsSync(path28.join(cwd, "gradlew.bat"));
41382
41475
  return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
41383
41476
  }
41384
41477
  function detectDotnetTest(cwd) {
@@ -41391,30 +41484,30 @@ function detectDotnetTest(cwd) {
41391
41484
  }
41392
41485
  }
41393
41486
  function detectCTest(cwd) {
41394
- const hasSource = fs17.existsSync(path27.join(cwd, "CMakeLists.txt"));
41395
- const hasBuildCache = fs17.existsSync(path27.join(cwd, "CMakeCache.txt")) || fs17.existsSync(path27.join(cwd, "build", "CMakeCache.txt"));
41487
+ const hasSource = fs17.existsSync(path28.join(cwd, "CMakeLists.txt"));
41488
+ const hasBuildCache = fs17.existsSync(path28.join(cwd, "CMakeCache.txt")) || fs17.existsSync(path28.join(cwd, "build", "CMakeCache.txt"));
41396
41489
  return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
41397
41490
  }
41398
41491
  function detectSwiftTest(cwd) {
41399
- return fs17.existsSync(path27.join(cwd, "Package.swift")) && isCommandAvailable("swift");
41492
+ return fs17.existsSync(path28.join(cwd, "Package.swift")) && isCommandAvailable("swift");
41400
41493
  }
41401
41494
  function detectDartTest(cwd) {
41402
- return fs17.existsSync(path27.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
41495
+ return fs17.existsSync(path28.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
41403
41496
  }
41404
41497
  function detectRSpec(cwd) {
41405
- const hasRSpecFile = fs17.existsSync(path27.join(cwd, ".rspec"));
41406
- const hasGemfile = fs17.existsSync(path27.join(cwd, "Gemfile"));
41407
- const hasSpecDir = fs17.existsSync(path27.join(cwd, "spec"));
41498
+ const hasRSpecFile = fs17.existsSync(path28.join(cwd, ".rspec"));
41499
+ const hasGemfile = fs17.existsSync(path28.join(cwd, "Gemfile"));
41500
+ const hasSpecDir = fs17.existsSync(path28.join(cwd, "spec"));
41408
41501
  const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
41409
41502
  return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
41410
41503
  }
41411
41504
  function detectMinitest(cwd) {
41412
- return fs17.existsSync(path27.join(cwd, "test")) && (fs17.existsSync(path27.join(cwd, "Gemfile")) || fs17.existsSync(path27.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
41505
+ return fs17.existsSync(path28.join(cwd, "test")) && (fs17.existsSync(path28.join(cwd, "Gemfile")) || fs17.existsSync(path28.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
41413
41506
  }
41414
41507
  async function detectTestFramework(cwd) {
41415
41508
  const baseDir = cwd;
41416
41509
  try {
41417
- const packageJsonPath = path27.join(baseDir, "package.json");
41510
+ const packageJsonPath = path28.join(baseDir, "package.json");
41418
41511
  if (fs17.existsSync(packageJsonPath)) {
41419
41512
  const content = fs17.readFileSync(packageJsonPath, "utf-8");
41420
41513
  const pkg = JSON.parse(content);
@@ -41435,16 +41528,16 @@ async function detectTestFramework(cwd) {
41435
41528
  return "jest";
41436
41529
  if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
41437
41530
  return "mocha";
41438
- if (fs17.existsSync(path27.join(baseDir, "bun.lockb")) || fs17.existsSync(path27.join(baseDir, "bun.lock"))) {
41531
+ if (fs17.existsSync(path28.join(baseDir, "bun.lockb")) || fs17.existsSync(path28.join(baseDir, "bun.lock"))) {
41439
41532
  if (scripts.test?.includes("bun"))
41440
41533
  return "bun";
41441
41534
  }
41442
41535
  }
41443
41536
  } catch {}
41444
41537
  try {
41445
- const pyprojectTomlPath = path27.join(baseDir, "pyproject.toml");
41446
- const setupCfgPath = path27.join(baseDir, "setup.cfg");
41447
- const requirementsTxtPath = path27.join(baseDir, "requirements.txt");
41538
+ const pyprojectTomlPath = path28.join(baseDir, "pyproject.toml");
41539
+ const setupCfgPath = path28.join(baseDir, "setup.cfg");
41540
+ const requirementsTxtPath = path28.join(baseDir, "requirements.txt");
41448
41541
  if (fs17.existsSync(pyprojectTomlPath)) {
41449
41542
  const content = fs17.readFileSync(pyprojectTomlPath, "utf-8");
41450
41543
  if (content.includes("[tool.pytest"))
@@ -41464,7 +41557,7 @@ async function detectTestFramework(cwd) {
41464
41557
  }
41465
41558
  } catch {}
41466
41559
  try {
41467
- const cargoTomlPath = path27.join(baseDir, "Cargo.toml");
41560
+ const cargoTomlPath = path28.join(baseDir, "Cargo.toml");
41468
41561
  if (fs17.existsSync(cargoTomlPath)) {
41469
41562
  const content = fs17.readFileSync(cargoTomlPath, "utf-8");
41470
41563
  if (content.includes("[dev-dependencies]")) {
@@ -41475,9 +41568,9 @@ async function detectTestFramework(cwd) {
41475
41568
  }
41476
41569
  } catch {}
41477
41570
  try {
41478
- const pesterConfigPath = path27.join(baseDir, "pester.config.ps1");
41479
- const pesterConfigJsonPath = path27.join(baseDir, "pester.config.ps1.json");
41480
- const pesterPs1Path = path27.join(baseDir, "tests.ps1");
41571
+ const pesterConfigPath = path28.join(baseDir, "pester.config.ps1");
41572
+ const pesterConfigJsonPath = path28.join(baseDir, "pester.config.ps1.json");
41573
+ const pesterPs1Path = path28.join(baseDir, "tests.ps1");
41481
41574
  if (fs17.existsSync(pesterConfigPath) || fs17.existsSync(pesterConfigJsonPath) || fs17.existsSync(pesterPs1Path)) {
41482
41575
  return "pester";
41483
41576
  }
@@ -41520,12 +41613,12 @@ function isTestDirectoryPath(normalizedPath) {
41520
41613
  return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
41521
41614
  }
41522
41615
  function resolveWorkspacePath(file3, workingDir) {
41523
- return path27.isAbsolute(file3) ? path27.resolve(file3) : path27.resolve(workingDir, file3);
41616
+ return path28.isAbsolute(file3) ? path28.resolve(file3) : path28.resolve(workingDir, file3);
41524
41617
  }
41525
41618
  function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
41526
41619
  if (!preferRelative)
41527
41620
  return absolutePath;
41528
- return path27.relative(workingDir, absolutePath);
41621
+ return path28.relative(workingDir, absolutePath);
41529
41622
  }
41530
41623
  function dedupePush(target, value) {
41531
41624
  if (!target.includes(value)) {
@@ -41562,18 +41655,18 @@ function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
41562
41655
  }
41563
41656
  }
41564
41657
  function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
41565
- const relativeDir = path27.dirname(relativePath);
41658
+ const relativeDir = path28.dirname(relativePath);
41566
41659
  const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
41567
41660
  const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
41568
- const rootDir = path27.join(workingDir, dirName);
41569
- return nestedRelativeDir ? [rootDir, path27.join(rootDir, nestedRelativeDir)] : [rootDir];
41661
+ const rootDir = path28.join(workingDir, dirName);
41662
+ return nestedRelativeDir ? [rootDir, path28.join(rootDir, nestedRelativeDir)] : [rootDir];
41570
41663
  });
41571
41664
  const normalizedRelativePath = relativePath.replace(/\\/g, "/");
41572
41665
  if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
41573
- directories.push(path27.join(workingDir, "src/test/java", path27.dirname(normalizedRelativePath.slice("src/main/java/".length))));
41666
+ directories.push(path28.join(workingDir, "src/test/java", path28.dirname(normalizedRelativePath.slice("src/main/java/".length))));
41574
41667
  }
41575
41668
  if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
41576
- directories.push(path27.join(workingDir, "src/test/kotlin", path27.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
41669
+ directories.push(path28.join(workingDir, "src/test/kotlin", path28.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
41577
41670
  }
41578
41671
  return [...new Set(directories)];
41579
41672
  }
@@ -41601,23 +41694,23 @@ function isLanguageSpecificTestFile(basename4) {
41601
41694
  }
41602
41695
  function isConventionTestFilePath(filePath) {
41603
41696
  const normalizedPath = filePath.replace(/\\/g, "/");
41604
- const basename4 = path27.basename(filePath);
41697
+ const basename4 = path28.basename(filePath);
41605
41698
  return hasCompoundTestExtension(basename4) || basename4.includes(".spec.") || basename4.includes(".test.") || isLanguageSpecificTestFile(basename4) || isTestDirectoryPath(normalizedPath);
41606
41699
  }
41607
41700
  function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
41608
41701
  const testFiles = [];
41609
41702
  for (const file3 of sourceFiles) {
41610
41703
  const absoluteFile = resolveWorkspacePath(file3, workingDir);
41611
- const relativeFile = path27.relative(workingDir, absoluteFile);
41612
- const basename4 = path27.basename(absoluteFile);
41613
- const dirname11 = path27.dirname(absoluteFile);
41614
- const preferRelativeOutput = !path27.isAbsolute(file3);
41704
+ const relativeFile = path28.relative(workingDir, absoluteFile);
41705
+ const basename4 = path28.basename(absoluteFile);
41706
+ const dirname11 = path28.dirname(absoluteFile);
41707
+ const preferRelativeOutput = !path28.isAbsolute(file3);
41615
41708
  if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file3)) {
41616
41709
  dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
41617
41710
  continue;
41618
41711
  }
41619
41712
  const nameWithoutExt = basename4.replace(/\.[^.]+$/, "");
41620
- const ext = path27.extname(basename4);
41713
+ const ext = path28.extname(basename4);
41621
41714
  const genericTestNames = [
41622
41715
  `${nameWithoutExt}.spec${ext}`,
41623
41716
  `${nameWithoutExt}.test${ext}`
@@ -41626,7 +41719,7 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
41626
41719
  const colocatedCandidates = [
41627
41720
  ...genericTestNames,
41628
41721
  ...languageSpecificTestNames
41629
- ].map((candidateName) => path27.join(dirname11, candidateName));
41722
+ ].map((candidateName) => path28.join(dirname11, candidateName));
41630
41723
  const testDirectoryNames = [
41631
41724
  basename4,
41632
41725
  ...genericTestNames,
@@ -41635,8 +41728,8 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
41635
41728
  const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
41636
41729
  const possibleTestFiles = [
41637
41730
  ...colocatedCandidates,
41638
- ...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path27.join(dirname11, dirName, candidateName))),
41639
- ...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path27.join(candidateDir, candidateName)))
41731
+ ...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path28.join(dirname11, dirName, candidateName))),
41732
+ ...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path28.join(candidateDir, candidateName)))
41640
41733
  ];
41641
41734
  for (const testFile of possibleTestFiles) {
41642
41735
  if (fs17.existsSync(testFile)) {
@@ -41657,7 +41750,7 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
41657
41750
  try {
41658
41751
  const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
41659
41752
  const content = fs17.readFileSync(absoluteTestFile, "utf-8");
41660
- const testDir = path27.dirname(absoluteTestFile);
41753
+ const testDir = path28.dirname(absoluteTestFile);
41661
41754
  const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
41662
41755
  let match;
41663
41756
  match = importRegex.exec(content);
@@ -41665,8 +41758,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
41665
41758
  const importPath = match[1];
41666
41759
  let resolvedImport;
41667
41760
  if (importPath.startsWith(".")) {
41668
- resolvedImport = path27.resolve(testDir, importPath);
41669
- const existingExt = path27.extname(resolvedImport);
41761
+ resolvedImport = path28.resolve(testDir, importPath);
41762
+ const existingExt = path28.extname(resolvedImport);
41670
41763
  if (!existingExt) {
41671
41764
  for (const extToTry of [
41672
41765
  ".ts",
@@ -41686,12 +41779,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
41686
41779
  } else {
41687
41780
  continue;
41688
41781
  }
41689
- const importBasename = path27.basename(resolvedImport, path27.extname(resolvedImport));
41690
- const importDir = path27.dirname(resolvedImport);
41782
+ const importBasename = path28.basename(resolvedImport, path28.extname(resolvedImport));
41783
+ const importDir = path28.dirname(resolvedImport);
41691
41784
  for (const sourceFile of absoluteSourceFiles) {
41692
- const sourceDir = path27.dirname(sourceFile);
41693
- const sourceBasename = path27.basename(sourceFile, path27.extname(sourceFile));
41694
- const isRelatedDir = importDir === sourceDir || importDir === path27.join(sourceDir, "__tests__") || importDir === path27.join(sourceDir, "tests") || importDir === path27.join(sourceDir, "test") || importDir === path27.join(sourceDir, "spec");
41785
+ const sourceDir = path28.dirname(sourceFile);
41786
+ const sourceBasename = path28.basename(sourceFile, path28.extname(sourceFile));
41787
+ const isRelatedDir = importDir === sourceDir || importDir === path28.join(sourceDir, "__tests__") || importDir === path28.join(sourceDir, "tests") || importDir === path28.join(sourceDir, "test") || importDir === path28.join(sourceDir, "spec");
41695
41788
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
41696
41789
  dedupePush(testFiles, testFile);
41697
41790
  break;
@@ -41704,8 +41797,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
41704
41797
  while (match !== null) {
41705
41798
  const importPath = match[1];
41706
41799
  if (importPath.startsWith(".")) {
41707
- let resolvedImport = path27.resolve(testDir, importPath);
41708
- const existingExt = path27.extname(resolvedImport);
41800
+ let resolvedImport = path28.resolve(testDir, importPath);
41801
+ const existingExt = path28.extname(resolvedImport);
41709
41802
  if (!existingExt) {
41710
41803
  for (const extToTry of [
41711
41804
  ".ts",
@@ -41722,12 +41815,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
41722
41815
  }
41723
41816
  }
41724
41817
  }
41725
- const importDir = path27.dirname(resolvedImport);
41726
- const importBasename = path27.basename(resolvedImport, path27.extname(resolvedImport));
41818
+ const importDir = path28.dirname(resolvedImport);
41819
+ const importBasename = path28.basename(resolvedImport, path28.extname(resolvedImport));
41727
41820
  for (const sourceFile of absoluteSourceFiles) {
41728
- const sourceDir = path27.dirname(sourceFile);
41729
- const sourceBasename = path27.basename(sourceFile, path27.extname(sourceFile));
41730
- const isRelatedDir = importDir === sourceDir || importDir === path27.join(sourceDir, "__tests__") || importDir === path27.join(sourceDir, "tests") || importDir === path27.join(sourceDir, "test") || importDir === path27.join(sourceDir, "spec");
41821
+ const sourceDir = path28.dirname(sourceFile);
41822
+ const sourceBasename = path28.basename(sourceFile, path28.extname(sourceFile));
41823
+ const isRelatedDir = importDir === sourceDir || importDir === path28.join(sourceDir, "__tests__") || importDir === path28.join(sourceDir, "tests") || importDir === path28.join(sourceDir, "test") || importDir === path28.join(sourceDir, "spec");
41731
41824
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
41732
41825
  dedupePush(testFiles, testFile);
41733
41826
  break;
@@ -41830,8 +41923,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
41830
41923
  return ["mvn", "test"];
41831
41924
  case "gradle": {
41832
41925
  const isWindows = process.platform === "win32";
41833
- const hasGradlewBat = fs17.existsSync(path27.join(baseDir, "gradlew.bat"));
41834
- const hasGradlew = fs17.existsSync(path27.join(baseDir, "gradlew"));
41926
+ const hasGradlewBat = fs17.existsSync(path28.join(baseDir, "gradlew.bat"));
41927
+ const hasGradlew = fs17.existsSync(path28.join(baseDir, "gradlew"));
41835
41928
  if (hasGradlewBat && isWindows)
41836
41929
  return ["gradlew.bat", "test"];
41837
41930
  if (hasGradlew)
@@ -41848,7 +41941,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
41848
41941
  "cmake-build-release",
41849
41942
  "out"
41850
41943
  ];
41851
- const actualBuildDir = buildDirCandidates.find((d) => fs17.existsSync(path27.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
41944
+ const actualBuildDir = buildDirCandidates.find((d) => fs17.existsSync(path28.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
41852
41945
  return ["ctest", "--test-dir", actualBuildDir];
41853
41946
  }
41854
41947
  case "swift-test":
@@ -42346,12 +42439,12 @@ function analyzeFailures(workingDir) {
42346
42439
  var test_runner = createSwarmTool({
42347
42440
  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.',
42348
42441
  args: {
42349
- 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'),
42350
- 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.'),
42351
- coverage: tool.schema.boolean().optional().describe("Enable coverage reporting if supported"),
42352
- timeout_ms: tool.schema.number().optional().describe("Timeout in milliseconds (default 60000, max 300000)"),
42353
- allow_full_suite: tool.schema.boolean().optional().describe('Explicit opt-in for scope "all". Required because full-suite output can destabilize SSE streaming.'),
42354
- 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.")
42442
+ 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'),
42443
+ 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.'),
42444
+ coverage: exports_external.boolean().optional().describe("Enable coverage reporting if supported"),
42445
+ timeout_ms: exports_external.number().optional().describe("Timeout in milliseconds (default 60000, max 300000)"),
42446
+ allow_full_suite: exports_external.boolean().optional().describe('Explicit opt-in for scope "all". Required because full-suite output can destabilize SSE streaming.'),
42447
+ 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.")
42355
42448
  },
42356
42449
  async execute(args, directory) {
42357
42450
  let workingDirInput;
@@ -42476,7 +42569,7 @@ var test_runner = createSwarmTool({
42476
42569
  const sourceFiles = args.files.filter((file3) => {
42477
42570
  if (directTestFiles.includes(file3))
42478
42571
  return false;
42479
- const ext = path27.extname(file3).toLowerCase();
42572
+ const ext = path28.extname(file3).toLowerCase();
42480
42573
  return SOURCE_EXTENSIONS.has(ext);
42481
42574
  });
42482
42575
  const invalidFiles = args.files.filter((file3) => !directTestFiles.includes(file3) && !sourceFiles.includes(file3));
@@ -42511,7 +42604,7 @@ var test_runner = createSwarmTool({
42511
42604
  if (isConventionTestFilePath(f)) {
42512
42605
  return false;
42513
42606
  }
42514
- const ext = path27.extname(f).toLowerCase();
42607
+ const ext = path28.extname(f).toLowerCase();
42515
42608
  return SOURCE_EXTENSIONS.has(ext);
42516
42609
  });
42517
42610
  if (sourceFiles.length === 0) {
@@ -42538,7 +42631,7 @@ var test_runner = createSwarmTool({
42538
42631
  if (isConventionTestFilePath(f)) {
42539
42632
  return false;
42540
42633
  }
42541
- const ext = path27.extname(f).toLowerCase();
42634
+ const ext = path28.extname(f).toLowerCase();
42542
42635
  return SOURCE_EXTENSIONS.has(ext);
42543
42636
  });
42544
42637
  if (sourceFiles.length === 0) {
@@ -42556,8 +42649,8 @@ var test_runner = createSwarmTool({
42556
42649
  const impactResult = await analyzeImpact(sourceFiles, workingDir);
42557
42650
  if (impactResult.impactedTests.length > 0) {
42558
42651
  testFiles = impactResult.impactedTests.map((absPath) => {
42559
- const relativePath = path27.relative(workingDir, absPath);
42560
- return path27.isAbsolute(relativePath) ? absPath : relativePath;
42652
+ const relativePath = path28.relative(workingDir, absPath);
42653
+ return path28.isAbsolute(relativePath) ? absPath : relativePath;
42561
42654
  });
42562
42655
  } else {
42563
42656
  graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
@@ -42650,8 +42743,8 @@ function validateDirectoryPath(dir) {
42650
42743
  if (dir.includes("..")) {
42651
42744
  throw new Error("Directory path must not contain path traversal sequences");
42652
42745
  }
42653
- const normalized = path28.normalize(dir);
42654
- const absolutePath = path28.isAbsolute(normalized) ? normalized : path28.resolve(normalized);
42746
+ const normalized = path29.normalize(dir);
42747
+ const absolutePath = path29.isAbsolute(normalized) ? normalized : path29.resolve(normalized);
42655
42748
  return absolutePath;
42656
42749
  }
42657
42750
  function validateTimeout(timeoutMs, defaultValue) {
@@ -42674,7 +42767,7 @@ function validateTimeout(timeoutMs, defaultValue) {
42674
42767
  }
42675
42768
  function getPackageVersion(dir) {
42676
42769
  try {
42677
- const packagePath = path28.join(dir, "package.json");
42770
+ const packagePath = path29.join(dir, "package.json");
42678
42771
  if (fs18.existsSync(packagePath)) {
42679
42772
  const content = fs18.readFileSync(packagePath, "utf-8");
42680
42773
  const pkg = JSON.parse(content);
@@ -42685,7 +42778,7 @@ function getPackageVersion(dir) {
42685
42778
  }
42686
42779
  function getChangelogVersion(dir) {
42687
42780
  try {
42688
- const changelogPath = path28.join(dir, "CHANGELOG.md");
42781
+ const changelogPath = path29.join(dir, "CHANGELOG.md");
42689
42782
  if (fs18.existsSync(changelogPath)) {
42690
42783
  const content = fs18.readFileSync(changelogPath, "utf-8");
42691
42784
  const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
@@ -42699,7 +42792,7 @@ function getChangelogVersion(dir) {
42699
42792
  function getVersionFileVersion(dir) {
42700
42793
  const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
42701
42794
  for (const file3 of possibleFiles) {
42702
- const filePath = path28.join(dir, file3);
42795
+ const filePath = path29.join(dir, file3);
42703
42796
  if (fs18.existsSync(filePath)) {
42704
42797
  try {
42705
42798
  const content = fs18.readFileSync(filePath, "utf-8").trim();
@@ -43026,7 +43119,7 @@ async function runEvidenceCheck(dir) {
43026
43119
  async function runRequirementCoverageCheck(dir, currentPhase) {
43027
43120
  const startTime = Date.now();
43028
43121
  try {
43029
- const specPath = path28.join(dir, ".swarm", "spec.md");
43122
+ const specPath = path29.join(dir, ".swarm", "spec.md");
43030
43123
  if (!fs18.existsSync(specPath)) {
43031
43124
  return {
43032
43125
  type: "req_coverage",
@@ -43239,144 +43332,6 @@ async function handlePreflightCommand(directory, _args) {
43239
43332
  const report = await runPreflight(directory, phase);
43240
43333
  return formatPreflightMarkdown(report);
43241
43334
  }
43242
- // src/knowledge/hive-promoter.ts
43243
- import * as fs19 from "fs";
43244
- import * as os6 from "os";
43245
- import * as path29 from "path";
43246
- var DANGEROUS_PATTERNS = [
43247
- [/rm\s+-rf/, "rm\\s+-rf"],
43248
- [/:\s*!\s*\|/, ":\\s*!\\s*\\|"],
43249
- [/\|\s*sh\b/, "\\|\\s*sh\\b"],
43250
- [/`[^`]*`/, "`[^`]*`"],
43251
- [/\$\(/, "\\$\\("],
43252
- [/;\s*rm\s+\//, ";\\s*rm\\s+\\/"],
43253
- [/>\s*\/dev\//, ">\\s*\\/dev\\/"],
43254
- [/\bmkfs\b/, "\\bmkfs\\b"],
43255
- [/\bdd\s+if=/, "\\bdd\\s+if="],
43256
- [/chmod\s+[0-7]*7[0-7]{2}/, "chmod\\s+[0-7]*7[0-7]\\{2\\}"],
43257
- [/\bchown\s+-R\b/, "\\bchown\\s+-R\\b"],
43258
- [/(?<!\.)\beval\s*\(/, "(?<!\\.)\\beval\\s*\\("],
43259
- [/(?<!\.)\bexec\s*\(/, "(?<!\\.)\\bexec\\s*\\("]
43260
- ];
43261
- 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/;
43262
- function validateLesson2(text) {
43263
- if (!text || !text.trim()) {
43264
- return { valid: false, reason: "Lesson text cannot be empty" };
43265
- }
43266
- for (const [pattern, patternSource] of DANGEROUS_PATTERNS) {
43267
- if (pattern.test(text)) {
43268
- return {
43269
- valid: false,
43270
- reason: `Dangerous pattern detected: ${patternSource}`
43271
- };
43272
- }
43273
- }
43274
- const trimmed = text.trim();
43275
- if (SHELL_COMMAND_START.test(trimmed)) {
43276
- const lastChar = trimmed[trimmed.length - 1];
43277
- if (![".", "!", "?", ";"].includes(lastChar)) {
43278
- return {
43279
- valid: false,
43280
- reason: "Lesson appears to contain raw shell commands"
43281
- };
43282
- }
43283
- }
43284
- return { valid: true };
43285
- }
43286
- function getHiveFilePath() {
43287
- const platform = process.platform;
43288
- const home = os6.homedir();
43289
- let dataDir;
43290
- if (platform === "win32") {
43291
- dataDir = path29.join(process.env.LOCALAPPDATA || path29.join(home, "AppData", "Local"), "opencode-swarm", "Data");
43292
- } else if (platform === "darwin") {
43293
- dataDir = path29.join(home, "Library", "Application Support", "opencode-swarm");
43294
- } else {
43295
- dataDir = path29.join(process.env.XDG_DATA_HOME || path29.join(home, ".local", "share"), "opencode-swarm");
43296
- }
43297
- return path29.join(dataDir, "hive-knowledge.jsonl");
43298
- }
43299
- async function promoteToHive(_directory, lesson, category) {
43300
- const trimmed = (lesson ?? "").trim();
43301
- if (!trimmed) {
43302
- throw new Error("Lesson text required");
43303
- }
43304
- const validation = validateLesson2(trimmed);
43305
- if (!validation.valid) {
43306
- throw new Error(`Lesson rejected by validator: ${validation.reason}`);
43307
- }
43308
- const hivePath = getHiveFilePath();
43309
- const hiveDir = path29.dirname(hivePath);
43310
- if (!fs19.existsSync(hiveDir)) {
43311
- fs19.mkdirSync(hiveDir, { recursive: true });
43312
- }
43313
- const now = new Date;
43314
- const entry = {
43315
- id: `hive-manual-${now.getTime()}`,
43316
- lesson: trimmed,
43317
- category: category || "process",
43318
- scope_tag: "global",
43319
- confidence: 1,
43320
- status: "promoted",
43321
- promotion_source: "manual",
43322
- promotedAt: now.toISOString(),
43323
- retrievalOutcomes: { applied: 0, succeededAfter: 0, failedAfter: 0 }
43324
- };
43325
- fs19.appendFileSync(hivePath, `${JSON.stringify(entry)}
43326
- `, "utf-8");
43327
- const preview = `${trimmed.slice(0, 50)}${trimmed.length > 50 ? "..." : ""}`;
43328
- return `Promoted to hive: "${preview}" (confidence: 1.0, source: manual)`;
43329
- }
43330
- async function promoteFromSwarm(directory, lessonId) {
43331
- const knowledgePath = path29.join(directory, ".swarm", "knowledge.jsonl");
43332
- const entries = [];
43333
- if (fs19.existsSync(knowledgePath)) {
43334
- const content = fs19.readFileSync(knowledgePath, "utf-8");
43335
- for (const line of content.split(`
43336
- `)) {
43337
- const t = line.trim();
43338
- if (!t)
43339
- continue;
43340
- try {
43341
- entries.push(JSON.parse(t));
43342
- } catch {}
43343
- }
43344
- }
43345
- const swarmEntry = entries.find((e) => e.id === lessonId);
43346
- if (!swarmEntry) {
43347
- throw new Error(`Lesson ${lessonId} not found in .swarm/knowledge.jsonl`);
43348
- }
43349
- const lessonText = typeof swarmEntry.lesson === "string" ? swarmEntry.lesson.trim() : "";
43350
- if (!lessonText) {
43351
- throw new Error("Lesson text required");
43352
- }
43353
- const validation = validateLesson2(lessonText);
43354
- if (!validation.valid) {
43355
- throw new Error(`Lesson rejected by validator: ${validation.reason}`);
43356
- }
43357
- const hivePath = getHiveFilePath();
43358
- const hiveDir = path29.dirname(hivePath);
43359
- if (!fs19.existsSync(hiveDir)) {
43360
- fs19.mkdirSync(hiveDir, { recursive: true });
43361
- }
43362
- const now = new Date;
43363
- const hiveEntry = {
43364
- id: `hive-manual-${now.getTime()}`,
43365
- lesson: lessonText,
43366
- category: typeof swarmEntry.category === "string" ? swarmEntry.category : "process",
43367
- scope_tag: typeof swarmEntry.scope === "string" ? swarmEntry.scope : "global",
43368
- confidence: 1,
43369
- status: "promoted",
43370
- promotion_source: "manual",
43371
- promotedAt: now.toISOString(),
43372
- retrievalOutcomes: { applied: 0, succeededAfter: 0, failedAfter: 0 }
43373
- };
43374
- fs19.appendFileSync(hivePath, `${JSON.stringify(hiveEntry)}
43375
- `, "utf-8");
43376
- const preview = `${lessonText.slice(0, 50)}${lessonText.length > 50 ? "..." : ""}`;
43377
- return `Promoted to hive: "${preview}" (confidence: 1.0, source: manual)`;
43378
- }
43379
-
43380
43335
  // src/commands/promote.ts
43381
43336
  async function handlePromoteCommand(directory, args) {
43382
43337
  let category;
@@ -43398,12 +43353,6 @@ async function handlePromoteCommand(directory, args) {
43398
43353
  if (!lessonText && !lessonId) {
43399
43354
  return `Usage: /swarm promote "<lesson text>" or /swarm promote --from-swarm <id>`;
43400
43355
  }
43401
- if (lessonText) {
43402
- const validation = validateLesson2(lessonText);
43403
- if (!validation.valid) {
43404
- return `Lesson rejected by validator: ${validation.reason}`;
43405
- }
43406
- }
43407
43356
  if (lessonId) {
43408
43357
  try {
43409
43358
  return await promoteFromSwarm(directory, lessonId);
@@ -43552,7 +43501,7 @@ async function handleQaGatesCommand(directory, args, sessionID) {
43552
43501
  }
43553
43502
 
43554
43503
  // src/commands/reset.ts
43555
- import * as fs20 from "fs";
43504
+ import * as fs19 from "fs";
43556
43505
 
43557
43506
  // src/background/manager.ts
43558
43507
  init_utils();
@@ -44253,8 +44202,8 @@ async function handleResetCommand(directory, args) {
44253
44202
  for (const filename of filesToReset) {
44254
44203
  try {
44255
44204
  const resolvedPath = validateSwarmPath(directory, filename);
44256
- if (fs20.existsSync(resolvedPath)) {
44257
- fs20.unlinkSync(resolvedPath);
44205
+ if (fs19.existsSync(resolvedPath)) {
44206
+ fs19.unlinkSync(resolvedPath);
44258
44207
  results.push(`- \u2705 Deleted ${filename}`);
44259
44208
  } else {
44260
44209
  results.push(`- \u23ED\uFE0F ${filename} not found (skipped)`);
@@ -44271,8 +44220,8 @@ async function handleResetCommand(directory, args) {
44271
44220
  }
44272
44221
  try {
44273
44222
  const summariesPath = validateSwarmPath(directory, "summaries");
44274
- if (fs20.existsSync(summariesPath)) {
44275
- fs20.rmSync(summariesPath, { recursive: true, force: true });
44223
+ if (fs19.existsSync(summariesPath)) {
44224
+ fs19.rmSync(summariesPath, { recursive: true, force: true });
44276
44225
  results.push("- \u2705 Deleted summaries/ directory");
44277
44226
  } else {
44278
44227
  results.push("- \u23ED\uFE0F summaries/ not found (skipped)");
@@ -44292,14 +44241,14 @@ async function handleResetCommand(directory, args) {
44292
44241
 
44293
44242
  // src/commands/reset-session.ts
44294
44243
  init_utils2();
44295
- import * as fs21 from "fs";
44244
+ import * as fs20 from "fs";
44296
44245
  import * as path30 from "path";
44297
44246
  async function handleResetSessionCommand(directory, _args) {
44298
44247
  const results = [];
44299
44248
  try {
44300
44249
  const statePath = validateSwarmPath(directory, "session/state.json");
44301
- if (fs21.existsSync(statePath)) {
44302
- fs21.unlinkSync(statePath);
44250
+ if (fs20.existsSync(statePath)) {
44251
+ fs20.unlinkSync(statePath);
44303
44252
  results.push("\u2705 Deleted .swarm/session/state.json");
44304
44253
  } else {
44305
44254
  results.push("\u23ED\uFE0F state.json not found (already clean)");
@@ -44309,14 +44258,14 @@ async function handleResetSessionCommand(directory, _args) {
44309
44258
  }
44310
44259
  try {
44311
44260
  const sessionDir = path30.dirname(validateSwarmPath(directory, "session/state.json"));
44312
- if (fs21.existsSync(sessionDir)) {
44313
- const files = fs21.readdirSync(sessionDir);
44261
+ if (fs20.existsSync(sessionDir)) {
44262
+ const files = fs20.readdirSync(sessionDir);
44314
44263
  const otherFiles = files.filter((f) => f !== "state.json");
44315
44264
  let deletedCount = 0;
44316
44265
  for (const file3 of otherFiles) {
44317
44266
  const filePath = path30.join(sessionDir, file3);
44318
- if (fs21.lstatSync(filePath).isFile()) {
44319
- fs21.unlinkSync(filePath);
44267
+ if (fs20.lstatSync(filePath).isFile()) {
44268
+ fs20.unlinkSync(filePath);
44320
44269
  deletedCount++;
44321
44270
  }
44322
44271
  }
@@ -44421,18 +44370,18 @@ ${error93 instanceof Error ? error93.message : String(error93)}`;
44421
44370
 
44422
44371
  // src/commands/rollback.ts
44423
44372
  init_utils2();
44424
- import * as fs22 from "fs";
44373
+ import * as fs21 from "fs";
44425
44374
  import * as path32 from "path";
44426
44375
  async function handleRollbackCommand(directory, args) {
44427
44376
  const phaseArg = args[0];
44428
44377
  if (!phaseArg) {
44429
44378
  const manifestPath2 = validateSwarmPath(directory, "checkpoints/manifest.json");
44430
- if (!fs22.existsSync(manifestPath2)) {
44379
+ if (!fs21.existsSync(manifestPath2)) {
44431
44380
  return "No checkpoints found. Use `/swarm checkpoint` to create checkpoints.";
44432
44381
  }
44433
44382
  let manifest2;
44434
44383
  try {
44435
- manifest2 = JSON.parse(fs22.readFileSync(manifestPath2, "utf-8"));
44384
+ manifest2 = JSON.parse(fs21.readFileSync(manifestPath2, "utf-8"));
44436
44385
  } catch {
44437
44386
  return "Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.";
44438
44387
  }
@@ -44454,12 +44403,12 @@ async function handleRollbackCommand(directory, args) {
44454
44403
  return "Error: Phase number must be a positive integer.";
44455
44404
  }
44456
44405
  const manifestPath = validateSwarmPath(directory, "checkpoints/manifest.json");
44457
- if (!fs22.existsSync(manifestPath)) {
44406
+ if (!fs21.existsSync(manifestPath)) {
44458
44407
  return `Error: No checkpoints found. Cannot rollback to phase ${targetPhase}.`;
44459
44408
  }
44460
44409
  let manifest;
44461
44410
  try {
44462
- manifest = JSON.parse(fs22.readFileSync(manifestPath, "utf-8"));
44411
+ manifest = JSON.parse(fs21.readFileSync(manifestPath, "utf-8"));
44463
44412
  } catch {
44464
44413
  return `Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.`;
44465
44414
  }
@@ -44469,10 +44418,10 @@ async function handleRollbackCommand(directory, args) {
44469
44418
  return `Error: Checkpoint for phase ${targetPhase} not found. Available phases: ${available}`;
44470
44419
  }
44471
44420
  const checkpointDir = validateSwarmPath(directory, `checkpoints/phase-${targetPhase}`);
44472
- if (!fs22.existsSync(checkpointDir)) {
44421
+ if (!fs21.existsSync(checkpointDir)) {
44473
44422
  return `Error: Checkpoint directory for phase ${targetPhase} does not exist.`;
44474
44423
  }
44475
- const checkpointFiles = fs22.readdirSync(checkpointDir);
44424
+ const checkpointFiles = fs21.readdirSync(checkpointDir);
44476
44425
  if (checkpointFiles.length === 0) {
44477
44426
  return `Error: Checkpoint for phase ${targetPhase} is empty. Cannot rollback.`;
44478
44427
  }
@@ -44483,7 +44432,7 @@ async function handleRollbackCommand(directory, args) {
44483
44432
  const src = path32.join(checkpointDir, file3);
44484
44433
  const dest = path32.join(swarmDir, file3);
44485
44434
  try {
44486
- fs22.cpSync(src, dest, { recursive: true, force: true });
44435
+ fs21.cpSync(src, dest, { recursive: true, force: true });
44487
44436
  successes.push(file3);
44488
44437
  } catch (error93) {
44489
44438
  failures.push({ file: file3, error: error93.message });
@@ -44500,7 +44449,7 @@ async function handleRollbackCommand(directory, args) {
44500
44449
  timestamp: new Date().toISOString()
44501
44450
  };
44502
44451
  try {
44503
- fs22.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
44452
+ fs21.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
44504
44453
  `);
44505
44454
  } catch (error93) {
44506
44455
  console.error("Failed to write rollback event:", error93 instanceof Error ? error93.message : String(error93));
@@ -44543,11 +44492,11 @@ async function handleSimulateCommand(directory, args) {
44543
44492
  ];
44544
44493
  const report = reportLines.filter(Boolean).join(`
44545
44494
  `);
44546
- const fs23 = await import("fs/promises");
44495
+ const fs22 = await import("fs/promises");
44547
44496
  const path33 = await import("path");
44548
44497
  const reportPath = path33.join(directory, ".swarm", "simulate-report.md");
44549
- await fs23.mkdir(path33.dirname(reportPath), { recursive: true });
44550
- await fs23.writeFile(reportPath, report, "utf-8");
44498
+ await fs22.mkdir(path33.dirname(reportPath), { recursive: true });
44499
+ await fs22.writeFile(reportPath, report, "utf-8");
44551
44500
  return `${darkMatterPairs.length} hidden coupling pairs detected`;
44552
44501
  }
44553
44502
 
@@ -45080,19 +45029,19 @@ function resolveCommand(tokens) {
45080
45029
  }
45081
45030
 
45082
45031
  // src/cli/index.ts
45083
- var CONFIG_DIR = path33.join(process.env.XDG_CONFIG_HOME || path33.join(os7.homedir(), ".config"), "opencode");
45032
+ var CONFIG_DIR = path33.join(process.env.XDG_CONFIG_HOME || path33.join(os6.homedir(), ".config"), "opencode");
45084
45033
  var OPENCODE_CONFIG_PATH = path33.join(CONFIG_DIR, "opencode.json");
45085
45034
  var PLUGIN_CONFIG_PATH = path33.join(CONFIG_DIR, "opencode-swarm.json");
45086
45035
  var PROMPTS_DIR = path33.join(CONFIG_DIR, "opencode-swarm");
45087
- var OPENCODE_PLUGIN_CACHE_PATH = path33.join(process.env.XDG_CACHE_HOME || path33.join(os7.homedir(), ".cache"), "opencode", "packages", "opencode-swarm@latest");
45036
+ var OPENCODE_PLUGIN_CACHE_PATH = path33.join(process.env.XDG_CACHE_HOME || path33.join(os6.homedir(), ".cache"), "opencode", "packages", "opencode-swarm@latest");
45088
45037
  function ensureDir(dir) {
45089
- if (!fs23.existsSync(dir)) {
45090
- fs23.mkdirSync(dir, { recursive: true });
45038
+ if (!fs22.existsSync(dir)) {
45039
+ fs22.mkdirSync(dir, { recursive: true });
45091
45040
  }
45092
45041
  }
45093
45042
  function loadJson(filepath) {
45094
45043
  try {
45095
- const content = fs23.readFileSync(filepath, "utf-8");
45044
+ const content = fs22.readFileSync(filepath, "utf-8");
45096
45045
  const stripped = content.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (match, comment) => comment ? "" : match).replace(/,(\s*[}\]])/g, "$1");
45097
45046
  return JSON.parse(stripped);
45098
45047
  } catch {
@@ -45100,7 +45049,7 @@ function loadJson(filepath) {
45100
45049
  }
45101
45050
  }
45102
45051
  function saveJson(filepath, data) {
45103
- fs23.writeFileSync(filepath, `${JSON.stringify(data, null, 2)}
45052
+ fs22.writeFileSync(filepath, `${JSON.stringify(data, null, 2)}
45104
45053
  `, "utf-8");
45105
45054
  }
45106
45055
  async function install() {
@@ -45140,15 +45089,15 @@ async function install() {
45140
45089
  console.log("\u2713 Added opencode-swarm to OpenCode plugins");
45141
45090
  console.log("\u2713 Disabled default OpenCode agents (explore, general)");
45142
45091
  try {
45143
- if (fs23.existsSync(OPENCODE_PLUGIN_CACHE_PATH)) {
45144
- fs23.rmSync(OPENCODE_PLUGIN_CACHE_PATH, { recursive: true, force: true });
45092
+ if (fs22.existsSync(OPENCODE_PLUGIN_CACHE_PATH)) {
45093
+ fs22.rmSync(OPENCODE_PLUGIN_CACHE_PATH, { recursive: true, force: true });
45145
45094
  console.log("\u2713 Cleared opencode plugin cache (next start will fetch latest)");
45146
45095
  }
45147
45096
  } catch {
45148
45097
  console.warn("\u26A0 Could not clear opencode plugin cache \u2014 you may need to delete it manually:");
45149
45098
  console.warn(` ${OPENCODE_PLUGIN_CACHE_PATH}`);
45150
45099
  }
45151
- if (!fs23.existsSync(PLUGIN_CONFIG_PATH)) {
45100
+ if (!fs22.existsSync(PLUGIN_CONFIG_PATH)) {
45152
45101
  const defaultConfig = {
45153
45102
  agents: {
45154
45103
  coder: {
@@ -45251,7 +45200,7 @@ async function uninstall() {
45251
45200
  `);
45252
45201
  const opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
45253
45202
  if (!opencodeConfig) {
45254
- if (fs23.existsSync(OPENCODE_CONFIG_PATH)) {
45203
+ if (fs22.existsSync(OPENCODE_CONFIG_PATH)) {
45255
45204
  console.log(`\u2717 Could not parse opencode config at: ${OPENCODE_CONFIG_PATH}`);
45256
45205
  return 1;
45257
45206
  } else {
@@ -45283,13 +45232,13 @@ async function uninstall() {
45283
45232
  console.log("\u2713 Re-enabled default OpenCode agents (explore, general)");
45284
45233
  if (process.argv.includes("--clean")) {
45285
45234
  let cleaned = false;
45286
- if (fs23.existsSync(PLUGIN_CONFIG_PATH)) {
45287
- fs23.unlinkSync(PLUGIN_CONFIG_PATH);
45235
+ if (fs22.existsSync(PLUGIN_CONFIG_PATH)) {
45236
+ fs22.unlinkSync(PLUGIN_CONFIG_PATH);
45288
45237
  console.log(`\u2713 Removed plugin config: ${PLUGIN_CONFIG_PATH}`);
45289
45238
  cleaned = true;
45290
45239
  }
45291
- if (fs23.existsSync(PROMPTS_DIR)) {
45292
- fs23.rmSync(PROMPTS_DIR, { recursive: true });
45240
+ if (fs22.existsSync(PROMPTS_DIR)) {
45241
+ fs22.rmSync(PROMPTS_DIR, { recursive: true });
45293
45242
  console.log(`\u2713 Removed custom prompts: ${PROMPTS_DIR}`);
45294
45243
  cleaned = true;
45295
45244
  }