opencode-swarm 7.19.1 → 7.19.3

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
@@ -34,7 +34,7 @@ var package_default;
34
34
  var init_package = __esm(() => {
35
35
  package_default = {
36
36
  name: "opencode-swarm",
37
- version: "7.19.1",
37
+ version: "7.19.3",
38
38
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
39
39
  main: "dist/index.js",
40
40
  types: "dist/index.d.ts",
@@ -48754,7 +48754,7 @@ function analyzeFailures(workingDir) {
48754
48754
  } catch {}
48755
48755
  return report;
48756
48756
  }
48757
- var MAX_OUTPUT_BYTES3 = 512000, MAX_COMMAND_LENGTH2 = 500, DEFAULT_TIMEOUT_MS = 60000, MAX_TIMEOUT_MS = 300000, MAX_SAFE_TEST_FILES = 50, POWERSHELL_METACHARACTERS, DISPATCH_FRAMEWORK_MAP, COMPOUND_TEST_EXTENSIONS, TEST_DIRECTORY_NAMES, SOURCE_EXTENSIONS, SKIP_DIRECTORIES, test_runner;
48757
+ var MAX_OUTPUT_BYTES3 = 512000, MAX_COMMAND_LENGTH2 = 500, DEFAULT_TIMEOUT_MS = 60000, MAX_TIMEOUT_MS = 300000, MAX_SAFE_TEST_FILES = 50, MAX_SAFE_SOURCE_FILES = 1, POWERSHELL_METACHARACTERS, DISPATCH_FRAMEWORK_MAP, COMPOUND_TEST_EXTENSIONS, TEST_DIRECTORY_NAMES, SOURCE_EXTENSIONS, SKIP_DIRECTORIES, test_runner;
48758
48758
  var init_test_runner = __esm(() => {
48759
48759
  init_zod();
48760
48760
  init_discovery();
@@ -48941,8 +48941,8 @@ var init_test_runner = __esm(() => {
48941
48941
  success: false,
48942
48942
  framework: "none",
48943
48943
  scope: "all",
48944
- error: 'scope "all" is not allowed without explicit files. Use scope "convention" or "graph" with a files array to run targeted tests.',
48945
- 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"] }',
48944
+ error: 'scope "all" is blocked for agent use. Use scope "convention" with specific test files, or scope "graph" with exactly one source file.',
48945
+ message: 'The full test suite is blocked in agent context. Use scope "convention" with specific test files, or scope "graph" with exactly one source file. Example: { scope: "convention", files: ["src/tools/test-runner.ts"] }',
48946
48946
  outcome: "error"
48947
48947
  };
48948
48948
  return JSON.stringify(errorResult, null, 2);
@@ -49023,6 +49023,17 @@ var init_test_runner = __esm(() => {
49023
49023
  };
49024
49024
  return JSON.stringify(errorResult, null, 2);
49025
49025
  }
49026
+ if (sourceFiles.length > MAX_SAFE_SOURCE_FILES) {
49027
+ const errorResult = {
49028
+ success: false,
49029
+ framework,
49030
+ scope,
49031
+ error: `scope "convention" accepts at most ${MAX_SAFE_SOURCE_FILES} source file for discovery (got ${sourceFiles.length}). Treat this as SKIP without retry.`,
49032
+ message: `Too many source files for scope "convention" discovery (${sourceFiles.length} provided, limit is ${MAX_SAFE_SOURCE_FILES}). Call test_runner once per source file, or pass direct test file paths instead of source files.`,
49033
+ outcome: "scope_exceeded"
49034
+ };
49035
+ return JSON.stringify(errorResult, null, 2);
49036
+ }
49026
49037
  testFiles = [
49027
49038
  ...directTestFiles,
49028
49039
  ...getTestFilesFromConvention(sourceFiles, workingDir)
@@ -49046,6 +49057,17 @@ var init_test_runner = __esm(() => {
49046
49057
  };
49047
49058
  return JSON.stringify(errorResult, null, 2);
49048
49059
  }
49060
+ if (sourceFiles.length > MAX_SAFE_SOURCE_FILES) {
49061
+ const errorResult = {
49062
+ success: false,
49063
+ framework,
49064
+ scope,
49065
+ error: `scope "graph" accepts at most ${MAX_SAFE_SOURCE_FILES} source file (got ${sourceFiles.length}). Treat this as SKIP without retry.`,
49066
+ message: `Too many source files for scope "graph" (${sourceFiles.length} provided, limit is ${MAX_SAFE_SOURCE_FILES}). Call test_runner once per source file, or use scope "convention" with direct test file paths.`,
49067
+ outcome: "scope_exceeded"
49068
+ };
49069
+ return JSON.stringify(errorResult, null, 2);
49070
+ }
49049
49071
  const graphTestFiles = await getTestFilesFromGraph(sourceFiles, workingDir);
49050
49072
  if (graphTestFiles.length > 0) {
49051
49073
  testFiles = graphTestFiles;
@@ -49073,6 +49095,17 @@ var init_test_runner = __esm(() => {
49073
49095
  };
49074
49096
  return JSON.stringify(errorResult, null, 2);
49075
49097
  }
49098
+ if (sourceFiles.length > MAX_SAFE_SOURCE_FILES) {
49099
+ const errorResult = {
49100
+ success: false,
49101
+ framework,
49102
+ scope,
49103
+ error: `scope "impact" accepts at most ${MAX_SAFE_SOURCE_FILES} source file (got ${sourceFiles.length}). Treat this as SKIP without retry.`,
49104
+ message: `Too many source files for scope "impact" (${sourceFiles.length} provided, limit is ${MAX_SAFE_SOURCE_FILES}). Call test_runner once per source file, or use scope "convention" with direct test file paths.`,
49105
+ outcome: "scope_exceeded"
49106
+ };
49107
+ return JSON.stringify(errorResult, null, 2);
49108
+ }
49076
49109
  try {
49077
49110
  const impactResult = await analyzeImpact(sourceFiles, workingDir);
49078
49111
  if (impactResult.impactedTests.length > 0) {
package/dist/index.js CHANGED
@@ -33,7 +33,7 @@ var package_default;
33
33
  var init_package = __esm(() => {
34
34
  package_default = {
35
35
  name: "opencode-swarm",
36
- version: "7.19.1",
36
+ version: "7.19.3",
37
37
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
38
38
  main: "dist/index.js",
39
39
  types: "dist/index.d.ts",
@@ -24183,6 +24183,91 @@ function extractStatusCode(errorMsg) {
24183
24183
  }
24184
24184
  return null;
24185
24185
  }
24186
+ function isPlainObject2(value) {
24187
+ return typeof value === "object" && value !== null && (value.constructor === Object || Object.getPrototypeOf(value) === null);
24188
+ }
24189
+ function readSignalField(source, key) {
24190
+ try {
24191
+ return source[key];
24192
+ } catch {
24193
+ return;
24194
+ }
24195
+ }
24196
+ function pushSignalValue(parts2, value) {
24197
+ if (typeof value === "string") {
24198
+ parts2.push(value);
24199
+ return;
24200
+ }
24201
+ if (typeof value === "number" || typeof value === "boolean") {
24202
+ parts2.push(String(value));
24203
+ }
24204
+ }
24205
+ function appendSelectedFields(parts2, source, keys) {
24206
+ for (const key of keys) {
24207
+ pushSignalValue(parts2, readSignalField(source, key));
24208
+ }
24209
+ }
24210
+ function appendNestedErrorSignal(parts2, value) {
24211
+ if (typeof value === "string") {
24212
+ parts2.push(value);
24213
+ return;
24214
+ }
24215
+ if (value instanceof Error) {
24216
+ parts2.push(value.name, value.message);
24217
+ appendSelectedFields(parts2, value, [
24218
+ "code",
24219
+ "status",
24220
+ "statusCode"
24221
+ ]);
24222
+ return;
24223
+ }
24224
+ if (!isPlainObject2(value))
24225
+ return;
24226
+ appendSelectedFields(parts2, value, [
24227
+ "code",
24228
+ "status",
24229
+ "statusCode",
24230
+ "message",
24231
+ "error_type"
24232
+ ]);
24233
+ }
24234
+ function extractErrorSignal(errorContent) {
24235
+ if (typeof errorContent === "string")
24236
+ return errorContent;
24237
+ if (errorContent == null)
24238
+ return "";
24239
+ const parts2 = [];
24240
+ try {
24241
+ if (errorContent instanceof Error) {
24242
+ parts2.push(errorContent.name, errorContent.message);
24243
+ appendSelectedFields(parts2, errorContent, ["code", "status", "statusCode"]);
24244
+ return parts2.join(" ");
24245
+ }
24246
+ if (!isPlainObject2(errorContent))
24247
+ return "";
24248
+ appendSelectedFields(parts2, errorContent, [
24249
+ "code",
24250
+ "status",
24251
+ "statusCode",
24252
+ "message",
24253
+ "error_type"
24254
+ ]);
24255
+ appendNestedErrorSignal(parts2, readSignalField(errorContent, "error"));
24256
+ const metadata2 = readSignalField(errorContent, "metadata");
24257
+ if (isPlainObject2(metadata2)) {
24258
+ appendSelectedFields(parts2, metadata2, [
24259
+ "code",
24260
+ "status",
24261
+ "statusCode",
24262
+ "error_type"
24263
+ ]);
24264
+ }
24265
+ appendNestedErrorSignal(parts2, readSignalField(errorContent, "cause"));
24266
+ } catch {
24267
+ return parts2.join(" ");
24268
+ }
24269
+ return parts2.join(" ");
24270
+ }
24186
24271
  function getStoredInputArgs(callID) {
24187
24272
  return storedInputArgs.get(callID);
24188
24273
  }
@@ -25392,16 +25477,17 @@ function createGuardrailsHooks(directory, directoryOrConfig, config2, authorityC
25392
25477
  if (hasError) {
25393
25478
  const outputStr = typeof output.output === "string" ? output.output : "";
25394
25479
  const errorContent = output.error ?? outputStr;
25395
- const extractedStatus = typeof errorContent === "string" ? extractStatusCode(errorContent) : null;
25480
+ const errorSignal = extractErrorSignal(errorContent);
25481
+ const extractedStatus = extractStatusCode(errorSignal);
25396
25482
  const isTransientStatusCode = extractedStatus !== null && TRANSIENT_STATUS_CODES.has(extractedStatus);
25397
- const isTransientPatternMatch = typeof errorContent === "string" && TRANSIENT_MODEL_ERROR_PATTERN.test(errorContent);
25483
+ const isTransientPatternMatch = TRANSIENT_MODEL_ERROR_PATTERN.test(errorSignal);
25398
25484
  const isTransientMatch = isTransientStatusCode || isTransientPatternMatch;
25399
25485
  const isTransient = !!session && isTransientMatch && window2.transientRetryCount < cfg.max_transient_retries;
25400
- const isDegraded = !isTransient && typeof errorContent === "string" && DEGRADED_ERROR_PATTERN.test(errorContent);
25486
+ const isDegraded = !isTransient && DEGRADED_ERROR_PATTERN.test(errorSignal);
25401
25487
  if (isTransient) {
25402
25488
  window2.transientRetryCount++;
25403
25489
  } else if (isDegraded) {
25404
- const isContentFilter = typeof errorContent === "string" && CONTENT_FILTER_PATTERN.test(errorContent);
25490
+ const isContentFilter = CONTENT_FILTER_PATTERN.test(errorSignal);
25405
25491
  if (session && !session.modelFallbackExhausted) {
25406
25492
  session.model_fallback_index++;
25407
25493
  const baseAgentName = session.agentName ? session.agentName.replace(/^[^_]+[_]/, "") : "";
@@ -26058,7 +26144,7 @@ var init_guardrails = __esm(() => {
26058
26144
  ]);
26059
26145
  storedInputArgs = new Map;
26060
26146
  TRANSIENT_STATUS_CODES = new Set([408, 429, 500, 502, 503, 504, 529]);
26061
- TRANSIENT_MODEL_ERROR_PATTERN = /rate.?limit|429|500|502|503|504|529|timeout|overloaded|model.?not.?found|temporarily.?unavailable|server.?error|connection.?(refused|reset|timeout)|bad.?gateway|gateway.?timeout|internal.?server.?error|service.?unavailable/i;
26147
+ TRANSIENT_MODEL_ERROR_PATTERN = /rate.?limit|429|500|502|503|504|529|timeout|overloaded|model.?not.?found|temporarily.?unavailable|provider.?unavailable|server.?error|connection.?(refused|reset|timeout|lost)|bad.?gateway|gateway.?timeout|internal.?server.?error|service.?unavailable/i;
26062
26148
  DEGRADED_ERROR_PATTERN = /context.?length|token.?(limit|budget)|input.?too.?long|content.?filter|exceeds?.?(maximum.?)?tokens|maximum.?context|context.?window|too.?many.?tokens|prompt.?too.?long|message.?too.?long|request.?too.?large|max.?tokens/i;
26063
26149
  CONTENT_FILTER_PATTERN = /content.?filter/i;
26064
26150
  toolCallsSinceLastWrite = new Map;
@@ -28257,7 +28343,7 @@ __export(exports_util2, {
28257
28343
  jsonStringifyReplacer: () => jsonStringifyReplacer2,
28258
28344
  joinValues: () => joinValues2,
28259
28345
  issue: () => issue2,
28260
- isPlainObject: () => isPlainObject2,
28346
+ isPlainObject: () => isPlainObject3,
28261
28347
  isObject: () => isObject2,
28262
28348
  hexToUint8Array: () => hexToUint8Array2,
28263
28349
  getSizableOrigin: () => getSizableOrigin2,
@@ -28425,7 +28511,7 @@ function esc2(str) {
28425
28511
  function isObject2(data) {
28426
28512
  return typeof data === "object" && data !== null && !Array.isArray(data);
28427
28513
  }
28428
- function isPlainObject2(o) {
28514
+ function isPlainObject3(o) {
28429
28515
  if (isObject2(o) === false)
28430
28516
  return false;
28431
28517
  const ctor = o.constructor;
@@ -28440,7 +28526,7 @@ function isPlainObject2(o) {
28440
28526
  return true;
28441
28527
  }
28442
28528
  function shallowClone2(o) {
28443
- if (isPlainObject2(o))
28529
+ if (isPlainObject3(o))
28444
28530
  return { ...o };
28445
28531
  if (Array.isArray(o))
28446
28532
  return [...o];
@@ -28566,7 +28652,7 @@ function omit2(schema, mask) {
28566
28652
  return clone2(schema, def);
28567
28653
  }
28568
28654
  function extend2(schema, shape) {
28569
- if (!isPlainObject2(shape)) {
28655
+ if (!isPlainObject3(shape)) {
28570
28656
  throw new Error("Invalid input to extend: expected a plain object");
28571
28657
  }
28572
28658
  const checks3 = schema._zod.def.checks;
@@ -28585,7 +28671,7 @@ function extend2(schema, shape) {
28585
28671
  return clone2(schema, def);
28586
28672
  }
28587
28673
  function safeExtend2(schema, shape) {
28588
- if (!isPlainObject2(shape)) {
28674
+ if (!isPlainObject3(shape)) {
28589
28675
  throw new Error("Invalid input to safeExtend: expected a plain object");
28590
28676
  }
28591
28677
  const def = {
@@ -29968,7 +30054,7 @@ function mergeValues2(a, b) {
29968
30054
  if (a instanceof Date && b instanceof Date && +a === +b) {
29969
30055
  return { valid: true, data: a };
29970
30056
  }
29971
- if (isPlainObject2(a) && isPlainObject2(b)) {
30057
+ if (isPlainObject3(a) && isPlainObject3(b)) {
29972
30058
  const bKeys = Object.keys(b);
29973
30059
  const sharedKeys = Object.keys(a).filter((key) => bKeys.indexOf(key) !== -1);
29974
30060
  const newObj = { ...a, ...b };
@@ -31065,7 +31151,7 @@ var init_schemas3 = __esm(() => {
31065
31151
  $ZodType2.init(inst, def);
31066
31152
  inst._zod.parse = (payload, ctx) => {
31067
31153
  const input = payload.value;
31068
- if (!isPlainObject2(input)) {
31154
+ if (!isPlainObject3(input)) {
31069
31155
  payload.issues.push({
31070
31156
  expected: "record",
31071
31157
  code: "invalid_type",
@@ -57290,7 +57376,7 @@ function analyzeFailures(workingDir) {
57290
57376
  } catch {}
57291
57377
  return report;
57292
57378
  }
57293
- var MAX_OUTPUT_BYTES3 = 512000, MAX_COMMAND_LENGTH2 = 500, DEFAULT_TIMEOUT_MS = 60000, MAX_TIMEOUT_MS = 300000, MAX_SAFE_TEST_FILES = 50, POWERSHELL_METACHARACTERS, DISPATCH_FRAMEWORK_MAP, COMPOUND_TEST_EXTENSIONS, TEST_DIRECTORY_NAMES, SOURCE_EXTENSIONS, SKIP_DIRECTORIES, test_runner;
57379
+ var MAX_OUTPUT_BYTES3 = 512000, MAX_COMMAND_LENGTH2 = 500, DEFAULT_TIMEOUT_MS = 60000, MAX_TIMEOUT_MS = 300000, MAX_SAFE_TEST_FILES = 50, MAX_SAFE_SOURCE_FILES = 1, POWERSHELL_METACHARACTERS, DISPATCH_FRAMEWORK_MAP, COMPOUND_TEST_EXTENSIONS, TEST_DIRECTORY_NAMES, SOURCE_EXTENSIONS, SKIP_DIRECTORIES, test_runner;
57294
57380
  var init_test_runner = __esm(() => {
57295
57381
  init_zod();
57296
57382
  init_discovery();
@@ -57477,8 +57563,8 @@ var init_test_runner = __esm(() => {
57477
57563
  success: false,
57478
57564
  framework: "none",
57479
57565
  scope: "all",
57480
- error: 'scope "all" is not allowed without explicit files. Use scope "convention" or "graph" with a files array to run targeted tests.',
57481
- 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"] }',
57566
+ error: 'scope "all" is blocked for agent use. Use scope "convention" with specific test files, or scope "graph" with exactly one source file.',
57567
+ message: 'The full test suite is blocked in agent context. Use scope "convention" with specific test files, or scope "graph" with exactly one source file. Example: { scope: "convention", files: ["src/tools/test-runner.ts"] }',
57482
57568
  outcome: "error"
57483
57569
  };
57484
57570
  return JSON.stringify(errorResult, null, 2);
@@ -57559,6 +57645,17 @@ var init_test_runner = __esm(() => {
57559
57645
  };
57560
57646
  return JSON.stringify(errorResult, null, 2);
57561
57647
  }
57648
+ if (sourceFiles.length > MAX_SAFE_SOURCE_FILES) {
57649
+ const errorResult = {
57650
+ success: false,
57651
+ framework,
57652
+ scope,
57653
+ error: `scope "convention" accepts at most ${MAX_SAFE_SOURCE_FILES} source file for discovery (got ${sourceFiles.length}). Treat this as SKIP without retry.`,
57654
+ message: `Too many source files for scope "convention" discovery (${sourceFiles.length} provided, limit is ${MAX_SAFE_SOURCE_FILES}). Call test_runner once per source file, or pass direct test file paths instead of source files.`,
57655
+ outcome: "scope_exceeded"
57656
+ };
57657
+ return JSON.stringify(errorResult, null, 2);
57658
+ }
57562
57659
  testFiles = [
57563
57660
  ...directTestFiles,
57564
57661
  ...getTestFilesFromConvention(sourceFiles, workingDir)
@@ -57582,6 +57679,17 @@ var init_test_runner = __esm(() => {
57582
57679
  };
57583
57680
  return JSON.stringify(errorResult, null, 2);
57584
57681
  }
57682
+ if (sourceFiles.length > MAX_SAFE_SOURCE_FILES) {
57683
+ const errorResult = {
57684
+ success: false,
57685
+ framework,
57686
+ scope,
57687
+ error: `scope "graph" accepts at most ${MAX_SAFE_SOURCE_FILES} source file (got ${sourceFiles.length}). Treat this as SKIP without retry.`,
57688
+ message: `Too many source files for scope "graph" (${sourceFiles.length} provided, limit is ${MAX_SAFE_SOURCE_FILES}). Call test_runner once per source file, or use scope "convention" with direct test file paths.`,
57689
+ outcome: "scope_exceeded"
57690
+ };
57691
+ return JSON.stringify(errorResult, null, 2);
57692
+ }
57585
57693
  const graphTestFiles = await getTestFilesFromGraph(sourceFiles, workingDir);
57586
57694
  if (graphTestFiles.length > 0) {
57587
57695
  testFiles = graphTestFiles;
@@ -57609,6 +57717,17 @@ var init_test_runner = __esm(() => {
57609
57717
  };
57610
57718
  return JSON.stringify(errorResult, null, 2);
57611
57719
  }
57720
+ if (sourceFiles.length > MAX_SAFE_SOURCE_FILES) {
57721
+ const errorResult = {
57722
+ success: false,
57723
+ framework,
57724
+ scope,
57725
+ error: `scope "impact" accepts at most ${MAX_SAFE_SOURCE_FILES} source file (got ${sourceFiles.length}). Treat this as SKIP without retry.`,
57726
+ message: `Too many source files for scope "impact" (${sourceFiles.length} provided, limit is ${MAX_SAFE_SOURCE_FILES}). Call test_runner once per source file, or use scope "convention" with direct test file paths.`,
57727
+ outcome: "scope_exceeded"
57728
+ };
57729
+ return JSON.stringify(errorResult, null, 2);
57730
+ }
57612
57731
  try {
57613
57732
  const impactResult = await analyzeImpact(sourceFiles, workingDir);
57614
57733
  if (impactResult.impactedTests.length > 0) {
@@ -4,6 +4,7 @@ export declare const MAX_COMMAND_LENGTH = 500;
4
4
  export declare const DEFAULT_TIMEOUT_MS = 60000;
5
5
  export declare const MAX_TIMEOUT_MS = 300000;
6
6
  export declare const MAX_SAFE_TEST_FILES = 50;
7
+ export declare const MAX_SAFE_SOURCE_FILES = 1;
7
8
  export declare const SUPPORTED_FRAMEWORKS: readonly ["bun", "vitest", "jest", "mocha", "pytest", "cargo", "pester", "go-test", "maven", "gradle", "dotnet-test", "ctest", "swift-test", "dart-test", "rspec", "minitest"];
8
9
  export type TestFramework = (typeof SUPPORTED_FRAMEWORKS)[number] | 'none';
9
10
  export interface TestRunnerArgs {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "7.19.1",
3
+ "version": "7.19.3",
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",