opencode-swarm 6.46.0 → 6.47.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -16987,13 +16987,13 @@ __export(exports_config_doctor, {
16987
16987
  import * as crypto3 from "crypto";
16988
16988
  import * as fs7 from "fs";
16989
16989
  import * as os4 from "os";
16990
- import * as path15 from "path";
16990
+ import * as path16 from "path";
16991
16991
  function getUserConfigDir3() {
16992
- return process.env.XDG_CONFIG_HOME || path15.join(os4.homedir(), ".config");
16992
+ return process.env.XDG_CONFIG_HOME || path16.join(os4.homedir(), ".config");
16993
16993
  }
16994
16994
  function getConfigPaths(directory) {
16995
- const userConfigPath = path15.join(getUserConfigDir3(), "opencode", "opencode-swarm.json");
16996
- const projectConfigPath = path15.join(directory, ".opencode", "opencode-swarm.json");
16995
+ const userConfigPath = path16.join(getUserConfigDir3(), "opencode", "opencode-swarm.json");
16996
+ const projectConfigPath = path16.join(directory, ".opencode", "opencode-swarm.json");
16997
16997
  return { userConfigPath, projectConfigPath };
16998
16998
  }
16999
16999
  function computeHash(content) {
@@ -17018,9 +17018,9 @@ function isValidConfigPath(configPath, directory) {
17018
17018
  const normalizedUser = userConfigPath.replace(/\\/g, "/");
17019
17019
  const normalizedProject = projectConfigPath.replace(/\\/g, "/");
17020
17020
  try {
17021
- const resolvedConfig = path15.resolve(configPath);
17022
- const resolvedUser = path15.resolve(normalizedUser);
17023
- const resolvedProject = path15.resolve(normalizedProject);
17021
+ const resolvedConfig = path16.resolve(configPath);
17022
+ const resolvedUser = path16.resolve(normalizedUser);
17023
+ const resolvedProject = path16.resolve(normalizedProject);
17024
17024
  return resolvedConfig === resolvedUser || resolvedConfig === resolvedProject;
17025
17025
  } catch {
17026
17026
  return false;
@@ -17060,12 +17060,12 @@ function createConfigBackup(directory) {
17060
17060
  };
17061
17061
  }
17062
17062
  function writeBackupArtifact(directory, backup) {
17063
- const swarmDir = path15.join(directory, ".swarm");
17063
+ const swarmDir = path16.join(directory, ".swarm");
17064
17064
  if (!fs7.existsSync(swarmDir)) {
17065
17065
  fs7.mkdirSync(swarmDir, { recursive: true });
17066
17066
  }
17067
17067
  const backupFilename = `config-backup-${backup.createdAt}.json`;
17068
- const backupPath = path15.join(swarmDir, backupFilename);
17068
+ const backupPath = path16.join(swarmDir, backupFilename);
17069
17069
  const artifact = {
17070
17070
  createdAt: backup.createdAt,
17071
17071
  configPath: backup.configPath,
@@ -17095,7 +17095,7 @@ function restoreFromBackup(backupPath, directory) {
17095
17095
  return null;
17096
17096
  }
17097
17097
  const targetPath = artifact.configPath;
17098
- const targetDir = path15.dirname(targetPath);
17098
+ const targetDir = path16.dirname(targetPath);
17099
17099
  if (!fs7.existsSync(targetDir)) {
17100
17100
  fs7.mkdirSync(targetDir, { recursive: true });
17101
17101
  }
@@ -17126,9 +17126,9 @@ function readConfigFromFile(directory) {
17126
17126
  return null;
17127
17127
  }
17128
17128
  }
17129
- function validateConfigKey(path16, value, _config) {
17129
+ function validateConfigKey(path17, value, _config) {
17130
17130
  const findings = [];
17131
- switch (path16) {
17131
+ switch (path17) {
17132
17132
  case "agents": {
17133
17133
  if (value !== undefined) {
17134
17134
  findings.push({
@@ -17375,27 +17375,27 @@ function validateConfigKey(path16, value, _config) {
17375
17375
  }
17376
17376
  return findings;
17377
17377
  }
17378
- function walkConfigAndValidate(obj, path16, config3, findings) {
17378
+ function walkConfigAndValidate(obj, path17, config3, findings) {
17379
17379
  if (obj === null || obj === undefined) {
17380
17380
  return;
17381
17381
  }
17382
- if (path16 && typeof obj === "object" && !Array.isArray(obj)) {
17383
- const keyFindings = validateConfigKey(path16, obj, config3);
17382
+ if (path17 && typeof obj === "object" && !Array.isArray(obj)) {
17383
+ const keyFindings = validateConfigKey(path17, obj, config3);
17384
17384
  findings.push(...keyFindings);
17385
17385
  }
17386
17386
  if (typeof obj !== "object") {
17387
- const keyFindings = validateConfigKey(path16, obj, config3);
17387
+ const keyFindings = validateConfigKey(path17, obj, config3);
17388
17388
  findings.push(...keyFindings);
17389
17389
  return;
17390
17390
  }
17391
17391
  if (Array.isArray(obj)) {
17392
17392
  obj.forEach((item, index) => {
17393
- walkConfigAndValidate(item, `${path16}[${index}]`, config3, findings);
17393
+ walkConfigAndValidate(item, `${path17}[${index}]`, config3, findings);
17394
17394
  });
17395
17395
  return;
17396
17396
  }
17397
17397
  for (const [key, value] of Object.entries(obj)) {
17398
- const newPath = path16 ? `${path16}.${key}` : key;
17398
+ const newPath = path17 ? `${path17}.${key}` : key;
17399
17399
  walkConfigAndValidate(value, newPath, config3, findings);
17400
17400
  }
17401
17401
  }
@@ -17515,7 +17515,7 @@ function applySafeAutoFixes(directory, result) {
17515
17515
  }
17516
17516
  }
17517
17517
  if (appliedFixes.length > 0) {
17518
- const configDir = path15.dirname(configPath);
17518
+ const configDir = path16.dirname(configPath);
17519
17519
  if (!fs7.existsSync(configDir)) {
17520
17520
  fs7.mkdirSync(configDir, { recursive: true });
17521
17521
  }
@@ -17525,12 +17525,12 @@ function applySafeAutoFixes(directory, result) {
17525
17525
  return { appliedFixes, updatedConfigPath };
17526
17526
  }
17527
17527
  function writeDoctorArtifact(directory, result) {
17528
- const swarmDir = path15.join(directory, ".swarm");
17528
+ const swarmDir = path16.join(directory, ".swarm");
17529
17529
  if (!fs7.existsSync(swarmDir)) {
17530
17530
  fs7.mkdirSync(swarmDir, { recursive: true });
17531
17531
  }
17532
17532
  const artifactFilename = "config-doctor.json";
17533
- const artifactPath = path15.join(swarmDir, artifactFilename);
17533
+ const artifactPath = path16.join(swarmDir, artifactFilename);
17534
17534
  const guiOutput = {
17535
17535
  timestamp: result.timestamp,
17536
17536
  summary: result.summary,
@@ -17893,7 +17893,7 @@ var init_evidence_summary_service = __esm(() => {
17893
17893
  // src/cli/index.ts
17894
17894
  import * as fs18 from "fs";
17895
17895
  import * as os6 from "os";
17896
- import * as path27 from "path";
17896
+ import * as path28 from "path";
17897
17897
 
17898
17898
  // src/commands/agents.ts
17899
17899
  function handleAgentsCommand(agents, guardrails) {
@@ -32005,7 +32005,9 @@ async function handleClarifyCommand(_directory, args) {
32005
32005
  }
32006
32006
 
32007
32007
  // src/commands/close.ts
32008
+ import { execFileSync } from "child_process";
32008
32009
  import { promises as fs6 } from "fs";
32010
+ import path11 from "path";
32009
32011
  init_manager();
32010
32012
 
32011
32013
  // src/hooks/knowledge-store.ts
@@ -33117,87 +33119,183 @@ var write_retro = createSwarmTool({
33117
33119
  });
33118
33120
 
33119
33121
  // src/commands/close.ts
33120
- async function handleCloseCommand(directory, _args) {
33122
+ async function handleCloseCommand(directory, args) {
33121
33123
  const planPath = validateSwarmPath(directory, "plan.json");
33122
- let planData;
33124
+ let planExists = false;
33125
+ let planData = {
33126
+ title: path11.basename(directory) || "Ad-hoc session",
33127
+ phases: []
33128
+ };
33123
33129
  try {
33124
33130
  const content = await fs6.readFile(planPath, "utf-8");
33125
33131
  planData = JSON.parse(content);
33132
+ planExists = true;
33126
33133
  } catch (error93) {
33127
- return `\u274C Failed to read plan.json: ${error93 instanceof Error ? error93.message : String(error93)}`;
33134
+ if (error93?.code !== "ENOENT") {
33135
+ return `\u274C Failed to read plan.json: ${error93 instanceof Error ? error93.message : String(error93)}`;
33136
+ }
33137
+ const swarmDirExists = await fs6.access(path11.join(directory, ".swarm")).then(() => true).catch(() => false);
33138
+ if (!swarmDirExists) {
33139
+ return `\u274C No .swarm/ directory found in ${directory}. Run /swarm close from the project root, or run /swarm plan first.`;
33140
+ }
33128
33141
  }
33129
33142
  const phases = planData.phases ?? [];
33130
33143
  const inProgressPhases = phases.filter((p) => p.status === "in_progress");
33131
- const allDone = phases.every((p) => p.status === "complete" || p.status === "completed" || p.status === "blocked" || p.status === "closed");
33132
- if (allDone) {
33133
- const closedCount = phases.filter((p) => p.status === "closed").length;
33134
- const blockedCount = phases.filter((p) => p.status === "blocked").length;
33135
- const completeCount = phases.filter((p) => p.status === "complete" || p.status === "completed").length;
33136
- return `\u2139\uFE0F Swarm already closed. ${completeCount} phases complete, ${closedCount} phases closed, ${blockedCount} phases blocked. No action taken.`;
33144
+ let planAlreadyDone = false;
33145
+ if (planExists) {
33146
+ planAlreadyDone = phases.length > 0 && phases.every((p) => p.status === "complete" || p.status === "completed" || p.status === "blocked" || p.status === "closed");
33137
33147
  }
33138
33148
  const config3 = KnowledgeConfigSchema.parse({});
33139
33149
  const projectName = planData.title ?? "Unknown Project";
33140
33150
  const closedPhases = [];
33141
33151
  const closedTasks = [];
33142
33152
  const warnings = [];
33143
- for (const phase of inProgressPhases) {
33144
- closedPhases.push(phase.id);
33145
- const retroResult = await executeWriteRetro({
33146
- phase: phase.id,
33147
- summary: "Phase closed via /swarm close",
33148
- task_count: Math.max(1, (phase.tasks ?? []).length),
33149
- task_complexity: "simple",
33150
- total_tool_calls: 0,
33151
- coder_revisions: 0,
33152
- reviewer_rejections: 0,
33153
- test_failures: 0,
33154
- security_findings: 0,
33155
- integration_issues: 0
33156
- }, directory);
33157
- try {
33158
- const parsed = JSON.parse(retroResult);
33159
- if (parsed.success !== true) {
33160
- warnings.push(`Retrospective write failed for phase ${phase.id}`);
33153
+ if (!planAlreadyDone) {
33154
+ for (const phase of inProgressPhases) {
33155
+ closedPhases.push(phase.id);
33156
+ let retroResult;
33157
+ try {
33158
+ retroResult = await executeWriteRetro({
33159
+ phase: phase.id,
33160
+ summary: "Phase closed via /swarm close",
33161
+ task_count: Math.max(1, (phase.tasks ?? []).length),
33162
+ task_complexity: "simple",
33163
+ total_tool_calls: 0,
33164
+ coder_revisions: 0,
33165
+ reviewer_rejections: 0,
33166
+ test_failures: 0,
33167
+ security_findings: 0,
33168
+ integration_issues: 0
33169
+ }, directory);
33170
+ } catch (retroError) {
33171
+ warnings.push(`Retrospective write threw for phase ${phase.id}: ${retroError instanceof Error ? retroError.message : String(retroError)}`);
33172
+ }
33173
+ if (retroResult !== undefined) {
33174
+ try {
33175
+ const parsed = JSON.parse(retroResult);
33176
+ if (parsed.success !== true) {
33177
+ warnings.push(`Retrospective write failed for phase ${phase.id}`);
33178
+ }
33179
+ } catch {}
33161
33180
  }
33162
- } catch {}
33163
- for (const task of phase.tasks ?? []) {
33164
- if (task.status !== "completed" && task.status !== "complete") {
33165
- closedTasks.push(task.id);
33181
+ for (const task of phase.tasks ?? []) {
33182
+ if (task.status !== "completed" && task.status !== "complete") {
33183
+ closedTasks.push(task.id);
33184
+ }
33166
33185
  }
33167
33186
  }
33168
33187
  }
33188
+ const lessonsFilePath = path11.join(directory, ".swarm", "close-lessons.md");
33189
+ let explicitLessons = [];
33190
+ try {
33191
+ const lessonsText = await fs6.readFile(lessonsFilePath, "utf-8");
33192
+ explicitLessons = lessonsText.split(`
33193
+ `).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
33194
+ } catch {}
33195
+ let curationSucceeded = false;
33169
33196
  try {
33170
- await curateAndStoreSwarm([], projectName, { phase_number: 0 }, directory, config3);
33197
+ await curateAndStoreSwarm(explicitLessons, projectName, { phase_number: 0 }, directory, config3);
33198
+ curationSucceeded = true;
33171
33199
  } catch (error93) {
33172
33200
  console.warn("[close-command] curateAndStoreSwarm error:", error93);
33173
33201
  }
33174
- for (const phase of phases) {
33175
- if (phase.status !== "complete" && phase.status !== "completed") {
33176
- phase.status = "closed";
33177
- if (!closedPhases.includes(phase.id)) {
33178
- closedPhases.push(phase.id);
33202
+ if (curationSucceeded && explicitLessons.length > 0) {
33203
+ await fs6.unlink(lessonsFilePath).catch(() => {});
33204
+ }
33205
+ if (planExists && !planAlreadyDone) {
33206
+ for (const phase of phases) {
33207
+ if (phase.status !== "complete" && phase.status !== "completed") {
33208
+ phase.status = "closed";
33209
+ if (!closedPhases.includes(phase.id)) {
33210
+ closedPhases.push(phase.id);
33211
+ }
33179
33212
  }
33180
- }
33181
- for (const task of phase.tasks ?? []) {
33182
- if (task.status !== "completed" && task.status !== "complete") {
33183
- task.status = "closed";
33184
- if (!closedTasks.includes(task.id)) {
33185
- closedTasks.push(task.id);
33213
+ for (const task of phase.tasks ?? []) {
33214
+ if (task.status !== "completed" && task.status !== "complete") {
33215
+ task.status = "closed";
33216
+ if (!closedTasks.includes(task.id)) {
33217
+ closedTasks.push(task.id);
33218
+ }
33186
33219
  }
33187
33220
  }
33188
33221
  }
33222
+ try {
33223
+ await fs6.writeFile(planPath, JSON.stringify(planData, null, 2), "utf-8");
33224
+ } catch (error93) {
33225
+ console.warn("[close-command] Failed to write plan.json:", error93);
33226
+ }
33189
33227
  }
33190
33228
  try {
33191
- await fs6.writeFile(planPath, JSON.stringify(planData, null, 2), "utf-8");
33229
+ await archiveEvidence(directory, 30, 10);
33192
33230
  } catch (error93) {
33193
- console.warn("[close-command] Failed to write plan.json:", error93);
33231
+ console.warn("[close-command] archiveEvidence error:", error93);
33194
33232
  }
33233
+ const swarmDir = path11.join(directory, ".swarm");
33234
+ let configBackupsRemoved = 0;
33195
33235
  try {
33196
- await archiveEvidence(directory, 30, 10);
33236
+ const swarmFiles = await fs6.readdir(swarmDir);
33237
+ const configBackups = swarmFiles.filter((f) => f.startsWith("config-backup-") && f.endsWith(".json"));
33238
+ for (const backup of configBackups) {
33239
+ try {
33240
+ await fs6.unlink(path11.join(swarmDir, backup));
33241
+ configBackupsRemoved++;
33242
+ } catch {}
33243
+ }
33244
+ } catch {}
33245
+ const contextPath = path11.join(directory, ".swarm", "context.md");
33246
+ const contextContent = [
33247
+ "# Context",
33248
+ "",
33249
+ "## Status",
33250
+ `Session closed after: ${projectName}`,
33251
+ `Closed: ${new Date().toISOString()}`,
33252
+ "No active plan. Next session starts fresh.",
33253
+ ""
33254
+ ].join(`
33255
+ `);
33256
+ try {
33257
+ await fs6.writeFile(contextPath, contextContent, "utf-8");
33197
33258
  } catch (error93) {
33198
- console.warn("[close-command] archiveEvidence error:", error93);
33259
+ console.warn("[close-command] Failed to write context.md:", error93);
33260
+ }
33261
+ const pruneBranches = args.includes("--prune-branches");
33262
+ const prunedBranches = [];
33263
+ const pruneErrors = [];
33264
+ if (pruneBranches) {
33265
+ try {
33266
+ const branchOutput = execFileSync("git", ["branch", "-vv"], {
33267
+ cwd: directory,
33268
+ encoding: "utf-8",
33269
+ stdio: ["pipe", "pipe", "pipe"]
33270
+ });
33271
+ const goneBranches = branchOutput.split(`
33272
+ `).filter((line) => line.includes(": gone]")).map((line) => line.trim().replace(/^[*+]\s+/, "").split(/\s+/)[0]).filter(Boolean);
33273
+ for (const branch of goneBranches) {
33274
+ try {
33275
+ execFileSync("git", ["branch", "-d", branch], {
33276
+ cwd: directory,
33277
+ encoding: "utf-8",
33278
+ stdio: ["pipe", "pipe", "pipe"]
33279
+ });
33280
+ prunedBranches.push(branch);
33281
+ } catch {
33282
+ pruneErrors.push(branch);
33283
+ }
33284
+ }
33285
+ } catch {}
33199
33286
  }
33200
33287
  const closeSummaryPath = validateSwarmPath(directory, "close-summary.md");
33288
+ const actionsPerformed = [
33289
+ ...!planAlreadyDone && inProgressPhases.length > 0 ? ["- Wrote retrospectives for in-progress phases"] : [],
33290
+ "- Archived evidence bundles",
33291
+ "- Reset context.md for next session",
33292
+ ...configBackupsRemoved > 0 ? [`- Removed ${configBackupsRemoved} stale config backup file(s)`] : [],
33293
+ ...prunedBranches.length > 0 ? [
33294
+ `- Pruned ${prunedBranches.length} stale local git branch(es): ${prunedBranches.join(", ")}`
33295
+ ] : [],
33296
+ "- Cleared agent sessions and delegation chains",
33297
+ ...planExists && !planAlreadyDone ? ["- Set non-completed phases/tasks to closed status"] : []
33298
+ ];
33201
33299
  const summaryContent = [
33202
33300
  "# Swarm Close Summary",
33203
33301
  "",
@@ -33205,18 +33303,15 @@ async function handleCloseCommand(directory, _args) {
33205
33303
  `**Closed:** ${new Date().toISOString()}`,
33206
33304
  "",
33207
33305
  `## Phases Closed: ${closedPhases.length}`,
33208
- closedPhases.map((id) => `- Phase ${id}`).join(`
33209
- `),
33306
+ !planExists ? "_No plan \u2014 ad-hoc session_" : closedPhases.length > 0 ? closedPhases.map((id) => `- Phase ${id}`).join(`
33307
+ `) : "_No phases to close_",
33210
33308
  "",
33211
33309
  `## Tasks Closed: ${closedTasks.length}`,
33212
33310
  closedTasks.length > 0 ? closedTasks.map((id) => `- ${id}`).join(`
33213
33311
  `) : "_No incomplete tasks_",
33214
33312
  "",
33215
33313
  "## Actions Performed",
33216
- "- Wrote retrospectives for in-progress phases",
33217
- "- Archived evidence bundles",
33218
- "- Cleared agent sessions and delegation chains",
33219
- "- Set non-completed phases/tasks to closed status"
33314
+ ...actionsPerformed
33220
33315
  ].join(`
33221
33316
  `);
33222
33317
  try {
@@ -33232,20 +33327,26 @@ async function handleCloseCommand(directory, _args) {
33232
33327
  await writeCheckpoint(directory).catch(() => {});
33233
33328
  swarmState.agentSessions.clear();
33234
33329
  swarmState.delegationChains.clear();
33330
+ if (pruneErrors.length > 0) {
33331
+ warnings.push(`Could not prune ${pruneErrors.length} branch(es) (unmerged or checked out): ${pruneErrors.join(", ")}`);
33332
+ }
33235
33333
  const warningMsg = warnings.length > 0 ? ` Warnings: ${warnings.join("; ")}.` : "";
33334
+ if (planAlreadyDone) {
33335
+ return `\u2705 Session closed. Plan was already in a terminal state \u2014 cleanup steps applied.${warningMsg}`;
33336
+ }
33236
33337
  return `\u2705 Swarm closed successfully. ${closedPhases.length} phase(s) closed, ${closedTasks.length} incomplete task(s) marked closed.${warningMsg}`;
33237
33338
  }
33238
33339
 
33239
33340
  // src/commands/config.ts
33240
33341
  import * as os3 from "os";
33241
- import * as path11 from "path";
33342
+ import * as path12 from "path";
33242
33343
  function getUserConfigDir2() {
33243
- return process.env.XDG_CONFIG_HOME || path11.join(os3.homedir(), ".config");
33344
+ return process.env.XDG_CONFIG_HOME || path12.join(os3.homedir(), ".config");
33244
33345
  }
33245
33346
  async function handleConfigCommand(directory, _args) {
33246
33347
  const config3 = loadPluginConfig(directory);
33247
- const userConfigPath = path11.join(getUserConfigDir2(), "opencode", "opencode-swarm.json");
33248
- const projectConfigPath = path11.join(directory, ".opencode", "opencode-swarm.json");
33348
+ const userConfigPath = path12.join(getUserConfigDir2(), "opencode", "opencode-swarm.json");
33349
+ const projectConfigPath = path12.join(directory, ".opencode", "opencode-swarm.json");
33249
33350
  const lines = [
33250
33351
  "## Swarm Configuration",
33251
33352
  "",
@@ -33513,13 +33614,13 @@ function formatCurationSummary(summary) {
33513
33614
  }
33514
33615
 
33515
33616
  // src/commands/dark-matter.ts
33516
- import path13 from "path";
33617
+ import path14 from "path";
33517
33618
 
33518
33619
  // src/tools/co-change-analyzer.ts
33519
33620
  import * as child_process2 from "child_process";
33520
33621
  import { randomUUID } from "crypto";
33521
33622
  import { readdir, readFile as readFile2, stat } from "fs/promises";
33522
- import * as path12 from "path";
33623
+ import * as path13 from "path";
33523
33624
  import { promisify } from "util";
33524
33625
  function getExecFileAsync() {
33525
33626
  return promisify(child_process2.execFile);
@@ -33621,7 +33722,7 @@ async function scanSourceFiles(dir) {
33621
33722
  try {
33622
33723
  const entries = await readdir(dir, { withFileTypes: true });
33623
33724
  for (const entry of entries) {
33624
- const fullPath = path12.join(dir, entry.name);
33725
+ const fullPath = path13.join(dir, entry.name);
33625
33726
  if (entry.isDirectory()) {
33626
33727
  if (skipDirs.has(entry.name)) {
33627
33728
  continue;
@@ -33629,7 +33730,7 @@ async function scanSourceFiles(dir) {
33629
33730
  const subFiles = await scanSourceFiles(fullPath);
33630
33731
  results.push(...subFiles);
33631
33732
  } else if (entry.isFile()) {
33632
- const ext = path12.extname(entry.name);
33733
+ const ext = path13.extname(entry.name);
33633
33734
  if ([".ts", ".tsx", ".js", ".jsx", ".mjs"].includes(ext)) {
33634
33735
  results.push(fullPath);
33635
33736
  }
@@ -33651,8 +33752,8 @@ async function getStaticEdges(directory) {
33651
33752
  continue;
33652
33753
  }
33653
33754
  try {
33654
- const sourceDir = path12.dirname(sourceFile);
33655
- const resolvedPath = path12.resolve(sourceDir, importPath);
33755
+ const sourceDir = path13.dirname(sourceFile);
33756
+ const resolvedPath = path13.resolve(sourceDir, importPath);
33656
33757
  const extensions = [
33657
33758
  "",
33658
33759
  ".ts",
@@ -33677,8 +33778,8 @@ async function getStaticEdges(directory) {
33677
33778
  if (!targetFile) {
33678
33779
  continue;
33679
33780
  }
33680
- const relSource = path12.relative(directory, sourceFile).replace(/\\/g, "/");
33681
- const relTarget = path12.relative(directory, targetFile).replace(/\\/g, "/");
33781
+ const relSource = path13.relative(directory, sourceFile).replace(/\\/g, "/");
33782
+ const relTarget = path13.relative(directory, targetFile).replace(/\\/g, "/");
33682
33783
  const [key] = relSource < relTarget ? [`${relSource}::${relTarget}`, relSource, relTarget] : [`${relTarget}::${relSource}`, relTarget, relSource];
33683
33784
  edges.add(key);
33684
33785
  } catch {}
@@ -33690,7 +33791,7 @@ async function getStaticEdges(directory) {
33690
33791
  function isTestImplementationPair(fileA, fileB) {
33691
33792
  const testPatterns = [".test.ts", ".test.js", ".spec.ts", ".spec.js"];
33692
33793
  const getBaseName = (filePath) => {
33693
- const base = path12.basename(filePath);
33794
+ const base = path13.basename(filePath);
33694
33795
  for (const pattern of testPatterns) {
33695
33796
  if (base.endsWith(pattern)) {
33696
33797
  return base.slice(0, -pattern.length);
@@ -33700,16 +33801,16 @@ function isTestImplementationPair(fileA, fileB) {
33700
33801
  };
33701
33802
  const baseA = getBaseName(fileA);
33702
33803
  const baseB = getBaseName(fileB);
33703
- return baseA === baseB && baseA !== path12.basename(fileA) && baseA !== path12.basename(fileB);
33804
+ return baseA === baseB && baseA !== path13.basename(fileA) && baseA !== path13.basename(fileB);
33704
33805
  }
33705
33806
  function hasSharedPrefix(fileA, fileB) {
33706
- const dirA = path12.dirname(fileA);
33707
- const dirB = path12.dirname(fileB);
33807
+ const dirA = path13.dirname(fileA);
33808
+ const dirB = path13.dirname(fileB);
33708
33809
  if (dirA !== dirB) {
33709
33810
  return false;
33710
33811
  }
33711
- const baseA = path12.basename(fileA).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
33712
- const baseB = path12.basename(fileB).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
33812
+ const baseA = path13.basename(fileA).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
33813
+ const baseB = path13.basename(fileB).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
33713
33814
  if (baseA.startsWith(baseB) || baseB.startsWith(baseA)) {
33714
33815
  return true;
33715
33816
  }
@@ -33763,8 +33864,8 @@ function darkMatterToKnowledgeEntries(pairs, projectName) {
33763
33864
  const entries = [];
33764
33865
  const now = new Date().toISOString();
33765
33866
  for (const pair of pairs.slice(0, 10)) {
33766
- const baseA = path12.basename(pair.fileA);
33767
- const baseB = path12.basename(pair.fileB);
33867
+ const baseA = path13.basename(pair.fileA);
33868
+ const baseB = path13.basename(pair.fileB);
33768
33869
  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.`;
33769
33870
  if (lesson.length > 280) {
33770
33871
  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.`;
@@ -33874,7 +33975,7 @@ async function handleDarkMatterCommand(directory, args) {
33874
33975
  const output = formatDarkMatterOutput(pairs);
33875
33976
  if (pairs.length > 0) {
33876
33977
  try {
33877
- const projectName = path13.basename(path13.resolve(directory));
33978
+ const projectName = path14.basename(path14.resolve(directory));
33878
33979
  const entries = darkMatterToKnowledgeEntries(pairs, projectName);
33879
33980
  if (entries.length > 0) {
33880
33981
  const knowledgePath = resolveSwarmKnowledgePath(directory);
@@ -33896,7 +33997,7 @@ async function handleDarkMatterCommand(directory, args) {
33896
33997
  // src/services/diagnose-service.ts
33897
33998
  import * as child_process3 from "child_process";
33898
33999
  import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync5, statSync as statSync3 } from "fs";
33899
- import path14 from "path";
34000
+ import path15 from "path";
33900
34001
  import { fileURLToPath } from "url";
33901
34002
  init_manager();
33902
34003
  init_utils2();
@@ -34196,7 +34297,7 @@ async function checkSpecStaleness(directory, plan) {
34196
34297
  };
34197
34298
  }
34198
34299
  async function checkConfigParseability(directory) {
34199
- const configPath = path14.join(directory, ".opencode/opencode-swarm.json");
34300
+ const configPath = path15.join(directory, ".opencode/opencode-swarm.json");
34200
34301
  if (!existsSync5(configPath)) {
34201
34302
  return {
34202
34303
  name: "Config Parseability",
@@ -34243,15 +34344,15 @@ async function checkGrammarWasmFiles() {
34243
34344
  "tree-sitter-ini.wasm",
34244
34345
  "tree-sitter-regex.wasm"
34245
34346
  ];
34246
- const thisDir = path14.dirname(fileURLToPath(import.meta.url));
34347
+ const thisDir = path15.dirname(fileURLToPath(import.meta.url));
34247
34348
  const isSource = thisDir.replace(/\\/g, "/").endsWith("/src/services");
34248
- const grammarDir = isSource ? path14.join(thisDir, "..", "lang", "grammars") : path14.join(thisDir, "lang", "grammars");
34349
+ const grammarDir = isSource ? path15.join(thisDir, "..", "lang", "grammars") : path15.join(thisDir, "lang", "grammars");
34249
34350
  const missing = [];
34250
- if (!existsSync5(path14.join(grammarDir, "tree-sitter.wasm"))) {
34351
+ if (!existsSync5(path15.join(grammarDir, "tree-sitter.wasm"))) {
34251
34352
  missing.push("tree-sitter.wasm (core runtime)");
34252
34353
  }
34253
34354
  for (const file3 of grammarFiles) {
34254
- if (!existsSync5(path14.join(grammarDir, file3))) {
34355
+ if (!existsSync5(path15.join(grammarDir, file3))) {
34255
34356
  missing.push(file3);
34256
34357
  }
34257
34358
  }
@@ -34269,7 +34370,7 @@ async function checkGrammarWasmFiles() {
34269
34370
  };
34270
34371
  }
34271
34372
  async function checkCheckpointManifest(directory) {
34272
- const manifestPath = path14.join(directory, ".swarm/checkpoints.json");
34373
+ const manifestPath = path15.join(directory, ".swarm/checkpoints.json");
34273
34374
  if (!existsSync5(manifestPath)) {
34274
34375
  return {
34275
34376
  name: "Checkpoint Manifest",
@@ -34321,7 +34422,7 @@ async function checkCheckpointManifest(directory) {
34321
34422
  }
34322
34423
  }
34323
34424
  async function checkEventStreamIntegrity(directory) {
34324
- const eventsPath = path14.join(directory, ".swarm/events.jsonl");
34425
+ const eventsPath = path15.join(directory, ".swarm/events.jsonl");
34325
34426
  if (!existsSync5(eventsPath)) {
34326
34427
  return {
34327
34428
  name: "Event Stream",
@@ -34362,7 +34463,7 @@ async function checkEventStreamIntegrity(directory) {
34362
34463
  }
34363
34464
  }
34364
34465
  async function checkSteeringDirectives(directory) {
34365
- const eventsPath = path14.join(directory, ".swarm/events.jsonl");
34466
+ const eventsPath = path15.join(directory, ".swarm/events.jsonl");
34366
34467
  if (!existsSync5(eventsPath)) {
34367
34468
  return {
34368
34469
  name: "Steering Directives",
@@ -34418,7 +34519,7 @@ async function checkCurator(directory) {
34418
34519
  detail: "Disabled (enable via curator.enabled)"
34419
34520
  };
34420
34521
  }
34421
- const summaryPath = path14.join(directory, ".swarm/curator-summary.json");
34522
+ const summaryPath = path15.join(directory, ".swarm/curator-summary.json");
34422
34523
  if (!existsSync5(summaryPath)) {
34423
34524
  return {
34424
34525
  name: "Curator",
@@ -35315,10 +35416,10 @@ async function handleHistoryCommand(directory, _args) {
35315
35416
  import { randomUUID as randomUUID2 } from "crypto";
35316
35417
  import { existsSync as existsSync7, readFileSync as readFileSync7 } from "fs";
35317
35418
  import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
35318
- import * as path16 from "path";
35419
+ import * as path17 from "path";
35319
35420
  async function migrateContextToKnowledge(directory, config3) {
35320
- const sentinelPath = path16.join(directory, ".swarm", ".knowledge-migrated");
35321
- const contextPath = path16.join(directory, ".swarm", "context.md");
35421
+ const sentinelPath = path17.join(directory, ".swarm", ".knowledge-migrated");
35422
+ const contextPath = path17.join(directory, ".swarm", "context.md");
35322
35423
  const knowledgePath = resolveSwarmKnowledgePath(directory);
35323
35424
  if (existsSync7(sentinelPath)) {
35324
35425
  return {
@@ -35514,7 +35615,7 @@ function truncateLesson(text) {
35514
35615
  return `${text.slice(0, 277)}...`;
35515
35616
  }
35516
35617
  function inferProjectName(directory) {
35517
- const packageJsonPath = path16.join(directory, "package.json");
35618
+ const packageJsonPath = path17.join(directory, "package.json");
35518
35619
  if (existsSync7(packageJsonPath)) {
35519
35620
  try {
35520
35621
  const pkg = JSON.parse(readFileSync7(packageJsonPath, "utf-8"));
@@ -35523,7 +35624,7 @@ function inferProjectName(directory) {
35523
35624
  }
35524
35625
  } catch {}
35525
35626
  }
35526
- return path16.basename(directory);
35627
+ return path17.basename(directory);
35527
35628
  }
35528
35629
  async function writeSentinel(sentinelPath, migrated, dropped) {
35529
35630
  const sentinel = {
@@ -35535,7 +35636,7 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
35535
35636
  schema_version: 1,
35536
35637
  migration_tool: "knowledge-migrator.ts"
35537
35638
  };
35538
- await mkdir3(path16.dirname(sentinelPath), { recursive: true });
35639
+ await mkdir3(path17.dirname(sentinelPath), { recursive: true });
35539
35640
  await writeFile3(sentinelPath, JSON.stringify(sentinel, null, 2), "utf-8");
35540
35641
  }
35541
35642
 
@@ -35772,15 +35873,15 @@ async function handlePlanCommand(directory, args) {
35772
35873
  init_manager();
35773
35874
  init_manager2();
35774
35875
  import * as fs13 from "fs";
35775
- import * as path22 from "path";
35876
+ import * as path23 from "path";
35776
35877
 
35777
35878
  // src/tools/lint.ts
35778
35879
  import * as fs9 from "fs";
35779
- import * as path18 from "path";
35880
+ import * as path19 from "path";
35780
35881
 
35781
35882
  // src/build/discovery.ts
35782
35883
  import * as fs8 from "fs";
35783
- import * as path17 from "path";
35884
+ import * as path18 from "path";
35784
35885
 
35785
35886
  // src/lang/detector.ts
35786
35887
  import { access, readdir as readdir2 } from "fs/promises";
@@ -36877,11 +36978,11 @@ function findBuildFiles(workingDir, patterns) {
36877
36978
  const regex = simpleGlobToRegex(pattern);
36878
36979
  const matches = files.filter((f) => regex.test(f));
36879
36980
  if (matches.length > 0) {
36880
- return path17.join(dir, matches[0]);
36981
+ return path18.join(dir, matches[0]);
36881
36982
  }
36882
36983
  } catch {}
36883
36984
  } else {
36884
- const filePath = path17.join(workingDir, pattern);
36985
+ const filePath = path18.join(workingDir, pattern);
36885
36986
  if (fs8.existsSync(filePath)) {
36886
36987
  return filePath;
36887
36988
  }
@@ -36890,7 +36991,7 @@ function findBuildFiles(workingDir, patterns) {
36890
36991
  return null;
36891
36992
  }
36892
36993
  function getRepoDefinedScripts(workingDir, scripts) {
36893
- const packageJsonPath = path17.join(workingDir, "package.json");
36994
+ const packageJsonPath = path18.join(workingDir, "package.json");
36894
36995
  if (!fs8.existsSync(packageJsonPath)) {
36895
36996
  return [];
36896
36997
  }
@@ -36931,7 +37032,7 @@ function findAllBuildFiles(workingDir) {
36931
37032
  const regex = simpleGlobToRegex(pattern);
36932
37033
  findFilesRecursive(workingDir, regex, allBuildFiles);
36933
37034
  } else {
36934
- const filePath = path17.join(workingDir, pattern);
37035
+ const filePath = path18.join(workingDir, pattern);
36935
37036
  if (fs8.existsSync(filePath)) {
36936
37037
  allBuildFiles.add(filePath);
36937
37038
  }
@@ -36944,7 +37045,7 @@ function findFilesRecursive(dir, regex, results) {
36944
37045
  try {
36945
37046
  const entries = fs8.readdirSync(dir, { withFileTypes: true });
36946
37047
  for (const entry of entries) {
36947
- const fullPath = path17.join(dir, entry.name);
37048
+ const fullPath = path18.join(dir, entry.name);
36948
37049
  if (entry.isDirectory() && !["node_modules", ".git", "dist", "build", "target"].includes(entry.name)) {
36949
37050
  findFilesRecursive(fullPath, regex, results);
36950
37051
  } else if (entry.isFile() && regex.test(entry.name)) {
@@ -36967,7 +37068,7 @@ async function discoverBuildCommandsFromProfiles(workingDir) {
36967
37068
  let foundCommand = false;
36968
37069
  for (const cmd of sortedCommands) {
36969
37070
  if (cmd.detectFile) {
36970
- const detectFilePath = path17.join(workingDir, cmd.detectFile);
37071
+ const detectFilePath = path18.join(workingDir, cmd.detectFile);
36971
37072
  if (!fs8.existsSync(detectFilePath)) {
36972
37073
  continue;
36973
37074
  }
@@ -37115,9 +37216,9 @@ function validateArgs(args) {
37115
37216
  }
37116
37217
  function getLinterCommand(linter, mode, projectDir) {
37117
37218
  const isWindows = process.platform === "win32";
37118
- const binDir = path18.join(projectDir, "node_modules", ".bin");
37119
- const biomeBin = isWindows ? path18.join(binDir, "biome.EXE") : path18.join(binDir, "biome");
37120
- const eslintBin = isWindows ? path18.join(binDir, "eslint.cmd") : path18.join(binDir, "eslint");
37219
+ const binDir = path19.join(projectDir, "node_modules", ".bin");
37220
+ const biomeBin = isWindows ? path19.join(binDir, "biome.EXE") : path19.join(binDir, "biome");
37221
+ const eslintBin = isWindows ? path19.join(binDir, "eslint.cmd") : path19.join(binDir, "eslint");
37121
37222
  switch (linter) {
37122
37223
  case "biome":
37123
37224
  if (mode === "fix") {
@@ -37133,7 +37234,7 @@ function getLinterCommand(linter, mode, projectDir) {
37133
37234
  }
37134
37235
  function getAdditionalLinterCommand(linter, mode, cwd) {
37135
37236
  const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
37136
- const gradlew = fs9.existsSync(path18.join(cwd, gradlewName)) ? path18.join(cwd, gradlewName) : null;
37237
+ const gradlew = fs9.existsSync(path19.join(cwd, gradlewName)) ? path19.join(cwd, gradlewName) : null;
37137
37238
  switch (linter) {
37138
37239
  case "ruff":
37139
37240
  return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
@@ -37167,10 +37268,10 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
37167
37268
  }
37168
37269
  }
37169
37270
  function detectRuff(cwd) {
37170
- if (fs9.existsSync(path18.join(cwd, "ruff.toml")))
37271
+ if (fs9.existsSync(path19.join(cwd, "ruff.toml")))
37171
37272
  return isCommandAvailable("ruff");
37172
37273
  try {
37173
- const pyproject = path18.join(cwd, "pyproject.toml");
37274
+ const pyproject = path19.join(cwd, "pyproject.toml");
37174
37275
  if (fs9.existsSync(pyproject)) {
37175
37276
  const content = fs9.readFileSync(pyproject, "utf-8");
37176
37277
  if (content.includes("[tool.ruff]"))
@@ -37180,19 +37281,19 @@ function detectRuff(cwd) {
37180
37281
  return false;
37181
37282
  }
37182
37283
  function detectClippy(cwd) {
37183
- return fs9.existsSync(path18.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
37284
+ return fs9.existsSync(path19.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
37184
37285
  }
37185
37286
  function detectGolangciLint(cwd) {
37186
- return fs9.existsSync(path18.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
37287
+ return fs9.existsSync(path19.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
37187
37288
  }
37188
37289
  function detectCheckstyle(cwd) {
37189
- const hasMaven = fs9.existsSync(path18.join(cwd, "pom.xml"));
37190
- const hasGradle = fs9.existsSync(path18.join(cwd, "build.gradle")) || fs9.existsSync(path18.join(cwd, "build.gradle.kts"));
37191
- const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs9.existsSync(path18.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
37290
+ const hasMaven = fs9.existsSync(path19.join(cwd, "pom.xml"));
37291
+ const hasGradle = fs9.existsSync(path19.join(cwd, "build.gradle")) || fs9.existsSync(path19.join(cwd, "build.gradle.kts"));
37292
+ const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs9.existsSync(path19.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
37192
37293
  return (hasMaven || hasGradle) && hasBinary;
37193
37294
  }
37194
37295
  function detectKtlint(cwd) {
37195
- const hasKotlin = fs9.existsSync(path18.join(cwd, "build.gradle.kts")) || fs9.existsSync(path18.join(cwd, "build.gradle")) || (() => {
37296
+ const hasKotlin = fs9.existsSync(path19.join(cwd, "build.gradle.kts")) || fs9.existsSync(path19.join(cwd, "build.gradle")) || (() => {
37196
37297
  try {
37197
37298
  return fs9.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
37198
37299
  } catch {
@@ -37211,11 +37312,11 @@ function detectDotnetFormat(cwd) {
37211
37312
  }
37212
37313
  }
37213
37314
  function detectCppcheck(cwd) {
37214
- if (fs9.existsSync(path18.join(cwd, "CMakeLists.txt"))) {
37315
+ if (fs9.existsSync(path19.join(cwd, "CMakeLists.txt"))) {
37215
37316
  return isCommandAvailable("cppcheck");
37216
37317
  }
37217
37318
  try {
37218
- const dirsToCheck = [cwd, path18.join(cwd, "src")];
37319
+ const dirsToCheck = [cwd, path19.join(cwd, "src")];
37219
37320
  const hasCpp = dirsToCheck.some((dir) => {
37220
37321
  try {
37221
37322
  return fs9.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
@@ -37229,13 +37330,13 @@ function detectCppcheck(cwd) {
37229
37330
  }
37230
37331
  }
37231
37332
  function detectSwiftlint(cwd) {
37232
- return fs9.existsSync(path18.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
37333
+ return fs9.existsSync(path19.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
37233
37334
  }
37234
37335
  function detectDartAnalyze(cwd) {
37235
- return fs9.existsSync(path18.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
37336
+ return fs9.existsSync(path19.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
37236
37337
  }
37237
37338
  function detectRubocop(cwd) {
37238
- return (fs9.existsSync(path18.join(cwd, "Gemfile")) || fs9.existsSync(path18.join(cwd, "gems.rb")) || fs9.existsSync(path18.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
37339
+ return (fs9.existsSync(path19.join(cwd, "Gemfile")) || fs9.existsSync(path19.join(cwd, "gems.rb")) || fs9.existsSync(path19.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
37239
37340
  }
37240
37341
  function detectAdditionalLinter(cwd) {
37241
37342
  if (detectRuff(cwd))
@@ -37263,10 +37364,10 @@ function detectAdditionalLinter(cwd) {
37263
37364
  function findBinInAncestors(startDir, binName) {
37264
37365
  let dir = startDir;
37265
37366
  while (true) {
37266
- const candidate = path18.join(dir, "node_modules", ".bin", binName);
37367
+ const candidate = path19.join(dir, "node_modules", ".bin", binName);
37267
37368
  if (fs9.existsSync(candidate))
37268
37369
  return candidate;
37269
- const parent = path18.dirname(dir);
37370
+ const parent = path19.dirname(dir);
37270
37371
  if (parent === dir)
37271
37372
  break;
37272
37373
  dir = parent;
@@ -37275,10 +37376,10 @@ function findBinInAncestors(startDir, binName) {
37275
37376
  }
37276
37377
  function findBinInEnvPath(binName) {
37277
37378
  const searchPath = process.env.PATH ?? "";
37278
- for (const dir of searchPath.split(path18.delimiter)) {
37379
+ for (const dir of searchPath.split(path19.delimiter)) {
37279
37380
  if (!dir)
37280
37381
  continue;
37281
- const candidate = path18.join(dir, binName);
37382
+ const candidate = path19.join(dir, binName);
37282
37383
  if (fs9.existsSync(candidate))
37283
37384
  return candidate;
37284
37385
  }
@@ -37291,13 +37392,13 @@ async function detectAvailableLinter(directory) {
37291
37392
  return null;
37292
37393
  const projectDir = directory;
37293
37394
  const isWindows = process.platform === "win32";
37294
- const biomeBin = isWindows ? path18.join(projectDir, "node_modules", ".bin", "biome.EXE") : path18.join(projectDir, "node_modules", ".bin", "biome");
37295
- const eslintBin = isWindows ? path18.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path18.join(projectDir, "node_modules", ".bin", "eslint");
37395
+ const biomeBin = isWindows ? path19.join(projectDir, "node_modules", ".bin", "biome.EXE") : path19.join(projectDir, "node_modules", ".bin", "biome");
37396
+ const eslintBin = isWindows ? path19.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path19.join(projectDir, "node_modules", ".bin", "eslint");
37296
37397
  const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
37297
37398
  if (localResult)
37298
37399
  return localResult;
37299
- const biomeAncestor = findBinInAncestors(path18.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
37300
- const eslintAncestor = findBinInAncestors(path18.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
37400
+ const biomeAncestor = findBinInAncestors(path19.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
37401
+ const eslintAncestor = findBinInAncestors(path19.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
37301
37402
  if (biomeAncestor || eslintAncestor) {
37302
37403
  return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
37303
37404
  }
@@ -37505,7 +37606,7 @@ For Rust: rustup component add clippy`
37505
37606
 
37506
37607
  // src/tools/secretscan.ts
37507
37608
  import * as fs10 from "fs";
37508
- import * as path19 from "path";
37609
+ import * as path20 from "path";
37509
37610
  var MAX_FILE_PATH_LENGTH = 500;
37510
37611
  var MAX_FILE_SIZE_BYTES = 512 * 1024;
37511
37612
  var MAX_FILES_SCANNED = 1000;
@@ -37732,7 +37833,7 @@ function isGlobOrPathPattern(pattern) {
37732
37833
  return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
37733
37834
  }
37734
37835
  function loadSecretScanIgnore(scanDir) {
37735
- const ignorePath = path19.join(scanDir, ".secretscanignore");
37836
+ const ignorePath = path20.join(scanDir, ".secretscanignore");
37736
37837
  try {
37737
37838
  if (!fs10.existsSync(ignorePath))
37738
37839
  return [];
@@ -37755,7 +37856,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
37755
37856
  if (exactNames.has(entry))
37756
37857
  return true;
37757
37858
  for (const pattern of globPatterns) {
37758
- if (path19.matchesGlob(relPath, pattern))
37859
+ if (path20.matchesGlob(relPath, pattern))
37759
37860
  return true;
37760
37861
  }
37761
37862
  return false;
@@ -37776,7 +37877,7 @@ function validateDirectoryInput(dir) {
37776
37877
  return null;
37777
37878
  }
37778
37879
  function isBinaryFile(filePath, buffer) {
37779
- const ext = path19.extname(filePath).toLowerCase();
37880
+ const ext = path20.extname(filePath).toLowerCase();
37780
37881
  if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
37781
37882
  return true;
37782
37883
  }
@@ -37913,9 +38014,9 @@ function isSymlinkLoop(realPath, visited) {
37913
38014
  return false;
37914
38015
  }
37915
38016
  function isPathWithinScope(realPath, scanDir) {
37916
- const resolvedScanDir = path19.resolve(scanDir);
37917
- const resolvedRealPath = path19.resolve(realPath);
37918
- return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path19.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
38017
+ const resolvedScanDir = path20.resolve(scanDir);
38018
+ const resolvedRealPath = path20.resolve(realPath);
38019
+ return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path20.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
37919
38020
  }
37920
38021
  function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
37921
38022
  skippedDirs: 0,
@@ -37941,8 +38042,8 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
37941
38042
  return a.localeCompare(b);
37942
38043
  });
37943
38044
  for (const entry of entries) {
37944
- const fullPath = path19.join(dir, entry);
37945
- const relPath = path19.relative(scanDir, fullPath).replace(/\\/g, "/");
38045
+ const fullPath = path20.join(dir, entry);
38046
+ const relPath = path20.relative(scanDir, fullPath).replace(/\\/g, "/");
37946
38047
  if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
37947
38048
  stats.skippedDirs++;
37948
38049
  continue;
@@ -37977,7 +38078,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
37977
38078
  const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
37978
38079
  files.push(...subFiles);
37979
38080
  } else if (lstat.isFile()) {
37980
- const ext = path19.extname(fullPath).toLowerCase();
38081
+ const ext = path20.extname(fullPath).toLowerCase();
37981
38082
  if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
37982
38083
  files.push(fullPath);
37983
38084
  } else {
@@ -38043,7 +38144,7 @@ var secretscan = createSwarmTool({
38043
38144
  }
38044
38145
  }
38045
38146
  try {
38046
- const _scanDirRaw = path19.resolve(directory);
38147
+ const _scanDirRaw = path20.resolve(directory);
38047
38148
  const scanDir = (() => {
38048
38149
  try {
38049
38150
  return fs10.realpathSync(_scanDirRaw);
@@ -38201,11 +38302,11 @@ async function runSecretscan(directory) {
38201
38302
 
38202
38303
  // src/tools/test-runner.ts
38203
38304
  import * as fs12 from "fs";
38204
- import * as path21 from "path";
38305
+ import * as path22 from "path";
38205
38306
 
38206
38307
  // src/tools/resolve-working-directory.ts
38207
38308
  import * as fs11 from "fs";
38208
- import * as path20 from "path";
38309
+ import * as path21 from "path";
38209
38310
  function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
38210
38311
  if (workingDirectory == null || workingDirectory === "") {
38211
38312
  return { success: true, directory: fallbackDirectory };
@@ -38225,15 +38326,15 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
38225
38326
  };
38226
38327
  }
38227
38328
  }
38228
- const normalizedDir = path20.normalize(workingDirectory);
38229
- const pathParts = normalizedDir.split(path20.sep);
38329
+ const normalizedDir = path21.normalize(workingDirectory);
38330
+ const pathParts = normalizedDir.split(path21.sep);
38230
38331
  if (pathParts.includes("..")) {
38231
38332
  return {
38232
38333
  success: false,
38233
38334
  message: "Invalid working_directory: path traversal sequences (..) are not allowed"
38234
38335
  };
38235
38336
  }
38236
- const resolvedDir = path20.resolve(normalizedDir);
38337
+ const resolvedDir = path21.resolve(normalizedDir);
38237
38338
  try {
38238
38339
  const realPath = fs11.realpathSync(resolvedDir);
38239
38340
  return { success: true, directory: realPath };
@@ -38316,14 +38417,14 @@ function hasDevDependency(devDeps, ...patterns) {
38316
38417
  return hasPackageJsonDependency(devDeps, ...patterns);
38317
38418
  }
38318
38419
  function detectGoTest(cwd) {
38319
- return fs12.existsSync(path21.join(cwd, "go.mod")) && isCommandAvailable("go");
38420
+ return fs12.existsSync(path22.join(cwd, "go.mod")) && isCommandAvailable("go");
38320
38421
  }
38321
38422
  function detectJavaMaven(cwd) {
38322
- return fs12.existsSync(path21.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
38423
+ return fs12.existsSync(path22.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
38323
38424
  }
38324
38425
  function detectGradle(cwd) {
38325
- const hasBuildFile = fs12.existsSync(path21.join(cwd, "build.gradle")) || fs12.existsSync(path21.join(cwd, "build.gradle.kts"));
38326
- const hasGradlew = fs12.existsSync(path21.join(cwd, "gradlew")) || fs12.existsSync(path21.join(cwd, "gradlew.bat"));
38426
+ const hasBuildFile = fs12.existsSync(path22.join(cwd, "build.gradle")) || fs12.existsSync(path22.join(cwd, "build.gradle.kts"));
38427
+ const hasGradlew = fs12.existsSync(path22.join(cwd, "gradlew")) || fs12.existsSync(path22.join(cwd, "gradlew.bat"));
38327
38428
  return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
38328
38429
  }
38329
38430
  function detectDotnetTest(cwd) {
@@ -38336,30 +38437,30 @@ function detectDotnetTest(cwd) {
38336
38437
  }
38337
38438
  }
38338
38439
  function detectCTest(cwd) {
38339
- const hasSource = fs12.existsSync(path21.join(cwd, "CMakeLists.txt"));
38340
- const hasBuildCache = fs12.existsSync(path21.join(cwd, "CMakeCache.txt")) || fs12.existsSync(path21.join(cwd, "build", "CMakeCache.txt"));
38440
+ const hasSource = fs12.existsSync(path22.join(cwd, "CMakeLists.txt"));
38441
+ const hasBuildCache = fs12.existsSync(path22.join(cwd, "CMakeCache.txt")) || fs12.existsSync(path22.join(cwd, "build", "CMakeCache.txt"));
38341
38442
  return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
38342
38443
  }
38343
38444
  function detectSwiftTest(cwd) {
38344
- return fs12.existsSync(path21.join(cwd, "Package.swift")) && isCommandAvailable("swift");
38445
+ return fs12.existsSync(path22.join(cwd, "Package.swift")) && isCommandAvailable("swift");
38345
38446
  }
38346
38447
  function detectDartTest(cwd) {
38347
- return fs12.existsSync(path21.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
38448
+ return fs12.existsSync(path22.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
38348
38449
  }
38349
38450
  function detectRSpec(cwd) {
38350
- const hasRSpecFile = fs12.existsSync(path21.join(cwd, ".rspec"));
38351
- const hasGemfile = fs12.existsSync(path21.join(cwd, "Gemfile"));
38352
- const hasSpecDir = fs12.existsSync(path21.join(cwd, "spec"));
38451
+ const hasRSpecFile = fs12.existsSync(path22.join(cwd, ".rspec"));
38452
+ const hasGemfile = fs12.existsSync(path22.join(cwd, "Gemfile"));
38453
+ const hasSpecDir = fs12.existsSync(path22.join(cwd, "spec"));
38353
38454
  const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
38354
38455
  return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
38355
38456
  }
38356
38457
  function detectMinitest(cwd) {
38357
- return fs12.existsSync(path21.join(cwd, "test")) && (fs12.existsSync(path21.join(cwd, "Gemfile")) || fs12.existsSync(path21.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
38458
+ return fs12.existsSync(path22.join(cwd, "test")) && (fs12.existsSync(path22.join(cwd, "Gemfile")) || fs12.existsSync(path22.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
38358
38459
  }
38359
38460
  async function detectTestFramework(cwd) {
38360
38461
  const baseDir = cwd;
38361
38462
  try {
38362
- const packageJsonPath = path21.join(baseDir, "package.json");
38463
+ const packageJsonPath = path22.join(baseDir, "package.json");
38363
38464
  if (fs12.existsSync(packageJsonPath)) {
38364
38465
  const content = fs12.readFileSync(packageJsonPath, "utf-8");
38365
38466
  const pkg = JSON.parse(content);
@@ -38380,16 +38481,16 @@ async function detectTestFramework(cwd) {
38380
38481
  return "jest";
38381
38482
  if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
38382
38483
  return "mocha";
38383
- if (fs12.existsSync(path21.join(baseDir, "bun.lockb")) || fs12.existsSync(path21.join(baseDir, "bun.lock"))) {
38484
+ if (fs12.existsSync(path22.join(baseDir, "bun.lockb")) || fs12.existsSync(path22.join(baseDir, "bun.lock"))) {
38384
38485
  if (scripts.test?.includes("bun"))
38385
38486
  return "bun";
38386
38487
  }
38387
38488
  }
38388
38489
  } catch {}
38389
38490
  try {
38390
- const pyprojectTomlPath = path21.join(baseDir, "pyproject.toml");
38391
- const setupCfgPath = path21.join(baseDir, "setup.cfg");
38392
- const requirementsTxtPath = path21.join(baseDir, "requirements.txt");
38491
+ const pyprojectTomlPath = path22.join(baseDir, "pyproject.toml");
38492
+ const setupCfgPath = path22.join(baseDir, "setup.cfg");
38493
+ const requirementsTxtPath = path22.join(baseDir, "requirements.txt");
38393
38494
  if (fs12.existsSync(pyprojectTomlPath)) {
38394
38495
  const content = fs12.readFileSync(pyprojectTomlPath, "utf-8");
38395
38496
  if (content.includes("[tool.pytest"))
@@ -38409,7 +38510,7 @@ async function detectTestFramework(cwd) {
38409
38510
  }
38410
38511
  } catch {}
38411
38512
  try {
38412
- const cargoTomlPath = path21.join(baseDir, "Cargo.toml");
38513
+ const cargoTomlPath = path22.join(baseDir, "Cargo.toml");
38413
38514
  if (fs12.existsSync(cargoTomlPath)) {
38414
38515
  const content = fs12.readFileSync(cargoTomlPath, "utf-8");
38415
38516
  if (content.includes("[dev-dependencies]")) {
@@ -38420,9 +38521,9 @@ async function detectTestFramework(cwd) {
38420
38521
  }
38421
38522
  } catch {}
38422
38523
  try {
38423
- const pesterConfigPath = path21.join(baseDir, "pester.config.ps1");
38424
- const pesterConfigJsonPath = path21.join(baseDir, "pester.config.ps1.json");
38425
- const pesterPs1Path = path21.join(baseDir, "tests.ps1");
38524
+ const pesterConfigPath = path22.join(baseDir, "pester.config.ps1");
38525
+ const pesterConfigJsonPath = path22.join(baseDir, "pester.config.ps1.json");
38526
+ const pesterPs1Path = path22.join(baseDir, "tests.ps1");
38426
38527
  if (fs12.existsSync(pesterConfigPath) || fs12.existsSync(pesterConfigJsonPath) || fs12.existsSync(pesterPs1Path)) {
38427
38528
  return "pester";
38428
38529
  }
@@ -38474,8 +38575,8 @@ function getTestFilesFromConvention(sourceFiles) {
38474
38575
  const testFiles = [];
38475
38576
  for (const file3 of sourceFiles) {
38476
38577
  const normalizedPath = file3.replace(/\\/g, "/");
38477
- const basename4 = path21.basename(file3);
38478
- const dirname10 = path21.dirname(file3);
38578
+ const basename4 = path22.basename(file3);
38579
+ const dirname10 = path22.dirname(file3);
38479
38580
  if (hasCompoundTestExtension(basename4) || basename4.includes(".spec.") || basename4.includes(".test.") || normalizedPath.includes("/__tests__/") || normalizedPath.includes("/tests/") || normalizedPath.includes("/test/")) {
38480
38581
  if (!testFiles.includes(file3)) {
38481
38582
  testFiles.push(file3);
@@ -38484,13 +38585,13 @@ function getTestFilesFromConvention(sourceFiles) {
38484
38585
  }
38485
38586
  for (const _pattern of TEST_PATTERNS) {
38486
38587
  const nameWithoutExt = basename4.replace(/\.[^.]+$/, "");
38487
- const ext = path21.extname(basename4);
38588
+ const ext = path22.extname(basename4);
38488
38589
  const possibleTestFiles = [
38489
- path21.join(dirname10, `${nameWithoutExt}.spec${ext}`),
38490
- path21.join(dirname10, `${nameWithoutExt}.test${ext}`),
38491
- path21.join(dirname10, "__tests__", `${nameWithoutExt}${ext}`),
38492
- path21.join(dirname10, "tests", `${nameWithoutExt}${ext}`),
38493
- path21.join(dirname10, "test", `${nameWithoutExt}${ext}`)
38590
+ path22.join(dirname10, `${nameWithoutExt}.spec${ext}`),
38591
+ path22.join(dirname10, `${nameWithoutExt}.test${ext}`),
38592
+ path22.join(dirname10, "__tests__", `${nameWithoutExt}${ext}`),
38593
+ path22.join(dirname10, "tests", `${nameWithoutExt}${ext}`),
38594
+ path22.join(dirname10, "test", `${nameWithoutExt}${ext}`)
38494
38595
  ];
38495
38596
  for (const testFile of possibleTestFiles) {
38496
38597
  if (fs12.existsSync(testFile) && !testFiles.includes(testFile)) {
@@ -38510,7 +38611,7 @@ async function getTestFilesFromGraph(sourceFiles) {
38510
38611
  for (const testFile of candidateTestFiles) {
38511
38612
  try {
38512
38613
  const content = fs12.readFileSync(testFile, "utf-8");
38513
- const testDir = path21.dirname(testFile);
38614
+ const testDir = path22.dirname(testFile);
38514
38615
  const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
38515
38616
  let match;
38516
38617
  match = importRegex.exec(content);
@@ -38518,8 +38619,8 @@ async function getTestFilesFromGraph(sourceFiles) {
38518
38619
  const importPath = match[1];
38519
38620
  let resolvedImport;
38520
38621
  if (importPath.startsWith(".")) {
38521
- resolvedImport = path21.resolve(testDir, importPath);
38522
- const existingExt = path21.extname(resolvedImport);
38622
+ resolvedImport = path22.resolve(testDir, importPath);
38623
+ const existingExt = path22.extname(resolvedImport);
38523
38624
  if (!existingExt) {
38524
38625
  for (const extToTry of [
38525
38626
  ".ts",
@@ -38539,12 +38640,12 @@ async function getTestFilesFromGraph(sourceFiles) {
38539
38640
  } else {
38540
38641
  continue;
38541
38642
  }
38542
- const importBasename = path21.basename(resolvedImport, path21.extname(resolvedImport));
38543
- const importDir = path21.dirname(resolvedImport);
38643
+ const importBasename = path22.basename(resolvedImport, path22.extname(resolvedImport));
38644
+ const importDir = path22.dirname(resolvedImport);
38544
38645
  for (const sourceFile of sourceFiles) {
38545
- const sourceDir = path21.dirname(sourceFile);
38546
- const sourceBasename = path21.basename(sourceFile, path21.extname(sourceFile));
38547
- const isRelatedDir = importDir === sourceDir || importDir === path21.join(sourceDir, "__tests__") || importDir === path21.join(sourceDir, "tests") || importDir === path21.join(sourceDir, "test");
38646
+ const sourceDir = path22.dirname(sourceFile);
38647
+ const sourceBasename = path22.basename(sourceFile, path22.extname(sourceFile));
38648
+ const isRelatedDir = importDir === sourceDir || importDir === path22.join(sourceDir, "__tests__") || importDir === path22.join(sourceDir, "tests") || importDir === path22.join(sourceDir, "test");
38548
38649
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
38549
38650
  if (!testFiles.includes(testFile)) {
38550
38651
  testFiles.push(testFile);
@@ -38559,8 +38660,8 @@ async function getTestFilesFromGraph(sourceFiles) {
38559
38660
  while (match !== null) {
38560
38661
  const importPath = match[1];
38561
38662
  if (importPath.startsWith(".")) {
38562
- let resolvedImport = path21.resolve(testDir, importPath);
38563
- const existingExt = path21.extname(resolvedImport);
38663
+ let resolvedImport = path22.resolve(testDir, importPath);
38664
+ const existingExt = path22.extname(resolvedImport);
38564
38665
  if (!existingExt) {
38565
38666
  for (const extToTry of [
38566
38667
  ".ts",
@@ -38577,12 +38678,12 @@ async function getTestFilesFromGraph(sourceFiles) {
38577
38678
  }
38578
38679
  }
38579
38680
  }
38580
- const importDir = path21.dirname(resolvedImport);
38581
- const importBasename = path21.basename(resolvedImport, path21.extname(resolvedImport));
38681
+ const importDir = path22.dirname(resolvedImport);
38682
+ const importBasename = path22.basename(resolvedImport, path22.extname(resolvedImport));
38582
38683
  for (const sourceFile of sourceFiles) {
38583
- const sourceDir = path21.dirname(sourceFile);
38584
- const sourceBasename = path21.basename(sourceFile, path21.extname(sourceFile));
38585
- const isRelatedDir = importDir === sourceDir || importDir === path21.join(sourceDir, "__tests__") || importDir === path21.join(sourceDir, "tests") || importDir === path21.join(sourceDir, "test");
38684
+ const sourceDir = path22.dirname(sourceFile);
38685
+ const sourceBasename = path22.basename(sourceFile, path22.extname(sourceFile));
38686
+ const isRelatedDir = importDir === sourceDir || importDir === path22.join(sourceDir, "__tests__") || importDir === path22.join(sourceDir, "tests") || importDir === path22.join(sourceDir, "test");
38586
38687
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
38587
38688
  if (!testFiles.includes(testFile)) {
38588
38689
  testFiles.push(testFile);
@@ -38667,8 +38768,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
38667
38768
  return ["mvn", "test"];
38668
38769
  case "gradle": {
38669
38770
  const isWindows = process.platform === "win32";
38670
- const hasGradlewBat = fs12.existsSync(path21.join(baseDir, "gradlew.bat"));
38671
- const hasGradlew = fs12.existsSync(path21.join(baseDir, "gradlew"));
38771
+ const hasGradlewBat = fs12.existsSync(path22.join(baseDir, "gradlew.bat"));
38772
+ const hasGradlew = fs12.existsSync(path22.join(baseDir, "gradlew"));
38672
38773
  if (hasGradlewBat && isWindows)
38673
38774
  return ["gradlew.bat", "test"];
38674
38775
  if (hasGradlew)
@@ -38685,7 +38786,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
38685
38786
  "cmake-build-release",
38686
38787
  "out"
38687
38788
  ];
38688
- const actualBuildDir = buildDirCandidates.find((d) => fs12.existsSync(path21.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
38789
+ const actualBuildDir = buildDirCandidates.find((d) => fs12.existsSync(path22.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
38689
38790
  return ["ctest", "--test-dir", actualBuildDir];
38690
38791
  }
38691
38792
  case "swift-test":
@@ -39227,7 +39328,7 @@ var test_runner = createSwarmTool({
39227
39328
  let effectiveScope = scope;
39228
39329
  if (scope === "all") {} else if (scope === "convention") {
39229
39330
  const sourceFiles = args.files.filter((f) => {
39230
- const ext = path21.extname(f).toLowerCase();
39331
+ const ext = path22.extname(f).toLowerCase();
39231
39332
  return SOURCE_EXTENSIONS.has(ext);
39232
39333
  });
39233
39334
  if (sourceFiles.length === 0) {
@@ -39243,7 +39344,7 @@ var test_runner = createSwarmTool({
39243
39344
  testFiles = getTestFilesFromConvention(sourceFiles);
39244
39345
  } else if (scope === "graph") {
39245
39346
  const sourceFiles = args.files.filter((f) => {
39246
- const ext = path21.extname(f).toLowerCase();
39347
+ const ext = path22.extname(f).toLowerCase();
39247
39348
  return SOURCE_EXTENSIONS.has(ext);
39248
39349
  });
39249
39350
  if (sourceFiles.length === 0) {
@@ -39314,8 +39415,8 @@ function validateDirectoryPath(dir) {
39314
39415
  if (dir.includes("..")) {
39315
39416
  throw new Error("Directory path must not contain path traversal sequences");
39316
39417
  }
39317
- const normalized = path22.normalize(dir);
39318
- const absolutePath = path22.isAbsolute(normalized) ? normalized : path22.resolve(normalized);
39418
+ const normalized = path23.normalize(dir);
39419
+ const absolutePath = path23.isAbsolute(normalized) ? normalized : path23.resolve(normalized);
39319
39420
  return absolutePath;
39320
39421
  }
39321
39422
  function validateTimeout(timeoutMs, defaultValue) {
@@ -39338,7 +39439,7 @@ function validateTimeout(timeoutMs, defaultValue) {
39338
39439
  }
39339
39440
  function getPackageVersion(dir) {
39340
39441
  try {
39341
- const packagePath = path22.join(dir, "package.json");
39442
+ const packagePath = path23.join(dir, "package.json");
39342
39443
  if (fs13.existsSync(packagePath)) {
39343
39444
  const content = fs13.readFileSync(packagePath, "utf-8");
39344
39445
  const pkg = JSON.parse(content);
@@ -39349,7 +39450,7 @@ function getPackageVersion(dir) {
39349
39450
  }
39350
39451
  function getChangelogVersion(dir) {
39351
39452
  try {
39352
- const changelogPath = path22.join(dir, "CHANGELOG.md");
39453
+ const changelogPath = path23.join(dir, "CHANGELOG.md");
39353
39454
  if (fs13.existsSync(changelogPath)) {
39354
39455
  const content = fs13.readFileSync(changelogPath, "utf-8");
39355
39456
  const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
@@ -39363,7 +39464,7 @@ function getChangelogVersion(dir) {
39363
39464
  function getVersionFileVersion(dir) {
39364
39465
  const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
39365
39466
  for (const file3 of possibleFiles) {
39366
- const filePath = path22.join(dir, file3);
39467
+ const filePath = path23.join(dir, file3);
39367
39468
  if (fs13.existsSync(filePath)) {
39368
39469
  try {
39369
39470
  const content = fs13.readFileSync(filePath, "utf-8").trim();
@@ -39861,7 +39962,7 @@ async function handlePreflightCommand(directory, _args) {
39861
39962
  // src/knowledge/hive-promoter.ts
39862
39963
  import * as fs14 from "fs";
39863
39964
  import * as os5 from "os";
39864
- import * as path23 from "path";
39965
+ import * as path24 from "path";
39865
39966
  var DANGEROUS_PATTERNS = [
39866
39967
  [/rm\s+-rf/, "rm\\s+-rf"],
39867
39968
  [/:\s*!\s*\|/, ":\\s*!\\s*\\|"],
@@ -39907,13 +40008,13 @@ function getHiveFilePath() {
39907
40008
  const home = os5.homedir();
39908
40009
  let dataDir;
39909
40010
  if (platform === "win32") {
39910
- dataDir = path23.join(process.env.LOCALAPPDATA || path23.join(home, "AppData", "Local"), "opencode-swarm", "Data");
40011
+ dataDir = path24.join(process.env.LOCALAPPDATA || path24.join(home, "AppData", "Local"), "opencode-swarm", "Data");
39911
40012
  } else if (platform === "darwin") {
39912
- dataDir = path23.join(home, "Library", "Application Support", "opencode-swarm");
40013
+ dataDir = path24.join(home, "Library", "Application Support", "opencode-swarm");
39913
40014
  } else {
39914
- dataDir = path23.join(process.env.XDG_DATA_HOME || path23.join(home, ".local", "share"), "opencode-swarm");
40015
+ dataDir = path24.join(process.env.XDG_DATA_HOME || path24.join(home, ".local", "share"), "opencode-swarm");
39915
40016
  }
39916
- return path23.join(dataDir, "hive-knowledge.jsonl");
40017
+ return path24.join(dataDir, "hive-knowledge.jsonl");
39917
40018
  }
39918
40019
  async function promoteToHive(_directory, lesson, category) {
39919
40020
  const trimmed = (lesson ?? "").trim();
@@ -39925,7 +40026,7 @@ async function promoteToHive(_directory, lesson, category) {
39925
40026
  throw new Error(`Lesson rejected by validator: ${validation.reason}`);
39926
40027
  }
39927
40028
  const hivePath = getHiveFilePath();
39928
- const hiveDir = path23.dirname(hivePath);
40029
+ const hiveDir = path24.dirname(hivePath);
39929
40030
  if (!fs14.existsSync(hiveDir)) {
39930
40031
  fs14.mkdirSync(hiveDir, { recursive: true });
39931
40032
  }
@@ -39947,7 +40048,7 @@ async function promoteToHive(_directory, lesson, category) {
39947
40048
  return `Promoted to hive: "${preview}" (confidence: 1.0, source: manual)`;
39948
40049
  }
39949
40050
  async function promoteFromSwarm(directory, lessonId) {
39950
- const knowledgePath = path23.join(directory, ".swarm", "knowledge.jsonl");
40051
+ const knowledgePath = path24.join(directory, ".swarm", "knowledge.jsonl");
39951
40052
  const entries = [];
39952
40053
  if (fs14.existsSync(knowledgePath)) {
39953
40054
  const content = fs14.readFileSync(knowledgePath, "utf-8");
@@ -39974,7 +40075,7 @@ async function promoteFromSwarm(directory, lessonId) {
39974
40075
  throw new Error(`Lesson rejected by validator: ${validation.reason}`);
39975
40076
  }
39976
40077
  const hivePath = getHiveFilePath();
39977
- const hiveDir = path23.dirname(hivePath);
40078
+ const hiveDir = path24.dirname(hivePath);
39978
40079
  if (!fs14.existsSync(hiveDir)) {
39979
40080
  fs14.mkdirSync(hiveDir, { recursive: true });
39980
40081
  }
@@ -40785,7 +40886,7 @@ async function handleResetCommand(directory, args) {
40785
40886
  // src/commands/reset-session.ts
40786
40887
  init_utils2();
40787
40888
  import * as fs16 from "fs";
40788
- import * as path24 from "path";
40889
+ import * as path25 from "path";
40789
40890
  async function handleResetSessionCommand(directory, _args) {
40790
40891
  const results = [];
40791
40892
  try {
@@ -40800,13 +40901,13 @@ async function handleResetSessionCommand(directory, _args) {
40800
40901
  results.push("\u274C Failed to delete state.json");
40801
40902
  }
40802
40903
  try {
40803
- const sessionDir = path24.dirname(validateSwarmPath(directory, "session/state.json"));
40904
+ const sessionDir = path25.dirname(validateSwarmPath(directory, "session/state.json"));
40804
40905
  if (fs16.existsSync(sessionDir)) {
40805
40906
  const files = fs16.readdirSync(sessionDir);
40806
40907
  const otherFiles = files.filter((f) => f !== "state.json");
40807
40908
  let deletedCount = 0;
40808
40909
  for (const file3 of otherFiles) {
40809
- const filePath = path24.join(sessionDir, file3);
40910
+ const filePath = path25.join(sessionDir, file3);
40810
40911
  if (fs16.lstatSync(filePath).isFile()) {
40811
40912
  fs16.unlinkSync(filePath);
40812
40913
  deletedCount++;
@@ -40836,7 +40937,7 @@ async function handleResetSessionCommand(directory, _args) {
40836
40937
  // src/summaries/manager.ts
40837
40938
  init_utils2();
40838
40939
  init_utils();
40839
- import * as path25 from "path";
40940
+ import * as path26 from "path";
40840
40941
  var SUMMARY_ID_REGEX = /^S\d+$/;
40841
40942
  function sanitizeSummaryId(id) {
40842
40943
  if (!id || id.length === 0) {
@@ -40860,7 +40961,7 @@ function sanitizeSummaryId(id) {
40860
40961
  }
40861
40962
  async function loadFullOutput(directory, id) {
40862
40963
  const sanitizedId = sanitizeSummaryId(id);
40863
- const relativePath = path25.join("summaries", `${sanitizedId}.json`);
40964
+ const relativePath = path26.join("summaries", `${sanitizedId}.json`);
40864
40965
  validateSwarmPath(directory, relativePath);
40865
40966
  const content = await readSwarmFileAsync(directory, relativePath);
40866
40967
  if (content === null) {
@@ -40914,7 +41015,7 @@ ${error93 instanceof Error ? error93.message : String(error93)}`;
40914
41015
  // src/commands/rollback.ts
40915
41016
  init_utils2();
40916
41017
  import * as fs17 from "fs";
40917
- import * as path26 from "path";
41018
+ import * as path27 from "path";
40918
41019
  async function handleRollbackCommand(directory, args) {
40919
41020
  const phaseArg = args[0];
40920
41021
  if (!phaseArg) {
@@ -40972,8 +41073,8 @@ async function handleRollbackCommand(directory, args) {
40972
41073
  const successes = [];
40973
41074
  const failures = [];
40974
41075
  for (const file3 of checkpointFiles) {
40975
- const src = path26.join(checkpointDir, file3);
40976
- const dest = path26.join(swarmDir, file3);
41076
+ const src = path27.join(checkpointDir, file3);
41077
+ const dest = path27.join(swarmDir, file3);
40977
41078
  try {
40978
41079
  fs17.cpSync(src, dest, { recursive: true, force: true });
40979
41080
  successes.push(file3);
@@ -41036,9 +41137,9 @@ async function handleSimulateCommand(directory, args) {
41036
41137
  const report = reportLines.filter(Boolean).join(`
41037
41138
  `);
41038
41139
  const fs18 = await import("fs/promises");
41039
- const path27 = await import("path");
41040
- const reportPath = path27.join(directory, ".swarm", "simulate-report.md");
41041
- await fs18.mkdir(path27.dirname(reportPath), { recursive: true });
41140
+ const path28 = await import("path");
41141
+ const reportPath = path28.join(directory, ".swarm", "simulate-report.md");
41142
+ await fs18.mkdir(path28.dirname(reportPath), { recursive: true });
41042
41143
  await fs18.writeFile(reportPath, report, "utf-8");
41043
41144
  return `${darkMatterPairs.length} hidden coupling pairs detected`;
41044
41145
  }
@@ -41521,10 +41622,10 @@ function resolveCommand(tokens) {
41521
41622
  }
41522
41623
 
41523
41624
  // src/cli/index.ts
41524
- var CONFIG_DIR = path27.join(process.env.XDG_CONFIG_HOME || path27.join(os6.homedir(), ".config"), "opencode");
41525
- var OPENCODE_CONFIG_PATH = path27.join(CONFIG_DIR, "opencode.json");
41526
- var PLUGIN_CONFIG_PATH = path27.join(CONFIG_DIR, "opencode-swarm.json");
41527
- var PROMPTS_DIR = path27.join(CONFIG_DIR, "opencode-swarm");
41625
+ var CONFIG_DIR = path28.join(process.env.XDG_CONFIG_HOME || path28.join(os6.homedir(), ".config"), "opencode");
41626
+ var OPENCODE_CONFIG_PATH = path28.join(CONFIG_DIR, "opencode.json");
41627
+ var PLUGIN_CONFIG_PATH = path28.join(CONFIG_DIR, "opencode-swarm.json");
41628
+ var PROMPTS_DIR = path28.join(CONFIG_DIR, "opencode-swarm");
41528
41629
  function ensureDir(dir) {
41529
41630
  if (!fs18.existsSync(dir)) {
41530
41631
  fs18.mkdirSync(dir, { recursive: true });
@@ -41548,7 +41649,7 @@ async function install() {
41548
41649
  `);
41549
41650
  ensureDir(CONFIG_DIR);
41550
41651
  ensureDir(PROMPTS_DIR);
41551
- const LEGACY_CONFIG_PATH = path27.join(CONFIG_DIR, "config.json");
41652
+ const LEGACY_CONFIG_PATH = path28.join(CONFIG_DIR, "config.json");
41552
41653
  let opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
41553
41654
  if (!opencodeConfig) {
41554
41655
  const legacyConfig = loadJson(LEGACY_CONFIG_PATH);