opencode-swarm 7.38.0 → 7.39.0
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 +131 -5
- package/dist/commands/concurrency.d.ts +10 -0
- package/dist/commands/index.d.ts +2 -1
- package/dist/commands/registry.d.ts +7 -0
- package/dist/hooks/delegation-gate.d.ts +4 -1
- package/dist/index.js +144 -15
- package/dist/session/snapshot-writer.d.ts +2 -0
- package/dist/state.d.ts +4 -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.
|
|
37
|
+
version: "7.39.0",
|
|
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",
|
|
@@ -38860,6 +38860,110 @@ var init_close = __esm(() => {
|
|
|
38860
38860
|
];
|
|
38861
38861
|
});
|
|
38862
38862
|
|
|
38863
|
+
// src/commands/concurrency.ts
|
|
38864
|
+
async function handleConcurrencyCommand(directory, args, sessionID) {
|
|
38865
|
+
if (!sessionID || sessionID.trim() === "") {
|
|
38866
|
+
return "Error: No active session context. Concurrency requires an active session. Use /swarm concurrency from within an OpenCode session, or start a session first.";
|
|
38867
|
+
}
|
|
38868
|
+
const session = getAgentSession(sessionID);
|
|
38869
|
+
if (!session) {
|
|
38870
|
+
return "Error: No active session. Concurrency requires an active session to operate.";
|
|
38871
|
+
}
|
|
38872
|
+
const arg0 = args[0]?.toLowerCase();
|
|
38873
|
+
const arg1 = args[1];
|
|
38874
|
+
const plan = await loadPlanJsonOnly(directory).catch(() => null);
|
|
38875
|
+
const hasPlan = plan !== null && plan !== undefined;
|
|
38876
|
+
if (arg0 === undefined) {
|
|
38877
|
+
return [
|
|
38878
|
+
"Concurrency commands:",
|
|
38879
|
+
" /swarm concurrency set <N|preset> \u2014 Set session concurrency override (1-64 or min/medium/max)",
|
|
38880
|
+
" /swarm concurrency status \u2014 Show effective concurrency",
|
|
38881
|
+
" /swarm concurrency reset \u2014 Clear the override"
|
|
38882
|
+
].join(`
|
|
38883
|
+
`);
|
|
38884
|
+
}
|
|
38885
|
+
if (arg0 === "status") {
|
|
38886
|
+
return buildStatusMessage(session, plan);
|
|
38887
|
+
}
|
|
38888
|
+
if (!hasPlan) {
|
|
38889
|
+
if (arg0 === "set") {
|
|
38890
|
+
return "No active plan. Concurrency override requires an active plan.";
|
|
38891
|
+
}
|
|
38892
|
+
}
|
|
38893
|
+
if (arg0 === "reset") {
|
|
38894
|
+
session.maxConcurrencyOverride = undefined;
|
|
38895
|
+
return "Concurrency override cleared";
|
|
38896
|
+
}
|
|
38897
|
+
if (arg0 === "set") {
|
|
38898
|
+
if (arg1 === undefined) {
|
|
38899
|
+
return "Error: /swarm concurrency set requires a value. Usage: /swarm concurrency set <N|preset>";
|
|
38900
|
+
}
|
|
38901
|
+
return handleSetCommand(session, arg1);
|
|
38902
|
+
}
|
|
38903
|
+
return [
|
|
38904
|
+
`Unknown concurrency subcommand: ${arg0}`,
|
|
38905
|
+
"Usage: /swarm concurrency <set|status|reset>"
|
|
38906
|
+
].join(`
|
|
38907
|
+
`);
|
|
38908
|
+
}
|
|
38909
|
+
function handleSetCommand(session, value) {
|
|
38910
|
+
const normalizedValue = value.toLowerCase();
|
|
38911
|
+
if (normalizedValue in PRESETS) {
|
|
38912
|
+
const presetConcurrency = PRESETS[normalizedValue];
|
|
38913
|
+
session.maxConcurrencyOverride = presetConcurrency;
|
|
38914
|
+
return `Concurrency override set to ${presetConcurrency} (${normalizedValue})`;
|
|
38915
|
+
}
|
|
38916
|
+
const numericValue = Number(value);
|
|
38917
|
+
if (Number.isNaN(numericValue)) {
|
|
38918
|
+
return `Invalid concurrency value: ${value}. Must be a number (1-64) or a preset (min, medium, max).`;
|
|
38919
|
+
}
|
|
38920
|
+
if (!Number.isInteger(numericValue)) {
|
|
38921
|
+
return `Invalid concurrency value: ${value}. Must be a number (1-64) or a preset (min, medium, max).`;
|
|
38922
|
+
}
|
|
38923
|
+
if (numericValue < MIN_CONCURRENCY || numericValue > MAX_CONCURRENCY) {
|
|
38924
|
+
return `Concurrency value ${value} is out of range. Must be between ${MIN_CONCURRENCY} and ${MAX_CONCURRENCY}.`;
|
|
38925
|
+
}
|
|
38926
|
+
session.maxConcurrencyOverride = numericValue;
|
|
38927
|
+
return `Concurrency override set to ${numericValue}`;
|
|
38928
|
+
}
|
|
38929
|
+
function buildStatusMessage(session, plan) {
|
|
38930
|
+
const overrideActive = session.maxConcurrencyOverride !== undefined;
|
|
38931
|
+
const configuredOverride = session.maxConcurrencyOverride ?? "absent";
|
|
38932
|
+
const hasPlan = plan !== null && plan !== undefined;
|
|
38933
|
+
const planBaseline = hasPlan ? plan.execution_profile?.max_concurrent_tasks ?? 1 : 1;
|
|
38934
|
+
const parallelizationEnabled = hasPlan ? plan.execution_profile?.parallelization_enabled ?? false : false;
|
|
38935
|
+
const operationalEffective = !parallelizationEnabled ? 1 : session.maxConcurrencyOverride ?? planBaseline;
|
|
38936
|
+
let description;
|
|
38937
|
+
if (!hasPlan) {
|
|
38938
|
+
description = "No active plan";
|
|
38939
|
+
} else if (!parallelizationEnabled) {
|
|
38940
|
+
description = "Parallelization disabled (always 1)";
|
|
38941
|
+
} else if (overrideActive) {
|
|
38942
|
+
description = `Override active (${session.maxConcurrencyOverride})`;
|
|
38943
|
+
} else {
|
|
38944
|
+
description = `Plan baseline (${planBaseline})`;
|
|
38945
|
+
}
|
|
38946
|
+
return [
|
|
38947
|
+
`Concurrency: ${description}`,
|
|
38948
|
+
` override_active: ${overrideActive}`,
|
|
38949
|
+
` configured_override: ${configuredOverride}`,
|
|
38950
|
+
` plan_baseline: ${planBaseline}`,
|
|
38951
|
+
` operational_effective: ${operationalEffective}`,
|
|
38952
|
+
` parallelization_enabled: ${parallelizationEnabled}`
|
|
38953
|
+
].join(`
|
|
38954
|
+
`);
|
|
38955
|
+
}
|
|
38956
|
+
var PRESETS, MIN_CONCURRENCY = 1, MAX_CONCURRENCY = 64;
|
|
38957
|
+
var init_concurrency = __esm(() => {
|
|
38958
|
+
init_manager();
|
|
38959
|
+
init_state();
|
|
38960
|
+
PRESETS = {
|
|
38961
|
+
min: 1,
|
|
38962
|
+
medium: 3,
|
|
38963
|
+
max: 8
|
|
38964
|
+
};
|
|
38965
|
+
});
|
|
38966
|
+
|
|
38863
38967
|
// src/commands/config.ts
|
|
38864
38968
|
import * as os4 from "os";
|
|
38865
38969
|
import * as path17 from "path";
|
|
@@ -44428,7 +44532,10 @@ function serializeAgentSession(s) {
|
|
|
44428
44532
|
fullAutoDeadlockCount: s.fullAutoDeadlockCount ?? 0,
|
|
44429
44533
|
fullAutoLastQuestionHash: s.fullAutoLastQuestionHash ?? null,
|
|
44430
44534
|
sessionRehydratedAt: s.sessionRehydratedAt ?? 0,
|
|
44431
|
-
...Object.keys(stageBCompletion).length > 0 && { stageBCompletion }
|
|
44535
|
+
...Object.keys(stageBCompletion).length > 0 && { stageBCompletion },
|
|
44536
|
+
...s.maxConcurrencyOverride !== undefined && {
|
|
44537
|
+
maxConcurrencyOverride: s.maxConcurrencyOverride
|
|
44538
|
+
}
|
|
44432
44539
|
};
|
|
44433
44540
|
}
|
|
44434
44541
|
async function writeSnapshot(directory, state) {
|
|
@@ -55699,7 +55806,7 @@ async function handleTurboCommand(directory, args, sessionID) {
|
|
|
55699
55806
|
const arg0 = args[0]?.toLowerCase();
|
|
55700
55807
|
const arg1 = args[1]?.toLowerCase();
|
|
55701
55808
|
if (arg0 === "status") {
|
|
55702
|
-
return
|
|
55809
|
+
return buildStatusMessage2(session, directory, sessionID);
|
|
55703
55810
|
}
|
|
55704
55811
|
const isTurboOn = session.turboMode;
|
|
55705
55812
|
const isLeanActive = session.leanTurboActive === true;
|
|
@@ -55830,7 +55937,7 @@ function enableLeanTurbo(session, directory, sessionID) {
|
|
|
55830
55937
|
`Full-Auto: ${fullAutoActive ? "active" : "inactive"})`
|
|
55831
55938
|
].join(" ");
|
|
55832
55939
|
}
|
|
55833
|
-
function
|
|
55940
|
+
function buildStatusMessage2(session, directory, sessionID) {
|
|
55834
55941
|
if (!session.turboMode) {
|
|
55835
55942
|
return "Turbo: off";
|
|
55836
55943
|
}
|
|
@@ -56278,7 +56385,6 @@ __export(exports_commands, {
|
|
|
56278
56385
|
handleMemoryMigrateCommand: () => handleMemoryMigrateCommand,
|
|
56279
56386
|
handleMemoryImportCommand: () => handleMemoryImportCommand,
|
|
56280
56387
|
handleMemoryExportCommand: () => handleMemoryExportCommand,
|
|
56281
|
-
handleMemoryEvaluateCommand: () => handleMemoryEvaluateCommand,
|
|
56282
56388
|
handleMemoryCommand: () => handleMemoryCommand,
|
|
56283
56389
|
handleKnowledgeRestoreCommand: () => handleKnowledgeRestoreCommand,
|
|
56284
56390
|
handleKnowledgeQuarantineCommand: () => handleKnowledgeQuarantineCommand,
|
|
@@ -56298,6 +56404,7 @@ __export(exports_commands, {
|
|
|
56298
56404
|
handleCurateCommand: () => handleCurateCommand,
|
|
56299
56405
|
handleCouncilCommand: () => handleCouncilCommand,
|
|
56300
56406
|
handleConfigCommand: () => handleConfigCommand,
|
|
56407
|
+
handleConcurrencyCommand: () => handleConcurrencyCommand,
|
|
56301
56408
|
handleCloseCommand: () => handleCloseCommand,
|
|
56302
56409
|
handleClarifyCommand: () => handleClarifyCommand,
|
|
56303
56410
|
handleCheckpointCommand: () => handleCheckpointCommand,
|
|
@@ -56544,6 +56651,7 @@ var init_commands = __esm(() => {
|
|
|
56544
56651
|
init_close();
|
|
56545
56652
|
init_command_dispatch();
|
|
56546
56653
|
init_command_names();
|
|
56654
|
+
init_concurrency();
|
|
56547
56655
|
init_config2();
|
|
56548
56656
|
init_council();
|
|
56549
56657
|
init_curate();
|
|
@@ -56764,6 +56872,7 @@ var init_registry = __esm(() => {
|
|
|
56764
56872
|
init_benchmark();
|
|
56765
56873
|
init_checkpoint2();
|
|
56766
56874
|
init_close();
|
|
56875
|
+
init_concurrency();
|
|
56767
56876
|
init_config2();
|
|
56768
56877
|
init_council();
|
|
56769
56878
|
init_curate();
|
|
@@ -57008,6 +57117,23 @@ var init_registry = __esm(() => {
|
|
|
57008
57117
|
aliasOf: "finalize",
|
|
57009
57118
|
deprecated: true
|
|
57010
57119
|
},
|
|
57120
|
+
concurrency: {
|
|
57121
|
+
handler: (ctx) => handleConcurrencyCommand(ctx.directory, ctx.args, ctx.sessionID),
|
|
57122
|
+
description: "Manage runtime concurrency override for plan execution [set|status|reset]",
|
|
57123
|
+
args: "set <N|preset>, status, reset",
|
|
57124
|
+
details: `Sets, queries, or clears a session-scoped concurrency override for max_concurrent_tasks during plan execution.
|
|
57125
|
+
When set, the override takes precedence over the plan's locked execution_profile.max_concurrent_tasks.
|
|
57126
|
+
` + `The override is session-scoped \u2014 it does not modify the plan and is cleared on session reset.
|
|
57127
|
+
` + `
|
|
57128
|
+
Subcommands:
|
|
57129
|
+
` + ` concurrency set <N> \u2014 Set session concurrency to N (1-64)
|
|
57130
|
+
` + ` concurrency set <preset> \u2014 Set to preset: min (1), medium (3), max (8)
|
|
57131
|
+
` + ` concurrency status \u2014 Show effective concurrency (override, plan baseline, operational effective)
|
|
57132
|
+
` + ` concurrency reset \u2014 Clear the session concurrency override
|
|
57133
|
+
` + `
|
|
57134
|
+
` + "Session-scoped \u2014 resets on new session.",
|
|
57135
|
+
category: "utility"
|
|
57136
|
+
},
|
|
57011
57137
|
simulate: {
|
|
57012
57138
|
handler: (ctx) => handleSimulateCommand(ctx.directory, ctx.args),
|
|
57013
57139
|
description: "Dry-run hidden coupling analysis with configurable thresholds",
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handles the /swarm concurrency command.
|
|
3
|
+
* Supports setting, resetting, and checking concurrency override values.
|
|
4
|
+
*
|
|
5
|
+
* @param directory - Project directory (used to load plan execution_profile)
|
|
6
|
+
* @param args - Optional arguments: "set" | "status" | "reset" with optional value
|
|
7
|
+
* @param sessionID - Session ID for accessing active session state
|
|
8
|
+
* @returns Feedback message about concurrency state
|
|
9
|
+
*/
|
|
10
|
+
export declare function handleConcurrencyCommand(directory: string, args: string[], sessionID: string): Promise<string>;
|
package/dist/commands/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export { handleCloseCommand } from './close';
|
|
|
11
11
|
export { executeSwarmCommand, formatCommandNotFound, normalizeSwarmCommandInput, } from './command-dispatch.js';
|
|
12
12
|
export type { CommandName } from './command-names.js';
|
|
13
13
|
export { COMMAND_NAME_SET, COMMAND_NAMES } from './command-names.js';
|
|
14
|
+
export { handleConcurrencyCommand } from './concurrency';
|
|
14
15
|
export { handleConfigCommand } from './config';
|
|
15
16
|
export { handleCouncilCommand } from './council';
|
|
16
17
|
export { handleCurateCommand } from './curate';
|
|
@@ -24,7 +25,7 @@ export { handleFullAutoCommand } from './full-auto';
|
|
|
24
25
|
export { handleHandoffCommand } from './handoff';
|
|
25
26
|
export { handleHistoryCommand } from './history';
|
|
26
27
|
export { handleKnowledgeListCommand, handleKnowledgeMigrateCommand, handleKnowledgeQuarantineCommand, handleKnowledgeRestoreCommand, } from './knowledge';
|
|
27
|
-
export { handleMemoryCommand,
|
|
28
|
+
export { handleMemoryCommand, handleMemoryExportCommand, handleMemoryImportCommand, handleMemoryMigrateCommand, handleMemoryStatusCommand, } from './memory';
|
|
28
29
|
export { handlePlanCommand } from './plan';
|
|
29
30
|
export { handlePreflightCommand } from './preflight';
|
|
30
31
|
export { handlePromoteCommand } from './promote';
|
|
@@ -256,6 +256,13 @@ export declare const COMMAND_REGISTRY: {
|
|
|
256
256
|
readonly aliasOf: "finalize";
|
|
257
257
|
readonly deprecated: true;
|
|
258
258
|
};
|
|
259
|
+
readonly concurrency: {
|
|
260
|
+
readonly handler: (ctx: CommandContext) => Promise<string>;
|
|
261
|
+
readonly description: "Manage runtime concurrency override for plan execution [set|status|reset]";
|
|
262
|
+
readonly args: "set <N|preset>, status, reset";
|
|
263
|
+
readonly details: string;
|
|
264
|
+
readonly category: "utility";
|
|
265
|
+
};
|
|
259
266
|
readonly simulate: {
|
|
260
267
|
readonly handler: (ctx: CommandContext) => Promise<string>;
|
|
261
268
|
readonly description: "Dry-run hidden coupling analysis with configurable thresholds";
|
|
@@ -55,6 +55,7 @@ interface MessageWithParts {
|
|
|
55
55
|
parts: MessagePart[];
|
|
56
56
|
}
|
|
57
57
|
declare function resolveDelegatedPlanTaskId(args: Record<string, unknown>, knownPlanTaskIds?: ReadonlySet<string>): string | null;
|
|
58
|
+
declare function buildParallelExecutionGuidance(directory: string | undefined, sessionID: string, session: AgentSessionState): Promise<string | null>;
|
|
58
59
|
/**
|
|
59
60
|
* Resolves the correct task ID for evidence recording by chaining:
|
|
60
61
|
* 1. Explicit task_id in direct args (structured field)
|
|
@@ -68,11 +69,13 @@ declare function resolveDelegatedPlanTaskId(args: Record<string, unknown>, known
|
|
|
68
69
|
declare function resolveEvidenceTaskId(args: Record<string, unknown> | undefined, session: AgentSessionState, directory: string): Promise<string | null>;
|
|
69
70
|
/**
|
|
70
71
|
* _internals export for testing — do not use in production code.
|
|
71
|
-
* Exposes resolveEvidenceTaskId
|
|
72
|
+
* Exposes resolveEvidenceTaskId, resolveDelegatedPlanTaskId, and
|
|
73
|
+
* buildParallelExecutionGuidance for unit testing.
|
|
72
74
|
*/
|
|
73
75
|
export declare const _internals: {
|
|
74
76
|
resolveEvidenceTaskId: typeof resolveEvidenceTaskId;
|
|
75
77
|
resolveDelegatedPlanTaskId: typeof resolveDelegatedPlanTaskId;
|
|
78
|
+
buildParallelExecutionGuidance: typeof buildParallelExecutionGuidance;
|
|
76
79
|
};
|
|
77
80
|
/**
|
|
78
81
|
* Creates the experimental.chat.messages.transform hook for delegation gating.
|
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.
|
|
51
|
+
version: "7.39.0",
|
|
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",
|
|
@@ -40120,7 +40120,8 @@ async function buildParallelExecutionGuidance(directory, sessionID, session) {
|
|
|
40120
40120
|
const profile = plan.execution_profile;
|
|
40121
40121
|
const enabled = profile?.parallelization_enabled === true;
|
|
40122
40122
|
const maxConcurrent = profile?.max_concurrent_tasks ?? 1;
|
|
40123
|
-
|
|
40123
|
+
const effectiveMaxConcurrent = session?.maxConcurrencyOverride ?? maxConcurrent;
|
|
40124
|
+
if (!enabled || effectiveMaxConcurrent <= 1)
|
|
40124
40125
|
return null;
|
|
40125
40126
|
if (hasActiveLeanTurbo(sessionID)) {
|
|
40126
40127
|
return "[NEXT] Lean Turbo is active; use lean_turbo_run_phase and Lean Turbo lane guidance instead of standard execution-profile slot filling.";
|
|
@@ -40149,9 +40150,9 @@ async function buildParallelExecutionGuidance(directory, sessionID, session) {
|
|
|
40149
40150
|
if (ACTIVE_PARALLEL_TASK_STATES.has(state))
|
|
40150
40151
|
occupied.add(taskId);
|
|
40151
40152
|
}
|
|
40152
|
-
const availableSlots = Math.max(0,
|
|
40153
|
+
const availableSlots = Math.max(0, effectiveMaxConcurrent - occupied.size);
|
|
40153
40154
|
if (availableSlots <= 0) {
|
|
40154
|
-
return `[PARALLEL EXECUTION PROFILE] parallelization_enabled=true max_concurrent_tasks=${
|
|
40155
|
+
return `[PARALLEL EXECUTION PROFILE] parallelization_enabled=true max_concurrent_tasks=${effectiveMaxConcurrent}; all standard execution slots are occupied. Continue current active task gates before starting more coder work.`;
|
|
40155
40156
|
}
|
|
40156
40157
|
const eligible = tasks.filter((task) => {
|
|
40157
40158
|
const taskId = task.id;
|
|
@@ -40163,9 +40164,9 @@ async function buildParallelExecutionGuidance(directory, sessionID, session) {
|
|
|
40163
40164
|
return task.depends.every((dep) => completed.has(dep));
|
|
40164
40165
|
}).map((task) => task.id).slice(0, availableSlots);
|
|
40165
40166
|
if (eligible.length === 0) {
|
|
40166
|
-
return `[PARALLEL EXECUTION PROFILE] parallelization_enabled=true max_concurrent_tasks=${
|
|
40167
|
+
return `[PARALLEL EXECUTION PROFILE] parallelization_enabled=true max_concurrent_tasks=${effectiveMaxConcurrent}; no dependency-ready pending tasks are available for a new coder slot. Continue the current task/gate.`;
|
|
40167
40168
|
}
|
|
40168
|
-
return `[PARALLEL EXECUTION PROFILE] parallelization_enabled=true max_concurrent_tasks=${
|
|
40169
|
+
return `[PARALLEL EXECUTION PROFILE] parallelization_enabled=true max_concurrent_tasks=${effectiveMaxConcurrent}; ${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.`;
|
|
40169
40170
|
}
|
|
40170
40171
|
function isParallelGuidancePhaseComplete(phase) {
|
|
40171
40172
|
return phase.status === "complete" || phase.status === "completed" || phase.status === "closed";
|
|
@@ -41006,6 +41007,7 @@ function startAgentSession(sessionId, agentName, staleDurationMs = 7200000, dire
|
|
|
41006
41007
|
turboStrategy: undefined,
|
|
41007
41008
|
leanTurboActive: false,
|
|
41008
41009
|
leanTurboCurrentPhase: undefined,
|
|
41010
|
+
maxConcurrencyOverride: undefined,
|
|
41009
41011
|
qaGateSessionOverrides: {},
|
|
41010
41012
|
fullAutoMode: false,
|
|
41011
41013
|
fullAutoInteractionCount: 0,
|
|
@@ -60234,6 +60236,110 @@ var init_close = __esm(() => {
|
|
|
60234
60236
|
];
|
|
60235
60237
|
});
|
|
60236
60238
|
|
|
60239
|
+
// src/commands/concurrency.ts
|
|
60240
|
+
async function handleConcurrencyCommand(directory, args2, sessionID) {
|
|
60241
|
+
if (!sessionID || sessionID.trim() === "") {
|
|
60242
|
+
return "Error: No active session context. Concurrency requires an active session. Use /swarm concurrency from within an OpenCode session, or start a session first.";
|
|
60243
|
+
}
|
|
60244
|
+
const session = getAgentSession(sessionID);
|
|
60245
|
+
if (!session) {
|
|
60246
|
+
return "Error: No active session. Concurrency requires an active session to operate.";
|
|
60247
|
+
}
|
|
60248
|
+
const arg0 = args2[0]?.toLowerCase();
|
|
60249
|
+
const arg1 = args2[1];
|
|
60250
|
+
const plan = await loadPlanJsonOnly(directory).catch(() => null);
|
|
60251
|
+
const hasPlan = plan !== null && plan !== undefined;
|
|
60252
|
+
if (arg0 === undefined) {
|
|
60253
|
+
return [
|
|
60254
|
+
"Concurrency commands:",
|
|
60255
|
+
" /swarm concurrency set <N|preset> — Set session concurrency override (1-64 or min/medium/max)",
|
|
60256
|
+
" /swarm concurrency status — Show effective concurrency",
|
|
60257
|
+
" /swarm concurrency reset — Clear the override"
|
|
60258
|
+
].join(`
|
|
60259
|
+
`);
|
|
60260
|
+
}
|
|
60261
|
+
if (arg0 === "status") {
|
|
60262
|
+
return buildStatusMessage(session, plan);
|
|
60263
|
+
}
|
|
60264
|
+
if (!hasPlan) {
|
|
60265
|
+
if (arg0 === "set") {
|
|
60266
|
+
return "No active plan. Concurrency override requires an active plan.";
|
|
60267
|
+
}
|
|
60268
|
+
}
|
|
60269
|
+
if (arg0 === "reset") {
|
|
60270
|
+
session.maxConcurrencyOverride = undefined;
|
|
60271
|
+
return "Concurrency override cleared";
|
|
60272
|
+
}
|
|
60273
|
+
if (arg0 === "set") {
|
|
60274
|
+
if (arg1 === undefined) {
|
|
60275
|
+
return "Error: /swarm concurrency set requires a value. Usage: /swarm concurrency set <N|preset>";
|
|
60276
|
+
}
|
|
60277
|
+
return handleSetCommand(session, arg1);
|
|
60278
|
+
}
|
|
60279
|
+
return [
|
|
60280
|
+
`Unknown concurrency subcommand: ${arg0}`,
|
|
60281
|
+
"Usage: /swarm concurrency <set|status|reset>"
|
|
60282
|
+
].join(`
|
|
60283
|
+
`);
|
|
60284
|
+
}
|
|
60285
|
+
function handleSetCommand(session, value) {
|
|
60286
|
+
const normalizedValue = value.toLowerCase();
|
|
60287
|
+
if (normalizedValue in PRESETS) {
|
|
60288
|
+
const presetConcurrency = PRESETS[normalizedValue];
|
|
60289
|
+
session.maxConcurrencyOverride = presetConcurrency;
|
|
60290
|
+
return `Concurrency override set to ${presetConcurrency} (${normalizedValue})`;
|
|
60291
|
+
}
|
|
60292
|
+
const numericValue = Number(value);
|
|
60293
|
+
if (Number.isNaN(numericValue)) {
|
|
60294
|
+
return `Invalid concurrency value: ${value}. Must be a number (1-64) or a preset (min, medium, max).`;
|
|
60295
|
+
}
|
|
60296
|
+
if (!Number.isInteger(numericValue)) {
|
|
60297
|
+
return `Invalid concurrency value: ${value}. Must be a number (1-64) or a preset (min, medium, max).`;
|
|
60298
|
+
}
|
|
60299
|
+
if (numericValue < MIN_CONCURRENCY || numericValue > MAX_CONCURRENCY) {
|
|
60300
|
+
return `Concurrency value ${value} is out of range. Must be between ${MIN_CONCURRENCY} and ${MAX_CONCURRENCY}.`;
|
|
60301
|
+
}
|
|
60302
|
+
session.maxConcurrencyOverride = numericValue;
|
|
60303
|
+
return `Concurrency override set to ${numericValue}`;
|
|
60304
|
+
}
|
|
60305
|
+
function buildStatusMessage(session, plan) {
|
|
60306
|
+
const overrideActive = session.maxConcurrencyOverride !== undefined;
|
|
60307
|
+
const configuredOverride = session.maxConcurrencyOverride ?? "absent";
|
|
60308
|
+
const hasPlan = plan !== null && plan !== undefined;
|
|
60309
|
+
const planBaseline = hasPlan ? plan.execution_profile?.max_concurrent_tasks ?? 1 : 1;
|
|
60310
|
+
const parallelizationEnabled = hasPlan ? plan.execution_profile?.parallelization_enabled ?? false : false;
|
|
60311
|
+
const operationalEffective = !parallelizationEnabled ? 1 : session.maxConcurrencyOverride ?? planBaseline;
|
|
60312
|
+
let description;
|
|
60313
|
+
if (!hasPlan) {
|
|
60314
|
+
description = "No active plan";
|
|
60315
|
+
} else if (!parallelizationEnabled) {
|
|
60316
|
+
description = "Parallelization disabled (always 1)";
|
|
60317
|
+
} else if (overrideActive) {
|
|
60318
|
+
description = `Override active (${session.maxConcurrencyOverride})`;
|
|
60319
|
+
} else {
|
|
60320
|
+
description = `Plan baseline (${planBaseline})`;
|
|
60321
|
+
}
|
|
60322
|
+
return [
|
|
60323
|
+
`Concurrency: ${description}`,
|
|
60324
|
+
` override_active: ${overrideActive}`,
|
|
60325
|
+
` configured_override: ${configuredOverride}`,
|
|
60326
|
+
` plan_baseline: ${planBaseline}`,
|
|
60327
|
+
` operational_effective: ${operationalEffective}`,
|
|
60328
|
+
` parallelization_enabled: ${parallelizationEnabled}`
|
|
60329
|
+
].join(`
|
|
60330
|
+
`);
|
|
60331
|
+
}
|
|
60332
|
+
var PRESETS, MIN_CONCURRENCY = 1, MAX_CONCURRENCY = 64;
|
|
60333
|
+
var init_concurrency = __esm(() => {
|
|
60334
|
+
init_manager();
|
|
60335
|
+
init_state();
|
|
60336
|
+
PRESETS = {
|
|
60337
|
+
min: 1,
|
|
60338
|
+
medium: 3,
|
|
60339
|
+
max: 8
|
|
60340
|
+
};
|
|
60341
|
+
});
|
|
60342
|
+
|
|
60237
60343
|
// src/commands/config.ts
|
|
60238
60344
|
import * as os7 from "node:os";
|
|
60239
60345
|
import * as path28 from "node:path";
|
|
@@ -65915,7 +66021,10 @@ function serializeAgentSession(s) {
|
|
|
65915
66021
|
fullAutoDeadlockCount: s.fullAutoDeadlockCount ?? 0,
|
|
65916
66022
|
fullAutoLastQuestionHash: s.fullAutoLastQuestionHash ?? null,
|
|
65917
66023
|
sessionRehydratedAt: s.sessionRehydratedAt ?? 0,
|
|
65918
|
-
...Object.keys(stageBCompletion).length > 0 && { stageBCompletion }
|
|
66024
|
+
...Object.keys(stageBCompletion).length > 0 && { stageBCompletion },
|
|
66025
|
+
...s.maxConcurrencyOverride !== undefined && {
|
|
66026
|
+
maxConcurrencyOverride: s.maxConcurrencyOverride
|
|
66027
|
+
}
|
|
65919
66028
|
};
|
|
65920
66029
|
}
|
|
65921
66030
|
async function writeSnapshot(directory, state) {
|
|
@@ -78502,7 +78611,7 @@ async function handleTurboCommand(directory, args2, sessionID) {
|
|
|
78502
78611
|
const arg0 = args2[0]?.toLowerCase();
|
|
78503
78612
|
const arg1 = args2[1]?.toLowerCase();
|
|
78504
78613
|
if (arg0 === "status") {
|
|
78505
|
-
return
|
|
78614
|
+
return buildStatusMessage2(session, directory, sessionID);
|
|
78506
78615
|
}
|
|
78507
78616
|
const isTurboOn = session.turboMode;
|
|
78508
78617
|
const isLeanActive = session.leanTurboActive === true;
|
|
@@ -78633,7 +78742,7 @@ function enableLeanTurbo(session, directory, sessionID) {
|
|
|
78633
78742
|
`Full-Auto: ${fullAutoActive ? "active" : "inactive"})`
|
|
78634
78743
|
].join(" ");
|
|
78635
78744
|
}
|
|
78636
|
-
function
|
|
78745
|
+
function buildStatusMessage2(session, directory, sessionID) {
|
|
78637
78746
|
if (!session.turboMode) {
|
|
78638
78747
|
return "Turbo: off";
|
|
78639
78748
|
}
|
|
@@ -79081,7 +79190,6 @@ __export(exports_commands, {
|
|
|
79081
79190
|
handleMemoryMigrateCommand: () => handleMemoryMigrateCommand,
|
|
79082
79191
|
handleMemoryImportCommand: () => handleMemoryImportCommand,
|
|
79083
79192
|
handleMemoryExportCommand: () => handleMemoryExportCommand,
|
|
79084
|
-
handleMemoryEvaluateCommand: () => handleMemoryEvaluateCommand,
|
|
79085
79193
|
handleMemoryCommand: () => handleMemoryCommand,
|
|
79086
79194
|
handleKnowledgeRestoreCommand: () => handleKnowledgeRestoreCommand,
|
|
79087
79195
|
handleKnowledgeQuarantineCommand: () => handleKnowledgeQuarantineCommand,
|
|
@@ -79101,6 +79209,7 @@ __export(exports_commands, {
|
|
|
79101
79209
|
handleCurateCommand: () => handleCurateCommand,
|
|
79102
79210
|
handleCouncilCommand: () => handleCouncilCommand,
|
|
79103
79211
|
handleConfigCommand: () => handleConfigCommand,
|
|
79212
|
+
handleConcurrencyCommand: () => handleConcurrencyCommand,
|
|
79104
79213
|
handleCloseCommand: () => handleCloseCommand,
|
|
79105
79214
|
handleClarifyCommand: () => handleClarifyCommand,
|
|
79106
79215
|
handleCheckpointCommand: () => handleCheckpointCommand,
|
|
@@ -79347,6 +79456,7 @@ var init_commands = __esm(() => {
|
|
|
79347
79456
|
init_close();
|
|
79348
79457
|
init_command_dispatch();
|
|
79349
79458
|
init_command_names();
|
|
79459
|
+
init_concurrency();
|
|
79350
79460
|
init_config2();
|
|
79351
79461
|
init_council();
|
|
79352
79462
|
init_curate();
|
|
@@ -79567,6 +79677,7 @@ var init_registry = __esm(() => {
|
|
|
79567
79677
|
init_benchmark();
|
|
79568
79678
|
init_checkpoint2();
|
|
79569
79679
|
init_close();
|
|
79680
|
+
init_concurrency();
|
|
79570
79681
|
init_config2();
|
|
79571
79682
|
init_council();
|
|
79572
79683
|
init_curate();
|
|
@@ -79811,6 +79922,23 @@ var init_registry = __esm(() => {
|
|
|
79811
79922
|
aliasOf: "finalize",
|
|
79812
79923
|
deprecated: true
|
|
79813
79924
|
},
|
|
79925
|
+
concurrency: {
|
|
79926
|
+
handler: (ctx) => handleConcurrencyCommand(ctx.directory, ctx.args, ctx.sessionID),
|
|
79927
|
+
description: "Manage runtime concurrency override for plan execution [set|status|reset]",
|
|
79928
|
+
args: "set <N|preset>, status, reset",
|
|
79929
|
+
details: `Sets, queries, or clears a session-scoped concurrency override for max_concurrent_tasks during plan execution.
|
|
79930
|
+
When set, the override takes precedence over the plan's locked execution_profile.max_concurrent_tasks.
|
|
79931
|
+
` + `The override is session-scoped — it does not modify the plan and is cleared on session reset.
|
|
79932
|
+
` + `
|
|
79933
|
+
Subcommands:
|
|
79934
|
+
` + ` concurrency set <N> — Set session concurrency to N (1-64)
|
|
79935
|
+
` + ` concurrency set <preset> — Set to preset: min (1), medium (3), max (8)
|
|
79936
|
+
` + ` concurrency status — Show effective concurrency (override, plan baseline, operational effective)
|
|
79937
|
+
` + ` concurrency reset — Clear the session concurrency override
|
|
79938
|
+
` + `
|
|
79939
|
+
` + "Session-scoped — resets on new session.",
|
|
79940
|
+
category: "utility"
|
|
79941
|
+
},
|
|
79814
79942
|
simulate: {
|
|
79815
79943
|
handler: (ctx) => handleSimulateCommand(ctx.directory, ctx.args),
|
|
79816
79944
|
description: "Dry-run hidden coupling analysis with configurable thresholds",
|
|
@@ -103304,6 +103432,7 @@ function deserializeAgentSession(s) {
|
|
|
103304
103432
|
fullAutoInteractionCount: s.fullAutoInteractionCount ?? 0,
|
|
103305
103433
|
fullAutoDeadlockCount: s.fullAutoDeadlockCount ?? 0,
|
|
103306
103434
|
fullAutoLastQuestionHash: s.fullAutoLastQuestionHash ?? null,
|
|
103435
|
+
maxConcurrencyOverride: typeof s.maxConcurrencyOverride === "number" ? Math.min(64, Math.max(1, s.maxConcurrencyOverride)) : undefined,
|
|
103307
103436
|
prmPatternCounts: new Map,
|
|
103308
103437
|
prmEscalationLevel: 0,
|
|
103309
103438
|
prmLastPatternDetected: null,
|
|
@@ -124027,7 +124156,7 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
124027
124156
|
...opencodeConfig.command || {},
|
|
124028
124157
|
swarm: {
|
|
124029
124158
|
template: "/swarm $ARGUMENTS",
|
|
124030
|
-
description: "Swarm management commands: /swarm [status|show-plan|plan|agents|history|config|help|evidence|handoff|archive|diagnose|diagnosis|preflight|sync-plan|benchmark|export|reset|rollback|retrieve|clarify|analyze|specify|brainstorm|council|pr-review|issue|qa-gates|dark-matter|knowledge|memory|curate|turbo|full-auto|write-retro|reset-session|simulate|promote|checkpoint|acknowledge-spec-drift|doctor tools|finalize|close]"
|
|
124159
|
+
description: "Swarm management commands: /swarm [status|show-plan|plan|agents|history|config|help|evidence|handoff|archive|diagnose|diagnosis|preflight|sync-plan|benchmark|export|reset|rollback|retrieve|clarify|analyze|specify|brainstorm|council|pr-review|issue|qa-gates|dark-matter|knowledge|memory|curate|concurrency|turbo|full-auto|write-retro|reset-session|simulate|promote|checkpoint|acknowledge-spec-drift|doctor tools|finalize|close]"
|
|
124031
124160
|
},
|
|
124032
124161
|
"swarm-status": {
|
|
124033
124162
|
template: "/swarm status",
|
|
@@ -124157,10 +124286,6 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
124157
124286
|
template: "/swarm memory export",
|
|
124158
124287
|
description: "Use /swarm memory export to write current memory to JSONL"
|
|
124159
124288
|
},
|
|
124160
|
-
"swarm-memory-evaluate": {
|
|
124161
|
-
template: "/swarm memory evaluate --json",
|
|
124162
|
-
description: "Use /swarm memory evaluate --json to generate the recall evaluation report"
|
|
124163
|
-
},
|
|
124164
124289
|
"swarm-memory-import": {
|
|
124165
124290
|
template: "/swarm memory import",
|
|
124166
124291
|
description: "Use /swarm memory import to import legacy JSONL into SQLite"
|
|
@@ -124173,6 +124298,10 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
124173
124298
|
template: "/swarm curate",
|
|
124174
124299
|
description: "Use /swarm curate to curate knowledge artifacts and entries"
|
|
124175
124300
|
},
|
|
124301
|
+
"swarm-concurrency": {
|
|
124302
|
+
template: "/swarm concurrency $ARGUMENTS",
|
|
124303
|
+
description: "Use /swarm concurrency to manage runtime concurrency override for plan execution"
|
|
124304
|
+
},
|
|
124176
124305
|
"swarm-turbo": {
|
|
124177
124306
|
template: "/swarm turbo",
|
|
124178
124307
|
description: "Use /swarm turbo to enable turbo mode for faster execution"
|
|
@@ -61,6 +61,8 @@ export interface SerializedAgentSession {
|
|
|
61
61
|
sessionRehydratedAt?: number;
|
|
62
62
|
/** Stage B completion tracking: per-task set of completed Stage B agents. Optional for backward compat with old snapshots. */
|
|
63
63
|
stageBCompletion?: Record<string, string[]>;
|
|
64
|
+
/** Session-scoped concurrency override for max_concurrent_tasks (Issue #761) */
|
|
65
|
+
maxConcurrencyOverride?: number;
|
|
64
66
|
}
|
|
65
67
|
/**
|
|
66
68
|
* Minimal interface for serialized InvocationWindow
|
package/dist/state.d.ts
CHANGED
|
@@ -165,6 +165,10 @@ export interface AgentSessionState {
|
|
|
165
165
|
leanTurboActive?: boolean;
|
|
166
166
|
/** Current phase number when Lean Turbo is active (for durable state sync). */
|
|
167
167
|
leanTurboCurrentPhase?: number;
|
|
168
|
+
/** Session-scoped concurrency override for max_concurrent_tasks (Issue #761).
|
|
169
|
+
* When set, overrides the plan's execution_profile.max_concurrent_tasks
|
|
170
|
+
* for delegation-gate guidance. Cleared on session reset. */
|
|
171
|
+
maxConcurrencyOverride?: number;
|
|
168
172
|
/** Session-level QA gate overrides layered on top of the spec-level profile.
|
|
169
173
|
* Overrides can only enable gates (true); false values are ignored by
|
|
170
174
|
* getEffectiveGates. Cleared on session reset. Optional for backwards
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.39.0",
|
|
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",
|