opencode-swarm 6.27.1 → 6.28.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
@@ -32989,7 +32989,15 @@ function detectAdditionalLinter(cwd) {
32989
32989
  return "rubocop";
32990
32990
  return null;
32991
32991
  }
32992
- async function detectAvailableLinter() {
32992
+ async function detectAvailableLinter(directory) {
32993
+ const DETECT_TIMEOUT = 2000;
32994
+ const projectDir = directory ?? process.cwd();
32995
+ const isWindows = process.platform === "win32";
32996
+ const biomeBin = isWindows ? path11.join(projectDir, "node_modules", ".bin", "biome.EXE") : path11.join(projectDir, "node_modules", ".bin", "biome");
32997
+ const eslintBin = isWindows ? path11.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path11.join(projectDir, "node_modules", ".bin", "eslint");
32998
+ return _detectAvailableLinter(projectDir, biomeBin, eslintBin);
32999
+ }
33000
+ async function _detectAvailableLinter(projectDir, biomeBin, eslintBin) {
32993
33001
  const DETECT_TIMEOUT = 2000;
32994
33002
  try {
32995
33003
  const biomeProc = Bun.spawn(["npx", "biome", "--version"], {
@@ -33001,7 +33009,7 @@ async function detectAvailableLinter() {
33001
33009
  const result = await Promise.race([biomeExit, timeout]);
33002
33010
  if (result === "timeout") {
33003
33011
  biomeProc.kill();
33004
- } else if (biomeProc.exitCode === 0) {
33012
+ } else if (biomeProc.exitCode === 0 && fs3.existsSync(biomeBin)) {
33005
33013
  return "biome";
33006
33014
  }
33007
33015
  } catch {}
@@ -33015,7 +33023,7 @@ async function detectAvailableLinter() {
33015
33023
  const result = await Promise.race([eslintExit, timeout]);
33016
33024
  if (result === "timeout") {
33017
33025
  eslintProc.kill();
33018
- } else if (eslintProc.exitCode === 0) {
33026
+ } else if (eslintProc.exitCode === 0 && fs3.existsSync(eslintBin)) {
33019
33027
  return "eslint";
33020
33028
  }
33021
33029
  } catch {}
@@ -33161,7 +33169,7 @@ var lint = createSwarmTool({
33161
33169
  }
33162
33170
  const { mode } = args;
33163
33171
  const cwd = directory;
33164
- const linter = await detectAvailableLinter();
33172
+ const linter = await detectAvailableLinter(directory);
33165
33173
  if (linter) {
33166
33174
  const result = await runLint(linter, mode, directory);
33167
33175
  return JSON.stringify(result, null, 2);
package/dist/index.js CHANGED
@@ -33386,7 +33386,15 @@ function detectAdditionalLinter(cwd) {
33386
33386
  return "rubocop";
33387
33387
  return null;
33388
33388
  }
33389
- async function detectAvailableLinter() {
33389
+ async function detectAvailableLinter(directory) {
33390
+ const DETECT_TIMEOUT = 2000;
33391
+ const projectDir = directory ?? process.cwd();
33392
+ const isWindows = process.platform === "win32";
33393
+ const biomeBin = isWindows ? path21.join(projectDir, "node_modules", ".bin", "biome.EXE") : path21.join(projectDir, "node_modules", ".bin", "biome");
33394
+ const eslintBin = isWindows ? path21.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path21.join(projectDir, "node_modules", ".bin", "eslint");
33395
+ return _detectAvailableLinter(projectDir, biomeBin, eslintBin);
33396
+ }
33397
+ async function _detectAvailableLinter(projectDir, biomeBin, eslintBin) {
33390
33398
  const DETECT_TIMEOUT = 2000;
33391
33399
  try {
33392
33400
  const biomeProc = Bun.spawn(["npx", "biome", "--version"], {
@@ -33398,7 +33406,7 @@ async function detectAvailableLinter() {
33398
33406
  const result = await Promise.race([biomeExit, timeout]);
33399
33407
  if (result === "timeout") {
33400
33408
  biomeProc.kill();
33401
- } else if (biomeProc.exitCode === 0) {
33409
+ } else if (biomeProc.exitCode === 0 && fs9.existsSync(biomeBin)) {
33402
33410
  return "biome";
33403
33411
  }
33404
33412
  } catch {}
@@ -33412,7 +33420,7 @@ async function detectAvailableLinter() {
33412
33420
  const result = await Promise.race([eslintExit, timeout]);
33413
33421
  if (result === "timeout") {
33414
33422
  eslintProc.kill();
33415
- } else if (eslintProc.exitCode === 0) {
33423
+ } else if (eslintProc.exitCode === 0 && fs9.existsSync(eslintBin)) {
33416
33424
  return "eslint";
33417
33425
  }
33418
33426
  } catch {}
@@ -33564,7 +33572,7 @@ var init_lint = __esm(() => {
33564
33572
  }
33565
33573
  const { mode } = args2;
33566
33574
  const cwd = directory;
33567
- const linter = await detectAvailableLinter();
33575
+ const linter = await detectAvailableLinter(directory);
33568
33576
  if (linter) {
33569
33577
  const result = await runLint(linter, mode, directory);
33570
33578
  return JSON.stringify(result, null, 2);
@@ -40332,11 +40340,11 @@ INPUT: [provide the complete plan content below]
40332
40340
  CONSTRAINT: Write EXACTLY the content provided. Do not modify, summarize, or interpret.
40333
40341
 
40334
40342
  TASK GRANULARITY RULES:
40335
- - SMALL task: 1 file, 1 function/class/component, 1 logical concern. Delegate as-is.
40336
- - MEDIUM task: If it touches >1 file, SPLIT into sequential file-scoped subtasks before writing to plan.
40337
- - LARGE task: MUST be decomposed before writing to plan. A LARGE task in the plan is a planning error.
40338
- - Litmus test: If you cannot write TASK + FILE + constraint in 3 bullet points, the task is too large. Split it.
40339
- - NEVER write a task with compound verbs: "implement X and add Y and update Z" = 3 tasks, not 1. Split before writing to plan.
40343
+ - SMALL task: 1-2 files, 1 logical concern. Delegate as-is.
40344
+ - MEDIUM task: 3-5 files within a single logical concern (e.g., implementation + test + type update). Delegate as-is.
40345
+ - LARGE task: 6+ files OR multiple unrelated concerns. SPLIT into logical units (not per-file) before writing to plan.
40346
+ - Litmus test: If the task has ONE clear purpose and the coder can hold the full context, it's fine. Split only when concerns are unrelated.
40347
+ - Compound verbs are OK when they describe a single logical change: "add validation to handler and update its test" = 1 task. "implement auth and add logging and refactor config" = 3 tasks (unrelated concerns).
40340
40348
  - Coder receives ONE task. You make ALL scope decisions in the plan. Coder makes zero scope decisions.
40341
40349
 
40342
40350
  PHASE COUNT GUIDANCE:
@@ -40815,7 +40823,7 @@ REVIEW CHECKLIST:
40815
40823
  - Dependencies: Are task dependencies correct? Will ordering work?
40816
40824
  - Risk: Are high-risk changes identified? Is there a rollback path?
40817
40825
  - AI-Slop Detection: Does the plan contain vague filler ("robust", "comprehensive", "leverage") without concrete specifics?
40818
- - Task Atomicity: Does any single task touch 2+ files or contain compound verbs ("implement X and add Y and update Z")? Flag as MAJOR \u2014 oversized tasks blow coder's context and cause downstream gate failures. Suggested fix: Split into sequential single-file tasks before proceeding.
40826
+ - Task Atomicity: Does any single task touch 6+ files or mix unrelated concerns ("implement auth and add logging and refactor config")? Flag as MAJOR \u2014 oversized tasks blow coder's context and cause downstream gate failures. Suggested fix: Split into logical units grouped by concern, not per-file subtasks.
40819
40827
  - Governance Compliance (conditional): If \`.swarm/context.md\` contains a \`## Project Governance\` section, read the MUST and SHOULD rules and validate the plan against them. MUST rule violations are CRITICAL severity. SHOULD rule violations are recommendation-level (note them but do not block approval). If no \`## Project Governance\` section exists in context.md, skip this check silently.
40820
40828
 
40821
40829
  ## PLAN ASSESSMENT DIMENSIONS
@@ -49557,7 +49565,8 @@ function createDelegationGateHook(config3, directory) {
49557
49565
  }
49558
49566
  }
49559
49567
  if (typeof subagentType === "string") {
49560
- const evidenceTaskId = getEvidenceTaskId(session, directory);
49568
+ const rawTaskId = directArgs?.task_id;
49569
+ const evidenceTaskId = typeof rawTaskId === "string" && rawTaskId.length <= 20 && /^\d+\.\d+$/.test(rawTaskId.trim()) ? rawTaskId.trim() : getEvidenceTaskId(session, directory);
49561
49570
  if (evidenceTaskId) {
49562
49571
  try {
49563
49572
  const turbo = hasActiveTurboMode();
@@ -49676,7 +49685,8 @@ function createDelegationGateHook(config3, directory) {
49676
49685
  }
49677
49686
  }
49678
49687
  {
49679
- const evidenceTaskId = getEvidenceTaskId(session, directory);
49688
+ const rawTaskId = directArgs?.task_id;
49689
+ const evidenceTaskId = typeof rawTaskId === "string" && rawTaskId.length <= 20 && /^\d+\.\d+$/.test(rawTaskId.trim()) ? rawTaskId.trim() : getEvidenceTaskId(session, directory);
49680
49690
  if (evidenceTaskId) {
49681
49691
  try {
49682
49692
  const turbo = hasActiveTurboMode();
@@ -52273,7 +52283,7 @@ function isWriteToEvidenceFile(input) {
52273
52283
  const rawFile = record3.file;
52274
52284
  const pathField = typeof rawPath === "string" ? rawPath.replace(/\\/g, "/") : undefined;
52275
52285
  const fileField = typeof rawFile === "string" ? rawFile.replace(/\\/g, "/") : undefined;
52276
- const evidenceRegex = /\.swarm\/evidence\/retro-[^/]+\/evidence\.json$/;
52286
+ const evidenceRegex = /\.swarm\/+evidence\/+/i;
52277
52287
  if (typeof pathField === "string" && evidenceRegex.test(pathField)) {
52278
52288
  return true;
52279
52289
  }
@@ -59157,7 +59167,7 @@ async function runWithTimeout(promise3, timeoutMs) {
59157
59167
  async function runLintWrapped(files, directory, _config) {
59158
59168
  const start2 = process.hrtime.bigint();
59159
59169
  try {
59160
- const linter = await detectAvailableLinter();
59170
+ const linter = await detectAvailableLinter(directory);
59161
59171
  if (!linter) {
59162
59172
  return {
59163
59173
  ran: false,
@@ -40,7 +40,13 @@ export declare function getAdditionalLinterCommand(linter: AdditionalLinter, mod
40
40
  * Returns null when no additional linter is detected or its binary is unavailable.
41
41
  */
42
42
  export declare function detectAdditionalLinter(cwd: string): 'ruff' | 'clippy' | 'golangci-lint' | 'checkstyle' | 'ktlint' | 'dotnet-format' | 'cppcheck' | 'swiftlint' | 'dart-analyze' | 'rubocop' | null;
43
- export declare function detectAvailableLinter(): Promise<SupportedLinter | null>;
43
+ /** Compute the local biome binary path for a given project directory. */
44
+ export declare function getBiomeBinPath(directory: string): string;
45
+ /** Compute the local eslint binary path for a given project directory. */
46
+ export declare function getEslintBinPath(directory: string): string;
47
+ export declare function detectAvailableLinter(directory?: string): Promise<SupportedLinter | null>;
48
+ /** Internal implementation — accepts pre-computed binary paths for testability. */
49
+ export declare function _detectAvailableLinter(projectDir: string, biomeBin: string, eslintBin: string): Promise<SupportedLinter | null>;
44
50
  export declare function runLint(linter: SupportedLinter, mode: 'fix' | 'check', directory: string): Promise<LintResult>;
45
51
  /**
46
52
  * Run an additional (non-JS/TS) linter.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "6.27.1",
3
+ "version": "6.28.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",