opencode-swarm 7.28.2 → 7.28.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.28.2",
37
+ version: "7.28.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",
@@ -308,6 +308,27 @@ function bunHash(input) {
308
308
  }
309
309
  return hash;
310
310
  }
311
+ function killProcessTreeImpl(pid, signal, directKill, wasDetached) {
312
+ if (typeof pid !== "number" || pid <= 0) {
313
+ directKill();
314
+ return;
315
+ }
316
+ if (process.platform === "win32") {
317
+ try {
318
+ nodeSpawnSync("taskkill", ["/PID", String(pid), "/T", "/F"]);
319
+ } catch {
320
+ directKill();
321
+ }
322
+ return;
323
+ }
324
+ if (wasDetached) {
325
+ try {
326
+ process.kill(-pid, signal ?? "SIGKILL");
327
+ return;
328
+ } catch {}
329
+ }
330
+ directKill();
331
+ }
311
332
  function streamFromNode(pipe) {
312
333
  const collected = new Promise((resolve) => {
313
334
  if (!pipe) {
@@ -430,20 +451,34 @@ function bunSpawn(cmd, options) {
430
451
  return proc2.exitCode;
431
452
  },
432
453
  kill(sig) {
433
- proc2.kill(sig);
454
+ if (options?.killProcessTree) {
455
+ killProcessTreeImpl(proc2.pid, sig, () => proc2.kill(sig), false);
456
+ } else {
457
+ proc2.kill(sig);
458
+ }
434
459
  }
435
460
  };
436
461
  }
437
462
  const [file, ...args] = cmd;
463
+ const detached = options?.killProcessTree === true;
438
464
  const proc = nodeSpawn(file, args, {
439
465
  cwd: options?.cwd,
440
466
  env: options?.env,
467
+ detached,
468
+ windowsHide: true,
441
469
  stdio: [
442
470
  mapStdio(options?.stdin),
443
471
  mapStdio(options?.stdout),
444
472
  mapStdio(options?.stderr)
445
473
  ]
446
474
  });
475
+ const killChild = (signal) => {
476
+ if (detached) {
477
+ killProcessTreeImpl(proc.pid, signal, () => proc.kill(signal), true);
478
+ } else {
479
+ proc.kill(signal);
480
+ }
481
+ };
447
482
  let timeoutHandle;
448
483
  const exited = new Promise((resolve) => {
449
484
  proc.on("exit", (code) => resolve(code ?? 0));
@@ -451,7 +486,7 @@ function bunSpawn(cmd, options) {
451
486
  if (options?.timeout && options.timeout > 0) {
452
487
  timeoutHandle = setTimeout(() => {
453
488
  try {
454
- proc.kill("SIGKILL");
489
+ killChild("SIGKILL");
455
490
  } catch {}
456
491
  }, options.timeout);
457
492
  if (typeof timeoutHandle.unref === "function") {
@@ -471,7 +506,7 @@ function bunSpawn(cmd, options) {
471
506
  },
472
507
  kill(signal) {
473
508
  try {
474
- proc.kill(signal);
509
+ killChild(signal);
475
510
  } catch {}
476
511
  }
477
512
  };
@@ -46255,7 +46290,7 @@ function defaultBuildTestCommand(profile, framework, files, dir = ".", opts = {}
46255
46290
  const coverage = opts.coverage ?? false;
46256
46291
  switch (framework) {
46257
46292
  case "bun": {
46258
- const args = ["bun", "test"];
46293
+ const args = ["bun", "--smol", "test"];
46259
46294
  if (coverage)
46260
46295
  args.push("--coverage");
46261
46296
  if (scope !== "all" && files.length > 0)
@@ -48688,7 +48723,7 @@ function getTargetedExecutionUnsupportedReason(framework) {
48688
48723
  function buildTestCommand2(framework, scope, files, coverage, baseDir) {
48689
48724
  switch (framework) {
48690
48725
  case "bun": {
48691
- const args = ["bun", "test"];
48726
+ const args = ["bun", "--smol", "test"];
48692
48727
  if (coverage)
48693
48728
  args.push("--coverage");
48694
48729
  if (scope !== "all" && files.length > 0) {
@@ -49225,17 +49260,24 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
49225
49260
  const proc = bunSpawn(command, {
49226
49261
  stdout: "pipe",
49227
49262
  stderr: "pipe",
49228
- cwd
49263
+ stdin: "ignore",
49264
+ cwd,
49265
+ killProcessTree: true
49266
+ });
49267
+ let timeoutHandle;
49268
+ const timeoutPromise = new Promise((resolve14) => {
49269
+ timeoutHandle = setTimeout(() => {
49270
+ proc.kill();
49271
+ resolve14(-1);
49272
+ }, timeout_ms);
49229
49273
  });
49230
- const timeoutPromise = new Promise((resolve14) => setTimeout(() => {
49231
- proc.kill();
49232
- resolve14(-1);
49233
- }, timeout_ms));
49234
49274
  const [exitCode, stdoutResult, stderrResult] = await Promise.all([
49235
49275
  Promise.race([proc.exited, timeoutPromise]),
49236
49276
  readBoundedStream(proc.stdout, MAX_OUTPUT_BYTES3),
49237
49277
  readBoundedStream(proc.stderr, MAX_OUTPUT_BYTES3)
49238
49278
  ]);
49279
+ if (timeoutHandle !== undefined)
49280
+ clearTimeout(timeoutHandle);
49239
49281
  const duration_ms = Date.now() - startTime;
49240
49282
  let output = stdoutResult.text;
49241
49283
  if (stderrResult.text) {
@@ -49538,7 +49580,6 @@ var init_test_runner = __esm(() => {
49538
49580
  files: exports_external.array(exports_external.string()).optional().describe('Specific files to test. For "convention", pass source files or direct test files. For "graph" and "impact", pass source files only.'),
49539
49581
  coverage: exports_external.boolean().optional().describe("Enable coverage reporting if supported"),
49540
49582
  timeout_ms: exports_external.number().optional().describe("Timeout in milliseconds (default 60000, max 300000)"),
49541
- allow_full_suite: exports_external.boolean().optional().describe('Explicit opt-in for scope "all". Required because full-suite output can destabilize SSE streaming.'),
49542
49583
  working_directory: exports_external.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.")
49543
49584
  },
49544
49585
  async execute(args, directory) {
@@ -49612,7 +49653,8 @@ var init_test_runner = __esm(() => {
49612
49653
  }
49613
49654
  const scope = args.scope || "all";
49614
49655
  if (scope === "all") {
49615
- if (!args.allow_full_suite) {
49656
+ const fullSuiteAllowed = process.env.SWARM_ALLOW_FULL_SUITE === "1" || process.env.SWARM_ALLOW_FULL_SUITE === "true";
49657
+ if (!fullSuiteAllowed) {
49616
49658
  const errorResult = {
49617
49659
  success: false,
49618
49660
  framework: "none",
package/dist/index.js CHANGED
@@ -48,7 +48,7 @@ var package_default;
48
48
  var init_package = __esm(() => {
49
49
  package_default = {
50
50
  name: "opencode-swarm",
51
- version: "7.28.2",
51
+ version: "7.28.3",
52
52
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
53
53
  main: "dist/index.js",
54
54
  types: "dist/index.d.ts",
@@ -16518,6 +16518,27 @@ function bunHash(input) {
16518
16518
  }
16519
16519
  return hash2;
16520
16520
  }
16521
+ function killProcessTreeImpl(pid, signal, directKill, wasDetached) {
16522
+ if (typeof pid !== "number" || pid <= 0) {
16523
+ directKill();
16524
+ return;
16525
+ }
16526
+ if (process.platform === "win32") {
16527
+ try {
16528
+ nodeSpawnSync("taskkill", ["/PID", String(pid), "/T", "/F"]);
16529
+ } catch {
16530
+ directKill();
16531
+ }
16532
+ return;
16533
+ }
16534
+ if (wasDetached) {
16535
+ try {
16536
+ process.kill(-pid, signal ?? "SIGKILL");
16537
+ return;
16538
+ } catch {}
16539
+ }
16540
+ directKill();
16541
+ }
16521
16542
  function streamFromNode(pipe2) {
16522
16543
  const collected = new Promise((resolve) => {
16523
16544
  if (!pipe2) {
@@ -16640,20 +16661,34 @@ function bunSpawn(cmd, options) {
16640
16661
  return proc2.exitCode;
16641
16662
  },
16642
16663
  kill(sig) {
16643
- proc2.kill(sig);
16664
+ if (options?.killProcessTree) {
16665
+ killProcessTreeImpl(proc2.pid, sig, () => proc2.kill(sig), false);
16666
+ } else {
16667
+ proc2.kill(sig);
16668
+ }
16644
16669
  }
16645
16670
  };
16646
16671
  }
16647
16672
  const [file2, ...args2] = cmd;
16673
+ const detached = options?.killProcessTree === true;
16648
16674
  const proc = nodeSpawn(file2, args2, {
16649
16675
  cwd: options?.cwd,
16650
16676
  env: options?.env,
16677
+ detached,
16678
+ windowsHide: true,
16651
16679
  stdio: [
16652
16680
  mapStdio(options?.stdin),
16653
16681
  mapStdio(options?.stdout),
16654
16682
  mapStdio(options?.stderr)
16655
16683
  ]
16656
16684
  });
16685
+ const killChild = (signal) => {
16686
+ if (detached) {
16687
+ killProcessTreeImpl(proc.pid, signal, () => proc.kill(signal), true);
16688
+ } else {
16689
+ proc.kill(signal);
16690
+ }
16691
+ };
16657
16692
  let timeoutHandle;
16658
16693
  const exited = new Promise((resolve) => {
16659
16694
  proc.on("exit", (code) => resolve(code ?? 0));
@@ -16661,7 +16696,7 @@ function bunSpawn(cmd, options) {
16661
16696
  if (options?.timeout && options.timeout > 0) {
16662
16697
  timeoutHandle = setTimeout(() => {
16663
16698
  try {
16664
- proc.kill("SIGKILL");
16699
+ killChild("SIGKILL");
16665
16700
  } catch {}
16666
16701
  }, options.timeout);
16667
16702
  if (typeof timeoutHandle.unref === "function") {
@@ -16681,7 +16716,7 @@ function bunSpawn(cmd, options) {
16681
16716
  },
16682
16717
  kill(signal) {
16683
16718
  try {
16684
- proc.kill(signal);
16719
+ killChild(signal);
16685
16720
  } catch {}
16686
16721
  }
16687
16722
  };
@@ -67348,7 +67383,7 @@ function defaultBuildTestCommand(profile, framework, files, dir = ".", opts = {}
67348
67383
  const coverage = opts.coverage ?? false;
67349
67384
  switch (framework) {
67350
67385
  case "bun": {
67351
- const args2 = ["bun", "test"];
67386
+ const args2 = ["bun", "--smol", "test"];
67352
67387
  if (coverage)
67353
67388
  args2.push("--coverage");
67354
67389
  if (scope !== "all" && files.length > 0)
@@ -69781,7 +69816,7 @@ function getTargetedExecutionUnsupportedReason(framework) {
69781
69816
  function buildTestCommand2(framework, scope, files, coverage, baseDir) {
69782
69817
  switch (framework) {
69783
69818
  case "bun": {
69784
- const args2 = ["bun", "test"];
69819
+ const args2 = ["bun", "--smol", "test"];
69785
69820
  if (coverage)
69786
69821
  args2.push("--coverage");
69787
69822
  if (scope !== "all" && files.length > 0) {
@@ -70318,17 +70353,24 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
70318
70353
  const proc = bunSpawn(command, {
70319
70354
  stdout: "pipe",
70320
70355
  stderr: "pipe",
70321
- cwd
70356
+ stdin: "ignore",
70357
+ cwd,
70358
+ killProcessTree: true
70359
+ });
70360
+ let timeoutHandle;
70361
+ const timeoutPromise = new Promise((resolve16) => {
70362
+ timeoutHandle = setTimeout(() => {
70363
+ proc.kill();
70364
+ resolve16(-1);
70365
+ }, timeout_ms);
70322
70366
  });
70323
- const timeoutPromise = new Promise((resolve16) => setTimeout(() => {
70324
- proc.kill();
70325
- resolve16(-1);
70326
- }, timeout_ms));
70327
70367
  const [exitCode, stdoutResult, stderrResult] = await Promise.all([
70328
70368
  Promise.race([proc.exited, timeoutPromise]),
70329
70369
  readBoundedStream(proc.stdout, MAX_OUTPUT_BYTES3),
70330
70370
  readBoundedStream(proc.stderr, MAX_OUTPUT_BYTES3)
70331
70371
  ]);
70372
+ if (timeoutHandle !== undefined)
70373
+ clearTimeout(timeoutHandle);
70332
70374
  const duration_ms = Date.now() - startTime;
70333
70375
  let output = stdoutResult.text;
70334
70376
  if (stderrResult.text) {
@@ -70631,7 +70673,6 @@ var init_test_runner = __esm(() => {
70631
70673
  files: exports_external.array(exports_external.string()).optional().describe('Specific files to test. For "convention", pass source files or direct test files. For "graph" and "impact", pass source files only.'),
70632
70674
  coverage: exports_external.boolean().optional().describe("Enable coverage reporting if supported"),
70633
70675
  timeout_ms: exports_external.number().optional().describe("Timeout in milliseconds (default 60000, max 300000)"),
70634
- allow_full_suite: exports_external.boolean().optional().describe('Explicit opt-in for scope "all". Required because full-suite output can destabilize SSE streaming.'),
70635
70676
  working_directory: exports_external.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.")
70636
70677
  },
70637
70678
  async execute(args2, directory) {
@@ -70705,7 +70746,8 @@ var init_test_runner = __esm(() => {
70705
70746
  }
70706
70747
  const scope = args2.scope || "all";
70707
70748
  if (scope === "all") {
70708
- if (!args2.allow_full_suite) {
70749
+ const fullSuiteAllowed = process.env.SWARM_ALLOW_FULL_SUITE === "1" || process.env.SWARM_ALLOW_FULL_SUITE === "true";
70750
+ if (!fullSuiteAllowed) {
70709
70751
  const errorResult = {
70710
70752
  success: false,
70711
70753
  framework: "none",
@@ -23,7 +23,6 @@ export interface TestRunnerArgs {
23
23
  files?: string[];
24
24
  coverage?: boolean;
25
25
  timeout_ms?: number;
26
- allow_full_suite?: boolean;
27
26
  }
28
27
  export type RegressionOutcome = 'pass' | 'skip' | 'regression' | 'scope_exceeded' | 'error';
29
28
  export interface TestTotals {
@@ -71,6 +71,16 @@ export interface BunCompatSpawnOptions {
71
71
  stdout?: 'inherit' | 'ignore' | 'pipe';
72
72
  stderr?: 'inherit' | 'ignore' | 'pipe';
73
73
  timeout?: number;
74
+ /**
75
+ * When true, spawn the child as its own process-group leader (Node path:
76
+ * `detached`) and kill the entire descendant tree on `kill()`/timeout
77
+ * rather than only the direct child. A test runner that forks worker
78
+ * processes (jest/vitest, or a runaway suite) can otherwise outlive a
79
+ * `proc.kill()` of the parent and keep consuming memory after the timeout.
80
+ * Opt-in because the default single-child kill is correct for the many
81
+ * short-lived `bunSpawn` callers (git, lint, version checks).
82
+ */
83
+ killProcessTree?: boolean;
74
84
  }
75
85
  export interface BunCompatStream {
76
86
  text(): Promise<string>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "7.28.2",
3
+ "version": "7.28.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",