opencode-swarm 6.44.0 → 6.44.1

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
@@ -37327,8 +37327,31 @@ function detectAdditionalLinter(cwd) {
37327
37327
  return "rubocop";
37328
37328
  return null;
37329
37329
  }
37330
+ function findBinInAncestors(startDir, binName) {
37331
+ let dir = startDir;
37332
+ while (true) {
37333
+ const candidate = path19.join(dir, "node_modules", ".bin", binName);
37334
+ if (fs9.existsSync(candidate))
37335
+ return candidate;
37336
+ const parent = path19.dirname(dir);
37337
+ if (parent === dir)
37338
+ break;
37339
+ dir = parent;
37340
+ }
37341
+ return null;
37342
+ }
37343
+ function findBinInEnvPath(binName) {
37344
+ const searchPath = process.env.PATH ?? "";
37345
+ for (const dir of searchPath.split(path19.delimiter)) {
37346
+ if (!dir)
37347
+ continue;
37348
+ const candidate = path19.join(dir, binName);
37349
+ if (fs9.existsSync(candidate))
37350
+ return candidate;
37351
+ }
37352
+ return null;
37353
+ }
37330
37354
  async function detectAvailableLinter(directory) {
37331
- const _DETECT_TIMEOUT = 2000;
37332
37355
  if (!directory)
37333
37356
  return null;
37334
37357
  if (!fs9.existsSync(directory))
@@ -37337,7 +37360,20 @@ async function detectAvailableLinter(directory) {
37337
37360
  const isWindows = process.platform === "win32";
37338
37361
  const biomeBin = isWindows ? path19.join(projectDir, "node_modules", ".bin", "biome.EXE") : path19.join(projectDir, "node_modules", ".bin", "biome");
37339
37362
  const eslintBin = isWindows ? path19.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path19.join(projectDir, "node_modules", ".bin", "eslint");
37340
- return _detectAvailableLinter(projectDir, biomeBin, eslintBin);
37363
+ const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
37364
+ if (localResult)
37365
+ return localResult;
37366
+ const biomeAncestor = findBinInAncestors(path19.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
37367
+ const eslintAncestor = findBinInAncestors(path19.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
37368
+ if (biomeAncestor || eslintAncestor) {
37369
+ return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
37370
+ }
37371
+ const pathBiome = findBinInEnvPath(isWindows ? "biome.EXE" : "biome");
37372
+ const pathEslint = findBinInEnvPath(isWindows ? "eslint.cmd" : "eslint");
37373
+ if (pathBiome || pathEslint) {
37374
+ return _detectAvailableLinter(projectDir, pathBiome ?? biomeBin, pathEslint ?? eslintBin);
37375
+ }
37376
+ return null;
37341
37377
  }
37342
37378
  async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
37343
37379
  const DETECT_TIMEOUT = 2000;
@@ -38499,7 +38535,7 @@ function getTestFilesFromConvention(sourceFiles) {
38499
38535
  for (const file3 of sourceFiles) {
38500
38536
  const normalizedPath = file3.replace(/\\/g, "/");
38501
38537
  const basename4 = path22.basename(file3);
38502
- const dirname9 = path22.dirname(file3);
38538
+ const dirname10 = path22.dirname(file3);
38503
38539
  if (hasCompoundTestExtension(basename4) || basename4.includes(".spec.") || basename4.includes(".test.") || normalizedPath.includes("/__tests__/") || normalizedPath.includes("/tests/") || normalizedPath.includes("/test/")) {
38504
38540
  if (!testFiles.includes(file3)) {
38505
38541
  testFiles.push(file3);
@@ -38510,11 +38546,11 @@ function getTestFilesFromConvention(sourceFiles) {
38510
38546
  const nameWithoutExt = basename4.replace(/\.[^.]+$/, "");
38511
38547
  const ext = path22.extname(basename4);
38512
38548
  const possibleTestFiles = [
38513
- path22.join(dirname9, `${nameWithoutExt}.spec${ext}`),
38514
- path22.join(dirname9, `${nameWithoutExt}.test${ext}`),
38515
- path22.join(dirname9, "__tests__", `${nameWithoutExt}${ext}`),
38516
- path22.join(dirname9, "tests", `${nameWithoutExt}${ext}`),
38517
- path22.join(dirname9, "test", `${nameWithoutExt}${ext}`)
38549
+ path22.join(dirname10, `${nameWithoutExt}.spec${ext}`),
38550
+ path22.join(dirname10, `${nameWithoutExt}.test${ext}`),
38551
+ path22.join(dirname10, "__tests__", `${nameWithoutExt}${ext}`),
38552
+ path22.join(dirname10, "tests", `${nameWithoutExt}${ext}`),
38553
+ path22.join(dirname10, "test", `${nameWithoutExt}${ext}`)
38518
38554
  ];
38519
38555
  for (const testFile of possibleTestFiles) {
38520
38556
  if (fs12.existsSync(testFile) && !testFiles.includes(testFile)) {
package/dist/index.js CHANGED
@@ -35010,8 +35010,45 @@ function detectAdditionalLinter(cwd) {
35010
35010
  return "rubocop";
35011
35011
  return null;
35012
35012
  }
35013
+ function resolveLinterBinPath(linter, projectDir) {
35014
+ const isWindows = process.platform === "win32";
35015
+ const binName = linter === "biome" ? isWindows ? "biome.EXE" : "biome" : isWindows ? "eslint.cmd" : "eslint";
35016
+ const localBin = path26.join(projectDir, "node_modules", ".bin", binName);
35017
+ if (fs15.existsSync(localBin))
35018
+ return localBin;
35019
+ const ancestor = findBinInAncestors(path26.dirname(projectDir), binName);
35020
+ if (ancestor)
35021
+ return ancestor;
35022
+ const fromPath = findBinInEnvPath(binName);
35023
+ if (fromPath)
35024
+ return fromPath;
35025
+ return localBin;
35026
+ }
35027
+ function findBinInAncestors(startDir, binName) {
35028
+ let dir = startDir;
35029
+ while (true) {
35030
+ const candidate = path26.join(dir, "node_modules", ".bin", binName);
35031
+ if (fs15.existsSync(candidate))
35032
+ return candidate;
35033
+ const parent = path26.dirname(dir);
35034
+ if (parent === dir)
35035
+ break;
35036
+ dir = parent;
35037
+ }
35038
+ return null;
35039
+ }
35040
+ function findBinInEnvPath(binName) {
35041
+ const searchPath = process.env.PATH ?? "";
35042
+ for (const dir of searchPath.split(path26.delimiter)) {
35043
+ if (!dir)
35044
+ continue;
35045
+ const candidate = path26.join(dir, binName);
35046
+ if (fs15.existsSync(candidate))
35047
+ return candidate;
35048
+ }
35049
+ return null;
35050
+ }
35013
35051
  async function detectAvailableLinter(directory) {
35014
- const _DETECT_TIMEOUT = 2000;
35015
35052
  if (!directory)
35016
35053
  return null;
35017
35054
  if (!fs15.existsSync(directory))
@@ -35020,7 +35057,20 @@ async function detectAvailableLinter(directory) {
35020
35057
  const isWindows = process.platform === "win32";
35021
35058
  const biomeBin = isWindows ? path26.join(projectDir, "node_modules", ".bin", "biome.EXE") : path26.join(projectDir, "node_modules", ".bin", "biome");
35022
35059
  const eslintBin = isWindows ? path26.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path26.join(projectDir, "node_modules", ".bin", "eslint");
35023
- return _detectAvailableLinter(projectDir, biomeBin, eslintBin);
35060
+ const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
35061
+ if (localResult)
35062
+ return localResult;
35063
+ const biomeAncestor = findBinInAncestors(path26.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
35064
+ const eslintAncestor = findBinInAncestors(path26.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
35065
+ if (biomeAncestor || eslintAncestor) {
35066
+ return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
35067
+ }
35068
+ const pathBiome = findBinInEnvPath(isWindows ? "biome.EXE" : "biome");
35069
+ const pathEslint = findBinInEnvPath(isWindows ? "eslint.cmd" : "eslint");
35070
+ if (pathBiome || pathEslint) {
35071
+ return _detectAvailableLinter(projectDir, pathBiome ?? biomeBin, pathEslint ?? eslintBin);
35072
+ }
35073
+ return null;
35024
35074
  }
35025
35075
  async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
35026
35076
  const DETECT_TIMEOUT = 2000;
@@ -36160,7 +36210,7 @@ function getTestFilesFromConvention(sourceFiles) {
36160
36210
  for (const file3 of sourceFiles) {
36161
36211
  const normalizedPath = file3.replace(/\\/g, "/");
36162
36212
  const basename4 = path29.basename(file3);
36163
- const dirname11 = path29.dirname(file3);
36213
+ const dirname12 = path29.dirname(file3);
36164
36214
  if (hasCompoundTestExtension(basename4) || basename4.includes(".spec.") || basename4.includes(".test.") || normalizedPath.includes("/__tests__/") || normalizedPath.includes("/tests/") || normalizedPath.includes("/test/")) {
36165
36215
  if (!testFiles.includes(file3)) {
36166
36216
  testFiles.push(file3);
@@ -36171,11 +36221,11 @@ function getTestFilesFromConvention(sourceFiles) {
36171
36221
  const nameWithoutExt = basename4.replace(/\.[^.]+$/, "");
36172
36222
  const ext = path29.extname(basename4);
36173
36223
  const possibleTestFiles = [
36174
- path29.join(dirname11, `${nameWithoutExt}.spec${ext}`),
36175
- path29.join(dirname11, `${nameWithoutExt}.test${ext}`),
36176
- path29.join(dirname11, "__tests__", `${nameWithoutExt}${ext}`),
36177
- path29.join(dirname11, "tests", `${nameWithoutExt}${ext}`),
36178
- path29.join(dirname11, "test", `${nameWithoutExt}${ext}`)
36224
+ path29.join(dirname12, `${nameWithoutExt}.spec${ext}`),
36225
+ path29.join(dirname12, `${nameWithoutExt}.test${ext}`),
36226
+ path29.join(dirname12, "__tests__", `${nameWithoutExt}${ext}`),
36227
+ path29.join(dirname12, "tests", `${nameWithoutExt}${ext}`),
36228
+ path29.join(dirname12, "test", `${nameWithoutExt}${ext}`)
36179
36229
  ];
36180
36230
  for (const testFile of possibleTestFiles) {
36181
36231
  if (fs18.existsSync(testFile) && !testFiles.includes(testFile)) {
@@ -45688,10 +45738,7 @@ class PlanSyncWorker {
45688
45738
  lastStat = null;
45689
45739
  disposed = false;
45690
45740
  constructor(options = {}) {
45691
- if (!options.directory) {
45692
- throw new Error("[plan-sync-worker] No directory provided - options.directory is required");
45693
- }
45694
- this.directory = options.directory;
45741
+ this.directory = options.directory ?? "";
45695
45742
  this.debounceMs = options.debounceMs ?? 300;
45696
45743
  this.pollIntervalMs = options.pollIntervalMs ?? 2000;
45697
45744
  this.syncTimeoutMs = options.syncTimeoutMs ?? 30000;
@@ -45708,6 +45755,10 @@ class PlanSyncWorker {
45708
45755
  log("[PlanSyncWorker] Cannot start - worker has been disposed");
45709
45756
  return;
45710
45757
  }
45758
+ if (!this.directory) {
45759
+ log("[PlanSyncWorker] Cannot start - no directory provided");
45760
+ return;
45761
+ }
45711
45762
  if (this.status === "running" || this.status === "starting") {
45712
45763
  log("[PlanSyncWorker] Already running or starting");
45713
45764
  return;
@@ -45715,10 +45766,8 @@ class PlanSyncWorker {
45715
45766
  this.status = "starting";
45716
45767
  log("[PlanSyncWorker] Starting...");
45717
45768
  this.initializeStat();
45718
- if (!this.setupNativeWatcher()) {
45719
- log("[PlanSyncWorker] Native watch unavailable, using polling fallback");
45720
- this.setupPolling();
45721
- }
45769
+ this.setupPolling();
45770
+ this.setupNativeWatcher();
45722
45771
  this.status = "running";
45723
45772
  log("[PlanSyncWorker] Started watching for plan.json changes");
45724
45773
  }
@@ -53417,7 +53466,7 @@ function createGuardrailsHooks(directory, directoryOrConfig, config3) {
53417
53466
  const delegTargetPath = delegArgs?.filePath ?? delegArgs?.path ?? delegArgs?.file ?? delegArgs?.target;
53418
53467
  if (typeof delegTargetPath === "string" && delegTargetPath.length > 0) {
53419
53468
  const agentName = swarmState.activeAgent.get(sessionID) ?? "unknown";
53420
- const cwd = directory ?? process.cwd();
53469
+ const cwd = effectiveDirectory;
53421
53470
  const authorityCheck = checkFileAuthority(agentName, delegTargetPath, cwd);
53422
53471
  if (!authorityCheck.allowed) {
53423
53472
  throw new Error(`WRITE BLOCKED: Agent "${agentName}" is not authorised to write "${delegTargetPath}". Reason: ${authorityCheck.reason}`);
@@ -65217,8 +65266,6 @@ async function runLintWrapped(files, directory, _config) {
65217
65266
  }
65218
65267
  }
65219
65268
  async function runLintOnFiles(linter, files, workspaceDir) {
65220
- const isWindows = process.platform === "win32";
65221
- const binDir = path60.join(workspaceDir, "node_modules", ".bin");
65222
65269
  const validatedFiles = [];
65223
65270
  for (const file3 of files) {
65224
65271
  if (typeof file3 !== "string") {
@@ -65240,13 +65287,12 @@ async function runLintOnFiles(linter, files, workspaceDir) {
65240
65287
  error: "No valid files after security validation"
65241
65288
  };
65242
65289
  }
65290
+ const resolvedBin = resolveLinterBinPath(linter, workspaceDir);
65243
65291
  let command;
65244
65292
  if (linter === "biome") {
65245
- const biomeBin = isWindows ? path60.join(binDir, "biome.EXE") : path60.join(binDir, "biome");
65246
- command = [biomeBin, "check", ...validatedFiles];
65293
+ command = [resolvedBin, "check", ...validatedFiles];
65247
65294
  } else {
65248
- const eslintBin = isWindows ? path60.join(binDir, "eslint.cmd") : path60.join(binDir, "eslint");
65249
- command = [eslintBin, ...validatedFiles];
65295
+ command = [resolvedBin, ...validatedFiles];
65250
65296
  }
65251
65297
  try {
65252
65298
  const proc = Bun.spawn(command, {
@@ -68339,7 +68385,7 @@ function checkReviewerGate(taskId, workingDirectory) {
68339
68385
  }
68340
68386
  } catch {}
68341
68387
  }
68342
- const resolvedDir = workingDirectory;
68388
+ const resolvedDir = workingDirectory ?? process.cwd();
68343
68389
  try {
68344
68390
  const evidence = readTaskEvidenceRaw(resolvedDir, taskId);
68345
68391
  if (evidence === null) {} else if (evidence.required_gates && Array.isArray(evidence.required_gates) && evidence.gates) {
@@ -41,6 +41,14 @@ export declare function getAdditionalLinterCommand(linter: AdditionalLinter, mod
41
41
  export declare function detectAdditionalLinter(cwd: string): 'ruff' | 'clippy' | 'golangci-lint' | 'checkstyle' | 'ktlint' | 'dotnet-format' | 'cppcheck' | 'swiftlint' | 'dart-analyze' | 'rubocop' | null;
42
42
  /** Compute the local biome binary path for a given project directory. */
43
43
  export declare function getBiomeBinPath(directory: string): string;
44
+ /**
45
+ * Resolve the binary path for a linter, using the same hierarchy as detectAvailableLinter:
46
+ * 1. Local node_modules/.bin
47
+ * 2. Ancestor node_modules/.bin (monorepo)
48
+ * 3. process.env.PATH scan
49
+ * 4. Local path as fallback (may not exist)
50
+ */
51
+ export declare function resolveLinterBinPath(linter: SupportedLinter, projectDir: string): string;
44
52
  /** Compute the local eslint binary path for a given project directory. */
45
53
  export declare function getEslintBinPath(directory: string): string;
46
54
  export declare function detectAvailableLinter(directory?: string): Promise<SupportedLinter | null>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "6.44.0",
3
+ "version": "6.44.1",
4
4
  "description": "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",