opencode-swarm 7.77.5 → 7.77.7
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
|
@@ -52,7 +52,7 @@ var package_default;
|
|
|
52
52
|
var init_package = __esm(() => {
|
|
53
53
|
package_default = {
|
|
54
54
|
name: "opencode-swarm",
|
|
55
|
-
version: "7.77.
|
|
55
|
+
version: "7.77.7",
|
|
56
56
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
57
57
|
main: "dist/index.js",
|
|
58
58
|
types: "dist/index.d.ts",
|
package/dist/index.js
CHANGED
|
@@ -69,7 +69,7 @@ var package_default;
|
|
|
69
69
|
var init_package = __esm(() => {
|
|
70
70
|
package_default = {
|
|
71
71
|
name: "opencode-swarm",
|
|
72
|
-
version: "7.77.
|
|
72
|
+
version: "7.77.7",
|
|
73
73
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
74
74
|
main: "dist/index.js",
|
|
75
75
|
types: "dist/index.d.ts",
|
|
@@ -105641,7 +105641,9 @@ async function dispatchFullAutoOversight(input) {
|
|
|
105641
105641
|
const oversightAgent = createCriticAutonomousOversightAgent(input.criticModel, buildOversightPrompt(input));
|
|
105642
105642
|
log(`[full-auto/oversight] Dispatching ${oversightAgent.name} via ${input.oversightAgentName} (model=${input.criticModel}, trigger=${input.triggerSource})`);
|
|
105643
105643
|
let ephemeralSessionId;
|
|
105644
|
+
const promptController = new AbortController;
|
|
105644
105645
|
const cleanup = () => {
|
|
105646
|
+
promptController.abort();
|
|
105645
105647
|
if (ephemeralSessionId) {
|
|
105646
105648
|
const id = ephemeralSessionId;
|
|
105647
105649
|
ephemeralSessionId = undefined;
|
|
@@ -105670,7 +105672,8 @@ async function dispatchFullAutoOversight(input) {
|
|
|
105670
105672
|
agent: input.oversightAgentName,
|
|
105671
105673
|
tools: { write: false, edit: false, patch: false },
|
|
105672
105674
|
parts: [{ type: "text", text: buildOversightPrompt(input) }]
|
|
105673
|
-
}
|
|
105675
|
+
},
|
|
105676
|
+
signal: promptController.signal
|
|
105674
105677
|
});
|
|
105675
105678
|
if (!promptResult.data) {
|
|
105676
105679
|
throw new Error(`Critic prompt failed: ${JSON.stringify(promptResult.error)}`);
|
|
@@ -107582,7 +107585,9 @@ async function dispatchCriticAndWriteEvent(directory, architectOutput, criticCon
|
|
|
107582
107585
|
const oversightAgent = createCriticAutonomousOversightAgent(criticModel, criticContext);
|
|
107583
107586
|
log(`[full-auto-intercept] Dispatching critic: ${oversightAgent.name} using model ${criticModel}`);
|
|
107584
107587
|
let ephemeralSessionId;
|
|
107588
|
+
const promptController = new AbortController;
|
|
107585
107589
|
const cleanup = () => {
|
|
107590
|
+
promptController.abort();
|
|
107586
107591
|
if (ephemeralSessionId) {
|
|
107587
107592
|
const id = ephemeralSessionId;
|
|
107588
107593
|
ephemeralSessionId = undefined;
|
|
@@ -107608,7 +107613,8 @@ async function dispatchCriticAndWriteEvent(directory, architectOutput, criticCon
|
|
|
107608
107613
|
agent: oversightAgentName,
|
|
107609
107614
|
tools: { write: false, edit: false, patch: false },
|
|
107610
107615
|
parts: [{ type: "text", text: criticContext }]
|
|
107611
|
-
}
|
|
107616
|
+
},
|
|
107617
|
+
signal: promptController.signal
|
|
107612
107618
|
});
|
|
107613
107619
|
if (!promptResult.data) {
|
|
107614
107620
|
throw new Error(`Critic LLM prompt failed: ${JSON.stringify(promptResult.error)}`);
|
|
@@ -110351,11 +110357,13 @@ init_path_security();
|
|
|
110351
110357
|
import { constants as constants5, existsSync as existsSync64, readFileSync as readFileSync44, statSync as statSync24 } from "node:fs";
|
|
110352
110358
|
import * as fsPromises6 from "node:fs/promises";
|
|
110353
110359
|
import * as path111 from "node:path";
|
|
110360
|
+
var WINDOWS_RENAME_MAX_RETRIES2 = 5;
|
|
110361
|
+
var WINDOWS_RENAME_RETRY_DELAY_MS2 = 100;
|
|
110354
110362
|
var _internals68 = {
|
|
110355
|
-
safeRealpathSync
|
|
110363
|
+
safeRealpathSync,
|
|
110364
|
+
fsRename: fsPromises6.rename.bind(fsPromises6),
|
|
110365
|
+
retryDelayMs: WINDOWS_RENAME_RETRY_DELAY_MS2
|
|
110356
110366
|
};
|
|
110357
|
-
var WINDOWS_RENAME_MAX_RETRIES2 = 3;
|
|
110358
|
-
var WINDOWS_RENAME_RETRY_DELAY_MS2 = 50;
|
|
110359
110367
|
function validateLoadedGraph(parsed) {
|
|
110360
110368
|
if (!parsed.schema_version) {
|
|
110361
110369
|
throw Object.assign(new Error("repo-graph.json missing schema_version"), {
|
|
@@ -110537,21 +110545,25 @@ async function saveGraph(workspace, graph, options) {
|
|
|
110537
110545
|
throw lastError;
|
|
110538
110546
|
}
|
|
110539
110547
|
} else {
|
|
110540
|
-
let
|
|
110541
|
-
while (retries < WINDOWS_RENAME_MAX_RETRIES2) {
|
|
110548
|
+
for (let attempt = 0;attempt < WINDOWS_RENAME_MAX_RETRIES2; attempt++) {
|
|
110542
110549
|
try {
|
|
110543
|
-
await
|
|
110550
|
+
await _internals68.fsRename(tempPath, graphPath);
|
|
110551
|
+
lastError = null;
|
|
110544
110552
|
break;
|
|
110545
110553
|
} catch (error93) {
|
|
110546
110554
|
lastError = error93 instanceof Error ? error93 : new Error(String(error93));
|
|
110547
|
-
|
|
110548
|
-
|
|
110549
|
-
|
|
110550
|
-
|
|
110555
|
+
const code = lastError.code;
|
|
110556
|
+
if (code !== "EEXIST" && code !== "EPERM" && code !== "EBUSY") {
|
|
110557
|
+
break;
|
|
110558
|
+
}
|
|
110559
|
+
if (attempt < WINDOWS_RENAME_MAX_RETRIES2 - 1) {
|
|
110560
|
+
await new Promise((resolve41) => setTimeout(resolve41, _internals68.retryDelayMs));
|
|
110551
110561
|
}
|
|
110552
|
-
throw lastError;
|
|
110553
110562
|
}
|
|
110554
110563
|
}
|
|
110564
|
+
if (lastError) {
|
|
110565
|
+
throw lastError;
|
|
110566
|
+
}
|
|
110555
110567
|
}
|
|
110556
110568
|
} finally {
|
|
110557
110569
|
try {
|
|
@@ -114183,6 +114195,8 @@ async function defaultDispatchReviewerAgent(directory, reviewPackage, agentName,
|
|
|
114183
114195
|
throw new Error("Failed to create reviewer session");
|
|
114184
114196
|
}
|
|
114185
114197
|
const sessionId = sessionResult.data.id;
|
|
114198
|
+
const promptController = new AbortController;
|
|
114199
|
+
let timeoutHandle;
|
|
114186
114200
|
try {
|
|
114187
114201
|
const promptText = `You are a read-only phase reviewer for Lean Turbo execution.
|
|
114188
114202
|
|
|
@@ -114227,16 +114241,23 @@ Be specific and evidence-based. Do not approve a phase with unresolved degraded
|
|
|
114227
114241
|
agent: agentName,
|
|
114228
114242
|
tools: { write: false, edit: false, patch: false },
|
|
114229
114243
|
parts: [{ type: "text", text: promptText }]
|
|
114230
|
-
}
|
|
114244
|
+
},
|
|
114245
|
+
signal: promptController.signal
|
|
114231
114246
|
}),
|
|
114232
|
-
new Promise((_, reject) =>
|
|
114247
|
+
new Promise((_, reject) => {
|
|
114248
|
+
timeoutHandle = setTimeout(() => {
|
|
114249
|
+
promptController.abort();
|
|
114250
|
+
reject(new Error(`Reviewer dispatch timed out after ${timeoutMs}ms`));
|
|
114251
|
+
}, timeoutMs);
|
|
114252
|
+
})
|
|
114233
114253
|
]) : await client.session.prompt({
|
|
114234
114254
|
path: { id: sessionId },
|
|
114235
114255
|
body: {
|
|
114236
114256
|
agent: agentName,
|
|
114237
114257
|
tools: { write: false, edit: false, patch: false },
|
|
114238
114258
|
parts: [{ type: "text", text: promptText }]
|
|
114239
|
-
}
|
|
114259
|
+
},
|
|
114260
|
+
signal: promptController.signal
|
|
114240
114261
|
});
|
|
114241
114262
|
if (!response.data) {
|
|
114242
114263
|
throw new Error("Reviewer session returned no data");
|
|
@@ -114245,6 +114266,9 @@ Be specific and evidence-based. Do not approve a phase with unresolved degraded
|
|
|
114245
114266
|
`);
|
|
114246
114267
|
return textParts;
|
|
114247
114268
|
} finally {
|
|
114269
|
+
if (timeoutHandle !== undefined)
|
|
114270
|
+
clearTimeout(timeoutHandle);
|
|
114271
|
+
promptController.abort();
|
|
114248
114272
|
client.session.delete({ path: { id: sessionId } }).catch(() => {});
|
|
114249
114273
|
}
|
|
114250
114274
|
}
|
|
@@ -114528,6 +114552,7 @@ async function dispatchReviewer(directory, prompt, agentName, timeoutMs) {
|
|
|
114528
114552
|
throw new Error("Failed to create auto-review session");
|
|
114529
114553
|
}
|
|
114530
114554
|
const sessionId = createResult.data.id;
|
|
114555
|
+
const promptController = new AbortController;
|
|
114531
114556
|
let timeoutHandle;
|
|
114532
114557
|
try {
|
|
114533
114558
|
const promptCall = client.session.prompt({
|
|
@@ -114536,12 +114561,16 @@ async function dispatchReviewer(directory, prompt, agentName, timeoutMs) {
|
|
|
114536
114561
|
agent: agentName,
|
|
114537
114562
|
tools: { write: false, edit: false, patch: false },
|
|
114538
114563
|
parts: [{ type: "text", text: prompt }]
|
|
114539
|
-
}
|
|
114564
|
+
},
|
|
114565
|
+
signal: promptController.signal
|
|
114540
114566
|
});
|
|
114541
114567
|
const response = await Promise.race([
|
|
114542
114568
|
promptCall,
|
|
114543
114569
|
new Promise((_, reject) => {
|
|
114544
|
-
timeoutHandle = setTimeout(() =>
|
|
114570
|
+
timeoutHandle = setTimeout(() => {
|
|
114571
|
+
promptController.abort();
|
|
114572
|
+
reject(new Error(`auto-review timed out after ${timeoutMs}ms`));
|
|
114573
|
+
}, timeoutMs);
|
|
114545
114574
|
})
|
|
114546
114575
|
]);
|
|
114547
114576
|
if (!response.data) {
|
|
@@ -114552,6 +114581,7 @@ async function dispatchReviewer(directory, prompt, agentName, timeoutMs) {
|
|
|
114552
114581
|
} finally {
|
|
114553
114582
|
if (timeoutHandle !== undefined)
|
|
114554
114583
|
clearTimeout(timeoutHandle);
|
|
114584
|
+
promptController.abort();
|
|
114555
114585
|
client.session.delete({ path: { id: sessionId } }).catch(() => {});
|
|
114556
114586
|
}
|
|
114557
114587
|
}
|
|
@@ -124895,6 +124925,7 @@ async function runLane(session, dispatcher, lane, directory, timeoutMs, context)
|
|
|
124895
124925
|
error: `dispatcher ${decision.action}: ${decision.reason}`
|
|
124896
124926
|
};
|
|
124897
124927
|
}
|
|
124928
|
+
const promptController = new AbortController;
|
|
124898
124929
|
let sessionId;
|
|
124899
124930
|
try {
|
|
124900
124931
|
const createTimeoutMessage = `Lane "${lane.id}" session.create timed out after ${timeoutMs}ms`;
|
|
@@ -124923,8 +124954,9 @@ async function runLane(session, dispatcher, lane, directory, timeoutMs, context)
|
|
|
124923
124954
|
agent: lane.agent,
|
|
124924
124955
|
tools: buildReadOnlyTools(),
|
|
124925
124956
|
parts: [{ type: "text", text: lane.prompt }]
|
|
124926
|
-
}
|
|
124927
|
-
|
|
124957
|
+
},
|
|
124958
|
+
signal: promptController.signal
|
|
124959
|
+
}), timeoutMs, `Lane "${lane.id}" session.prompt timed out after ${timeoutMs}ms`, promptController);
|
|
124928
124960
|
if (!promptResult.data) {
|
|
124929
124961
|
return failedLane(lane, role, startedAt, `session.prompt failed: ${formatError3(promptResult.error)}`, decision.slot.slotId, decision.slot.runId, sessionId);
|
|
124930
124962
|
}
|
|
@@ -124945,6 +124977,7 @@ async function runLane(session, dispatcher, lane, directory, timeoutMs, context)
|
|
|
124945
124977
|
return failedLane(lane, role, startedAt, formatError3(error93), decision.slot.slotId, decision.slot.runId, sessionId);
|
|
124946
124978
|
} finally {
|
|
124947
124979
|
dispatcher.releaseSlot(decision.slot.slotId);
|
|
124980
|
+
promptController.abort();
|
|
124948
124981
|
if (sessionId) {
|
|
124949
124982
|
scheduleSessionCleanup(session, sessionId);
|
|
124950
124983
|
}
|
|
@@ -125082,13 +125115,19 @@ function scheduleSessionCleanup(session, sessionId) {
|
|
|
125082
125115
|
return;
|
|
125083
125116
|
});
|
|
125084
125117
|
}
|
|
125085
|
-
async function withTimeout2(promise3, timeoutMs, message) {
|
|
125118
|
+
async function withTimeout2(promise3, timeoutMs, message, controller) {
|
|
125086
125119
|
let timeout;
|
|
125087
125120
|
try {
|
|
125088
125121
|
return await Promise.race([
|
|
125089
125122
|
promise3,
|
|
125090
125123
|
new Promise((_, reject) => {
|
|
125091
|
-
timeout = setTimeout(() =>
|
|
125124
|
+
timeout = setTimeout(() => {
|
|
125125
|
+
controller?.abort();
|
|
125126
|
+
reject(new Error(message));
|
|
125127
|
+
}, timeoutMs);
|
|
125128
|
+
if (typeof timeout.unref === "function") {
|
|
125129
|
+
timeout.unref();
|
|
125130
|
+
}
|
|
125092
125131
|
})
|
|
125093
125132
|
]);
|
|
125094
125133
|
} finally {
|
|
@@ -127361,7 +127400,9 @@ async function generateMutants(files, ctx) {
|
|
|
127361
127400
|
}
|
|
127362
127401
|
const directory = ctx.directory ?? process.cwd();
|
|
127363
127402
|
let ephemeralSessionId;
|
|
127403
|
+
const promptController = new AbortController;
|
|
127364
127404
|
const cleanup = () => {
|
|
127405
|
+
promptController.abort();
|
|
127365
127406
|
if (ephemeralSessionId) {
|
|
127366
127407
|
const id = ephemeralSessionId;
|
|
127367
127408
|
ephemeralSessionId = undefined;
|
|
@@ -127408,7 +127449,8 @@ Return ONLY a valid JSON array. No markdown, no code fences, no explanation. Sta
|
|
|
127408
127449
|
agent: undefined,
|
|
127409
127450
|
tools: { write: false, edit: false, patch: false },
|
|
127410
127451
|
parts: [{ type: "text", text: promptText }]
|
|
127411
|
-
}
|
|
127452
|
+
},
|
|
127453
|
+
signal: promptController.signal
|
|
127412
127454
|
});
|
|
127413
127455
|
if (!promptResult.data) {
|
|
127414
127456
|
console.warn(`[generateMutants] LLM prompt failed: ${JSON.stringify(promptResult.error)}; returning empty patch set`);
|
|
@@ -130336,10 +130378,17 @@ class LeanTurboRunner {
|
|
|
130336
130378
|
if (!session) {
|
|
130337
130379
|
return { ok: false, error: "NO_CLIENT" };
|
|
130338
130380
|
}
|
|
130339
|
-
const
|
|
130381
|
+
const promptController = new AbortController;
|
|
130382
|
+
const dispatchPromise = this._doDispatch(session, lane, agentName, worktreeDirectory, promptController);
|
|
130340
130383
|
const timeoutMs = LeanTurboRunner._internals.laneDispatchTimeoutMs;
|
|
130341
130384
|
if (timeoutMs !== undefined && timeoutMs > 0) {
|
|
130342
|
-
|
|
130385
|
+
let timeoutHandle;
|
|
130386
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
130387
|
+
timeoutHandle = setTimeout(() => {
|
|
130388
|
+
promptController.abort();
|
|
130389
|
+
reject(new Error(`Lane dispatch timed out after ${timeoutMs}ms`));
|
|
130390
|
+
}, timeoutMs);
|
|
130391
|
+
});
|
|
130343
130392
|
try {
|
|
130344
130393
|
return await Promise.race([dispatchPromise, timeoutPromise]);
|
|
130345
130394
|
} catch (err2) {
|
|
@@ -130363,11 +130412,15 @@ class LeanTurboRunner {
|
|
|
130363
130412
|
return { ok: false, error: err2.message };
|
|
130364
130413
|
}
|
|
130365
130414
|
throw err2;
|
|
130415
|
+
} finally {
|
|
130416
|
+
if (timeoutHandle !== undefined)
|
|
130417
|
+
clearTimeout(timeoutHandle);
|
|
130366
130418
|
}
|
|
130367
130419
|
}
|
|
130368
130420
|
return dispatchPromise;
|
|
130369
130421
|
}
|
|
130370
|
-
async _doDispatch(session, lane, agentName, worktreeDirectory) {
|
|
130422
|
+
async _doDispatch(session, lane, agentName, worktreeDirectory, abortController) {
|
|
130423
|
+
let sessionId;
|
|
130371
130424
|
try {
|
|
130372
130425
|
const effectiveDirectory = worktreeDirectory ?? this._directory;
|
|
130373
130426
|
const createResult = await session.create({
|
|
@@ -130385,7 +130438,7 @@ class LeanTurboRunner {
|
|
|
130385
130438
|
error: `session.create failed: ${typeof createResult.error === "string" ? createResult.error : JSON.stringify(createResult.error)}`
|
|
130386
130439
|
};
|
|
130387
130440
|
}
|
|
130388
|
-
|
|
130441
|
+
sessionId = createResult.data.id;
|
|
130389
130442
|
const promptText = this._buildLanePrompt(lane);
|
|
130390
130443
|
const promptResult = await session.prompt({
|
|
130391
130444
|
path: { id: sessionId },
|
|
@@ -130393,9 +130446,11 @@ class LeanTurboRunner {
|
|
|
130393
130446
|
agent: agentName,
|
|
130394
130447
|
tools: { write: true, edit: true, patch: true },
|
|
130395
130448
|
parts: [{ type: "text", text: promptText }]
|
|
130396
|
-
}
|
|
130449
|
+
},
|
|
130450
|
+
signal: abortController?.signal
|
|
130397
130451
|
});
|
|
130398
130452
|
if (!promptResult.data) {
|
|
130453
|
+
abortController?.abort();
|
|
130399
130454
|
session.delete({ path: { id: sessionId } }).catch(() => {});
|
|
130400
130455
|
return {
|
|
130401
130456
|
ok: false,
|
|
@@ -130404,6 +130459,10 @@ class LeanTurboRunner {
|
|
|
130404
130459
|
}
|
|
130405
130460
|
return { ok: true, sessionId };
|
|
130406
130461
|
} catch (err2) {
|
|
130462
|
+
if (sessionId) {
|
|
130463
|
+
abortController?.abort();
|
|
130464
|
+
session.delete({ path: { id: sessionId } }).catch(() => {});
|
|
130465
|
+
}
|
|
130407
130466
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
130408
130467
|
return { ok: false, error: msg };
|
|
130409
130468
|
}
|
|
@@ -5,14 +5,21 @@
|
|
|
5
5
|
* writes. Reads validate schema and content before updating the in-memory
|
|
6
6
|
* cache. Symlink resolution guards against workspace-escape attacks.
|
|
7
7
|
*/
|
|
8
|
+
import * as fsPromises from 'node:fs/promises';
|
|
8
9
|
import { safeRealpathSync } from './safe-realpath';
|
|
9
10
|
import type { RepoGraph } from './types';
|
|
10
11
|
/**
|
|
11
12
|
* Internal function references for testability.
|
|
12
13
|
* Replace _internals.safeRealpathSync in tests to mock symlink resolution.
|
|
14
|
+
* Replace _internals.fsRename to exercise the rename retry path (e.g. EPERM).
|
|
15
|
+
* Set _internals.retryDelayMs = 0 in tests to skip real sleeps while still
|
|
16
|
+
* exercising multi-retry paths.
|
|
17
|
+
* Restore each entry in afterEach via the saved original reference.
|
|
13
18
|
*/
|
|
14
19
|
export declare const _internals: {
|
|
15
20
|
safeRealpathSync: typeof safeRealpathSync;
|
|
21
|
+
fsRename: typeof fsPromises.rename;
|
|
22
|
+
retryDelayMs: number;
|
|
16
23
|
};
|
|
17
24
|
/**
|
|
18
25
|
* Get the validated path for the repo-graph.json file.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "7.77.
|
|
3
|
+
"version": "7.77.7",
|
|
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",
|