opencode-swarm 7.22.0 → 7.22.1
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 +9 -2
- package/dist/index.js +79 -5
- 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.22.
|
|
37
|
+
version: "7.22.1",
|
|
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",
|
|
@@ -21023,9 +21023,10 @@ var init_guardrails = __esm(() => {
|
|
|
21023
21023
|
function clearPendingCoderScope() {
|
|
21024
21024
|
pendingCoderScopeByTaskId.clear();
|
|
21025
21025
|
}
|
|
21026
|
-
var pendingCoderScopeByTaskId;
|
|
21026
|
+
var pendingCoderScopeByTaskId, ACTIVE_PARALLEL_TASK_STATES;
|
|
21027
21027
|
var init_delegation_gate = __esm(() => {
|
|
21028
21028
|
init_schema();
|
|
21029
|
+
init_manager();
|
|
21029
21030
|
init_state();
|
|
21030
21031
|
init_telemetry();
|
|
21031
21032
|
init_logger();
|
|
@@ -21034,6 +21035,12 @@ var init_delegation_gate = __esm(() => {
|
|
|
21034
21035
|
init_normalize_tool_name();
|
|
21035
21036
|
init_utils2();
|
|
21036
21037
|
pendingCoderScopeByTaskId = new Map;
|
|
21038
|
+
ACTIVE_PARALLEL_TASK_STATES = new Set([
|
|
21039
|
+
"coder_delegated",
|
|
21040
|
+
"pre_check_passed",
|
|
21041
|
+
"reviewer_run",
|
|
21042
|
+
"tests_run"
|
|
21043
|
+
]);
|
|
21037
21044
|
});
|
|
21038
21045
|
|
|
21039
21046
|
// src/state/agent-run-context.ts
|
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.22.
|
|
36
|
+
version: "7.22.1",
|
|
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",
|
|
@@ -26774,6 +26774,70 @@ function extractPlanTaskId(text) {
|
|
|
26774
26774
|
function getSeedTaskId(session) {
|
|
26775
26775
|
return session.currentTaskId ?? session.lastCoderDelegationTaskId;
|
|
26776
26776
|
}
|
|
26777
|
+
function isTaskCompletedForParallelGuidance(task) {
|
|
26778
|
+
const status = task.status ?? "pending";
|
|
26779
|
+
return status === "completed" || status === "closed";
|
|
26780
|
+
}
|
|
26781
|
+
async function buildParallelExecutionGuidance(directory, sessionID, session) {
|
|
26782
|
+
if (!directory)
|
|
26783
|
+
return null;
|
|
26784
|
+
const plan = await loadPlanJsonOnly(directory);
|
|
26785
|
+
if (!plan) {
|
|
26786
|
+
return null;
|
|
26787
|
+
}
|
|
26788
|
+
const profile = plan.execution_profile;
|
|
26789
|
+
const enabled = profile?.parallelization_enabled === true;
|
|
26790
|
+
const maxConcurrent = profile?.max_concurrent_tasks ?? 1;
|
|
26791
|
+
if (!enabled || maxConcurrent <= 1)
|
|
26792
|
+
return null;
|
|
26793
|
+
if (hasActiveLeanTurbo(sessionID)) {
|
|
26794
|
+
return "[NEXT] Lean Turbo is active; use lean_turbo_run_phase and Lean Turbo lane guidance instead of standard execution-profile slot filling.";
|
|
26795
|
+
}
|
|
26796
|
+
const currentPhase = plan.current_phase !== undefined ? plan.phases.find((phase) => phase.id === plan.current_phase) : plan.phases.find((phase) => !isParallelGuidancePhaseComplete(phase));
|
|
26797
|
+
if (!currentPhase)
|
|
26798
|
+
return null;
|
|
26799
|
+
const tasks = currentPhase.tasks;
|
|
26800
|
+
if (tasks.length === 0)
|
|
26801
|
+
return null;
|
|
26802
|
+
const allTasks = plan.phases.flatMap((phase) => phase.tasks);
|
|
26803
|
+
const completed = new Set;
|
|
26804
|
+
for (const task of allTasks) {
|
|
26805
|
+
const taskId = task.id;
|
|
26806
|
+
if (isTaskCompletedForParallelGuidance(task))
|
|
26807
|
+
completed.add(taskId);
|
|
26808
|
+
if (getTaskState(session, taskId) === "complete")
|
|
26809
|
+
completed.add(taskId);
|
|
26810
|
+
}
|
|
26811
|
+
const occupied = new Set;
|
|
26812
|
+
for (const task of allTasks) {
|
|
26813
|
+
const taskId = task.id;
|
|
26814
|
+
if (task.status === "in_progress")
|
|
26815
|
+
occupied.add(taskId);
|
|
26816
|
+
const state = getTaskState(session, taskId);
|
|
26817
|
+
if (ACTIVE_PARALLEL_TASK_STATES.has(state))
|
|
26818
|
+
occupied.add(taskId);
|
|
26819
|
+
}
|
|
26820
|
+
const availableSlots = Math.max(0, maxConcurrent - occupied.size);
|
|
26821
|
+
if (availableSlots <= 0) {
|
|
26822
|
+
return `[PARALLEL EXECUTION PROFILE] parallelization_enabled=true max_concurrent_tasks=${maxConcurrent}; all standard execution slots are occupied. Continue current active task gates before starting more coder work.`;
|
|
26823
|
+
}
|
|
26824
|
+
const eligible = tasks.filter((task) => {
|
|
26825
|
+
const taskId = task.id;
|
|
26826
|
+
const status = task.status ?? "pending";
|
|
26827
|
+
if (status !== "pending")
|
|
26828
|
+
return false;
|
|
26829
|
+
if (occupied.has(taskId))
|
|
26830
|
+
return false;
|
|
26831
|
+
return task.depends.every((dep) => completed.has(dep));
|
|
26832
|
+
}).map((task) => task.id).slice(0, availableSlots);
|
|
26833
|
+
if (eligible.length === 0) {
|
|
26834
|
+
return `[PARALLEL EXECUTION PROFILE] parallelization_enabled=true max_concurrent_tasks=${maxConcurrent}; no dependency-ready pending tasks are available for a new coder slot. Continue the current task/gate.`;
|
|
26835
|
+
}
|
|
26836
|
+
return `[PARALLEL EXECUTION PROFILE] parallelization_enabled=true max_concurrent_tasks=${maxConcurrent}; ${occupied.size} slot(s) occupied. Eligible now: ${eligible.join(", ")}. [NEXT] dispatch up to ${availableSlots} eligible coder task(s) before waiting; preserve ONE task per coder call and call declare_scope for each task.`;
|
|
26837
|
+
}
|
|
26838
|
+
function isParallelGuidancePhaseComplete(phase) {
|
|
26839
|
+
return phase.status === "complete" || phase.status === "completed" || phase.status === "closed";
|
|
26840
|
+
}
|
|
26777
26841
|
async function getEvidenceTaskId(session, directory) {
|
|
26778
26842
|
const primary = session.currentTaskId ?? session.lastCoderDelegationTaskId;
|
|
26779
26843
|
if (primary)
|
|
@@ -27279,15 +27343,16 @@ ${trimComment}${after}`;
|
|
|
27279
27343
|
if (!/^[a-zA-Z0-9_-]{1,128}$/.test(deliberationSessionID)) {} else {
|
|
27280
27344
|
const deliberationSession = ensureAgentSession(deliberationSessionID);
|
|
27281
27345
|
const lastGate = deliberationSession.lastGateOutcome;
|
|
27346
|
+
const parallelGuidance = await buildParallelExecutionGuidance(directory, deliberationSessionID, deliberationSession);
|
|
27282
27347
|
let guidance;
|
|
27283
27348
|
if (lastGate?.taskId) {
|
|
27284
27349
|
const gateResult = lastGate.passed ? "PASSED" : "FAILED";
|
|
27285
27350
|
const sanitizedGate = lastGate.gate.replace(/</g, "<").replace(/>/g, ">").replace(/\[ \]/g, "()").replace(/\[/g, "(").replace(/\]/g, ")").replace(/[\r\n]/g, " ").slice(0, 64);
|
|
27286
27351
|
const sanitizedTaskId = lastGate.taskId.replace(/</g, "<").replace(/>/g, ">").replace(/\[/g, "(").replace(/\]/g, ")").replace(/[\r\n]/g, " ").slice(0, 32);
|
|
27287
27352
|
guidance = `[Last gate: ${sanitizedGate} ${gateResult} for task ${sanitizedTaskId}]
|
|
27288
|
-
[NEXT] Execute the next gate for the current task
|
|
27353
|
+
${parallelGuidance ?? "[NEXT] Execute the next gate for the current task."}`;
|
|
27289
27354
|
} else {
|
|
27290
|
-
guidance = "[NEXT] Begin the first plan task and run gates sequentially.";
|
|
27355
|
+
guidance = parallelGuidance ?? "[NEXT] Begin the first plan task and run gates sequentially.";
|
|
27291
27356
|
}
|
|
27292
27357
|
const systemMsgIdx = messages.findIndex((m) => m && m.info?.role === "system");
|
|
27293
27358
|
const insertIdx = systemMsgIdx >= 0 ? systemMsgIdx + 1 : 0;
|
|
@@ -27380,9 +27445,10 @@ ${warningLines.join(`
|
|
|
27380
27445
|
toolAfter
|
|
27381
27446
|
};
|
|
27382
27447
|
}
|
|
27383
|
-
var pendingCoderScopeByTaskId;
|
|
27448
|
+
var pendingCoderScopeByTaskId, ACTIVE_PARALLEL_TASK_STATES;
|
|
27384
27449
|
var init_delegation_gate = __esm(() => {
|
|
27385
27450
|
init_schema();
|
|
27451
|
+
init_manager();
|
|
27386
27452
|
init_state();
|
|
27387
27453
|
init_telemetry();
|
|
27388
27454
|
init_logger();
|
|
@@ -27391,6 +27457,12 @@ var init_delegation_gate = __esm(() => {
|
|
|
27391
27457
|
init_normalize_tool_name();
|
|
27392
27458
|
init_utils2();
|
|
27393
27459
|
pendingCoderScopeByTaskId = new Map;
|
|
27460
|
+
ACTIVE_PARALLEL_TASK_STATES = new Set([
|
|
27461
|
+
"coder_delegated",
|
|
27462
|
+
"pre_check_passed",
|
|
27463
|
+
"reviewer_run",
|
|
27464
|
+
"tests_run"
|
|
27465
|
+
]);
|
|
27394
27466
|
});
|
|
27395
27467
|
|
|
27396
27468
|
// src/state/agent-run-context.ts
|
|
@@ -62853,6 +62925,8 @@ If a tool modifies a file, it is a CODER tool. Delegate.
|
|
|
62853
62925
|
- Rationale: declare_scope persists the allowed set to disk (.swarm/scopes/scope-\${taskId}.json) so it survives cross-process delegation. Without a call, the coder process reads an empty scope and every Edit/Write is denied.
|
|
62854
62926
|
<!-- BEHAVIORAL_GUIDANCE_END -->
|
|
62855
62927
|
2. ONE agent per message. Send, STOP, wait for response.
|
|
62928
|
+
Exception: Stage B reviewer/test_engineer gate agents for the SAME completed coder task may be dispatched together before waiting when both gates are required.
|
|
62929
|
+
This exception NEVER applies to coder delegations. Preserve ONE task per coder call.
|
|
62856
62930
|
3. ONE task per {{AGENT_PREFIX}}coder call. Never batch.
|
|
62857
62931
|
3a. PRE-DELEGATION SCOPE CALL (required): BEFORE every {{AGENT_PREFIX}}coder delegation, you MUST call \`declare_scope\` with { taskId, files } listing the exact file(s) this task will modify (including generated/lockfile paths). No \`declare_scope\` call → no coder delegation. See Rule 1a.
|
|
62858
62932
|
<!-- BEHAVIORAL_GUIDANCE_START -->
|
|
@@ -62993,7 +63067,7 @@ VERIFICATION PROTOCOL: After the coder reports DONE, and before running Stage B
|
|
|
62993
63067
|
The reviewer's verdict MUST include a REUSE_RE_VERIFICATION field — do NOT accept an APPROVED verdict without it. Validate the field value against context: if the coder's EXPORTS_ADDED was non-empty, REUSE_RE_VERIFICATION must be VERIFIED or DUPLICATION_DETECTED (not SKIPPED). If EXPORTS_ADDED was "none", REUSE_RE_VERIFICATION must be SKIPPED.
|
|
62994
63068
|
Stage B runs by default for TIER 1-3 classifications. Stage A passing does not satisfy Stage B.
|
|
62995
63069
|
Stage B is where logic errors, security flaws, edge cases, and behavioral bugs are caught.
|
|
62996
|
-
You MUST delegate to each Stage B agent
|
|
63070
|
+
You MUST delegate to each required Stage B agent. For the standard reviewer + test_engineer pair, dispatch both before waiting so Stage B actually runs in parallel.
|
|
62997
63071
|
|
|
62998
63072
|
Stage B (reviewer + test_engineer) **always runs per-task** regardless of council mode — it is never replaced, never omitted, never deferred. When \`council_mode\` is enabled in the QA gate profile, a **phase-level** council review is additionally required before calling \`phase_complete\`: dispatch all 5 council members, collect their verdicts, call \`submit_phase_council_verdicts\`, then call \`phase_complete\` (Gate 5 validates the resulting \`phase-council.json\` evidence). Stage A (\`pre_check_batch\`) still runs as the pre-review gate for each task.
|
|
62999
63073
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "7.22.
|
|
3
|
+
"version": "7.22.1",
|
|
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",
|