opencode-swarm 6.41.2 → 6.41.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -17531,9 +17531,9 @@ var init_evidence_summary_service = __esm(() => {
17531
17531
  });
17532
17532
 
17533
17533
  // src/cli/index.ts
17534
- import * as fs14 from "fs";
17534
+ import * as fs15 from "fs";
17535
17535
  import * as os5 from "os";
17536
- import * as path24 from "path";
17536
+ import * as path25 from "path";
17537
17537
 
17538
17538
  // src/commands/agents.ts
17539
17539
  function handleAgentsCommand(agents, guardrails) {
@@ -33432,7 +33432,7 @@ function darkMatterToKnowledgeEntries(pairs, projectName) {
33432
33432
  lesson,
33433
33433
  category: "architecture",
33434
33434
  tags: ["hidden-coupling", "co-change", "dark-matter"],
33435
- scope: "project",
33435
+ scope: "global",
33436
33436
  confidence,
33437
33437
  status: "candidate",
33438
33438
  confirmed_by: [],
@@ -35418,8 +35418,8 @@ async function handlePlanCommand(directory, args) {
35418
35418
  // src/services/preflight-service.ts
35419
35419
  init_manager();
35420
35420
  init_manager2();
35421
- import * as fs10 from "fs";
35422
- import * as path20 from "path";
35421
+ import * as fs11 from "fs";
35422
+ import * as path21 from "path";
35423
35423
 
35424
35424
  // src/tools/lint.ts
35425
35425
  import * as fs7 from "fs";
@@ -37804,8 +37804,52 @@ async function runSecretscan(directory) {
37804
37804
  }
37805
37805
 
37806
37806
  // src/tools/test-runner.ts
37807
+ import * as fs10 from "fs";
37808
+ import * as path20 from "path";
37809
+
37810
+ // src/tools/resolve-working-directory.ts
37807
37811
  import * as fs9 from "fs";
37808
37812
  import * as path19 from "path";
37813
+ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
37814
+ if (workingDirectory == null || workingDirectory === "") {
37815
+ return { success: true, directory: fallbackDirectory };
37816
+ }
37817
+ if (workingDirectory.includes("\x00")) {
37818
+ return {
37819
+ success: false,
37820
+ message: "Invalid working_directory: null bytes are not allowed"
37821
+ };
37822
+ }
37823
+ if (process.platform === "win32") {
37824
+ const devicePathPattern = /^\\\\|^(NUL|CON|AUX|COM[1-9]|LPT[1-9])(\..*)?$/i;
37825
+ if (devicePathPattern.test(workingDirectory)) {
37826
+ return {
37827
+ success: false,
37828
+ message: "Invalid working_directory: Windows device paths are not allowed"
37829
+ };
37830
+ }
37831
+ }
37832
+ const normalizedDir = path19.normalize(workingDirectory);
37833
+ const pathParts = normalizedDir.split(path19.sep);
37834
+ if (pathParts.includes("..")) {
37835
+ return {
37836
+ success: false,
37837
+ message: "Invalid working_directory: path traversal sequences (..) are not allowed"
37838
+ };
37839
+ }
37840
+ const resolvedDir = path19.resolve(normalizedDir);
37841
+ try {
37842
+ const realPath = fs9.realpathSync(resolvedDir);
37843
+ return { success: true, directory: realPath };
37844
+ } catch {
37845
+ return {
37846
+ success: false,
37847
+ message: `Invalid working_directory: path "${resolvedDir}" does not exist or is inaccessible`
37848
+ };
37849
+ }
37850
+ }
37851
+
37852
+ // src/tools/test-runner.ts
37809
37853
  var MAX_OUTPUT_BYTES3 = 512000;
37810
37854
  var MAX_COMMAND_LENGTH2 = 500;
37811
37855
  var DEFAULT_TIMEOUT_MS = 60000;
@@ -37876,19 +37920,19 @@ function hasDevDependency(devDeps, ...patterns) {
37876
37920
  return hasPackageJsonDependency(devDeps, ...patterns);
37877
37921
  }
37878
37922
  function detectGoTest(cwd) {
37879
- return fs9.existsSync(path19.join(cwd, "go.mod")) && isCommandAvailable("go");
37923
+ return fs10.existsSync(path20.join(cwd, "go.mod")) && isCommandAvailable("go");
37880
37924
  }
37881
37925
  function detectJavaMaven(cwd) {
37882
- return fs9.existsSync(path19.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
37926
+ return fs10.existsSync(path20.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
37883
37927
  }
37884
37928
  function detectGradle(cwd) {
37885
- const hasBuildFile = fs9.existsSync(path19.join(cwd, "build.gradle")) || fs9.existsSync(path19.join(cwd, "build.gradle.kts"));
37886
- const hasGradlew = fs9.existsSync(path19.join(cwd, "gradlew")) || fs9.existsSync(path19.join(cwd, "gradlew.bat"));
37929
+ const hasBuildFile = fs10.existsSync(path20.join(cwd, "build.gradle")) || fs10.existsSync(path20.join(cwd, "build.gradle.kts"));
37930
+ const hasGradlew = fs10.existsSync(path20.join(cwd, "gradlew")) || fs10.existsSync(path20.join(cwd, "gradlew.bat"));
37887
37931
  return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
37888
37932
  }
37889
37933
  function detectDotnetTest(cwd) {
37890
37934
  try {
37891
- const files = fs9.readdirSync(cwd);
37935
+ const files = fs10.readdirSync(cwd);
37892
37936
  const hasCsproj = files.some((f) => f.endsWith(".csproj"));
37893
37937
  return hasCsproj && isCommandAvailable("dotnet");
37894
37938
  } catch {
@@ -37896,32 +37940,32 @@ function detectDotnetTest(cwd) {
37896
37940
  }
37897
37941
  }
37898
37942
  function detectCTest(cwd) {
37899
- const hasSource = fs9.existsSync(path19.join(cwd, "CMakeLists.txt"));
37900
- const hasBuildCache = fs9.existsSync(path19.join(cwd, "CMakeCache.txt")) || fs9.existsSync(path19.join(cwd, "build", "CMakeCache.txt"));
37943
+ const hasSource = fs10.existsSync(path20.join(cwd, "CMakeLists.txt"));
37944
+ const hasBuildCache = fs10.existsSync(path20.join(cwd, "CMakeCache.txt")) || fs10.existsSync(path20.join(cwd, "build", "CMakeCache.txt"));
37901
37945
  return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
37902
37946
  }
37903
37947
  function detectSwiftTest(cwd) {
37904
- return fs9.existsSync(path19.join(cwd, "Package.swift")) && isCommandAvailable("swift");
37948
+ return fs10.existsSync(path20.join(cwd, "Package.swift")) && isCommandAvailable("swift");
37905
37949
  }
37906
37950
  function detectDartTest(cwd) {
37907
- return fs9.existsSync(path19.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
37951
+ return fs10.existsSync(path20.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
37908
37952
  }
37909
37953
  function detectRSpec(cwd) {
37910
- const hasRSpecFile = fs9.existsSync(path19.join(cwd, ".rspec"));
37911
- const hasGemfile = fs9.existsSync(path19.join(cwd, "Gemfile"));
37912
- const hasSpecDir = fs9.existsSync(path19.join(cwd, "spec"));
37954
+ const hasRSpecFile = fs10.existsSync(path20.join(cwd, ".rspec"));
37955
+ const hasGemfile = fs10.existsSync(path20.join(cwd, "Gemfile"));
37956
+ const hasSpecDir = fs10.existsSync(path20.join(cwd, "spec"));
37913
37957
  const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
37914
37958
  return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
37915
37959
  }
37916
37960
  function detectMinitest(cwd) {
37917
- return fs9.existsSync(path19.join(cwd, "test")) && (fs9.existsSync(path19.join(cwd, "Gemfile")) || fs9.existsSync(path19.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
37961
+ return fs10.existsSync(path20.join(cwd, "test")) && (fs10.existsSync(path20.join(cwd, "Gemfile")) || fs10.existsSync(path20.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
37918
37962
  }
37919
37963
  async function detectTestFramework(cwd) {
37920
37964
  const baseDir = cwd;
37921
37965
  try {
37922
- const packageJsonPath = path19.join(baseDir, "package.json");
37923
- if (fs9.existsSync(packageJsonPath)) {
37924
- const content = fs9.readFileSync(packageJsonPath, "utf-8");
37966
+ const packageJsonPath = path20.join(baseDir, "package.json");
37967
+ if (fs10.existsSync(packageJsonPath)) {
37968
+ const content = fs10.readFileSync(packageJsonPath, "utf-8");
37925
37969
  const pkg = JSON.parse(content);
37926
37970
  const _deps = pkg.dependencies || {};
37927
37971
  const devDeps = pkg.devDependencies || {};
@@ -37940,38 +37984,38 @@ async function detectTestFramework(cwd) {
37940
37984
  return "jest";
37941
37985
  if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
37942
37986
  return "mocha";
37943
- if (fs9.existsSync(path19.join(baseDir, "bun.lockb")) || fs9.existsSync(path19.join(baseDir, "bun.lock"))) {
37987
+ if (fs10.existsSync(path20.join(baseDir, "bun.lockb")) || fs10.existsSync(path20.join(baseDir, "bun.lock"))) {
37944
37988
  if (scripts.test?.includes("bun"))
37945
37989
  return "bun";
37946
37990
  }
37947
37991
  }
37948
37992
  } catch {}
37949
37993
  try {
37950
- const pyprojectTomlPath = path19.join(baseDir, "pyproject.toml");
37951
- const setupCfgPath = path19.join(baseDir, "setup.cfg");
37952
- const requirementsTxtPath = path19.join(baseDir, "requirements.txt");
37953
- if (fs9.existsSync(pyprojectTomlPath)) {
37954
- const content = fs9.readFileSync(pyprojectTomlPath, "utf-8");
37994
+ const pyprojectTomlPath = path20.join(baseDir, "pyproject.toml");
37995
+ const setupCfgPath = path20.join(baseDir, "setup.cfg");
37996
+ const requirementsTxtPath = path20.join(baseDir, "requirements.txt");
37997
+ if (fs10.existsSync(pyprojectTomlPath)) {
37998
+ const content = fs10.readFileSync(pyprojectTomlPath, "utf-8");
37955
37999
  if (content.includes("[tool.pytest"))
37956
38000
  return "pytest";
37957
38001
  if (content.includes("pytest"))
37958
38002
  return "pytest";
37959
38003
  }
37960
- if (fs9.existsSync(setupCfgPath)) {
37961
- const content = fs9.readFileSync(setupCfgPath, "utf-8");
38004
+ if (fs10.existsSync(setupCfgPath)) {
38005
+ const content = fs10.readFileSync(setupCfgPath, "utf-8");
37962
38006
  if (content.includes("[pytest]"))
37963
38007
  return "pytest";
37964
38008
  }
37965
- if (fs9.existsSync(requirementsTxtPath)) {
37966
- const content = fs9.readFileSync(requirementsTxtPath, "utf-8");
38009
+ if (fs10.existsSync(requirementsTxtPath)) {
38010
+ const content = fs10.readFileSync(requirementsTxtPath, "utf-8");
37967
38011
  if (content.includes("pytest"))
37968
38012
  return "pytest";
37969
38013
  }
37970
38014
  } catch {}
37971
38015
  try {
37972
- const cargoTomlPath = path19.join(baseDir, "Cargo.toml");
37973
- if (fs9.existsSync(cargoTomlPath)) {
37974
- const content = fs9.readFileSync(cargoTomlPath, "utf-8");
38016
+ const cargoTomlPath = path20.join(baseDir, "Cargo.toml");
38017
+ if (fs10.existsSync(cargoTomlPath)) {
38018
+ const content = fs10.readFileSync(cargoTomlPath, "utf-8");
37975
38019
  if (content.includes("[dev-dependencies]")) {
37976
38020
  if (content.includes("tokio") || content.includes("mockall") || content.includes("pretty_assertions")) {
37977
38021
  return "cargo";
@@ -37980,10 +38024,10 @@ async function detectTestFramework(cwd) {
37980
38024
  }
37981
38025
  } catch {}
37982
38026
  try {
37983
- const pesterConfigPath = path19.join(baseDir, "pester.config.ps1");
37984
- const pesterConfigJsonPath = path19.join(baseDir, "pester.config.ps1.json");
37985
- const pesterPs1Path = path19.join(baseDir, "tests.ps1");
37986
- if (fs9.existsSync(pesterConfigPath) || fs9.existsSync(pesterConfigJsonPath) || fs9.existsSync(pesterPs1Path)) {
38027
+ const pesterConfigPath = path20.join(baseDir, "pester.config.ps1");
38028
+ const pesterConfigJsonPath = path20.join(baseDir, "pester.config.ps1.json");
38029
+ const pesterPs1Path = path20.join(baseDir, "tests.ps1");
38030
+ if (fs10.existsSync(pesterConfigPath) || fs10.existsSync(pesterConfigJsonPath) || fs10.existsSync(pesterPs1Path)) {
37987
38031
  return "pester";
37988
38032
  }
37989
38033
  } catch {}
@@ -38034,8 +38078,8 @@ function getTestFilesFromConvention(sourceFiles) {
38034
38078
  const testFiles = [];
38035
38079
  for (const file3 of sourceFiles) {
38036
38080
  const normalizedPath = file3.replace(/\\/g, "/");
38037
- const basename4 = path19.basename(file3);
38038
- const dirname9 = path19.dirname(file3);
38081
+ const basename4 = path20.basename(file3);
38082
+ const dirname9 = path20.dirname(file3);
38039
38083
  if (hasCompoundTestExtension(basename4) || basename4.includes(".spec.") || basename4.includes(".test.") || normalizedPath.includes("/__tests__/") || normalizedPath.includes("/tests/") || normalizedPath.includes("/test/")) {
38040
38084
  if (!testFiles.includes(file3)) {
38041
38085
  testFiles.push(file3);
@@ -38044,16 +38088,16 @@ function getTestFilesFromConvention(sourceFiles) {
38044
38088
  }
38045
38089
  for (const _pattern of TEST_PATTERNS) {
38046
38090
  const nameWithoutExt = basename4.replace(/\.[^.]+$/, "");
38047
- const ext = path19.extname(basename4);
38091
+ const ext = path20.extname(basename4);
38048
38092
  const possibleTestFiles = [
38049
- path19.join(dirname9, `${nameWithoutExt}.spec${ext}`),
38050
- path19.join(dirname9, `${nameWithoutExt}.test${ext}`),
38051
- path19.join(dirname9, "__tests__", `${nameWithoutExt}${ext}`),
38052
- path19.join(dirname9, "tests", `${nameWithoutExt}${ext}`),
38053
- path19.join(dirname9, "test", `${nameWithoutExt}${ext}`)
38093
+ path20.join(dirname9, `${nameWithoutExt}.spec${ext}`),
38094
+ path20.join(dirname9, `${nameWithoutExt}.test${ext}`),
38095
+ path20.join(dirname9, "__tests__", `${nameWithoutExt}${ext}`),
38096
+ path20.join(dirname9, "tests", `${nameWithoutExt}${ext}`),
38097
+ path20.join(dirname9, "test", `${nameWithoutExt}${ext}`)
38054
38098
  ];
38055
38099
  for (const testFile of possibleTestFiles) {
38056
- if (fs9.existsSync(testFile) && !testFiles.includes(testFile)) {
38100
+ if (fs10.existsSync(testFile) && !testFiles.includes(testFile)) {
38057
38101
  testFiles.push(testFile);
38058
38102
  }
38059
38103
  }
@@ -38069,8 +38113,8 @@ async function getTestFilesFromGraph(sourceFiles) {
38069
38113
  }
38070
38114
  for (const testFile of candidateTestFiles) {
38071
38115
  try {
38072
- const content = fs9.readFileSync(testFile, "utf-8");
38073
- const testDir = path19.dirname(testFile);
38116
+ const content = fs10.readFileSync(testFile, "utf-8");
38117
+ const testDir = path20.dirname(testFile);
38074
38118
  const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
38075
38119
  let match;
38076
38120
  match = importRegex.exec(content);
@@ -38078,8 +38122,8 @@ async function getTestFilesFromGraph(sourceFiles) {
38078
38122
  const importPath = match[1];
38079
38123
  let resolvedImport;
38080
38124
  if (importPath.startsWith(".")) {
38081
- resolvedImport = path19.resolve(testDir, importPath);
38082
- const existingExt = path19.extname(resolvedImport);
38125
+ resolvedImport = path20.resolve(testDir, importPath);
38126
+ const existingExt = path20.extname(resolvedImport);
38083
38127
  if (!existingExt) {
38084
38128
  for (const extToTry of [
38085
38129
  ".ts",
@@ -38090,7 +38134,7 @@ async function getTestFilesFromGraph(sourceFiles) {
38090
38134
  ".cjs"
38091
38135
  ]) {
38092
38136
  const withExt = resolvedImport + extToTry;
38093
- if (sourceFiles.includes(withExt) || fs9.existsSync(withExt)) {
38137
+ if (sourceFiles.includes(withExt) || fs10.existsSync(withExt)) {
38094
38138
  resolvedImport = withExt;
38095
38139
  break;
38096
38140
  }
@@ -38099,12 +38143,12 @@ async function getTestFilesFromGraph(sourceFiles) {
38099
38143
  } else {
38100
38144
  continue;
38101
38145
  }
38102
- const importBasename = path19.basename(resolvedImport, path19.extname(resolvedImport));
38103
- const importDir = path19.dirname(resolvedImport);
38146
+ const importBasename = path20.basename(resolvedImport, path20.extname(resolvedImport));
38147
+ const importDir = path20.dirname(resolvedImport);
38104
38148
  for (const sourceFile of sourceFiles) {
38105
- const sourceDir = path19.dirname(sourceFile);
38106
- const sourceBasename = path19.basename(sourceFile, path19.extname(sourceFile));
38107
- const isRelatedDir = importDir === sourceDir || importDir === path19.join(sourceDir, "__tests__") || importDir === path19.join(sourceDir, "tests") || importDir === path19.join(sourceDir, "test");
38149
+ const sourceDir = path20.dirname(sourceFile);
38150
+ const sourceBasename = path20.basename(sourceFile, path20.extname(sourceFile));
38151
+ const isRelatedDir = importDir === sourceDir || importDir === path20.join(sourceDir, "__tests__") || importDir === path20.join(sourceDir, "tests") || importDir === path20.join(sourceDir, "test");
38108
38152
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
38109
38153
  if (!testFiles.includes(testFile)) {
38110
38154
  testFiles.push(testFile);
@@ -38119,8 +38163,8 @@ async function getTestFilesFromGraph(sourceFiles) {
38119
38163
  while (match !== null) {
38120
38164
  const importPath = match[1];
38121
38165
  if (importPath.startsWith(".")) {
38122
- let resolvedImport = path19.resolve(testDir, importPath);
38123
- const existingExt = path19.extname(resolvedImport);
38166
+ let resolvedImport = path20.resolve(testDir, importPath);
38167
+ const existingExt = path20.extname(resolvedImport);
38124
38168
  if (!existingExt) {
38125
38169
  for (const extToTry of [
38126
38170
  ".ts",
@@ -38131,18 +38175,18 @@ async function getTestFilesFromGraph(sourceFiles) {
38131
38175
  ".cjs"
38132
38176
  ]) {
38133
38177
  const withExt = resolvedImport + extToTry;
38134
- if (sourceFiles.includes(withExt) || fs9.existsSync(withExt)) {
38178
+ if (sourceFiles.includes(withExt) || fs10.existsSync(withExt)) {
38135
38179
  resolvedImport = withExt;
38136
38180
  break;
38137
38181
  }
38138
38182
  }
38139
38183
  }
38140
- const importDir = path19.dirname(resolvedImport);
38141
- const importBasename = path19.basename(resolvedImport, path19.extname(resolvedImport));
38184
+ const importDir = path20.dirname(resolvedImport);
38185
+ const importBasename = path20.basename(resolvedImport, path20.extname(resolvedImport));
38142
38186
  for (const sourceFile of sourceFiles) {
38143
- const sourceDir = path19.dirname(sourceFile);
38144
- const sourceBasename = path19.basename(sourceFile, path19.extname(sourceFile));
38145
- const isRelatedDir = importDir === sourceDir || importDir === path19.join(sourceDir, "__tests__") || importDir === path19.join(sourceDir, "tests") || importDir === path19.join(sourceDir, "test");
38187
+ const sourceDir = path20.dirname(sourceFile);
38188
+ const sourceBasename = path20.basename(sourceFile, path20.extname(sourceFile));
38189
+ const isRelatedDir = importDir === sourceDir || importDir === path20.join(sourceDir, "__tests__") || importDir === path20.join(sourceDir, "tests") || importDir === path20.join(sourceDir, "test");
38146
38190
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
38147
38191
  if (!testFiles.includes(testFile)) {
38148
38192
  testFiles.push(testFile);
@@ -38227,8 +38271,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
38227
38271
  return ["mvn", "test"];
38228
38272
  case "gradle": {
38229
38273
  const isWindows = process.platform === "win32";
38230
- const hasGradlewBat = fs9.existsSync(path19.join(baseDir, "gradlew.bat"));
38231
- const hasGradlew = fs9.existsSync(path19.join(baseDir, "gradlew"));
38274
+ const hasGradlewBat = fs10.existsSync(path20.join(baseDir, "gradlew.bat"));
38275
+ const hasGradlew = fs10.existsSync(path20.join(baseDir, "gradlew"));
38232
38276
  if (hasGradlewBat && isWindows)
38233
38277
  return ["gradlew.bat", "test"];
38234
38278
  if (hasGradlew)
@@ -38245,7 +38289,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
38245
38289
  "cmake-build-release",
38246
38290
  "out"
38247
38291
  ];
38248
- const actualBuildDir = buildDirCandidates.find((d) => fs9.existsSync(path19.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
38292
+ const actualBuildDir = buildDirCandidates.find((d) => fs10.existsSync(path20.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
38249
38293
  return ["ctest", "--test-dir", actualBuildDir];
38250
38294
  }
38251
38295
  case "swift-test":
@@ -38477,6 +38521,43 @@ function parseTestOutput(framework, output) {
38477
38521
  }
38478
38522
  return { totals, coveragePercent };
38479
38523
  }
38524
+ async function readBoundedStream(stream, maxBytes) {
38525
+ const reader = stream.getReader();
38526
+ const chunks = [];
38527
+ let totalBytes = 0;
38528
+ let truncated = false;
38529
+ try {
38530
+ while (true) {
38531
+ const { done, value } = await reader.read();
38532
+ if (done)
38533
+ break;
38534
+ if (totalBytes + value.length > maxBytes) {
38535
+ const remaining = maxBytes - totalBytes;
38536
+ if (remaining > 0) {
38537
+ chunks.push(value.slice(0, remaining));
38538
+ }
38539
+ totalBytes = maxBytes;
38540
+ truncated = true;
38541
+ reader.cancel().catch(() => {});
38542
+ break;
38543
+ }
38544
+ chunks.push(value);
38545
+ totalBytes += value.length;
38546
+ }
38547
+ } catch {} finally {
38548
+ try {
38549
+ reader.releaseLock();
38550
+ } catch {}
38551
+ }
38552
+ const decoder = new TextDecoder("utf-8", { fatal: false });
38553
+ const combined = new Uint8Array(totalBytes);
38554
+ let offset = 0;
38555
+ for (const chunk of chunks) {
38556
+ combined.set(chunk, offset);
38557
+ offset += chunk.length;
38558
+ }
38559
+ return { text: decoder.decode(combined), truncated };
38560
+ }
38480
38561
  async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
38481
38562
  const command = buildTestCommand(framework, scope, files, coverage, cwd);
38482
38563
  if (!command) {
@@ -38505,34 +38586,24 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
38505
38586
  stderr: "pipe",
38506
38587
  cwd
38507
38588
  });
38508
- const exitPromise = proc.exited;
38509
- const timeoutPromise = new Promise((resolve7) => setTimeout(() => {
38589
+ const timeoutPromise = new Promise((resolve8) => setTimeout(() => {
38510
38590
  proc.kill();
38511
- resolve7(-1);
38591
+ resolve8(-1);
38512
38592
  }, timeout_ms));
38513
- const exitCode = await Promise.race([exitPromise, timeoutPromise]);
38514
- const duration_ms = Date.now() - startTime;
38515
- const [stdout, stderr] = await Promise.all([
38516
- new Response(proc.stdout).text(),
38517
- new Response(proc.stderr).text()
38593
+ const [exitCode, stdoutResult, stderrResult] = await Promise.all([
38594
+ Promise.race([proc.exited, timeoutPromise]),
38595
+ readBoundedStream(proc.stdout, MAX_OUTPUT_BYTES3),
38596
+ readBoundedStream(proc.stderr, MAX_OUTPUT_BYTES3)
38518
38597
  ]);
38519
- let output = stdout;
38520
- if (stderr) {
38598
+ const duration_ms = Date.now() - startTime;
38599
+ let output = stdoutResult.text;
38600
+ if (stderrResult.text) {
38521
38601
  output += (output ? `
38522
- ` : "") + stderr;
38602
+ ` : "") + stderrResult.text;
38523
38603
  }
38524
- const outputBytes = Buffer.byteLength(output, "utf-8");
38525
- if (outputBytes > MAX_OUTPUT_BYTES3) {
38526
- let truncIndex = MAX_OUTPUT_BYTES3;
38527
- while (truncIndex > 0) {
38528
- const truncated = output.slice(0, truncIndex);
38529
- if (Buffer.byteLength(truncated, "utf-8") <= MAX_OUTPUT_BYTES3) {
38530
- break;
38531
- }
38532
- truncIndex--;
38533
- }
38534
- output = `${output.slice(0, truncIndex)}
38535
- ... (output truncated)`;
38604
+ if (stdoutResult.truncated || stderrResult.truncated) {
38605
+ output += `
38606
+ ... (output truncated at stream read limit)`;
38536
38607
  }
38537
38608
  const { totals, coveragePercent } = parseTestOutput(framework, output);
38538
38609
  const isTimeout = exitCode === -1;
@@ -38646,10 +38717,26 @@ var test_runner = createSwarmTool({
38646
38717
  files: tool.schema.array(tool.schema.string()).optional().describe("Specific files to test (used with convention or graph scope)"),
38647
38718
  coverage: tool.schema.boolean().optional().describe("Enable coverage reporting if supported"),
38648
38719
  timeout_ms: tool.schema.number().optional().describe("Timeout in milliseconds (default 60000, max 300000)"),
38649
- allow_full_suite: tool.schema.boolean().optional().describe('Explicit opt-in for scope "all". Required because full-suite output can destabilize SSE streaming.')
38720
+ allow_full_suite: tool.schema.boolean().optional().describe('Explicit opt-in for scope "all". Required because full-suite output can destabilize SSE streaming.'),
38721
+ 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.")
38650
38722
  },
38651
38723
  async execute(args, directory) {
38652
- const workingDir = directory.trim() || directory;
38724
+ let workingDirInput;
38725
+ if (args && typeof args === "object") {
38726
+ const obj = args;
38727
+ workingDirInput = typeof obj.working_directory === "string" ? obj.working_directory : undefined;
38728
+ }
38729
+ const dirResult = resolveWorkingDirectory(workingDirInput, directory);
38730
+ if (!dirResult.success) {
38731
+ const errorResult = {
38732
+ success: false,
38733
+ framework: "none",
38734
+ scope: "all",
38735
+ error: dirResult.message
38736
+ };
38737
+ return JSON.stringify(errorResult, null, 2);
38738
+ }
38739
+ const workingDir = dirResult.directory;
38653
38740
  if (workingDir.length > 4096) {
38654
38741
  const errorResult = {
38655
38742
  success: false,
@@ -38703,8 +38790,8 @@ var test_runner = createSwarmTool({
38703
38790
  success: false,
38704
38791
  framework: "none",
38705
38792
  scope: "all",
38706
- error: 'Full-suite test execution (scope: "all") requires allow_full_suite: true',
38707
- message: 'Set allow_full_suite: true to confirm intentional full-suite execution. Use scope "convention" or "graph" for targeted tests. Full-suite output is large and may destabilize SSE streaming on some opencode versions.'
38793
+ error: 'scope "all" is not allowed without explicit files. Use scope "convention" or "graph" with a files array to run targeted tests.',
38794
+ message: 'Running the full test suite without file targeting is blocked. Provide scope "convention" or "graph" with specific source files in the files array. Example: { scope: "convention", files: ["src/tools/test-runner.ts"] }'
38708
38795
  };
38709
38796
  return JSON.stringify(errorResult, null, 2);
38710
38797
  }
@@ -38744,7 +38831,7 @@ var test_runner = createSwarmTool({
38744
38831
  let effectiveScope = scope;
38745
38832
  if (scope === "all") {} else if (scope === "convention") {
38746
38833
  const sourceFiles = args.files.filter((f) => {
38747
- const ext = path19.extname(f).toLowerCase();
38834
+ const ext = path20.extname(f).toLowerCase();
38748
38835
  return SOURCE_EXTENSIONS.has(ext);
38749
38836
  });
38750
38837
  if (sourceFiles.length === 0) {
@@ -38760,7 +38847,7 @@ var test_runner = createSwarmTool({
38760
38847
  testFiles = getTestFilesFromConvention(sourceFiles);
38761
38848
  } else if (scope === "graph") {
38762
38849
  const sourceFiles = args.files.filter((f) => {
38763
- const ext = path19.extname(f).toLowerCase();
38850
+ const ext = path20.extname(f).toLowerCase();
38764
38851
  return SOURCE_EXTENSIONS.has(ext);
38765
38852
  });
38766
38853
  if (sourceFiles.length === 0) {
@@ -38831,8 +38918,8 @@ function validateDirectoryPath(dir) {
38831
38918
  if (dir.includes("..")) {
38832
38919
  throw new Error("Directory path must not contain path traversal sequences");
38833
38920
  }
38834
- const normalized = path20.normalize(dir);
38835
- const absolutePath = path20.isAbsolute(normalized) ? normalized : path20.resolve(normalized);
38921
+ const normalized = path21.normalize(dir);
38922
+ const absolutePath = path21.isAbsolute(normalized) ? normalized : path21.resolve(normalized);
38836
38923
  return absolutePath;
38837
38924
  }
38838
38925
  function validateTimeout(timeoutMs, defaultValue) {
@@ -38855,9 +38942,9 @@ function validateTimeout(timeoutMs, defaultValue) {
38855
38942
  }
38856
38943
  function getPackageVersion(dir) {
38857
38944
  try {
38858
- const packagePath = path20.join(dir, "package.json");
38859
- if (fs10.existsSync(packagePath)) {
38860
- const content = fs10.readFileSync(packagePath, "utf-8");
38945
+ const packagePath = path21.join(dir, "package.json");
38946
+ if (fs11.existsSync(packagePath)) {
38947
+ const content = fs11.readFileSync(packagePath, "utf-8");
38861
38948
  const pkg = JSON.parse(content);
38862
38949
  return pkg.version ?? null;
38863
38950
  }
@@ -38866,9 +38953,9 @@ function getPackageVersion(dir) {
38866
38953
  }
38867
38954
  function getChangelogVersion(dir) {
38868
38955
  try {
38869
- const changelogPath = path20.join(dir, "CHANGELOG.md");
38870
- if (fs10.existsSync(changelogPath)) {
38871
- const content = fs10.readFileSync(changelogPath, "utf-8");
38956
+ const changelogPath = path21.join(dir, "CHANGELOG.md");
38957
+ if (fs11.existsSync(changelogPath)) {
38958
+ const content = fs11.readFileSync(changelogPath, "utf-8");
38872
38959
  const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
38873
38960
  if (match) {
38874
38961
  return match[1];
@@ -38880,10 +38967,10 @@ function getChangelogVersion(dir) {
38880
38967
  function getVersionFileVersion(dir) {
38881
38968
  const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
38882
38969
  for (const file3 of possibleFiles) {
38883
- const filePath = path20.join(dir, file3);
38884
- if (fs10.existsSync(filePath)) {
38970
+ const filePath = path21.join(dir, file3);
38971
+ if (fs11.existsSync(filePath)) {
38885
38972
  try {
38886
- const content = fs10.readFileSync(filePath, "utf-8").trim();
38973
+ const content = fs11.readFileSync(filePath, "utf-8").trim();
38887
38974
  const match = content.match(/(\d+\.\d+\.\d+)/);
38888
38975
  if (match) {
38889
38976
  return match[1];
@@ -39427,7 +39514,7 @@ async function handlePromoteCommand(directory, args) {
39427
39514
  }
39428
39515
 
39429
39516
  // src/commands/reset.ts
39430
- import * as fs11 from "fs";
39517
+ import * as fs12 from "fs";
39431
39518
 
39432
39519
  // src/background/manager.ts
39433
39520
  init_utils();
@@ -39482,13 +39569,13 @@ class CircuitBreaker {
39482
39569
  if (this.config.callTimeoutMs <= 0) {
39483
39570
  return fn();
39484
39571
  }
39485
- return new Promise((resolve8, reject) => {
39572
+ return new Promise((resolve9, reject) => {
39486
39573
  const timeout = setTimeout(() => {
39487
39574
  reject(new Error(`Call timeout after ${this.config.callTimeoutMs}ms`));
39488
39575
  }, this.config.callTimeoutMs);
39489
39576
  fn().then((result) => {
39490
39577
  clearTimeout(timeout);
39491
- resolve8(result);
39578
+ resolve9(result);
39492
39579
  }).catch((error93) => {
39493
39580
  clearTimeout(timeout);
39494
39581
  reject(error93);
@@ -39772,7 +39859,7 @@ class AutomationQueue {
39772
39859
 
39773
39860
  // src/background/worker.ts
39774
39861
  function sleep(ms) {
39775
- return new Promise((resolve8) => setTimeout(resolve8, ms));
39862
+ return new Promise((resolve9) => setTimeout(resolve9, ms));
39776
39863
  }
39777
39864
 
39778
39865
  class WorkerManager {
@@ -40128,8 +40215,8 @@ async function handleResetCommand(directory, args) {
40128
40215
  for (const filename of filesToReset) {
40129
40216
  try {
40130
40217
  const resolvedPath = validateSwarmPath(directory, filename);
40131
- if (fs11.existsSync(resolvedPath)) {
40132
- fs11.unlinkSync(resolvedPath);
40218
+ if (fs12.existsSync(resolvedPath)) {
40219
+ fs12.unlinkSync(resolvedPath);
40133
40220
  results.push(`- \u2705 Deleted ${filename}`);
40134
40221
  } else {
40135
40222
  results.push(`- \u23ED\uFE0F ${filename} not found (skipped)`);
@@ -40146,8 +40233,8 @@ async function handleResetCommand(directory, args) {
40146
40233
  }
40147
40234
  try {
40148
40235
  const summariesPath = validateSwarmPath(directory, "summaries");
40149
- if (fs11.existsSync(summariesPath)) {
40150
- fs11.rmSync(summariesPath, { recursive: true, force: true });
40236
+ if (fs12.existsSync(summariesPath)) {
40237
+ fs12.rmSync(summariesPath, { recursive: true, force: true });
40151
40238
  results.push("- \u2705 Deleted summaries/ directory");
40152
40239
  } else {
40153
40240
  results.push("- \u23ED\uFE0F summaries/ not found (skipped)");
@@ -40167,14 +40254,14 @@ async function handleResetCommand(directory, args) {
40167
40254
 
40168
40255
  // src/commands/reset-session.ts
40169
40256
  init_utils2();
40170
- import * as fs12 from "fs";
40171
- import * as path21 from "path";
40257
+ import * as fs13 from "fs";
40258
+ import * as path22 from "path";
40172
40259
  async function handleResetSessionCommand(directory, _args) {
40173
40260
  const results = [];
40174
40261
  try {
40175
40262
  const statePath = validateSwarmPath(directory, "session/state.json");
40176
- if (fs12.existsSync(statePath)) {
40177
- fs12.unlinkSync(statePath);
40263
+ if (fs13.existsSync(statePath)) {
40264
+ fs13.unlinkSync(statePath);
40178
40265
  results.push("\u2705 Deleted .swarm/session/state.json");
40179
40266
  } else {
40180
40267
  results.push("\u23ED\uFE0F state.json not found (already clean)");
@@ -40183,15 +40270,15 @@ async function handleResetSessionCommand(directory, _args) {
40183
40270
  results.push("\u274C Failed to delete state.json");
40184
40271
  }
40185
40272
  try {
40186
- const sessionDir = path21.dirname(validateSwarmPath(directory, "session/state.json"));
40187
- if (fs12.existsSync(sessionDir)) {
40188
- const files = fs12.readdirSync(sessionDir);
40273
+ const sessionDir = path22.dirname(validateSwarmPath(directory, "session/state.json"));
40274
+ if (fs13.existsSync(sessionDir)) {
40275
+ const files = fs13.readdirSync(sessionDir);
40189
40276
  const otherFiles = files.filter((f) => f !== "state.json");
40190
40277
  let deletedCount = 0;
40191
40278
  for (const file3 of otherFiles) {
40192
- const filePath = path21.join(sessionDir, file3);
40193
- if (fs12.lstatSync(filePath).isFile()) {
40194
- fs12.unlinkSync(filePath);
40279
+ const filePath = path22.join(sessionDir, file3);
40280
+ if (fs13.lstatSync(filePath).isFile()) {
40281
+ fs13.unlinkSync(filePath);
40195
40282
  deletedCount++;
40196
40283
  }
40197
40284
  }
@@ -40219,7 +40306,7 @@ async function handleResetSessionCommand(directory, _args) {
40219
40306
  // src/summaries/manager.ts
40220
40307
  init_utils2();
40221
40308
  init_utils();
40222
- import * as path22 from "path";
40309
+ import * as path23 from "path";
40223
40310
  var SUMMARY_ID_REGEX = /^S\d+$/;
40224
40311
  function sanitizeSummaryId(id) {
40225
40312
  if (!id || id.length === 0) {
@@ -40243,7 +40330,7 @@ function sanitizeSummaryId(id) {
40243
40330
  }
40244
40331
  async function loadFullOutput(directory, id) {
40245
40332
  const sanitizedId = sanitizeSummaryId(id);
40246
- const relativePath = path22.join("summaries", `${sanitizedId}.json`);
40333
+ const relativePath = path23.join("summaries", `${sanitizedId}.json`);
40247
40334
  validateSwarmPath(directory, relativePath);
40248
40335
  const content = await readSwarmFileAsync(directory, relativePath);
40249
40336
  if (content === null) {
@@ -40296,18 +40383,18 @@ ${error93 instanceof Error ? error93.message : String(error93)}`;
40296
40383
 
40297
40384
  // src/commands/rollback.ts
40298
40385
  init_utils2();
40299
- import * as fs13 from "fs";
40300
- import * as path23 from "path";
40386
+ import * as fs14 from "fs";
40387
+ import * as path24 from "path";
40301
40388
  async function handleRollbackCommand(directory, args) {
40302
40389
  const phaseArg = args[0];
40303
40390
  if (!phaseArg) {
40304
40391
  const manifestPath2 = validateSwarmPath(directory, "checkpoints/manifest.json");
40305
- if (!fs13.existsSync(manifestPath2)) {
40392
+ if (!fs14.existsSync(manifestPath2)) {
40306
40393
  return "No checkpoints found. Use `/swarm checkpoint` to create checkpoints.";
40307
40394
  }
40308
40395
  let manifest2;
40309
40396
  try {
40310
- manifest2 = JSON.parse(fs13.readFileSync(manifestPath2, "utf-8"));
40397
+ manifest2 = JSON.parse(fs14.readFileSync(manifestPath2, "utf-8"));
40311
40398
  } catch {
40312
40399
  return "Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.";
40313
40400
  }
@@ -40329,12 +40416,12 @@ async function handleRollbackCommand(directory, args) {
40329
40416
  return "Error: Phase number must be a positive integer.";
40330
40417
  }
40331
40418
  const manifestPath = validateSwarmPath(directory, "checkpoints/manifest.json");
40332
- if (!fs13.existsSync(manifestPath)) {
40419
+ if (!fs14.existsSync(manifestPath)) {
40333
40420
  return `Error: No checkpoints found. Cannot rollback to phase ${targetPhase}.`;
40334
40421
  }
40335
40422
  let manifest;
40336
40423
  try {
40337
- manifest = JSON.parse(fs13.readFileSync(manifestPath, "utf-8"));
40424
+ manifest = JSON.parse(fs14.readFileSync(manifestPath, "utf-8"));
40338
40425
  } catch {
40339
40426
  return `Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.`;
40340
40427
  }
@@ -40344,10 +40431,10 @@ async function handleRollbackCommand(directory, args) {
40344
40431
  return `Error: Checkpoint for phase ${targetPhase} not found. Available phases: ${available}`;
40345
40432
  }
40346
40433
  const checkpointDir = validateSwarmPath(directory, `checkpoints/phase-${targetPhase}`);
40347
- if (!fs13.existsSync(checkpointDir)) {
40434
+ if (!fs14.existsSync(checkpointDir)) {
40348
40435
  return `Error: Checkpoint directory for phase ${targetPhase} does not exist.`;
40349
40436
  }
40350
- const checkpointFiles = fs13.readdirSync(checkpointDir);
40437
+ const checkpointFiles = fs14.readdirSync(checkpointDir);
40351
40438
  if (checkpointFiles.length === 0) {
40352
40439
  return `Error: Checkpoint for phase ${targetPhase} is empty. Cannot rollback.`;
40353
40440
  }
@@ -40355,10 +40442,10 @@ async function handleRollbackCommand(directory, args) {
40355
40442
  const successes = [];
40356
40443
  const failures = [];
40357
40444
  for (const file3 of checkpointFiles) {
40358
- const src = path23.join(checkpointDir, file3);
40359
- const dest = path23.join(swarmDir, file3);
40445
+ const src = path24.join(checkpointDir, file3);
40446
+ const dest = path24.join(swarmDir, file3);
40360
40447
  try {
40361
- fs13.cpSync(src, dest, { recursive: true, force: true });
40448
+ fs14.cpSync(src, dest, { recursive: true, force: true });
40362
40449
  successes.push(file3);
40363
40450
  } catch (error93) {
40364
40451
  failures.push({ file: file3, error: error93.message });
@@ -40375,7 +40462,7 @@ async function handleRollbackCommand(directory, args) {
40375
40462
  timestamp: new Date().toISOString()
40376
40463
  };
40377
40464
  try {
40378
- fs13.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
40465
+ fs14.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
40379
40466
  `);
40380
40467
  } catch (error93) {
40381
40468
  console.error("Failed to write rollback event:", error93 instanceof Error ? error93.message : String(error93));
@@ -40418,11 +40505,11 @@ async function handleSimulateCommand(directory, args) {
40418
40505
  ];
40419
40506
  const report = reportLines.filter(Boolean).join(`
40420
40507
  `);
40421
- const fs14 = await import("fs/promises");
40422
- const path24 = await import("path");
40423
- const reportPath = path24.join(directory, ".swarm", "simulate-report.md");
40424
- await fs14.mkdir(path24.dirname(reportPath), { recursive: true });
40425
- await fs14.writeFile(reportPath, report, "utf-8");
40508
+ const fs15 = await import("fs/promises");
40509
+ const path25 = await import("path");
40510
+ const reportPath = path25.join(directory, ".swarm", "simulate-report.md");
40511
+ await fs15.mkdir(path25.dirname(reportPath), { recursive: true });
40512
+ await fs15.writeFile(reportPath, report, "utf-8");
40426
40513
  return `${darkMatterPairs.length} hidden coupling pairs detected`;
40427
40514
  }
40428
40515
 
@@ -40904,18 +40991,18 @@ function resolveCommand(tokens) {
40904
40991
  }
40905
40992
 
40906
40993
  // src/cli/index.ts
40907
- var CONFIG_DIR = path24.join(process.env.XDG_CONFIG_HOME || path24.join(os5.homedir(), ".config"), "opencode");
40908
- var OPENCODE_CONFIG_PATH = path24.join(CONFIG_DIR, "opencode.json");
40909
- var PLUGIN_CONFIG_PATH = path24.join(CONFIG_DIR, "opencode-swarm.json");
40910
- var PROMPTS_DIR = path24.join(CONFIG_DIR, "opencode-swarm");
40994
+ var CONFIG_DIR = path25.join(process.env.XDG_CONFIG_HOME || path25.join(os5.homedir(), ".config"), "opencode");
40995
+ var OPENCODE_CONFIG_PATH = path25.join(CONFIG_DIR, "opencode.json");
40996
+ var PLUGIN_CONFIG_PATH = path25.join(CONFIG_DIR, "opencode-swarm.json");
40997
+ var PROMPTS_DIR = path25.join(CONFIG_DIR, "opencode-swarm");
40911
40998
  function ensureDir(dir) {
40912
- if (!fs14.existsSync(dir)) {
40913
- fs14.mkdirSync(dir, { recursive: true });
40999
+ if (!fs15.existsSync(dir)) {
41000
+ fs15.mkdirSync(dir, { recursive: true });
40914
41001
  }
40915
41002
  }
40916
41003
  function loadJson(filepath) {
40917
41004
  try {
40918
- const content = fs14.readFileSync(filepath, "utf-8");
41005
+ const content = fs15.readFileSync(filepath, "utf-8");
40919
41006
  const stripped = content.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (match, comment) => comment ? "" : match).replace(/,(\s*[}\]])/g, "$1");
40920
41007
  return JSON.parse(stripped);
40921
41008
  } catch {
@@ -40923,7 +41010,7 @@ function loadJson(filepath) {
40923
41010
  }
40924
41011
  }
40925
41012
  function saveJson(filepath, data) {
40926
- fs14.writeFileSync(filepath, `${JSON.stringify(data, null, 2)}
41013
+ fs15.writeFileSync(filepath, `${JSON.stringify(data, null, 2)}
40927
41014
  `, "utf-8");
40928
41015
  }
40929
41016
  async function install() {
@@ -40931,7 +41018,7 @@ async function install() {
40931
41018
  `);
40932
41019
  ensureDir(CONFIG_DIR);
40933
41020
  ensureDir(PROMPTS_DIR);
40934
- const LEGACY_CONFIG_PATH = path24.join(CONFIG_DIR, "config.json");
41021
+ const LEGACY_CONFIG_PATH = path25.join(CONFIG_DIR, "config.json");
40935
41022
  let opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
40936
41023
  if (!opencodeConfig) {
40937
41024
  const legacyConfig = loadJson(LEGACY_CONFIG_PATH);
@@ -40956,7 +41043,7 @@ async function install() {
40956
41043
  saveJson(OPENCODE_CONFIG_PATH, opencodeConfig);
40957
41044
  console.log("\u2713 Added opencode-swarm to OpenCode plugins");
40958
41045
  console.log("\u2713 Disabled default OpenCode agents (explore, general)");
40959
- if (!fs14.existsSync(PLUGIN_CONFIG_PATH)) {
41046
+ if (!fs15.existsSync(PLUGIN_CONFIG_PATH)) {
40960
41047
  const defaultConfig = {
40961
41048
  agents: {
40962
41049
  coder: { model: "opencode/minimax-m2.5-free" },
@@ -40999,7 +41086,7 @@ async function uninstall() {
40999
41086
  `);
41000
41087
  const opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
41001
41088
  if (!opencodeConfig) {
41002
- if (fs14.existsSync(OPENCODE_CONFIG_PATH)) {
41089
+ if (fs15.existsSync(OPENCODE_CONFIG_PATH)) {
41003
41090
  console.log(`\u2717 Could not parse opencode config at: ${OPENCODE_CONFIG_PATH}`);
41004
41091
  return 1;
41005
41092
  } else {
@@ -41031,13 +41118,13 @@ async function uninstall() {
41031
41118
  console.log("\u2713 Re-enabled default OpenCode agents (explore, general)");
41032
41119
  if (process.argv.includes("--clean")) {
41033
41120
  let cleaned = false;
41034
- if (fs14.existsSync(PLUGIN_CONFIG_PATH)) {
41035
- fs14.unlinkSync(PLUGIN_CONFIG_PATH);
41121
+ if (fs15.existsSync(PLUGIN_CONFIG_PATH)) {
41122
+ fs15.unlinkSync(PLUGIN_CONFIG_PATH);
41036
41123
  console.log(`\u2713 Removed plugin config: ${PLUGIN_CONFIG_PATH}`);
41037
41124
  cleaned = true;
41038
41125
  }
41039
- if (fs14.existsSync(PROMPTS_DIR)) {
41040
- fs14.rmSync(PROMPTS_DIR, { recursive: true });
41126
+ if (fs15.existsSync(PROMPTS_DIR)) {
41127
+ fs15.rmSync(PROMPTS_DIR, { recursive: true });
41041
41128
  console.log(`\u2713 Removed custom prompts: ${PROMPTS_DIR}`);
41042
41129
  cleaned = true;
41043
41130
  }