opencode-swarm 7.81.3 → 7.81.4

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.
@@ -92,7 +92,11 @@ RESEARCH CONTEXT
92
92
  continue only non-dependent architect work: prepare the synthesis outline,
93
93
  normalize the RESEARCH CONTEXT citations, and draft disagreement categories.
94
94
  Do not call `convene_general_council` or present conclusions from running
95
- lanes. Each dispatch message must
95
+ lanes. Dispatch promptly do not accumulate extensive planning prose before the
96
+ call, or output truncation may swallow the tool call itself. Keep each lane `prompt`
97
+ compact: send shared context ONCE via the `common_prompt` field, or have lanes read
98
+ it from a file by absolute path, instead of inlining the same large blob into every
99
+ lane prompt. Each dispatch message must
96
100
  include:
97
101
  - The question
98
102
  - Round number: 1
@@ -71,7 +71,7 @@ Each explorer mission receives:
71
71
  - The scope map context from Step 2
72
72
  - Instruction: "You are performing a [LANE] audit. Report findings as candidate observations with severity (INFO/LOW/MEDIUM/HIGH/CRITICAL), location, and evidence."
73
73
 
74
- Explorer missions are dispatched in parallel waves. Launch the wave, record the returned `batch_id`, then continue deterministic architect work that does not depend on lane output: refine the scope map, build the candidate ledger shell, inspect local evidence with read-only tools, and prepare reviewer shard structure. Do not synthesize findings from running lanes.
74
+ Explorer missions are dispatched in parallel waves. Launch the wave promptly — do not accumulate extensive planning prose before the call, or output truncation may swallow the tool call itself. Launch the wave, record the returned `batch_id`, then continue deterministic architect work that does not depend on lane output: refine the scope map, build the candidate ledger shell, inspect local evidence with read-only tools, and prepare reviewer shard structure. Do not synthesize findings from running lanes. Keep each lane `prompt` compact: send shared context ONCE via the `common_prompt` field, or have lanes read it from a file by absolute path, instead of inlining the same large blob into every lane prompt — oversized inline prompts produce malformed or truncated tool-call JSON.
75
75
 
76
76
  At the Step 4 boundary, call `collect_lane_results` with `wait: true` for every open wave batch. Treat missing, stale, cancelled, or failed lanes as explicit coverage gaps; do not silently proceed past a required lane. If `dispatch_lanes_async` is unavailable, use blocking `dispatch_lanes` or parallel Task calls and record that async advisory lanes were unavailable.
77
77
 
@@ -102,7 +102,12 @@ Dispatch up to `max_researchers` `the active swarm's sme agent` calls with
102
102
  `batch_id`, then continue architect-owned retrieval quality work that does not
103
103
  depend on worker output: tighten the evidence ledger, check source authority,
104
104
  prepare reviewer shard structure, and identify unresolved gaps. Do not write final
105
- claims from running lanes. Each sme dispatch must
105
+ claims from running lanes. Dispatch promptly do not accumulate extensive planning
106
+ prose before the call, or output truncation may swallow the tool call itself. Keep each
107
+ lane `prompt` compact: send shared context ONCE via the `common_prompt` field, or have
108
+ lanes read it from a file by absolute path, instead of inlining the same large blob into
109
+ every lane prompt — oversized inline prompts produce malformed or truncated tool-call
110
+ JSON. Each sme dispatch must
106
111
  include:
107
112
  - `DOMAIN`: the subtopic
108
113
  - `TASK`: "Synthesize an evidence-grounded answer for this subtopic. Cite each
@@ -491,7 +491,7 @@ Tool candidate rules:
491
491
 
492
492
  ## Phase 3: Parallel Base Explorer Lanes
493
493
 
494
- Launch all base lanes with `dispatch_lanes_async` when available. Pass the six lane specs together, set `max_concurrent` to `6`, record the returned `batch_id`, and continue only non-dependent architect work: refine the obligation ledger, inspect PR metadata, prepare micro-lane trigger checks, and run deterministic read-only local tools. Do not synthesize findings from running lanes.
494
+ Launch all base lanes with `dispatch_lanes_async` when available. Pass the six lane specs together, set `max_concurrent` to `6`, record the returned `batch_id`, and continue only non-dependent architect work: refine the obligation ledger, inspect PR metadata, prepare micro-lane trigger checks, and run deterministic read-only local tools. Do not synthesize findings from running lanes. Keep each lane `prompt` compact: send the shared review context (PR diff, obligation ledger, scope) ONCE via the `common_prompt` field, or have lanes read it from a file by absolute path, instead of inlining the same large blob into all six prompts — oversized inline prompts produce malformed or truncated tool-call JSON and force clumsy file workarounds.
495
495
 
496
496
  Before Phase 4 or synthesis, call `collect_lane_results` with `wait: true` for the base-lane batch and treat the collected `lane_results` as the join barrier. Missing, stale, cancelled, or failed base lanes are explicit review coverage gaps. If `dispatch_lanes_async` is unavailable, use blocking `dispatch_lanes`; if that is also unavailable, simulate isolated passes. Do not let one lane's conclusions bias another lane, and record unavailable deterministic dispatch in the validation gate.
497
497
 
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.81.3",
55
+ version: "7.81.4",
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",
@@ -17763,11 +17763,11 @@ var init_tool_metadata = __esm(() => {
17763
17763
  ]
17764
17764
  },
17765
17765
  dispatch_lanes: {
17766
- description: "dispatch multiple read-only exploration/review lanes concurrently and return a structured join result",
17766
+ description: "dispatch read-only exploration/review lanes concurrently and BLOCK until all finish; prefer dispatch_lanes_async for non-blocking dispatch, use this only when promptAsync is unavailable",
17767
17767
  agents: ["architect"]
17768
17768
  },
17769
17769
  dispatch_lanes_async: {
17770
- description: "launch multiple read-only advisory lanes asynchronously and return a batch id for later collection",
17770
+ description: "launch read-only advisory lanes non-blockingly and return a batch id immediately so you can keep working; join later with collect_lane_results",
17771
17771
  agents: ["architect"]
17772
17772
  },
17773
17773
  collect_lane_results: {
@@ -41475,6 +41475,14 @@ async function activateProposal(directory, slug, force = false, options = {}) {
41475
41475
  reason: `proposal not found or already activated: ${readErr instanceof Error ? readErr.message : String(readErr)}`
41476
41476
  };
41477
41477
  }
41478
+ if (await isRejectedSkillContent(directory, cleanSlug, proposalContent)) {
41479
+ return {
41480
+ activated: false,
41481
+ from,
41482
+ to,
41483
+ reason: "previously rejected equivalent content"
41484
+ };
41485
+ }
41478
41486
  const flipped = proposalContent.replace(/^status:\s*draft\s*$/m, "status: active");
41479
41487
  let evaluation;
41480
41488
  if (options.evaluate) {
@@ -41497,7 +41505,7 @@ async function activateProposal(directory, slug, force = false, options = {}) {
41497
41505
  await appendRejectedSkillEdit({
41498
41506
  directory,
41499
41507
  slug: cleanSlug,
41500
- candidateContent: flipped,
41508
+ candidateContent: proposalContent,
41501
41509
  incumbentContent,
41502
41510
  operation: options.operation ?? "skill_apply"
41503
41511
  }, evaluation);
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.81.3",
72
+ version: "7.81.4",
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",
@@ -680,11 +680,11 @@ var init_tool_metadata = __esm(() => {
680
680
  ]
681
681
  },
682
682
  dispatch_lanes: {
683
- description: "dispatch multiple read-only exploration/review lanes concurrently and return a structured join result",
683
+ description: "dispatch read-only exploration/review lanes concurrently and BLOCK until all finish; prefer dispatch_lanes_async for non-blocking dispatch, use this only when promptAsync is unavailable",
684
684
  agents: ["architect"]
685
685
  },
686
686
  dispatch_lanes_async: {
687
- description: "launch multiple read-only advisory lanes asynchronously and return a batch id for later collection",
687
+ description: "launch read-only advisory lanes non-blockingly and return a batch id immediately so you can keep working; join later with collect_lane_results",
688
688
  agents: ["architect"]
689
689
  },
690
690
  collect_lane_results: {
@@ -64040,6 +64040,14 @@ async function activateProposal(directory, slug, force = false, options = {}) {
64040
64040
  reason: `proposal not found or already activated: ${readErr instanceof Error ? readErr.message : String(readErr)}`
64041
64041
  };
64042
64042
  }
64043
+ if (await isRejectedSkillContent(directory, cleanSlug, proposalContent)) {
64044
+ return {
64045
+ activated: false,
64046
+ from,
64047
+ to,
64048
+ reason: "previously rejected equivalent content"
64049
+ };
64050
+ }
64043
64051
  const flipped = proposalContent.replace(/^status:\s*draft\s*$/m, "status: active");
64044
64052
  let evaluation;
64045
64053
  if (options.evaluate) {
@@ -64062,7 +64070,7 @@ async function activateProposal(directory, slug, force = false, options = {}) {
64062
64070
  await appendRejectedSkillEdit({
64063
64071
  directory,
64064
64072
  slug: cleanSlug,
64065
- candidateContent: flipped,
64073
+ candidateContent: proposalContent,
64066
64074
  incumbentContent,
64067
64075
  operation: options.operation ?? "skill_apply"
64068
64076
  }, evaluation);
@@ -96247,6 +96255,7 @@ If a tool modifies a file, it is a CODER tool. Delegate.
96247
96255
  2. ONE agent per message. Send, STOP, wait for response.
96248
96256
  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. This exception NEVER applies to coder delegations. Preserve ONE task per coder call.
96249
96257
  Separate parallel-mode exception (distinct from the Stage B exception above, and the ONLY case where more than one coder may be dispatched before waiting): when an active \`[PARALLEL EXECUTION PROFILE]\` directive is present in your context (parallelization_enabled=true), you MAY dispatch multiple {{AGENT_PREFIX}}coder agents in a single message — up to the stated max_concurrent_tasks — but ONLY for distinct, dependency-ready tasks whose declared file scopes do NOT overlap. Each coder still requires its own \`declare_scope\` call and carries exactly ONE task (Rule 3 still holds: never batch multiple objectives into one coder). Parallel coders each run in an isolated git worktree, so their writes never collide and are merged back automatically. If no \`[PARALLEL EXECUTION PROFILE]\` directive is present, dispatch coders one at a time.
96258
+ Read-only advisory-lane exception (NON-BLOCKING; distinct from both exceptions above): the "Send, STOP, wait" rule governs MUTATION delegations (coder, and the test_engineer/reviewer Stage B completion gates). It does NOT govern read-only advisory exploration/review lanes. When you dispatch read-only advisory lanes — \`{{AGENT_PREFIX}}explorer\`, \`{{AGENT_PREFIX}}sme\`, \`{{AGENT_PREFIX}}researcher\`, the council members (\`council_generalist\`/\`council_skeptic\`/\`council_domain_expert\`), or an advisory \`{{AGENT_PREFIX}}critic\` lane — use the NON-BLOCKING path so you keep working while they run. Dispatch PROMPTLY: emit the \`dispatch_lanes_async\` call EARLY with compact lane prompts — do not accumulate long planning prose or build oversized inline prompts first, or the tool call can be truncated out of your message and the lanes never launch (a real failure mode on smaller models). The lane mechanism is a SINGLE \`dispatch_lanes_async\` call carrying all lane specs — NOT a per-agent Task/run-in-background pattern. Call \`dispatch_lanes_async\` with all lane specs in one call, record the returned \`batch_id\`, then IMMEDIATELY continue non-dependent architect work (refine the plan/obligation ledger, inspect metadata, prepare the synthesis/reviewer structure, run deterministic read-only tools). Do NOT sit idle waiting on running lanes, and do NOT synthesize findings from still-running lanes. Join later by calling \`collect_lane_results\` with \`wait: true\` as the explicit barrier immediately before you synthesize. Use blocking \`dispatch_lanes\` only when \`dispatch_lanes_async\`/promptAsync is unavailable. Keep each lane prompt compact: send large shared context (PR diff, ledger, scope) ONCE via the \`common_prompt\` field, or have lanes read it from a file by absolute path, instead of inlining the same blob into every lane prompt — inlining large context into many lanes is what produces malformed or truncated tool-call JSON and forces clumsy file workarounds. This non-blocking exception applies ONLY to read-only advisory lanes; it NEVER applies to coder delegations, to the test_engineer/reviewer Stage B completion gates, or to the critic PLAN-review gate, which all still follow "Send, STOP, wait" (or the Stage B parallel-dispatch exception above).
96250
96259
  3. ONE task per {{AGENT_PREFIX}}coder call. Never batch.
96251
96260
  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.
96252
96261
  3b. PRE-DELEGATION SCOPE CALL (test_engineer): BEFORE any {{AGENT_PREFIX}}test_engineer delegation that will CREATE or MODIFY test files, you MUST call \`declare_scope\` with { taskId, files } listing the exact test file path(s) to write. Omitting this call leaves the write scope undeclared and will block the write. See Rule 1a.
@@ -126414,6 +126423,9 @@ init_state();
126414
126423
  init_create_tool();
126415
126424
  var MAX_LANES = 8;
126416
126425
  var MAX_PROMPT_CHARS = 80000;
126426
+ var COMMON_PROMPT_SEPARATOR = `
126427
+
126428
+ `;
126417
126429
  var DEFAULT_TIMEOUT_MS3 = 300000;
126418
126430
  var MAX_TIMEOUT_MS2 = 1800000;
126419
126431
  var MAX_LANE_OUTPUT_CHARS = 20000;
@@ -126473,6 +126485,7 @@ var LaneSchema = exports_external.object({
126473
126485
  });
126474
126486
  var DispatchLanesArgsSchema = exports_external.object({
126475
126487
  lanes: exports_external.array(LaneSchema).min(1).max(MAX_LANES).describe("Read-only lane specs to dispatch concurrently"),
126488
+ common_prompt: exports_external.string().min(1).regex(/\S/, "common_prompt must contain non-whitespace content").max(MAX_PROMPT_CHARS - COMMON_PROMPT_SEPARATOR.length - 1).optional().describe("Optional shared context prepended to every lane prompt. Send large shared context (PR diff, obligation ledger, scope) ONCE here instead of inlining the same blob into each lane prompt; this keeps the tool-call payload small and avoids malformed/truncated tool-call JSON. Combined common_prompt + per-lane prompt must not exceed the per-lane character limit."),
126476
126489
  max_concurrent: exports_external.number().int().min(1).max(MAX_LANES).optional().describe("Maximum lanes in flight at once; defaults to lane count"),
126477
126490
  timeout_ms: exports_external.number().int().min(10).max(MAX_TIMEOUT_MS2).optional().describe("Per-lane session create/prompt timeout in milliseconds")
126478
126491
  });
@@ -126520,7 +126533,15 @@ async function executeDispatchLanes(args2, directory, context = {}) {
126520
126533
  message: "OpenCode session client is not available"
126521
126534
  });
126522
126535
  }
126523
- const lanes = parsed.data.lanes;
126536
+ const common = applyCommonPrompt(parsed.data.lanes, parsed.data.common_prompt);
126537
+ if (!common.ok) {
126538
+ return failureResult({
126539
+ failure_class: "invalid_args",
126540
+ message: "Invalid dispatch_lanes arguments",
126541
+ errors: common.errors
126542
+ });
126543
+ }
126544
+ const lanes = common.lanes;
126524
126545
  const maxConcurrent = Math.min(parsed.data.max_concurrent ?? lanes.length, lanes.length, MAX_LANES);
126525
126546
  const timeoutMs = parsed.data.timeout_ms ?? DEFAULT_TIMEOUT_MS3;
126526
126547
  const dispatcher = _internals82.createParallelDispatcher({
@@ -126560,7 +126581,15 @@ async function executeDispatchLanesAsync(args2, directory, context = {}) {
126560
126581
  message: "OpenCode session promptAsync client is not available"
126561
126582
  });
126562
126583
  }
126563
- const lanes = parsed.data.lanes;
126584
+ const common = applyCommonPrompt(parsed.data.lanes, parsed.data.common_prompt);
126585
+ if (!common.ok) {
126586
+ return asyncFailureResult({
126587
+ failure_class: "invalid_args",
126588
+ message: "Invalid dispatch_lanes_async arguments",
126589
+ errors: common.errors
126590
+ });
126591
+ }
126592
+ const lanes = common.lanes;
126564
126593
  const batchId = parsed.data.batch_id ?? makeBatchId();
126565
126594
  if (findByBatchId(directory, batchId).length > 0) {
126566
126595
  return asyncFailureResult({
@@ -127131,6 +127160,21 @@ function collectFailureResult(args2) {
127131
127160
  errors: args2.errors
127132
127161
  };
127133
127162
  }
127163
+ function applyCommonPrompt(lanes, commonPrompt) {
127164
+ if (!commonPrompt)
127165
+ return { ok: true, lanes: [...lanes] };
127166
+ const errors5 = [];
127167
+ const merged = lanes.map((lane) => {
127168
+ const prompt = `${commonPrompt}${COMMON_PROMPT_SEPARATOR}${lane.prompt}`;
127169
+ if (prompt.length > MAX_PROMPT_CHARS) {
127170
+ errors5.push(`Lane "${lane.id}" combined common_prompt + prompt is ${prompt.length} chars ` + `(common_prompt ${commonPrompt.length} + separator ${COMMON_PROMPT_SEPARATOR.length} + ` + `lane prompt ${lane.prompt.length}; max ${MAX_PROMPT_CHARS})`);
127171
+ }
127172
+ return { ...lane, prompt };
127173
+ });
127174
+ if (errors5.length > 0)
127175
+ return { ok: false, errors: errors5 };
127176
+ return { ok: true, lanes: merged };
127177
+ }
127134
127178
  function findDuplicateLaneIds(lanes) {
127135
127179
  const seen = new Set;
127136
127180
  const duplicates = new Set;
@@ -127215,9 +127259,10 @@ function sleep2(ms) {
127215
127259
  });
127216
127260
  }
127217
127261
  var dispatch_lanes = createSwarmTool({
127218
- description: "Dispatch multiple read-only exploration/review lanes concurrently through OpenCode sessions and return a structured join result.",
127262
+ description: "Dispatch multiple read-only exploration/review lanes concurrently and BLOCK until every lane finishes, returning a structured join result. This blocks the caller until completion; for non-blocking dispatch that lets you keep working while lanes run, prefer dispatch_lanes_async + collect_lane_results and use this blocking variant only when promptAsync is unavailable. Keep each lane prompt compact: send large shared context once via common_prompt (or have lanes read it from a file by absolute path) instead of inlining it into every lane prompt.",
127219
127263
  args: {
127220
127264
  lanes: DispatchLanesArgsSchema.shape.lanes,
127265
+ common_prompt: DispatchLanesArgsSchema.shape.common_prompt,
127221
127266
  max_concurrent: DispatchLanesArgsSchema.shape.max_concurrent,
127222
127267
  timeout_ms: DispatchLanesArgsSchema.shape.timeout_ms
127223
127268
  },
@@ -127229,9 +127274,10 @@ var dispatch_lanes = createSwarmTool({
127229
127274
  }
127230
127275
  });
127231
127276
  var dispatch_lanes_async = createSwarmTool({
127232
- description: "Launch multiple read-only advisory lanes with OpenCode promptAsync and return immediately with a batch id for collect_lane_results.",
127277
+ description: "Launch multiple read-only advisory lanes with OpenCode promptAsync and return IMMEDIATELY with a batch id (non-blocking). After launching, keep working on non-dependent tasks while the lanes run, then call collect_lane_results to join. Keep each lane prompt compact: send large shared context once via common_prompt (or have lanes read it from a file by absolute path) instead of inlining it into every lane prompt, which can produce oversized or malformed tool-call JSON.",
127233
127278
  args: {
127234
127279
  lanes: DispatchLanesAsyncArgsSchema.shape.lanes,
127280
+ common_prompt: DispatchLanesAsyncArgsSchema.shape.common_prompt,
127235
127281
  max_concurrent: DispatchLanesAsyncArgsSchema.shape.max_concurrent,
127236
127282
  timeout_ms: DispatchLanesAsyncArgsSchema.shape.timeout_ms,
127237
127283
  batch_id: DispatchLanesAsyncArgsSchema.shape.batch_id,
@@ -8,9 +8,9 @@
8
8
  * - Escalation tracking via escalation
9
9
  *
10
10
  * This module provides the createPrmHook factory that returns the toolAfter
11
- * handler used by the swarm hook system. PRM replaces loop-detector.ts for
12
- * repetition_loop detection, but loop-detector.ts is kept as a fast circuit
13
- * breaker for backward compatibility.
11
+ * handler used by the swarm hook system. PRM complements loop-detector.ts:
12
+ * loop-detector.ts remains the fast circuit breaker in guardrails/tool-before,
13
+ * while PRM provides deeper multi-pattern detection and escalation.
14
14
  */
15
15
  export { formatCourseCorrectionForInjection, generateCourseCorrection, } from './course-correction';
16
16
  export { createDefaultEscalationState, EscalationTracker } from './escalation';
@@ -1,6 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  import { createParallelDispatcher } from '../parallel/dispatcher/parallel-dispatcher.js';
3
3
  import { createSwarmTool } from './create-tool.js';
4
+ export declare const MAX_PROMPT_CHARS = 80000;
4
5
  declare const LaneSchema: z.ZodObject<{
5
6
  id: z.ZodString;
6
7
  agent: z.ZodString;
@@ -12,6 +13,7 @@ declare const DispatchLanesArgsSchema: z.ZodObject<{
12
13
  agent: z.ZodString;
13
14
  prompt: z.ZodString;
14
15
  }, z.core.$strip>>;
16
+ common_prompt: z.ZodOptional<z.ZodString>;
15
17
  max_concurrent: z.ZodOptional<z.ZodNumber>;
16
18
  timeout_ms: z.ZodOptional<z.ZodNumber>;
17
19
  }, z.core.$strip>;
@@ -21,6 +23,7 @@ declare const DispatchLanesAsyncArgsSchema: z.ZodObject<{
21
23
  agent: z.ZodString;
22
24
  prompt: z.ZodString;
23
25
  }, z.core.$strip>>;
26
+ common_prompt: z.ZodOptional<z.ZodString>;
24
27
  max_concurrent: z.ZodOptional<z.ZodNumber>;
25
28
  timeout_ms: z.ZodOptional<z.ZodNumber>;
26
29
  batch_id: z.ZodOptional<z.ZodString>;
@@ -190,10 +193,35 @@ export declare const _internals: {
190
193
  sleep: (ms: number) => Promise<void>;
191
194
  };
192
195
  export declare const _test_exports: {
196
+ applyCommonPrompt: typeof applyCommonPrompt;
193
197
  extractLastAssistantText: typeof extractLastAssistantText;
194
198
  formatError: typeof formatError;
195
199
  nextCollectPollInterval: typeof nextCollectPollInterval;
196
200
  promptHash: typeof promptHash;
201
+ DispatchLanesArgsSchema: z.ZodObject<{
202
+ lanes: z.ZodArray<z.ZodObject<{
203
+ id: z.ZodString;
204
+ agent: z.ZodString;
205
+ prompt: z.ZodString;
206
+ }, z.core.$strip>>;
207
+ common_prompt: z.ZodOptional<z.ZodString>;
208
+ max_concurrent: z.ZodOptional<z.ZodNumber>;
209
+ timeout_ms: z.ZodOptional<z.ZodNumber>;
210
+ }, z.core.$strip>;
211
+ DispatchLanesAsyncArgsSchema: z.ZodObject<{
212
+ lanes: z.ZodArray<z.ZodObject<{
213
+ id: z.ZodString;
214
+ agent: z.ZodString;
215
+ prompt: z.ZodString;
216
+ }, z.core.$strip>>;
217
+ common_prompt: z.ZodOptional<z.ZodString>;
218
+ max_concurrent: z.ZodOptional<z.ZodNumber>;
219
+ timeout_ms: z.ZodOptional<z.ZodNumber>;
220
+ batch_id: z.ZodOptional<z.ZodString>;
221
+ mode: z.ZodOptional<z.ZodString>;
222
+ pr_head_sha: z.ZodOptional<z.ZodString>;
223
+ scope: z.ZodOptional<z.ZodString>;
224
+ }, z.core.$strip>;
197
225
  };
198
226
  type ReadOnlyToolPermissions = Record<string, false> & {
199
227
  write: false;
@@ -217,6 +245,24 @@ declare function extractLastAssistantText(messages: Array<{
217
245
  }>;
218
246
  }>): string;
219
247
  declare function nextCollectPollInterval(currentMs: number): number;
248
+ type ApplyCommonPromptResult = {
249
+ ok: true;
250
+ lanes: DispatchLaneSpec[];
251
+ } | {
252
+ ok: false;
253
+ errors: string[];
254
+ };
255
+ /**
256
+ * Prepend an optional shared `common_prompt` to every lane prompt so callers can
257
+ * send large shared context once instead of inlining it into each lane (which
258
+ * bloats the tool-call payload and triggers truncated/malformed tool-call JSON).
259
+ * Returns an error when any assembled prompt exceeds the per-lane character limit.
260
+ *
261
+ * Always returns a fresh array the caller owns: a shallow copy of the originals
262
+ * when no `commonPrompt` is provided, or shallow-copied lanes with rewritten
263
+ * prompts when it is. Callers may treat the returned array as their own.
264
+ */
265
+ declare function applyCommonPrompt(lanes: DispatchLaneSpec[], commonPrompt: string | undefined): ApplyCommonPromptResult;
220
266
  declare function formatError(error: unknown): string;
221
267
  declare function promptHash(lane: DispatchLaneSpec, directory: string, batchId: string): string;
222
268
  export declare const dispatch_lanes: ReturnType<typeof createSwarmTool>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "7.81.3",
3
+ "version": "7.81.4",
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",