opencode-swarm 7.28.1 → 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 +55 -13
- package/dist/hooks/delegation-gate.d.ts +21 -0
- package/dist/index.js +76 -17
- package/dist/tools/test-runner.d.ts +0 -1
- package/dist/utils/bun-compat.d.ts +10 -0
- package/package.json +1 -1
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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",
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Uses experimental.chat.messages.transform to provide non-blocking guidance.
|
|
6
6
|
*/
|
|
7
7
|
import type { PluginConfig } from '../config';
|
|
8
|
+
import type { AgentSessionState } from '../state';
|
|
8
9
|
import type { DelegationEnvelope, EnvelopeValidationResult } from '../types/delegation.js';
|
|
9
10
|
/**
|
|
10
11
|
* v6.33.1 CRIT-1: Fallback map for declared coder scope by taskId.
|
|
@@ -53,6 +54,26 @@ interface MessageWithParts {
|
|
|
53
54
|
info: MessageInfo;
|
|
54
55
|
parts: MessagePart[];
|
|
55
56
|
}
|
|
57
|
+
declare function resolveDelegatedPlanTaskId(args: Record<string, unknown>, knownPlanTaskIds?: ReadonlySet<string>): string | null;
|
|
58
|
+
/**
|
|
59
|
+
* Resolves the correct task ID for evidence recording by chaining:
|
|
60
|
+
* 1. Explicit task_id in direct args (structured field)
|
|
61
|
+
* 2. Prompt-text extraction via resolveDelegatedPlanTaskId (plan-aware)
|
|
62
|
+
* 3. Session-state fallback via getEvidenceTaskId
|
|
63
|
+
*
|
|
64
|
+
* This fixes parallel evidence recording where multiple reviewer/test_engineer
|
|
65
|
+
* agents are dispatched for different tasks from the same architect session.
|
|
66
|
+
* Issue #970.
|
|
67
|
+
*/
|
|
68
|
+
declare function resolveEvidenceTaskId(args: Record<string, unknown> | undefined, session: AgentSessionState, directory: string): Promise<string | null>;
|
|
69
|
+
/**
|
|
70
|
+
* _internals export for testing — do not use in production code.
|
|
71
|
+
* Exposes resolveEvidenceTaskId and resolveDelegatedPlanTaskId for unit testing.
|
|
72
|
+
*/
|
|
73
|
+
export declare const _internals: {
|
|
74
|
+
resolveEvidenceTaskId: typeof resolveEvidenceTaskId;
|
|
75
|
+
resolveDelegatedPlanTaskId: typeof resolveDelegatedPlanTaskId;
|
|
76
|
+
};
|
|
56
77
|
/**
|
|
57
78
|
* Creates the experimental.chat.messages.transform hook for delegation gating.
|
|
58
79
|
* Inspects coder delegations and warns when tasks are oversized or batched.
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
16719
|
+
killChild(signal);
|
|
16685
16720
|
} catch {}
|
|
16686
16721
|
}
|
|
16687
16722
|
};
|
|
@@ -39012,6 +39047,24 @@ async function getEvidenceTaskId(session, directory) {
|
|
|
39012
39047
|
}
|
|
39013
39048
|
return null;
|
|
39014
39049
|
}
|
|
39050
|
+
async function resolveEvidenceTaskId(args2, session, directory) {
|
|
39051
|
+
const rawTaskId = args2?.task_id;
|
|
39052
|
+
if (typeof rawTaskId === "string" && rawTaskId.length <= 20 && isStrictTaskId(rawTaskId.trim())) {
|
|
39053
|
+
return rawTaskId.trim();
|
|
39054
|
+
}
|
|
39055
|
+
if (args2) {
|
|
39056
|
+
try {
|
|
39057
|
+
const plan = await loadPlanJsonOnly(directory);
|
|
39058
|
+
if (plan) {
|
|
39059
|
+
const planTaskIds = new Set(plan.phases.flatMap((p) => p.tasks.map((t) => t.id)));
|
|
39060
|
+
const promptTaskId = resolveDelegatedPlanTaskId(args2, planTaskIds);
|
|
39061
|
+
if (promptTaskId)
|
|
39062
|
+
return promptTaskId;
|
|
39063
|
+
}
|
|
39064
|
+
} catch {}
|
|
39065
|
+
}
|
|
39066
|
+
return getEvidenceTaskId(session, directory);
|
|
39067
|
+
}
|
|
39015
39068
|
function createDelegationGateHook(config2, directory) {
|
|
39016
39069
|
const enabled = config2.hooks?.delegation_gate !== false;
|
|
39017
39070
|
const delegationMaxChars = config2.hooks?.delegation_max_chars ?? 4000;
|
|
@@ -39253,8 +39306,8 @@ function createDelegationGateHook(config2, directory) {
|
|
|
39253
39306
|
}
|
|
39254
39307
|
if (typeof subagentType === "string") {
|
|
39255
39308
|
try {
|
|
39256
|
-
const
|
|
39257
|
-
const evidenceTaskId =
|
|
39309
|
+
const mergedArgs = { ...storedArgs ?? {}, ...directArgs };
|
|
39310
|
+
const evidenceTaskId = await resolveEvidenceTaskId(mergedArgs, session, directory);
|
|
39258
39311
|
if (evidenceTaskId) {
|
|
39259
39312
|
const turbo = hasActiveTurboMode(input.sessionID);
|
|
39260
39313
|
const gateAgents = [
|
|
@@ -39376,8 +39429,7 @@ function createDelegationGateHook(config2, directory) {
|
|
|
39376
39429
|
}
|
|
39377
39430
|
}
|
|
39378
39431
|
try {
|
|
39379
|
-
const
|
|
39380
|
-
const evidenceTaskId = typeof rawTaskId === "string" && rawTaskId.length <= 20 && isStrictTaskId(rawTaskId.trim()) ? rawTaskId.trim() : await getEvidenceTaskId(session, directory);
|
|
39432
|
+
const evidenceTaskId = await resolveEvidenceTaskId(directArgs, session, directory);
|
|
39381
39433
|
if (evidenceTaskId) {
|
|
39382
39434
|
const turbo = hasActiveTurboMode(input.sessionID);
|
|
39383
39435
|
if (hasReviewer) {
|
|
@@ -67331,7 +67383,7 @@ function defaultBuildTestCommand(profile, framework, files, dir = ".", opts = {}
|
|
|
67331
67383
|
const coverage = opts.coverage ?? false;
|
|
67332
67384
|
switch (framework) {
|
|
67333
67385
|
case "bun": {
|
|
67334
|
-
const args2 = ["bun", "test"];
|
|
67386
|
+
const args2 = ["bun", "--smol", "test"];
|
|
67335
67387
|
if (coverage)
|
|
67336
67388
|
args2.push("--coverage");
|
|
67337
67389
|
if (scope !== "all" && files.length > 0)
|
|
@@ -69764,7 +69816,7 @@ function getTargetedExecutionUnsupportedReason(framework) {
|
|
|
69764
69816
|
function buildTestCommand2(framework, scope, files, coverage, baseDir) {
|
|
69765
69817
|
switch (framework) {
|
|
69766
69818
|
case "bun": {
|
|
69767
|
-
const args2 = ["bun", "test"];
|
|
69819
|
+
const args2 = ["bun", "--smol", "test"];
|
|
69768
69820
|
if (coverage)
|
|
69769
69821
|
args2.push("--coverage");
|
|
69770
69822
|
if (scope !== "all" && files.length > 0) {
|
|
@@ -70301,17 +70353,24 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
|
|
|
70301
70353
|
const proc = bunSpawn(command, {
|
|
70302
70354
|
stdout: "pipe",
|
|
70303
70355
|
stderr: "pipe",
|
|
70304
|
-
|
|
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);
|
|
70305
70366
|
});
|
|
70306
|
-
const timeoutPromise = new Promise((resolve16) => setTimeout(() => {
|
|
70307
|
-
proc.kill();
|
|
70308
|
-
resolve16(-1);
|
|
70309
|
-
}, timeout_ms));
|
|
70310
70367
|
const [exitCode, stdoutResult, stderrResult] = await Promise.all([
|
|
70311
70368
|
Promise.race([proc.exited, timeoutPromise]),
|
|
70312
70369
|
readBoundedStream(proc.stdout, MAX_OUTPUT_BYTES3),
|
|
70313
70370
|
readBoundedStream(proc.stderr, MAX_OUTPUT_BYTES3)
|
|
70314
70371
|
]);
|
|
70372
|
+
if (timeoutHandle !== undefined)
|
|
70373
|
+
clearTimeout(timeoutHandle);
|
|
70315
70374
|
const duration_ms = Date.now() - startTime;
|
|
70316
70375
|
let output = stdoutResult.text;
|
|
70317
70376
|
if (stderrResult.text) {
|
|
@@ -70614,7 +70673,6 @@ var init_test_runner = __esm(() => {
|
|
|
70614
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.'),
|
|
70615
70674
|
coverage: exports_external.boolean().optional().describe("Enable coverage reporting if supported"),
|
|
70616
70675
|
timeout_ms: exports_external.number().optional().describe("Timeout in milliseconds (default 60000, max 300000)"),
|
|
70617
|
-
allow_full_suite: exports_external.boolean().optional().describe('Explicit opt-in for scope "all". Required because full-suite output can destabilize SSE streaming.'),
|
|
70618
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.")
|
|
70619
70677
|
},
|
|
70620
70678
|
async execute(args2, directory) {
|
|
@@ -70688,7 +70746,8 @@ var init_test_runner = __esm(() => {
|
|
|
70688
70746
|
}
|
|
70689
70747
|
const scope = args2.scope || "all";
|
|
70690
70748
|
if (scope === "all") {
|
|
70691
|
-
|
|
70749
|
+
const fullSuiteAllowed = process.env.SWARM_ALLOW_FULL_SUITE === "1" || process.env.SWARM_ALLOW_FULL_SUITE === "true";
|
|
70750
|
+
if (!fullSuiteAllowed) {
|
|
70692
70751
|
const errorResult = {
|
|
70693
70752
|
success: false,
|
|
70694
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.
|
|
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",
|