opencode-swarm 6.75.0 → 6.77.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
@@ -19414,7 +19414,12 @@ var CouncilConfigSchema = exports_external.object({
19414
19414
  var ParallelizationConfigSchema = exports_external.object({
19415
19415
  enabled: exports_external.boolean().default(false),
19416
19416
  maxConcurrentTasks: exports_external.number().int().min(1).max(64).default(1),
19417
- evidenceLockTimeoutMs: exports_external.number().int().min(1000).max(300000).default(60000)
19417
+ evidenceLockTimeoutMs: exports_external.number().int().min(1000).max(300000).default(60000),
19418
+ stageB: exports_external.object({
19419
+ parallel: exports_external.object({
19420
+ enabled: exports_external.boolean().default(false)
19421
+ }).default({ enabled: false })
19422
+ }).default({ parallel: { enabled: false } })
19418
19423
  });
19419
19424
  var PluginConfigSchema = exports_external.object({
19420
19425
  agents: exports_external.record(exports_external.string(), AgentOverrideConfigSchema).optional(),
@@ -41276,18 +41281,12 @@ async function detectTestFramework(cwd) {
41276
41281
  return "minitest";
41277
41282
  return "none";
41278
41283
  }
41279
- var TEST_PATTERNS = [
41280
- { test: ".spec.", source: "." },
41281
- { test: ".test.", source: "." },
41282
- { test: "/__tests__/", source: "/" },
41283
- { test: "/tests/", source: "/" },
41284
- { test: "/test/", source: "/" }
41285
- ];
41286
41284
  var COMPOUND_TEST_EXTENSIONS = [
41287
41285
  ".test.ts",
41288
41286
  ".test.tsx",
41289
41287
  ".test.js",
41290
41288
  ".test.jsx",
41289
+ ".tests.ps1",
41291
41290
  ".spec.ts",
41292
41291
  ".spec.tsx",
41293
41292
  ".spec.js",
@@ -41295,51 +41294,149 @@ var COMPOUND_TEST_EXTENSIONS = [
41295
41294
  ".test.ps1",
41296
41295
  ".spec.ps1"
41297
41296
  ];
41297
+ var TEST_DIRECTORY_NAMES = ["__tests__", "tests", "test", "spec"];
41298
+ function isTestDirectoryPath(normalizedPath) {
41299
+ return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
41300
+ }
41301
+ function resolveWorkspacePath(file3, workingDir) {
41302
+ return path27.isAbsolute(file3) ? path27.resolve(file3) : path27.resolve(workingDir, file3);
41303
+ }
41304
+ function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
41305
+ if (!preferRelative)
41306
+ return absolutePath;
41307
+ return path27.relative(workingDir, absolutePath);
41308
+ }
41309
+ function dedupePush(target, value) {
41310
+ if (!target.includes(value)) {
41311
+ target.push(value);
41312
+ }
41313
+ }
41314
+ function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
41315
+ switch (ext) {
41316
+ case ".go":
41317
+ return [`${nameWithoutExt}_test.go`];
41318
+ case ".py":
41319
+ return [`test_${nameWithoutExt}.py`, `${nameWithoutExt}_test.py`];
41320
+ case ".rb":
41321
+ return [`${nameWithoutExt}_spec.rb`];
41322
+ case ".java":
41323
+ return [
41324
+ `${nameWithoutExt}Test.java`,
41325
+ `${nameWithoutExt}Tests.java`,
41326
+ `Test${nameWithoutExt}.java`,
41327
+ `${nameWithoutExt}IT.java`
41328
+ ];
41329
+ case ".cs":
41330
+ return [`${nameWithoutExt}Test.cs`, `${nameWithoutExt}Tests.cs`];
41331
+ case ".kt":
41332
+ return [
41333
+ `${nameWithoutExt}Test.kt`,
41334
+ `${nameWithoutExt}Tests.kt`,
41335
+ `Test${nameWithoutExt}.kt`
41336
+ ];
41337
+ case ".ps1":
41338
+ return [`${nameWithoutExt}.Tests.ps1`, `${nameWithoutExt}.tests.ps1`];
41339
+ default:
41340
+ return [];
41341
+ }
41342
+ }
41343
+ function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
41344
+ const relativeDir = path27.dirname(relativePath);
41345
+ const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
41346
+ const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
41347
+ const rootDir = path27.join(workingDir, dirName);
41348
+ return nestedRelativeDir ? [rootDir, path27.join(rootDir, nestedRelativeDir)] : [rootDir];
41349
+ });
41350
+ const normalizedRelativePath = relativePath.replace(/\\/g, "/");
41351
+ if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
41352
+ directories.push(path27.join(workingDir, "src/test/java", path27.dirname(normalizedRelativePath.slice("src/main/java/".length))));
41353
+ }
41354
+ if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
41355
+ directories.push(path27.join(workingDir, "src/test/kotlin", path27.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
41356
+ }
41357
+ return [...new Set(directories)];
41358
+ }
41298
41359
  function hasCompoundTestExtension(filename) {
41299
41360
  const lower = filename.toLowerCase();
41300
41361
  return COMPOUND_TEST_EXTENSIONS.some((ext) => lower.endsWith(ext));
41301
41362
  }
41302
- function getTestFilesFromConvention(sourceFiles) {
41363
+ function isLanguageSpecificTestFile(basename4) {
41364
+ const lower = basename4.toLowerCase();
41365
+ if (lower.endsWith("_test.go"))
41366
+ return true;
41367
+ if (lower.endsWith(".py") && (lower.startsWith("test_") || lower.endsWith("_test.py")))
41368
+ return true;
41369
+ if (lower.endsWith("_spec.rb"))
41370
+ return true;
41371
+ if (lower.endsWith(".java") && (/^Test[A-Z]/.test(basename4) || basename4.endsWith("Test.java") || basename4.endsWith("Tests.java") || lower.endsWith("it.java")))
41372
+ return true;
41373
+ if (lower.endsWith(".cs") && (lower.endsWith("test.cs") || lower.endsWith("tests.cs")))
41374
+ return true;
41375
+ if (lower.endsWith(".kt") && (/^Test[A-Z]/.test(basename4) || lower.endsWith("test.kt") || lower.endsWith("tests.kt")))
41376
+ return true;
41377
+ if (lower.endsWith(".tests.ps1"))
41378
+ return true;
41379
+ return false;
41380
+ }
41381
+ function isConventionTestFilePath(filePath) {
41382
+ const normalizedPath = filePath.replace(/\\/g, "/");
41383
+ const basename4 = path27.basename(filePath);
41384
+ return hasCompoundTestExtension(basename4) || basename4.includes(".spec.") || basename4.includes(".test.") || isLanguageSpecificTestFile(basename4) || isTestDirectoryPath(normalizedPath);
41385
+ }
41386
+ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
41303
41387
  const testFiles = [];
41304
41388
  for (const file3 of sourceFiles) {
41305
- const normalizedPath = file3.replace(/\\/g, "/");
41306
- const basename4 = path27.basename(file3);
41307
- const dirname11 = path27.dirname(file3);
41308
- if (hasCompoundTestExtension(basename4) || basename4.includes(".spec.") || basename4.includes(".test.") || normalizedPath.includes("/__tests__/") || normalizedPath.includes("/tests/") || normalizedPath.includes("/test/")) {
41309
- if (!testFiles.includes(file3)) {
41310
- testFiles.push(file3);
41311
- }
41389
+ const absoluteFile = resolveWorkspacePath(file3, workingDir);
41390
+ const relativeFile = path27.relative(workingDir, absoluteFile);
41391
+ const basename4 = path27.basename(absoluteFile);
41392
+ const dirname11 = path27.dirname(absoluteFile);
41393
+ const preferRelativeOutput = !path27.isAbsolute(file3);
41394
+ if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file3)) {
41395
+ dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
41312
41396
  continue;
41313
41397
  }
41314
- for (const _pattern of TEST_PATTERNS) {
41315
- const nameWithoutExt = basename4.replace(/\.[^.]+$/, "");
41316
- const ext = path27.extname(basename4);
41317
- const possibleTestFiles = [
41318
- path27.join(dirname11, `${nameWithoutExt}.spec${ext}`),
41319
- path27.join(dirname11, `${nameWithoutExt}.test${ext}`),
41320
- path27.join(dirname11, "__tests__", `${nameWithoutExt}${ext}`),
41321
- path27.join(dirname11, "tests", `${nameWithoutExt}${ext}`),
41322
- path27.join(dirname11, "test", `${nameWithoutExt}${ext}`)
41323
- ];
41324
- for (const testFile of possibleTestFiles) {
41325
- if (fs17.existsSync(testFile) && !testFiles.includes(testFile)) {
41326
- testFiles.push(testFile);
41327
- }
41398
+ const nameWithoutExt = basename4.replace(/\.[^.]+$/, "");
41399
+ const ext = path27.extname(basename4);
41400
+ const genericTestNames = [
41401
+ `${nameWithoutExt}.spec${ext}`,
41402
+ `${nameWithoutExt}.test${ext}`
41403
+ ];
41404
+ const languageSpecificTestNames = buildLanguageSpecificTestNames(nameWithoutExt, ext);
41405
+ const colocatedCandidates = [
41406
+ ...genericTestNames,
41407
+ ...languageSpecificTestNames
41408
+ ].map((candidateName) => path27.join(dirname11, candidateName));
41409
+ const testDirectoryNames = [
41410
+ basename4,
41411
+ ...genericTestNames,
41412
+ ...languageSpecificTestNames
41413
+ ];
41414
+ const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
41415
+ const possibleTestFiles = [
41416
+ ...colocatedCandidates,
41417
+ ...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path27.join(dirname11, dirName, candidateName))),
41418
+ ...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path27.join(candidateDir, candidateName)))
41419
+ ];
41420
+ for (const testFile of possibleTestFiles) {
41421
+ if (fs17.existsSync(testFile)) {
41422
+ dedupePush(testFiles, toWorkspaceOutputPath(testFile, workingDir, preferRelativeOutput));
41328
41423
  }
41329
41424
  }
41330
41425
  }
41331
41426
  return testFiles;
41332
41427
  }
41333
- async function getTestFilesFromGraph(sourceFiles) {
41428
+ async function getTestFilesFromGraph(sourceFiles, workingDir) {
41334
41429
  const testFiles = [];
41335
- const candidateTestFiles = getTestFilesFromConvention(sourceFiles);
41430
+ const absoluteSourceFiles = sourceFiles.map((sourceFile) => resolveWorkspacePath(sourceFile, workingDir));
41431
+ const candidateTestFiles = getTestFilesFromConvention(sourceFiles, workingDir);
41336
41432
  if (sourceFiles.length === 0) {
41337
41433
  return testFiles;
41338
41434
  }
41339
41435
  for (const testFile of candidateTestFiles) {
41340
41436
  try {
41341
- const content = fs17.readFileSync(testFile, "utf-8");
41342
- const testDir = path27.dirname(testFile);
41437
+ const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
41438
+ const content = fs17.readFileSync(absoluteTestFile, "utf-8");
41439
+ const testDir = path27.dirname(absoluteTestFile);
41343
41440
  const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
41344
41441
  let match;
41345
41442
  match = importRegex.exec(content);
@@ -41359,7 +41456,7 @@ async function getTestFilesFromGraph(sourceFiles) {
41359
41456
  ".cjs"
41360
41457
  ]) {
41361
41458
  const withExt = resolvedImport + extToTry;
41362
- if (sourceFiles.includes(withExt) || fs17.existsSync(withExt)) {
41459
+ if (absoluteSourceFiles.includes(withExt) || fs17.existsSync(withExt)) {
41363
41460
  resolvedImport = withExt;
41364
41461
  break;
41365
41462
  }
@@ -41370,14 +41467,12 @@ async function getTestFilesFromGraph(sourceFiles) {
41370
41467
  }
41371
41468
  const importBasename = path27.basename(resolvedImport, path27.extname(resolvedImport));
41372
41469
  const importDir = path27.dirname(resolvedImport);
41373
- for (const sourceFile of sourceFiles) {
41470
+ for (const sourceFile of absoluteSourceFiles) {
41374
41471
  const sourceDir = path27.dirname(sourceFile);
41375
41472
  const sourceBasename = path27.basename(sourceFile, path27.extname(sourceFile));
41376
- const isRelatedDir = importDir === sourceDir || importDir === path27.join(sourceDir, "__tests__") || importDir === path27.join(sourceDir, "tests") || importDir === path27.join(sourceDir, "test");
41473
+ const isRelatedDir = importDir === sourceDir || importDir === path27.join(sourceDir, "__tests__") || importDir === path27.join(sourceDir, "tests") || importDir === path27.join(sourceDir, "test") || importDir === path27.join(sourceDir, "spec");
41377
41474
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
41378
- if (!testFiles.includes(testFile)) {
41379
- testFiles.push(testFile);
41380
- }
41475
+ dedupePush(testFiles, testFile);
41381
41476
  break;
41382
41477
  }
41383
41478
  }
@@ -41400,7 +41495,7 @@ async function getTestFilesFromGraph(sourceFiles) {
41400
41495
  ".cjs"
41401
41496
  ]) {
41402
41497
  const withExt = resolvedImport + extToTry;
41403
- if (sourceFiles.includes(withExt) || fs17.existsSync(withExt)) {
41498
+ if (absoluteSourceFiles.includes(withExt) || fs17.existsSync(withExt)) {
41404
41499
  resolvedImport = withExt;
41405
41500
  break;
41406
41501
  }
@@ -41408,14 +41503,12 @@ async function getTestFilesFromGraph(sourceFiles) {
41408
41503
  }
41409
41504
  const importDir = path27.dirname(resolvedImport);
41410
41505
  const importBasename = path27.basename(resolvedImport, path27.extname(resolvedImport));
41411
- for (const sourceFile of sourceFiles) {
41506
+ for (const sourceFile of absoluteSourceFiles) {
41412
41507
  const sourceDir = path27.dirname(sourceFile);
41413
41508
  const sourceBasename = path27.basename(sourceFile, path27.extname(sourceFile));
41414
- const isRelatedDir = importDir === sourceDir || importDir === path27.join(sourceDir, "__tests__") || importDir === path27.join(sourceDir, "tests") || importDir === path27.join(sourceDir, "test");
41509
+ const isRelatedDir = importDir === sourceDir || importDir === path27.join(sourceDir, "__tests__") || importDir === path27.join(sourceDir, "tests") || importDir === path27.join(sourceDir, "test") || importDir === path27.join(sourceDir, "spec");
41415
41510
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
41416
- if (!testFiles.includes(testFile)) {
41417
- testFiles.push(testFile);
41418
- }
41511
+ dedupePush(testFiles, testFile);
41419
41512
  break;
41420
41513
  }
41421
41514
  }
@@ -41426,6 +41519,26 @@ async function getTestFilesFromGraph(sourceFiles) {
41426
41519
  }
41427
41520
  return testFiles;
41428
41521
  }
41522
+ function getTargetedExecutionUnsupportedReason(framework) {
41523
+ switch (framework) {
41524
+ case "go-test":
41525
+ return "go test targets packages, not individual test files";
41526
+ case "cargo":
41527
+ return "cargo test targets crates, targets, or test names rather than file paths";
41528
+ case "maven":
41529
+ return "maven test selection is class-based, not file-path based";
41530
+ case "gradle":
41531
+ return "gradle test selection is class-based, not file-path based";
41532
+ case "dotnet-test":
41533
+ return "dotnet test filters by fully qualified names, not file paths";
41534
+ case "ctest":
41535
+ return "ctest filters named tests from the build tree, not source test files";
41536
+ case "swift-test":
41537
+ return "swift test filters test names, not file paths";
41538
+ default:
41539
+ return null;
41540
+ }
41541
+ }
41429
41542
  function buildTestCommand(framework, scope, files, coverage, baseDir) {
41430
41543
  switch (framework) {
41431
41544
  case "bun": {
@@ -41520,10 +41633,19 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
41520
41633
  case "swift-test":
41521
41634
  return ["swift", "test"];
41522
41635
  case "dart-test":
41523
- return isCommandAvailable("flutter") ? ["flutter", "test"] : ["dart", "test"];
41524
- case "rspec":
41525
- return isCommandAvailable("bundle") ? ["bundle", "exec", "rspec"] : ["rspec"];
41636
+ return isCommandAvailable("flutter") ? ["flutter", "test", ...files] : ["dart", "test", ...files];
41637
+ case "rspec": {
41638
+ const args = isCommandAvailable("bundle") ? ["bundle", "exec", "rspec"] : ["rspec"];
41639
+ if (scope !== "all" && files.length > 0) {
41640
+ args.push(...files);
41641
+ }
41642
+ return args;
41643
+ }
41526
41644
  case "minitest":
41645
+ if (scope !== "all" && files.length > 0) {
41646
+ const requires = files.map((f) => `require_relative '${f.replace(/\\/g, "/").replace(/'/g, "\\'")}'`).join("; ");
41647
+ return ["ruby", "-Itest", "-e", requires];
41648
+ }
41527
41649
  return [
41528
41650
  "ruby",
41529
41651
  "-Itest",
@@ -41784,6 +41906,19 @@ async function readBoundedStream(stream, maxBytes) {
41784
41906
  return { text: decoder.decode(combined), truncated };
41785
41907
  }
41786
41908
  async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
41909
+ if (scope !== "all" && files.length > 0) {
41910
+ const unsupportedReason = getTargetedExecutionUnsupportedReason(framework);
41911
+ if (unsupportedReason) {
41912
+ return {
41913
+ success: false,
41914
+ framework,
41915
+ scope,
41916
+ error: `Framework "${framework}" does not support targeted test-file execution`,
41917
+ message: `The resolved test selection cannot be run safely because ${unsupportedReason}. Use a framework-native selector manually or let the architect handle the broader sweep.`,
41918
+ outcome: "error"
41919
+ };
41920
+ }
41921
+ }
41787
41922
  const command = buildTestCommand(framework, scope, files, coverage, cwd);
41788
41923
  if (!command) {
41789
41924
  return {
@@ -41988,10 +42123,10 @@ function analyzeFailures(workingDir) {
41988
42123
  return report;
41989
42124
  }
41990
42125
  var test_runner = createSwarmTool({
41991
- description: 'Run project tests with framework detection. Supports bun, vitest, jest, mocha, pytest, cargo, pester, go-test, maven, gradle, dotnet-test, ctest, swift-test, dart-test, rspec, and minitest. Returns deterministic normalized JSON with framework, scope, command, totals, coverage, duration, success status, and failures. Use scope "all" for full suite, "convention" to map source files to test files, "graph" to find related tests via imports, or "impact" to find tests covering changed files using test-impact analysis.',
42126
+ description: 'Run project tests with framework detection. Supports bun, vitest, jest, mocha, pytest, cargo, pester, go-test, maven, gradle, dotnet-test, ctest, swift-test, dart-test, rspec, and minitest. Returns deterministic normalized JSON with framework, scope, command, totals, coverage, duration, success status, and failures. Use scope "all" for full suite, "convention" to accept direct test files or map source files to test files, "graph" to find related tests via imports from source files, or "impact" to find tests covering changed source files using test-impact analysis.',
41992
42127
  args: {
41993
- scope: tool.schema.enum(["all", "convention", "graph", "impact"]).optional().describe('Test scope: "all" runs full suite, "convention" maps source files to test files by naming, "graph" finds related tests via imports, "impact" finds tests covering changed files via test-impact analysis'),
41994
- files: tool.schema.array(tool.schema.string()).optional().describe("Specific files to test (used with convention or graph scope)"),
42128
+ scope: tool.schema.enum(["all", "convention", "graph", "impact"]).optional().describe('Test scope: "all" runs full suite, "convention" accepts direct test files or maps source files to tests by naming, "graph" finds related tests via imports from source files, "impact" finds tests covering changed source files via test-impact analysis'),
42129
+ files: tool.schema.array(tool.schema.string()).optional().describe('Specific files to test. For "convention", pass source files or direct test files. For "graph" and "impact", pass source files only.'),
41995
42130
  coverage: tool.schema.boolean().optional().describe("Enable coverage reporting if supported"),
41996
42131
  timeout_ms: tool.schema.number().optional().describe("Timeout in milliseconds (default 60000, max 300000)"),
41997
42132
  allow_full_suite: tool.schema.boolean().optional().describe('Explicit opt-in for scope "all". Required because full-suite output can destabilize SSE streaming.'),
@@ -42116,24 +42251,45 @@ var test_runner = createSwarmTool({
42116
42251
  let graphFallbackReason;
42117
42252
  let effectiveScope = scope;
42118
42253
  if (scope === "all") {} else if (scope === "convention") {
42119
- const sourceFiles = args.files.filter((f) => {
42120
- const ext = path27.extname(f).toLowerCase();
42254
+ const directTestFiles = args.files.filter((file3) => isConventionTestFilePath(file3));
42255
+ const sourceFiles = args.files.filter((file3) => {
42256
+ if (directTestFiles.includes(file3))
42257
+ return false;
42258
+ const ext = path27.extname(file3).toLowerCase();
42121
42259
  return SOURCE_EXTENSIONS.has(ext);
42122
42260
  });
42123
- if (sourceFiles.length === 0) {
42261
+ const invalidFiles = args.files.filter((file3) => !directTestFiles.includes(file3) && !sourceFiles.includes(file3));
42262
+ if (directTestFiles.length === 0 && sourceFiles.length === 0) {
42124
42263
  const errorResult = {
42125
42264
  success: false,
42126
42265
  framework,
42127
42266
  scope,
42128
- error: "Provided files contain no source files with recognized extensions",
42129
- message: "The files array must contain at least one source file with a recognized extension (.ts, .tsx, .js, .jsx, .py, .rs, .ps1, etc.). Non-source files like README.md or config.json are not valid for test discovery.",
42267
+ error: "Provided files contain no recognized source files or direct test files",
42268
+ message: "The files array must contain at least one source file with a recognized extension (.ts, .tsx, .js, .jsx, .py, .rs, .ps1, etc.) or a direct test file in a supported test location/naming convention.",
42269
+ outcome: "error"
42270
+ };
42271
+ return JSON.stringify(errorResult, null, 2);
42272
+ }
42273
+ if (invalidFiles.length > 0) {
42274
+ const errorResult = {
42275
+ success: false,
42276
+ framework,
42277
+ scope,
42278
+ error: "Provided files include entries that are neither recognized source files nor direct test files",
42279
+ message: `These files are not valid for targeted test discovery: ${invalidFiles.join(", ")}`,
42130
42280
  outcome: "error"
42131
42281
  };
42132
42282
  return JSON.stringify(errorResult, null, 2);
42133
42283
  }
42134
- testFiles = getTestFilesFromConvention(sourceFiles);
42284
+ testFiles = [
42285
+ ...directTestFiles,
42286
+ ...getTestFilesFromConvention(sourceFiles, workingDir)
42287
+ ].filter((file3, index, items) => items.indexOf(file3) === index);
42135
42288
  } else if (scope === "graph") {
42136
42289
  const sourceFiles = args.files.filter((f) => {
42290
+ if (isConventionTestFilePath(f)) {
42291
+ return false;
42292
+ }
42137
42293
  const ext = path27.extname(f).toLowerCase();
42138
42294
  return SOURCE_EXTENSIONS.has(ext);
42139
42295
  });
@@ -42143,21 +42299,24 @@ var test_runner = createSwarmTool({
42143
42299
  framework,
42144
42300
  scope,
42145
42301
  error: "Provided files contain no source files with recognized extensions",
42146
- message: "The files array must contain at least one source file with a recognized extension (.ts, .tsx, .js, .jsx, .py, .rs, .ps1, etc.). Non-source files like README.md or config.json are not valid for test discovery.",
42302
+ message: 'The files array for scope "graph" must contain at least one source file with a recognized extension (.ts, .tsx, .js, .jsx, .py, .rs, .ps1, etc.). Direct test files belong in scope "convention".',
42147
42303
  outcome: "error"
42148
42304
  };
42149
42305
  return JSON.stringify(errorResult, null, 2);
42150
42306
  }
42151
- const graphTestFiles = await getTestFilesFromGraph(sourceFiles);
42307
+ const graphTestFiles = await getTestFilesFromGraph(sourceFiles, workingDir);
42152
42308
  if (graphTestFiles.length > 0) {
42153
42309
  testFiles = graphTestFiles;
42154
42310
  } else {
42155
42311
  graphFallbackReason = "imports resolution returned no results, falling back to convention";
42156
42312
  effectiveScope = "convention";
42157
- testFiles = getTestFilesFromConvention(sourceFiles);
42313
+ testFiles = getTestFilesFromConvention(sourceFiles, workingDir);
42158
42314
  }
42159
42315
  } else if (scope === "impact") {
42160
42316
  const sourceFiles = args.files.filter((f) => {
42317
+ if (isConventionTestFilePath(f)) {
42318
+ return false;
42319
+ }
42161
42320
  const ext = path27.extname(f).toLowerCase();
42162
42321
  return SOURCE_EXTENSIONS.has(ext);
42163
42322
  });
@@ -42167,7 +42326,7 @@ var test_runner = createSwarmTool({
42167
42326
  framework,
42168
42327
  scope,
42169
42328
  error: "Provided files contain no source files with recognized extensions",
42170
- message: "The files array must contain at least one source file with a recognized extension (.ts, .tsx, .js, .jsx, .py, .rs, .ps1, etc.).",
42329
+ message: 'The files array for scope "impact" must contain at least one source file with a recognized extension (.ts, .tsx, .js, .jsx, .py, .rs, .ps1, etc.). Direct test files belong in scope "convention".',
42171
42330
  outcome: "error"
42172
42331
  };
42173
42332
  return JSON.stringify(errorResult, null, 2);
@@ -42182,30 +42341,30 @@ var test_runner = createSwarmTool({
42182
42341
  } else {
42183
42342
  graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
42184
42343
  effectiveScope = "graph";
42185
- const graphTestFiles = await getTestFilesFromGraph(sourceFiles);
42344
+ const graphTestFiles = await getTestFilesFromGraph(sourceFiles, workingDir);
42186
42345
  if (graphTestFiles.length > 0) {
42187
42346
  testFiles = graphTestFiles;
42188
42347
  } else {
42189
42348
  graphFallbackReason = "imports resolution returned no results, falling back to convention";
42190
42349
  effectiveScope = "convention";
42191
- testFiles = getTestFilesFromConvention(sourceFiles);
42350
+ testFiles = getTestFilesFromConvention(sourceFiles, workingDir);
42192
42351
  }
42193
42352
  }
42194
42353
  } catch {
42195
42354
  graphFallbackReason = "impact analysis failed, falling back to graph";
42196
42355
  effectiveScope = "graph";
42197
- const graphTestFiles = await getTestFilesFromGraph(sourceFiles);
42356
+ const graphTestFiles = await getTestFilesFromGraph(sourceFiles, workingDir);
42198
42357
  if (graphTestFiles.length > 0) {
42199
42358
  testFiles = graphTestFiles;
42200
42359
  } else {
42201
42360
  graphFallbackReason = "imports resolution returned no results, falling back to convention";
42202
42361
  effectiveScope = "convention";
42203
- testFiles = getTestFilesFromConvention(sourceFiles);
42362
+ testFiles = getTestFilesFromConvention(sourceFiles, workingDir);
42204
42363
  }
42205
42364
  }
42206
42365
  }
42207
42366
  if (scope !== "all" && testFiles.length === 0) {
42208
- const baseMessage = "No matching test files found for the provided source files. Check that test files exist with matching naming conventions (.spec.*, .test.*, __tests__/, tests/, test/).";
42367
+ const baseMessage = "No matching test files found for the provided source files. Check that test files exist with matching naming conventions (.spec.*, .test.*, .Tests.ps1, __tests__/, tests/, test/, spec/).";
42209
42368
  const errorResult = {
42210
42369
  success: false,
42211
42370
  framework,
@@ -530,6 +530,11 @@ export declare const ParallelizationConfigSchema: z.ZodObject<{
530
530
  enabled: z.ZodDefault<z.ZodBoolean>;
531
531
  maxConcurrentTasks: z.ZodDefault<z.ZodNumber>;
532
532
  evidenceLockTimeoutMs: z.ZodDefault<z.ZodNumber>;
533
+ stageB: z.ZodDefault<z.ZodObject<{
534
+ parallel: z.ZodDefault<z.ZodObject<{
535
+ enabled: z.ZodDefault<z.ZodBoolean>;
536
+ }, z.core.$strip>>;
537
+ }, z.core.$strip>>;
533
538
  }, z.core.$strip>;
534
539
  export type ParallelizationConfig = z.infer<typeof ParallelizationConfigSchema>;
535
540
  export declare const PluginConfigSchema: z.ZodObject<{
@@ -893,6 +898,11 @@ export declare const PluginConfigSchema: z.ZodObject<{
893
898
  enabled: z.ZodDefault<z.ZodBoolean>;
894
899
  maxConcurrentTasks: z.ZodDefault<z.ZodNumber>;
895
900
  evidenceLockTimeoutMs: z.ZodDefault<z.ZodNumber>;
901
+ stageB: z.ZodDefault<z.ZodObject<{
902
+ parallel: z.ZodDefault<z.ZodObject<{
903
+ enabled: z.ZodDefault<z.ZodBoolean>;
904
+ }, z.core.$strip>>;
905
+ }, z.core.$strip>>;
896
906
  }, z.core.$strip>>;
897
907
  turbo_mode: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
898
908
  full_auto: z.ZodDefault<z.ZodOptional<z.ZodObject<{