opencode-swarm-plugin 0.11.2 → 0.12.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.
@@ -0,0 +1,723 @@
1
+ /**
2
+ * OpenCode Swarm Plugin Wrapper
3
+ *
4
+ * This is a thin wrapper that shells out to the `swarm` CLI for all tool execution.
5
+ * Generated by: swarm setup
6
+ *
7
+ * The plugin only depends on @opencode-ai/plugin (provided by OpenCode).
8
+ * All tool logic lives in the npm package - this just bridges to it.
9
+ *
10
+ * Environment variables:
11
+ * - OPENCODE_SESSION_ID: Passed to CLI for session state persistence
12
+ * - OPENCODE_MESSAGE_ID: Passed to CLI for context
13
+ * - OPENCODE_AGENT: Passed to CLI for context
14
+ */
15
+ import type { Plugin, PluginInput, Hooks } from "@opencode-ai/plugin";
16
+ import { tool } from "@opencode-ai/plugin";
17
+ import { spawn } from "child_process";
18
+
19
+ const SWARM_CLI = "swarm";
20
+
21
+ // =============================================================================
22
+ // CLI Execution Helper
23
+ // =============================================================================
24
+
25
+ /**
26
+ * Execute a swarm tool via CLI
27
+ *
28
+ * Spawns `swarm tool <name> --json '<args>'` and returns the result.
29
+ * Passes session context via environment variables.
30
+ */
31
+ async function execTool(
32
+ name: string,
33
+ args: Record<string, unknown>,
34
+ ctx: { sessionID: string; messageID: string; agent: string },
35
+ ): Promise<string> {
36
+ return new Promise((resolve, reject) => {
37
+ const hasArgs = Object.keys(args).length > 0;
38
+ const cliArgs = hasArgs
39
+ ? ["tool", name, "--json", JSON.stringify(args)]
40
+ : ["tool", name];
41
+
42
+ const proc = spawn(SWARM_CLI, cliArgs, {
43
+ stdio: ["ignore", "pipe", "pipe"],
44
+ env: {
45
+ ...process.env,
46
+ OPENCODE_SESSION_ID: ctx.sessionID,
47
+ OPENCODE_MESSAGE_ID: ctx.messageID,
48
+ OPENCODE_AGENT: ctx.agent,
49
+ },
50
+ });
51
+
52
+ let stdout = "";
53
+ let stderr = "";
54
+
55
+ proc.stdout.on("data", (data) => {
56
+ stdout += data;
57
+ });
58
+ proc.stderr.on("data", (data) => {
59
+ stderr += data;
60
+ });
61
+
62
+ proc.on("close", (code) => {
63
+ if (code === 0) {
64
+ // Success - return the JSON output
65
+ try {
66
+ const result = JSON.parse(stdout);
67
+ if (result.success && result.data !== undefined) {
68
+ // Unwrap the data for cleaner tool output
69
+ resolve(
70
+ typeof result.data === "string"
71
+ ? result.data
72
+ : JSON.stringify(result.data, null, 2),
73
+ );
74
+ } else if (!result.success && result.error) {
75
+ // Tool returned an error in JSON format
76
+ reject(new Error(result.error.message || "Tool execution failed"));
77
+ } else {
78
+ resolve(stdout);
79
+ }
80
+ } catch {
81
+ resolve(stdout);
82
+ }
83
+ } else if (code === 2) {
84
+ reject(new Error(`Unknown tool: ${name}`));
85
+ } else if (code === 3) {
86
+ reject(new Error(`Invalid JSON args: ${stderr}`));
87
+ } else {
88
+ // Tool returned error
89
+ try {
90
+ const result = JSON.parse(stdout);
91
+ if (!result.success && result.error) {
92
+ reject(
93
+ new Error(
94
+ result.error.message || `Tool failed with code ${code}`,
95
+ ),
96
+ );
97
+ } else {
98
+ reject(
99
+ new Error(stderr || stdout || `Tool failed with code ${code}`),
100
+ );
101
+ }
102
+ } catch {
103
+ reject(
104
+ new Error(stderr || stdout || `Tool failed with code ${code}`),
105
+ );
106
+ }
107
+ }
108
+ });
109
+
110
+ proc.on("error", (err) => {
111
+ if ((err as NodeJS.ErrnoException).code === "ENOENT") {
112
+ reject(
113
+ new Error(
114
+ `swarm CLI not found. Install with: npm install -g opencode-swarm-plugin`,
115
+ ),
116
+ );
117
+ } else {
118
+ reject(err);
119
+ }
120
+ });
121
+ });
122
+ }
123
+
124
+ // =============================================================================
125
+ // Beads Tools
126
+ // =============================================================================
127
+
128
+ const beads_create = tool({
129
+ description: "Create a new bead with type-safe validation",
130
+ args: {
131
+ title: tool.schema.string().describe("Bead title"),
132
+ type: tool.schema
133
+ .enum(["bug", "feature", "task", "epic", "chore"])
134
+ .optional()
135
+ .describe("Issue type (default: task)"),
136
+ priority: tool.schema
137
+ .number()
138
+ .min(0)
139
+ .max(3)
140
+ .optional()
141
+ .describe("Priority 0-3 (default: 2)"),
142
+ description: tool.schema.string().optional().describe("Bead description"),
143
+ parent_id: tool.schema
144
+ .string()
145
+ .optional()
146
+ .describe("Parent bead ID for epic children"),
147
+ },
148
+ execute: (args, ctx) => execTool("beads_create", args, ctx),
149
+ });
150
+
151
+ const beads_create_epic = tool({
152
+ description: "Create epic with subtasks in one atomic operation",
153
+ args: {
154
+ epic_title: tool.schema.string().describe("Epic title"),
155
+ epic_description: tool.schema
156
+ .string()
157
+ .optional()
158
+ .describe("Epic description"),
159
+ subtasks: tool.schema
160
+ .array(
161
+ tool.schema.object({
162
+ title: tool.schema.string(),
163
+ priority: tool.schema.number().min(0).max(3).optional(),
164
+ files: tool.schema.array(tool.schema.string()).optional(),
165
+ }),
166
+ )
167
+ .describe("Subtasks to create under the epic"),
168
+ },
169
+ execute: (args, ctx) => execTool("beads_create_epic", args, ctx),
170
+ });
171
+
172
+ const beads_query = tool({
173
+ description: "Query beads with filters (replaces bd list, bd ready, bd wip)",
174
+ args: {
175
+ status: tool.schema
176
+ .enum(["open", "in_progress", "blocked", "closed"])
177
+ .optional()
178
+ .describe("Filter by status"),
179
+ type: tool.schema
180
+ .enum(["bug", "feature", "task", "epic", "chore"])
181
+ .optional()
182
+ .describe("Filter by type"),
183
+ ready: tool.schema
184
+ .boolean()
185
+ .optional()
186
+ .describe("Only show unblocked beads"),
187
+ limit: tool.schema
188
+ .number()
189
+ .optional()
190
+ .describe("Max results (default: 20)"),
191
+ },
192
+ execute: (args, ctx) => execTool("beads_query", args, ctx),
193
+ });
194
+
195
+ const beads_update = tool({
196
+ description: "Update bead status/description",
197
+ args: {
198
+ id: tool.schema.string().describe("Bead ID"),
199
+ status: tool.schema
200
+ .enum(["open", "in_progress", "blocked", "closed"])
201
+ .optional()
202
+ .describe("New status"),
203
+ description: tool.schema.string().optional().describe("New description"),
204
+ priority: tool.schema
205
+ .number()
206
+ .min(0)
207
+ .max(3)
208
+ .optional()
209
+ .describe("New priority"),
210
+ },
211
+ execute: (args, ctx) => execTool("beads_update", args, ctx),
212
+ });
213
+
214
+ const beads_close = tool({
215
+ description: "Close a bead with reason",
216
+ args: {
217
+ id: tool.schema.string().describe("Bead ID"),
218
+ reason: tool.schema.string().describe("Completion reason"),
219
+ },
220
+ execute: (args, ctx) => execTool("beads_close", args, ctx),
221
+ });
222
+
223
+ const beads_start = tool({
224
+ description: "Mark a bead as in-progress",
225
+ args: {
226
+ id: tool.schema.string().describe("Bead ID"),
227
+ },
228
+ execute: (args, ctx) => execTool("beads_start", args, ctx),
229
+ });
230
+
231
+ const beads_ready = tool({
232
+ description: "Get the next ready bead (unblocked, highest priority)",
233
+ args: {},
234
+ execute: (args, ctx) => execTool("beads_ready", args, ctx),
235
+ });
236
+
237
+ const beads_sync = tool({
238
+ description: "Sync beads to git and push (MANDATORY at session end)",
239
+ args: {
240
+ auto_pull: tool.schema.boolean().optional().describe("Pull before sync"),
241
+ },
242
+ execute: (args, ctx) => execTool("beads_sync", args, ctx),
243
+ });
244
+
245
+ const beads_link_thread = tool({
246
+ description: "Add metadata linking bead to Agent Mail thread",
247
+ args: {
248
+ bead_id: tool.schema.string().describe("Bead ID"),
249
+ thread_id: tool.schema.string().describe("Agent Mail thread ID"),
250
+ },
251
+ execute: (args, ctx) => execTool("beads_link_thread", args, ctx),
252
+ });
253
+
254
+ // =============================================================================
255
+ // Agent Mail Tools
256
+ // =============================================================================
257
+
258
+ const agentmail_init = tool({
259
+ description: "Initialize Agent Mail session",
260
+ args: {
261
+ project_path: tool.schema.string().describe("Absolute path to the project"),
262
+ agent_name: tool.schema.string().optional().describe("Custom agent name"),
263
+ task_description: tool.schema
264
+ .string()
265
+ .optional()
266
+ .describe("Task description"),
267
+ },
268
+ execute: (args, ctx) => execTool("agentmail_init", args, ctx),
269
+ });
270
+
271
+ const agentmail_send = tool({
272
+ description: "Send message to other agents",
273
+ args: {
274
+ to: tool.schema
275
+ .array(tool.schema.string())
276
+ .describe("Recipient agent names"),
277
+ subject: tool.schema.string().describe("Message subject"),
278
+ body: tool.schema.string().describe("Message body"),
279
+ thread_id: tool.schema
280
+ .string()
281
+ .optional()
282
+ .describe("Thread ID for grouping"),
283
+ importance: tool.schema
284
+ .enum(["low", "normal", "high", "urgent"])
285
+ .optional()
286
+ .describe("Message importance"),
287
+ ack_required: tool.schema
288
+ .boolean()
289
+ .optional()
290
+ .describe("Require acknowledgment"),
291
+ },
292
+ execute: (args, ctx) => execTool("agentmail_send", args, ctx),
293
+ });
294
+
295
+ const agentmail_inbox = tool({
296
+ description: "Fetch inbox (CONTEXT-SAFE: bodies excluded, limit 5)",
297
+ args: {
298
+ limit: tool.schema
299
+ .number()
300
+ .max(5)
301
+ .optional()
302
+ .describe("Max messages (max 5)"),
303
+ urgent_only: tool.schema
304
+ .boolean()
305
+ .optional()
306
+ .describe("Only urgent messages"),
307
+ since_ts: tool.schema
308
+ .string()
309
+ .optional()
310
+ .describe("Messages since timestamp"),
311
+ },
312
+ execute: (args, ctx) => execTool("agentmail_inbox", args, ctx),
313
+ });
314
+
315
+ const agentmail_read_message = tool({
316
+ description: "Fetch ONE message body by ID",
317
+ args: {
318
+ message_id: tool.schema.number().describe("Message ID"),
319
+ },
320
+ execute: (args, ctx) => execTool("agentmail_read_message", args, ctx),
321
+ });
322
+
323
+ const agentmail_summarize_thread = tool({
324
+ description: "Summarize thread (PREFERRED over fetching all messages)",
325
+ args: {
326
+ thread_id: tool.schema.string().describe("Thread ID"),
327
+ include_examples: tool.schema
328
+ .boolean()
329
+ .optional()
330
+ .describe("Include example messages"),
331
+ },
332
+ execute: (args, ctx) => execTool("agentmail_summarize_thread", args, ctx),
333
+ });
334
+
335
+ const agentmail_reserve = tool({
336
+ description: "Reserve file paths for exclusive editing",
337
+ args: {
338
+ paths: tool.schema
339
+ .array(tool.schema.string())
340
+ .describe("File paths/patterns"),
341
+ ttl_seconds: tool.schema.number().optional().describe("Reservation TTL"),
342
+ exclusive: tool.schema.boolean().optional().describe("Exclusive lock"),
343
+ reason: tool.schema.string().optional().describe("Reservation reason"),
344
+ },
345
+ execute: (args, ctx) => execTool("agentmail_reserve", args, ctx),
346
+ });
347
+
348
+ const agentmail_release = tool({
349
+ description: "Release file reservations",
350
+ args: {
351
+ paths: tool.schema
352
+ .array(tool.schema.string())
353
+ .optional()
354
+ .describe("Paths to release"),
355
+ reservation_ids: tool.schema
356
+ .array(tool.schema.number())
357
+ .optional()
358
+ .describe("Reservation IDs"),
359
+ },
360
+ execute: (args, ctx) => execTool("agentmail_release", args, ctx),
361
+ });
362
+
363
+ const agentmail_ack = tool({
364
+ description: "Acknowledge a message",
365
+ args: {
366
+ message_id: tool.schema.number().describe("Message ID"),
367
+ },
368
+ execute: (args, ctx) => execTool("agentmail_ack", args, ctx),
369
+ });
370
+
371
+ const agentmail_search = tool({
372
+ description: "Search messages by keyword",
373
+ args: {
374
+ query: tool.schema.string().describe("Search query"),
375
+ limit: tool.schema.number().optional().describe("Max results"),
376
+ },
377
+ execute: (args, ctx) => execTool("agentmail_search", args, ctx),
378
+ });
379
+
380
+ const agentmail_health = tool({
381
+ description: "Check if Agent Mail server is running",
382
+ args: {},
383
+ execute: (args, ctx) => execTool("agentmail_health", args, ctx),
384
+ });
385
+
386
+ // =============================================================================
387
+ // Structured Tools
388
+ // =============================================================================
389
+
390
+ const structured_extract_json = tool({
391
+ description: "Extract JSON from markdown/text response",
392
+ args: {
393
+ text: tool.schema.string().describe("Text containing JSON"),
394
+ },
395
+ execute: (args, ctx) => execTool("structured_extract_json", args, ctx),
396
+ });
397
+
398
+ const structured_validate = tool({
399
+ description: "Validate agent response against a schema",
400
+ args: {
401
+ response: tool.schema.string().describe("Agent response to validate"),
402
+ schema_name: tool.schema
403
+ .enum(["evaluation", "task_decomposition", "bead_tree"])
404
+ .describe("Schema to validate against"),
405
+ max_retries: tool.schema
406
+ .number()
407
+ .min(1)
408
+ .max(5)
409
+ .optional()
410
+ .describe("Max retries"),
411
+ },
412
+ execute: (args, ctx) => execTool("structured_validate", args, ctx),
413
+ });
414
+
415
+ const structured_parse_evaluation = tool({
416
+ description: "Parse and validate evaluation response",
417
+ args: {
418
+ response: tool.schema.string().describe("Agent response"),
419
+ },
420
+ execute: (args, ctx) => execTool("structured_parse_evaluation", args, ctx),
421
+ });
422
+
423
+ const structured_parse_decomposition = tool({
424
+ description: "Parse and validate task decomposition response",
425
+ args: {
426
+ response: tool.schema.string().describe("Agent response"),
427
+ },
428
+ execute: (args, ctx) => execTool("structured_parse_decomposition", args, ctx),
429
+ });
430
+
431
+ const structured_parse_bead_tree = tool({
432
+ description: "Parse and validate bead tree response",
433
+ args: {
434
+ response: tool.schema.string().describe("Agent response"),
435
+ },
436
+ execute: (args, ctx) => execTool("structured_parse_bead_tree", args, ctx),
437
+ });
438
+
439
+ // =============================================================================
440
+ // Swarm Tools
441
+ // =============================================================================
442
+
443
+ const swarm_init = tool({
444
+ description: "Initialize swarm session and check tool availability",
445
+ args: {
446
+ project_path: tool.schema.string().optional().describe("Project path"),
447
+ },
448
+ execute: (args, ctx) => execTool("swarm_init", args, ctx),
449
+ });
450
+
451
+ const swarm_select_strategy = tool({
452
+ description: "Analyze task and recommend decomposition strategy",
453
+ args: {
454
+ task: tool.schema.string().min(1).describe("Task to analyze"),
455
+ codebase_context: tool.schema
456
+ .string()
457
+ .optional()
458
+ .describe("Codebase context"),
459
+ },
460
+ execute: (args, ctx) => execTool("swarm_select_strategy", args, ctx),
461
+ });
462
+
463
+ const swarm_plan_prompt = tool({
464
+ description: "Generate strategy-specific decomposition prompt",
465
+ args: {
466
+ task: tool.schema.string().min(1).describe("Task to decompose"),
467
+ strategy: tool.schema
468
+ .enum(["file-based", "feature-based", "risk-based", "auto"])
469
+ .optional()
470
+ .describe("Decomposition strategy"),
471
+ max_subtasks: tool.schema
472
+ .number()
473
+ .int()
474
+ .min(2)
475
+ .max(10)
476
+ .optional()
477
+ .describe("Max subtasks"),
478
+ context: tool.schema.string().optional().describe("Additional context"),
479
+ query_cass: tool.schema
480
+ .boolean()
481
+ .optional()
482
+ .describe("Query CASS for similar tasks"),
483
+ cass_limit: tool.schema
484
+ .number()
485
+ .int()
486
+ .min(1)
487
+ .max(10)
488
+ .optional()
489
+ .describe("CASS limit"),
490
+ },
491
+ execute: (args, ctx) => execTool("swarm_plan_prompt", args, ctx),
492
+ });
493
+
494
+ const swarm_decompose = tool({
495
+ description: "Generate decomposition prompt for breaking task into subtasks",
496
+ args: {
497
+ task: tool.schema.string().min(1).describe("Task to decompose"),
498
+ max_subtasks: tool.schema
499
+ .number()
500
+ .int()
501
+ .min(2)
502
+ .max(10)
503
+ .optional()
504
+ .describe("Max subtasks"),
505
+ context: tool.schema.string().optional().describe("Additional context"),
506
+ query_cass: tool.schema.boolean().optional().describe("Query CASS"),
507
+ cass_limit: tool.schema
508
+ .number()
509
+ .int()
510
+ .min(1)
511
+ .max(10)
512
+ .optional()
513
+ .describe("CASS limit"),
514
+ },
515
+ execute: (args, ctx) => execTool("swarm_decompose", args, ctx),
516
+ });
517
+
518
+ const swarm_validate_decomposition = tool({
519
+ description: "Validate a decomposition response against BeadTreeSchema",
520
+ args: {
521
+ response: tool.schema.string().describe("Decomposition response"),
522
+ },
523
+ execute: (args, ctx) => execTool("swarm_validate_decomposition", args, ctx),
524
+ });
525
+
526
+ const swarm_status = tool({
527
+ description: "Get status of a swarm by epic ID",
528
+ args: {
529
+ epic_id: tool.schema.string().describe("Epic bead ID"),
530
+ project_key: tool.schema.string().describe("Project key"),
531
+ },
532
+ execute: (args, ctx) => execTool("swarm_status", args, ctx),
533
+ });
534
+
535
+ const swarm_progress = tool({
536
+ description: "Report progress on a subtask to coordinator",
537
+ args: {
538
+ project_key: tool.schema.string().describe("Project key"),
539
+ agent_name: tool.schema.string().describe("Agent name"),
540
+ bead_id: tool.schema.string().describe("Bead ID"),
541
+ status: tool.schema
542
+ .enum(["in_progress", "blocked", "completed", "failed"])
543
+ .describe("Status"),
544
+ message: tool.schema.string().optional().describe("Progress message"),
545
+ progress_percent: tool.schema
546
+ .number()
547
+ .min(0)
548
+ .max(100)
549
+ .optional()
550
+ .describe("Progress %"),
551
+ files_touched: tool.schema
552
+ .array(tool.schema.string())
553
+ .optional()
554
+ .describe("Files modified"),
555
+ },
556
+ execute: (args, ctx) => execTool("swarm_progress", args, ctx),
557
+ });
558
+
559
+ const swarm_complete = tool({
560
+ description:
561
+ "Mark subtask complete, release reservations, notify coordinator",
562
+ args: {
563
+ project_key: tool.schema.string().describe("Project key"),
564
+ agent_name: tool.schema.string().describe("Agent name"),
565
+ bead_id: tool.schema.string().describe("Bead ID"),
566
+ summary: tool.schema.string().describe("Completion summary"),
567
+ evaluation: tool.schema.string().optional().describe("Self-evaluation"),
568
+ files_touched: tool.schema
569
+ .array(tool.schema.string())
570
+ .optional()
571
+ .describe("Files modified"),
572
+ skip_ubs_scan: tool.schema.boolean().optional().describe("Skip UBS scan"),
573
+ },
574
+ execute: (args, ctx) => execTool("swarm_complete", args, ctx),
575
+ });
576
+
577
+ const swarm_record_outcome = tool({
578
+ description: "Record subtask outcome for implicit feedback scoring",
579
+ args: {
580
+ bead_id: tool.schema.string().describe("Bead ID"),
581
+ duration_ms: tool.schema.number().int().min(0).describe("Duration in ms"),
582
+ error_count: tool.schema
583
+ .number()
584
+ .int()
585
+ .min(0)
586
+ .optional()
587
+ .describe("Error count"),
588
+ retry_count: tool.schema
589
+ .number()
590
+ .int()
591
+ .min(0)
592
+ .optional()
593
+ .describe("Retry count"),
594
+ success: tool.schema.boolean().describe("Whether task succeeded"),
595
+ files_touched: tool.schema
596
+ .array(tool.schema.string())
597
+ .optional()
598
+ .describe("Files modified"),
599
+ criteria: tool.schema
600
+ .array(tool.schema.string())
601
+ .optional()
602
+ .describe("Evaluation criteria"),
603
+ strategy: tool.schema
604
+ .enum(["file-based", "feature-based", "risk-based"])
605
+ .optional()
606
+ .describe("Strategy used"),
607
+ },
608
+ execute: (args, ctx) => execTool("swarm_record_outcome", args, ctx),
609
+ });
610
+
611
+ const swarm_subtask_prompt = tool({
612
+ description: "Generate the prompt for a spawned subtask agent",
613
+ args: {
614
+ agent_name: tool.schema.string().describe("Agent name"),
615
+ bead_id: tool.schema.string().describe("Bead ID"),
616
+ epic_id: tool.schema.string().describe("Epic ID"),
617
+ subtask_title: tool.schema.string().describe("Subtask title"),
618
+ subtask_description: tool.schema
619
+ .string()
620
+ .optional()
621
+ .describe("Description"),
622
+ files: tool.schema.array(tool.schema.string()).describe("Files to work on"),
623
+ shared_context: tool.schema.string().optional().describe("Shared context"),
624
+ },
625
+ execute: (args, ctx) => execTool("swarm_subtask_prompt", args, ctx),
626
+ });
627
+
628
+ const swarm_spawn_subtask = tool({
629
+ description: "Prepare a subtask for spawning with Task tool",
630
+ args: {
631
+ bead_id: tool.schema.string().describe("Bead ID"),
632
+ epic_id: tool.schema.string().describe("Epic ID"),
633
+ subtask_title: tool.schema.string().describe("Subtask title"),
634
+ subtask_description: tool.schema
635
+ .string()
636
+ .optional()
637
+ .describe("Description"),
638
+ files: tool.schema.array(tool.schema.string()).describe("Files to work on"),
639
+ shared_context: tool.schema.string().optional().describe("Shared context"),
640
+ },
641
+ execute: (args, ctx) => execTool("swarm_spawn_subtask", args, ctx),
642
+ });
643
+
644
+ const swarm_complete_subtask = tool({
645
+ description: "Handle subtask completion after Task agent returns",
646
+ args: {
647
+ bead_id: tool.schema.string().describe("Bead ID"),
648
+ task_result: tool.schema.string().describe("Task result JSON"),
649
+ files_touched: tool.schema
650
+ .array(tool.schema.string())
651
+ .optional()
652
+ .describe("Files modified"),
653
+ },
654
+ execute: (args, ctx) => execTool("swarm_complete_subtask", args, ctx),
655
+ });
656
+
657
+ const swarm_evaluation_prompt = tool({
658
+ description: "Generate self-evaluation prompt for a completed subtask",
659
+ args: {
660
+ bead_id: tool.schema.string().describe("Bead ID"),
661
+ subtask_title: tool.schema.string().describe("Subtask title"),
662
+ files_touched: tool.schema
663
+ .array(tool.schema.string())
664
+ .describe("Files modified"),
665
+ },
666
+ execute: (args, ctx) => execTool("swarm_evaluation_prompt", args, ctx),
667
+ });
668
+
669
+ // =============================================================================
670
+ // Plugin Export
671
+ // =============================================================================
672
+
673
+ export const SwarmPlugin: Plugin = async (
674
+ _input: PluginInput,
675
+ ): Promise<Hooks> => {
676
+ return {
677
+ tool: {
678
+ // Beads
679
+ beads_create,
680
+ beads_create_epic,
681
+ beads_query,
682
+ beads_update,
683
+ beads_close,
684
+ beads_start,
685
+ beads_ready,
686
+ beads_sync,
687
+ beads_link_thread,
688
+ // Agent Mail
689
+ agentmail_init,
690
+ agentmail_send,
691
+ agentmail_inbox,
692
+ agentmail_read_message,
693
+ agentmail_summarize_thread,
694
+ agentmail_reserve,
695
+ agentmail_release,
696
+ agentmail_ack,
697
+ agentmail_search,
698
+ agentmail_health,
699
+ // Structured
700
+ structured_extract_json,
701
+ structured_validate,
702
+ structured_parse_evaluation,
703
+ structured_parse_decomposition,
704
+ structured_parse_bead_tree,
705
+ // Swarm
706
+ swarm_init,
707
+ swarm_select_strategy,
708
+ swarm_plan_prompt,
709
+ swarm_decompose,
710
+ swarm_validate_decomposition,
711
+ swarm_status,
712
+ swarm_progress,
713
+ swarm_complete,
714
+ swarm_record_outcome,
715
+ swarm_subtask_prompt,
716
+ swarm_spawn_subtask,
717
+ swarm_complete_subtask,
718
+ swarm_evaluation_prompt,
719
+ },
720
+ };
721
+ };
722
+
723
+ export default SwarmPlugin;