opencode-swarm-plugin 0.26.1 → 0.27.2
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/.turbo/turbo-build.log +4 -4
- package/CHANGELOG.md +38 -0
- package/README.md +43 -46
- package/bin/swarm.ts +10 -54
- package/dist/compaction-hook.d.ts +57 -0
- package/dist/compaction-hook.d.ts.map +1 -0
- package/dist/hive.d.ts +741 -0
- package/dist/hive.d.ts.map +1 -0
- package/dist/index.d.ts +139 -23
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1353 -350
- package/dist/learning.d.ts +9 -9
- package/dist/plugin.js +1176 -350
- package/dist/schemas/cell-events.d.ts +1352 -0
- package/dist/schemas/{bead-events.d.ts.map → cell-events.d.ts.map} +1 -1
- package/dist/schemas/{bead.d.ts → cell.d.ts} +173 -29
- package/dist/schemas/cell.d.ts.map +1 -0
- package/dist/schemas/index.d.ts +11 -7
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/structured.d.ts +17 -7
- package/dist/structured.d.ts.map +1 -1
- package/dist/swarm-decompose.d.ts +5 -5
- package/dist/swarm-orchestrate.d.ts +16 -2
- package/dist/swarm-orchestrate.d.ts.map +1 -1
- package/dist/swarm-prompts.d.ts +9 -9
- package/dist/swarm-prompts.d.ts.map +1 -1
- package/dist/swarm-review.d.ts +210 -0
- package/dist/swarm-review.d.ts.map +1 -0
- package/dist/swarm-worktree.d.ts +185 -0
- package/dist/swarm-worktree.d.ts.map +1 -0
- package/dist/swarm.d.ts +7 -0
- package/dist/swarm.d.ts.map +1 -1
- package/dist/tool-availability.d.ts +3 -2
- package/dist/tool-availability.d.ts.map +1 -1
- package/docs/analysis-socratic-planner-pattern.md +1 -1
- package/docs/planning/ADR-007-swarm-enhancements-worktree-review.md +168 -0
- package/docs/testing/context-recovery-test.md +2 -2
- package/evals/README.md +2 -2
- package/evals/scorers/index.ts +7 -7
- package/examples/commands/swarm.md +21 -23
- package/examples/plugin-wrapper-template.ts +310 -44
- package/examples/skills/{beads-workflow → hive-workflow}/SKILL.md +40 -40
- package/examples/skills/swarm-coordination/SKILL.md +1 -1
- package/global-skills/swarm-coordination/SKILL.md +14 -14
- package/global-skills/swarm-coordination/references/coordinator-patterns.md +3 -3
- package/package.json +2 -2
- package/src/compaction-hook.ts +161 -0
- package/src/{beads.integration.test.ts → hive.integration.test.ts} +92 -80
- package/src/{beads.ts → hive.ts} +378 -219
- package/src/index.ts +57 -20
- package/src/learning.ts +9 -9
- package/src/output-guardrails.test.ts +4 -4
- package/src/output-guardrails.ts +9 -9
- package/src/planning-guardrails.test.ts +1 -1
- package/src/planning-guardrails.ts +1 -1
- package/src/schemas/{bead-events.test.ts → cell-events.test.ts} +83 -77
- package/src/schemas/cell-events.ts +807 -0
- package/src/schemas/{bead.ts → cell.ts} +95 -41
- package/src/schemas/evaluation.ts +1 -1
- package/src/schemas/index.ts +90 -18
- package/src/schemas/swarm-context.ts +2 -2
- package/src/structured.test.ts +15 -15
- package/src/structured.ts +18 -11
- package/src/swarm-decompose.ts +23 -23
- package/src/swarm-orchestrate.ts +135 -21
- package/src/swarm-prompts.ts +43 -43
- package/src/swarm-review.test.ts +702 -0
- package/src/swarm-review.ts +696 -0
- package/src/swarm-worktree.test.ts +501 -0
- package/src/swarm-worktree.ts +575 -0
- package/src/swarm.integration.test.ts +12 -12
- package/src/tool-availability.ts +36 -3
- package/dist/beads.d.ts +0 -386
- package/dist/beads.d.ts.map +0 -1
- package/dist/schemas/bead-events.d.ts +0 -698
- package/dist/schemas/bead.d.ts.map +0 -1
- package/src/schemas/bead-events.ts +0 -583
|
@@ -125,7 +125,7 @@ async function execTool(
|
|
|
125
125
|
// Beads Tools
|
|
126
126
|
// =============================================================================
|
|
127
127
|
|
|
128
|
-
const
|
|
128
|
+
const hive_create = tool({
|
|
129
129
|
description: "Create a new bead with type-safe validation",
|
|
130
130
|
args: {
|
|
131
131
|
title: tool.schema.string().describe("Bead title"),
|
|
@@ -145,10 +145,10 @@ const beads_create = tool({
|
|
|
145
145
|
.optional()
|
|
146
146
|
.describe("Parent bead ID for epic children"),
|
|
147
147
|
},
|
|
148
|
-
execute: (args, ctx) => execTool("
|
|
148
|
+
execute: (args, ctx) => execTool("hive_create", args, ctx),
|
|
149
149
|
});
|
|
150
150
|
|
|
151
|
-
const
|
|
151
|
+
const hive_create_epic = tool({
|
|
152
152
|
description: "Create epic with subtasks in one atomic operation",
|
|
153
153
|
args: {
|
|
154
154
|
epic_title: tool.schema.string().describe("Epic title"),
|
|
@@ -166,10 +166,10 @@ const beads_create_epic = tool({
|
|
|
166
166
|
)
|
|
167
167
|
.describe("Subtasks to create under the epic"),
|
|
168
168
|
},
|
|
169
|
-
execute: (args, ctx) => execTool("
|
|
169
|
+
execute: (args, ctx) => execTool("hive_create_epic", args, ctx),
|
|
170
170
|
});
|
|
171
171
|
|
|
172
|
-
const
|
|
172
|
+
const hive_query = tool({
|
|
173
173
|
description: "Query beads with filters (replaces bd list, bd ready, bd wip)",
|
|
174
174
|
args: {
|
|
175
175
|
status: tool.schema
|
|
@@ -189,13 +189,13 @@ const beads_query = tool({
|
|
|
189
189
|
.optional()
|
|
190
190
|
.describe("Max results (default: 20)"),
|
|
191
191
|
},
|
|
192
|
-
execute: (args, ctx) => execTool("
|
|
192
|
+
execute: (args, ctx) => execTool("hive_query", args, ctx),
|
|
193
193
|
});
|
|
194
194
|
|
|
195
|
-
const
|
|
195
|
+
const hive_update = tool({
|
|
196
196
|
description: "Update bead status/description",
|
|
197
197
|
args: {
|
|
198
|
-
id: tool.schema.string().describe("
|
|
198
|
+
id: tool.schema.string().describe("Cell ID"),
|
|
199
199
|
status: tool.schema
|
|
200
200
|
.enum(["open", "in_progress", "blocked", "closed"])
|
|
201
201
|
.optional()
|
|
@@ -208,44 +208,44 @@ const beads_update = tool({
|
|
|
208
208
|
.optional()
|
|
209
209
|
.describe("New priority"),
|
|
210
210
|
},
|
|
211
|
-
execute: (args, ctx) => execTool("
|
|
211
|
+
execute: (args, ctx) => execTool("hive_update", args, ctx),
|
|
212
212
|
});
|
|
213
213
|
|
|
214
|
-
const
|
|
214
|
+
const hive_close = tool({
|
|
215
215
|
description: "Close a bead with reason",
|
|
216
216
|
args: {
|
|
217
|
-
id: tool.schema.string().describe("
|
|
217
|
+
id: tool.schema.string().describe("Cell ID"),
|
|
218
218
|
reason: tool.schema.string().describe("Completion reason"),
|
|
219
219
|
},
|
|
220
|
-
execute: (args, ctx) => execTool("
|
|
220
|
+
execute: (args, ctx) => execTool("hive_close", args, ctx),
|
|
221
221
|
});
|
|
222
222
|
|
|
223
|
-
const
|
|
223
|
+
const hive_start = tool({
|
|
224
224
|
description: "Mark a bead as in-progress",
|
|
225
225
|
args: {
|
|
226
|
-
id: tool.schema.string().describe("
|
|
226
|
+
id: tool.schema.string().describe("Cell ID"),
|
|
227
227
|
},
|
|
228
|
-
execute: (args, ctx) => execTool("
|
|
228
|
+
execute: (args, ctx) => execTool("hive_start", args, ctx),
|
|
229
229
|
});
|
|
230
230
|
|
|
231
|
-
const
|
|
231
|
+
const hive_ready = tool({
|
|
232
232
|
description: "Get the next ready bead (unblocked, highest priority)",
|
|
233
233
|
args: {},
|
|
234
|
-
execute: (args, ctx) => execTool("
|
|
234
|
+
execute: (args, ctx) => execTool("hive_ready", args, ctx),
|
|
235
235
|
});
|
|
236
236
|
|
|
237
|
-
const
|
|
237
|
+
const hive_sync = tool({
|
|
238
238
|
description: "Sync beads to git and push (MANDATORY at session end)",
|
|
239
239
|
args: {
|
|
240
240
|
auto_pull: tool.schema.boolean().optional().describe("Pull before sync"),
|
|
241
241
|
},
|
|
242
|
-
execute: (args, ctx) => execTool("
|
|
242
|
+
execute: (args, ctx) => execTool("hive_sync", args, ctx),
|
|
243
243
|
});
|
|
244
244
|
|
|
245
245
|
const beads_link_thread = tool({
|
|
246
246
|
description: "Add metadata linking bead to Agent Mail thread",
|
|
247
247
|
args: {
|
|
248
|
-
bead_id: tool.schema.string().describe("
|
|
248
|
+
bead_id: tool.schema.string().describe("Cell ID"),
|
|
249
249
|
thread_id: tool.schema.string().describe("Agent Mail thread ID"),
|
|
250
250
|
},
|
|
251
251
|
execute: (args, ctx) => execTool("beads_link_thread", args, ctx),
|
|
@@ -375,7 +375,7 @@ const structured_validate = tool({
|
|
|
375
375
|
args: {
|
|
376
376
|
response: tool.schema.string().describe("Agent response to validate"),
|
|
377
377
|
schema_name: tool.schema
|
|
378
|
-
.enum(["evaluation", "task_decomposition", "
|
|
378
|
+
.enum(["evaluation", "task_decomposition", "cell_tree"])
|
|
379
379
|
.describe("Schema to validate against"),
|
|
380
380
|
max_retries: tool.schema
|
|
381
381
|
.number()
|
|
@@ -403,12 +403,12 @@ const structured_parse_decomposition = tool({
|
|
|
403
403
|
execute: (args, ctx) => execTool("structured_parse_decomposition", args, ctx),
|
|
404
404
|
});
|
|
405
405
|
|
|
406
|
-
const
|
|
406
|
+
const structured_parse_cell_tree = tool({
|
|
407
407
|
description: "Parse and validate bead tree response",
|
|
408
408
|
args: {
|
|
409
409
|
response: tool.schema.string().describe("Agent response"),
|
|
410
410
|
},
|
|
411
|
-
execute: (args, ctx) => execTool("
|
|
411
|
+
execute: (args, ctx) => execTool("structured_parse_cell_tree", args, ctx),
|
|
412
412
|
});
|
|
413
413
|
|
|
414
414
|
// =============================================================================
|
|
@@ -419,6 +419,12 @@ const swarm_init = tool({
|
|
|
419
419
|
description: "Initialize swarm session and check tool availability",
|
|
420
420
|
args: {
|
|
421
421
|
project_path: tool.schema.string().optional().describe("Project path"),
|
|
422
|
+
isolation: tool.schema
|
|
423
|
+
.enum(["worktree", "reservation"])
|
|
424
|
+
.optional()
|
|
425
|
+
.describe(
|
|
426
|
+
"Isolation mode: 'worktree' for git worktree isolation, 'reservation' for file reservations (default)",
|
|
427
|
+
),
|
|
422
428
|
},
|
|
423
429
|
execute: (args, ctx) => execTool("swarm_init", args, ctx),
|
|
424
430
|
});
|
|
@@ -491,7 +497,7 @@ const swarm_decompose = tool({
|
|
|
491
497
|
});
|
|
492
498
|
|
|
493
499
|
const swarm_validate_decomposition = tool({
|
|
494
|
-
description: "Validate a decomposition response against
|
|
500
|
+
description: "Validate a decomposition response against CellTreeSchema",
|
|
495
501
|
args: {
|
|
496
502
|
response: tool.schema.string().describe("Decomposition response"),
|
|
497
503
|
},
|
|
@@ -512,7 +518,7 @@ const swarm_progress = tool({
|
|
|
512
518
|
args: {
|
|
513
519
|
project_key: tool.schema.string().describe("Project key"),
|
|
514
520
|
agent_name: tool.schema.string().describe("Agent name"),
|
|
515
|
-
bead_id: tool.schema.string().describe("
|
|
521
|
+
bead_id: tool.schema.string().describe("Cell ID"),
|
|
516
522
|
status: tool.schema
|
|
517
523
|
.enum(["in_progress", "blocked", "completed", "failed"])
|
|
518
524
|
.describe("Status"),
|
|
@@ -533,18 +539,26 @@ const swarm_progress = tool({
|
|
|
533
539
|
|
|
534
540
|
const swarm_complete = tool({
|
|
535
541
|
description:
|
|
536
|
-
"Mark subtask complete
|
|
542
|
+
"Mark subtask complete with Verification Gate. Runs UBS scan, typecheck, and tests before allowing completion.",
|
|
537
543
|
args: {
|
|
538
544
|
project_key: tool.schema.string().describe("Project key"),
|
|
539
545
|
agent_name: tool.schema.string().describe("Agent name"),
|
|
540
|
-
bead_id: tool.schema.string().describe("
|
|
546
|
+
bead_id: tool.schema.string().describe("Cell ID"),
|
|
541
547
|
summary: tool.schema.string().describe("Completion summary"),
|
|
542
|
-
evaluation: tool.schema.string().optional().describe("Self-evaluation"),
|
|
548
|
+
evaluation: tool.schema.string().optional().describe("Self-evaluation JSON"),
|
|
543
549
|
files_touched: tool.schema
|
|
544
550
|
.array(tool.schema.string())
|
|
545
551
|
.optional()
|
|
546
|
-
.describe("Files modified"),
|
|
552
|
+
.describe("Files modified - will be verified"),
|
|
547
553
|
skip_ubs_scan: tool.schema.boolean().optional().describe("Skip UBS scan"),
|
|
554
|
+
skip_verification: tool.schema
|
|
555
|
+
.boolean()
|
|
556
|
+
.optional()
|
|
557
|
+
.describe("Skip ALL verification (UBS, typecheck, tests)"),
|
|
558
|
+
skip_review: tool.schema
|
|
559
|
+
.boolean()
|
|
560
|
+
.optional()
|
|
561
|
+
.describe("Skip review gate check"),
|
|
548
562
|
},
|
|
549
563
|
execute: (args, ctx) => execTool("swarm_complete", args, ctx),
|
|
550
564
|
});
|
|
@@ -552,7 +566,7 @@ const swarm_complete = tool({
|
|
|
552
566
|
const swarm_record_outcome = tool({
|
|
553
567
|
description: "Record subtask outcome for implicit feedback scoring",
|
|
554
568
|
args: {
|
|
555
|
-
bead_id: tool.schema.string().describe("
|
|
569
|
+
bead_id: tool.schema.string().describe("Cell ID"),
|
|
556
570
|
duration_ms: tool.schema.number().int().min(0).describe("Duration in ms"),
|
|
557
571
|
error_count: tool.schema
|
|
558
572
|
.number()
|
|
@@ -587,7 +601,7 @@ const swarm_subtask_prompt = tool({
|
|
|
587
601
|
description: "Generate the prompt for a spawned subtask agent",
|
|
588
602
|
args: {
|
|
589
603
|
agent_name: tool.schema.string().describe("Agent name"),
|
|
590
|
-
bead_id: tool.schema.string().describe("
|
|
604
|
+
bead_id: tool.schema.string().describe("Cell ID"),
|
|
591
605
|
epic_id: tool.schema.string().describe("Epic ID"),
|
|
592
606
|
subtask_title: tool.schema.string().describe("Subtask title"),
|
|
593
607
|
subtask_description: tool.schema
|
|
@@ -603,7 +617,7 @@ const swarm_subtask_prompt = tool({
|
|
|
603
617
|
const swarm_spawn_subtask = tool({
|
|
604
618
|
description: "Prepare a subtask for spawning with Task tool",
|
|
605
619
|
args: {
|
|
606
|
-
bead_id: tool.schema.string().describe("
|
|
620
|
+
bead_id: tool.schema.string().describe("Cell ID"),
|
|
607
621
|
epic_id: tool.schema.string().describe("Epic ID"),
|
|
608
622
|
subtask_title: tool.schema.string().describe("Subtask title"),
|
|
609
623
|
subtask_description: tool.schema
|
|
@@ -619,7 +633,7 @@ const swarm_spawn_subtask = tool({
|
|
|
619
633
|
const swarm_complete_subtask = tool({
|
|
620
634
|
description: "Handle subtask completion after Task agent returns",
|
|
621
635
|
args: {
|
|
622
|
-
bead_id: tool.schema.string().describe("
|
|
636
|
+
bead_id: tool.schema.string().describe("Cell ID"),
|
|
623
637
|
task_result: tool.schema.string().describe("Task result JSON"),
|
|
624
638
|
files_touched: tool.schema
|
|
625
639
|
.array(tool.schema.string())
|
|
@@ -632,7 +646,7 @@ const swarm_complete_subtask = tool({
|
|
|
632
646
|
const swarm_evaluation_prompt = tool({
|
|
633
647
|
description: "Generate self-evaluation prompt for a completed subtask",
|
|
634
648
|
args: {
|
|
635
|
-
bead_id: tool.schema.string().describe("
|
|
649
|
+
bead_id: tool.schema.string().describe("Cell ID"),
|
|
636
650
|
subtask_title: tool.schema.string().describe("Subtask title"),
|
|
637
651
|
files_touched: tool.schema
|
|
638
652
|
.array(tool.schema.string())
|
|
@@ -641,6 +655,117 @@ const swarm_evaluation_prompt = tool({
|
|
|
641
655
|
execute: (args, ctx) => execTool("swarm_evaluation_prompt", args, ctx),
|
|
642
656
|
});
|
|
643
657
|
|
|
658
|
+
const swarm_broadcast = tool({
|
|
659
|
+
description:
|
|
660
|
+
"Broadcast context update to all agents working on the same epic",
|
|
661
|
+
args: {
|
|
662
|
+
project_path: tool.schema.string().describe("Project path"),
|
|
663
|
+
agent_name: tool.schema.string().describe("Agent name"),
|
|
664
|
+
epic_id: tool.schema.string().describe("Epic ID"),
|
|
665
|
+
message: tool.schema.string().describe("Context update message"),
|
|
666
|
+
importance: tool.schema
|
|
667
|
+
.enum(["info", "warning", "blocker"])
|
|
668
|
+
.optional()
|
|
669
|
+
.describe("Priority level (default: info)"),
|
|
670
|
+
files_affected: tool.schema
|
|
671
|
+
.array(tool.schema.string())
|
|
672
|
+
.optional()
|
|
673
|
+
.describe("Files this context relates to"),
|
|
674
|
+
},
|
|
675
|
+
execute: (args, ctx) => execTool("swarm_broadcast", args, ctx),
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
// =============================================================================
|
|
679
|
+
// Worktree Isolation Tools
|
|
680
|
+
// =============================================================================
|
|
681
|
+
|
|
682
|
+
const swarm_worktree_create = tool({
|
|
683
|
+
description:
|
|
684
|
+
"Create a git worktree for isolated task execution. Worker operates in worktree, not main branch.",
|
|
685
|
+
args: {
|
|
686
|
+
project_path: tool.schema.string().describe("Absolute path to project root"),
|
|
687
|
+
task_id: tool.schema.string().describe("Task/bead ID (e.g., bd-abc123.1)"),
|
|
688
|
+
start_commit: tool.schema
|
|
689
|
+
.string()
|
|
690
|
+
.describe("Commit SHA to create worktree at (swarm start point)"),
|
|
691
|
+
},
|
|
692
|
+
execute: (args, ctx) => execTool("swarm_worktree_create", args, ctx),
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
const swarm_worktree_merge = tool({
|
|
696
|
+
description:
|
|
697
|
+
"Cherry-pick commits from worktree back to main branch. Call after worker completes.",
|
|
698
|
+
args: {
|
|
699
|
+
project_path: tool.schema.string().describe("Absolute path to project root"),
|
|
700
|
+
task_id: tool.schema.string().describe("Task/bead ID"),
|
|
701
|
+
start_commit: tool.schema
|
|
702
|
+
.string()
|
|
703
|
+
.optional()
|
|
704
|
+
.describe("Original start commit (to find new commits)"),
|
|
705
|
+
},
|
|
706
|
+
execute: (args, ctx) => execTool("swarm_worktree_merge", args, ctx),
|
|
707
|
+
});
|
|
708
|
+
|
|
709
|
+
const swarm_worktree_cleanup = tool({
|
|
710
|
+
description:
|
|
711
|
+
"Remove a worktree after completion or abort. Idempotent - safe to call multiple times.",
|
|
712
|
+
args: {
|
|
713
|
+
project_path: tool.schema.string().describe("Absolute path to project root"),
|
|
714
|
+
task_id: tool.schema.string().optional().describe("Task/bead ID to clean up"),
|
|
715
|
+
cleanup_all: tool.schema
|
|
716
|
+
.boolean()
|
|
717
|
+
.optional()
|
|
718
|
+
.describe("Remove all worktrees for this project"),
|
|
719
|
+
},
|
|
720
|
+
execute: (args, ctx) => execTool("swarm_worktree_cleanup", args, ctx),
|
|
721
|
+
});
|
|
722
|
+
|
|
723
|
+
const swarm_worktree_list = tool({
|
|
724
|
+
description: "List all active worktrees for a project",
|
|
725
|
+
args: {
|
|
726
|
+
project_path: tool.schema.string().describe("Absolute path to project root"),
|
|
727
|
+
},
|
|
728
|
+
execute: (args, ctx) => execTool("swarm_worktree_list", args, ctx),
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
// =============================================================================
|
|
732
|
+
// Structured Review Tools
|
|
733
|
+
// =============================================================================
|
|
734
|
+
|
|
735
|
+
const swarm_review = tool({
|
|
736
|
+
description:
|
|
737
|
+
"Generate a review prompt for a completed subtask. Includes epic context, dependencies, and diff.",
|
|
738
|
+
args: {
|
|
739
|
+
project_key: tool.schema.string().describe("Project path"),
|
|
740
|
+
epic_id: tool.schema.string().describe("Epic bead ID"),
|
|
741
|
+
task_id: tool.schema.string().describe("Subtask bead ID to review"),
|
|
742
|
+
files_touched: tool.schema
|
|
743
|
+
.array(tool.schema.string())
|
|
744
|
+
.optional()
|
|
745
|
+
.describe("Files modified (will get diff for these)"),
|
|
746
|
+
},
|
|
747
|
+
execute: (args, ctx) => execTool("swarm_review", args, ctx),
|
|
748
|
+
});
|
|
749
|
+
|
|
750
|
+
const swarm_review_feedback = tool({
|
|
751
|
+
description:
|
|
752
|
+
"Send review feedback to a worker. Tracks attempts (max 3). Fails task after 3 rejections.",
|
|
753
|
+
args: {
|
|
754
|
+
project_key: tool.schema.string().describe("Project path"),
|
|
755
|
+
task_id: tool.schema.string().describe("Subtask bead ID"),
|
|
756
|
+
worker_id: tool.schema.string().describe("Worker agent name"),
|
|
757
|
+
status: tool.schema
|
|
758
|
+
.enum(["approved", "needs_changes"])
|
|
759
|
+
.describe("Review status"),
|
|
760
|
+
summary: tool.schema.string().optional().describe("Review summary"),
|
|
761
|
+
issues: tool.schema
|
|
762
|
+
.string()
|
|
763
|
+
.optional()
|
|
764
|
+
.describe("JSON array of ReviewIssue objects (for needs_changes)"),
|
|
765
|
+
},
|
|
766
|
+
execute: (args, ctx) => execTool("swarm_review_feedback", args, ctx),
|
|
767
|
+
});
|
|
768
|
+
|
|
644
769
|
// =============================================================================
|
|
645
770
|
// Skills Tools
|
|
646
771
|
// =============================================================================
|
|
@@ -754,20 +879,141 @@ const skills_execute = tool({
|
|
|
754
879
|
// Plugin Export
|
|
755
880
|
// =============================================================================
|
|
756
881
|
|
|
882
|
+
// =============================================================================
|
|
883
|
+
// Compaction Hook - Swarm Recovery Context
|
|
884
|
+
// =============================================================================
|
|
885
|
+
|
|
886
|
+
/**
|
|
887
|
+
* Check for swarm sign - evidence a swarm passed through
|
|
888
|
+
*
|
|
889
|
+
* Like deer scat on a trail, we look for traces:
|
|
890
|
+
* - In-progress beads (active work)
|
|
891
|
+
* - Open beads with parent_id (subtasks of an epic)
|
|
892
|
+
* - Unclosed epics
|
|
893
|
+
*/
|
|
894
|
+
async function hasSwarmSign(): Promise<boolean> {
|
|
895
|
+
try {
|
|
896
|
+
const result = await new Promise<{ exitCode: number; stdout: string }>(
|
|
897
|
+
(resolve) => {
|
|
898
|
+
// Use swarm tool to query beads
|
|
899
|
+
const proc = spawn(SWARM_CLI, ["tool", "hive_query"], {
|
|
900
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
901
|
+
});
|
|
902
|
+
let stdout = "";
|
|
903
|
+
proc.stdout.on("data", (d) => {
|
|
904
|
+
stdout += d;
|
|
905
|
+
});
|
|
906
|
+
proc.on("close", (exitCode) =>
|
|
907
|
+
resolve({ exitCode: exitCode ?? 1, stdout }),
|
|
908
|
+
);
|
|
909
|
+
},
|
|
910
|
+
);
|
|
911
|
+
|
|
912
|
+
if (result.exitCode !== 0) return false;
|
|
913
|
+
|
|
914
|
+
const beads = JSON.parse(result.stdout);
|
|
915
|
+
if (!Array.isArray(beads)) return false;
|
|
916
|
+
|
|
917
|
+
// Look for swarm sign:
|
|
918
|
+
// 1. Any in_progress beads
|
|
919
|
+
// 2. Any open beads with a parent (subtasks)
|
|
920
|
+
// 3. Any epics that aren't closed
|
|
921
|
+
return beads.some(
|
|
922
|
+
(b: { status: string; parent_id?: string; type?: string }) =>
|
|
923
|
+
b.status === "in_progress" ||
|
|
924
|
+
(b.status === "open" && b.parent_id) ||
|
|
925
|
+
(b.type === "epic" && b.status !== "closed"),
|
|
926
|
+
);
|
|
927
|
+
} catch {
|
|
928
|
+
return false;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
/**
|
|
933
|
+
* Swarm-aware compaction context
|
|
934
|
+
*
|
|
935
|
+
* Injected during compaction to keep the swarm cooking. The coordinator should
|
|
936
|
+
* wake up from compaction and immediately resume orchestration - spawning agents,
|
|
937
|
+
* monitoring progress, unblocking work.
|
|
938
|
+
*/
|
|
939
|
+
const SWARM_COMPACTION_CONTEXT = `## 🐝 SWARM ACTIVE - Keep Cooking
|
|
940
|
+
|
|
941
|
+
You are the **COORDINATOR** of an active swarm. Context was compacted but the swarm is still running.
|
|
942
|
+
|
|
943
|
+
**YOUR JOB:** Keep orchestrating. Spawn agents. Monitor progress. Unblock work. Ship it.
|
|
944
|
+
|
|
945
|
+
### Preserve in Summary
|
|
946
|
+
|
|
947
|
+
Extract from session context:
|
|
948
|
+
|
|
949
|
+
1. **Epic & Subtasks** - IDs, titles, status, file assignments
|
|
950
|
+
2. **What's Running** - Which agents are active, what they're working on
|
|
951
|
+
3. **What's Blocked** - Blockers and what's needed to unblock
|
|
952
|
+
4. **What's Done** - Completed work and any follow-ups needed
|
|
953
|
+
5. **What's Next** - Pending subtasks ready to spawn
|
|
954
|
+
|
|
955
|
+
### Summary Format
|
|
956
|
+
|
|
957
|
+
\`\`\`
|
|
958
|
+
## 🐝 Swarm State
|
|
959
|
+
|
|
960
|
+
**Epic:** <bd-xxx> - <title>
|
|
961
|
+
**Project:** <path>
|
|
962
|
+
**Progress:** X/Y subtasks complete
|
|
963
|
+
|
|
964
|
+
**Active:**
|
|
965
|
+
- <bd-xxx>: <title> [in_progress] → <agent> working on <files>
|
|
966
|
+
|
|
967
|
+
**Blocked:**
|
|
968
|
+
- <bd-xxx>: <title> - BLOCKED: <reason>
|
|
969
|
+
|
|
970
|
+
**Completed:**
|
|
971
|
+
- <bd-xxx>: <title> ✓
|
|
972
|
+
|
|
973
|
+
**Ready to Spawn:**
|
|
974
|
+
- <bd-xxx>: <title> (files: <...>)
|
|
975
|
+
\`\`\`
|
|
976
|
+
|
|
977
|
+
### On Resume - IMMEDIATELY
|
|
978
|
+
|
|
979
|
+
1. \`swarm_status(epic_id="<epic>", project_key="<path>")\` - Get current state
|
|
980
|
+
2. \`swarmmail_inbox(limit=5)\` - Check for agent messages
|
|
981
|
+
3. **Spawn ready subtasks** - Don't wait, fire them off
|
|
982
|
+
4. **Unblock blocked work** - Resolve dependencies, reassign if needed
|
|
983
|
+
5. **Collect completed work** - Close done subtasks, verify quality
|
|
984
|
+
|
|
985
|
+
### Keep the Swarm Cooking
|
|
986
|
+
|
|
987
|
+
- **Spawn aggressively** - If a subtask is ready and unblocked, spawn an agent
|
|
988
|
+
- **Monitor actively** - Check status, read messages, respond to blockers
|
|
989
|
+
- **Close the loop** - When all subtasks done, verify and close the epic
|
|
990
|
+
- **Don't stop** - The swarm runs until the epic is closed
|
|
991
|
+
|
|
992
|
+
**You are not waiting for instructions. You are the coordinator. Coordinate.**
|
|
993
|
+
`;
|
|
994
|
+
|
|
995
|
+
// Extended hooks type to include experimental compaction hook
|
|
996
|
+
type ExtendedHooks = Hooks & {
|
|
997
|
+
"experimental.session.compacting"?: (
|
|
998
|
+
input: { sessionID: string },
|
|
999
|
+
output: { context: string[] },
|
|
1000
|
+
) => Promise<void>;
|
|
1001
|
+
};
|
|
1002
|
+
|
|
757
1003
|
export const SwarmPlugin: Plugin = async (
|
|
758
1004
|
_input: PluginInput,
|
|
759
|
-
): Promise<
|
|
1005
|
+
): Promise<ExtendedHooks> => {
|
|
760
1006
|
return {
|
|
761
1007
|
tool: {
|
|
762
1008
|
// Beads
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
1009
|
+
hive_create,
|
|
1010
|
+
hive_create_epic,
|
|
1011
|
+
hive_query,
|
|
1012
|
+
hive_update,
|
|
1013
|
+
hive_close,
|
|
1014
|
+
hive_start,
|
|
1015
|
+
hive_ready,
|
|
1016
|
+
hive_sync,
|
|
771
1017
|
beads_link_thread,
|
|
772
1018
|
// Swarm Mail (Embedded)
|
|
773
1019
|
swarmmail_init,
|
|
@@ -783,7 +1029,7 @@ export const SwarmPlugin: Plugin = async (
|
|
|
783
1029
|
structured_validate,
|
|
784
1030
|
structured_parse_evaluation,
|
|
785
1031
|
structured_parse_decomposition,
|
|
786
|
-
|
|
1032
|
+
structured_parse_cell_tree,
|
|
787
1033
|
// Swarm
|
|
788
1034
|
swarm_init,
|
|
789
1035
|
swarm_select_strategy,
|
|
@@ -798,6 +1044,15 @@ export const SwarmPlugin: Plugin = async (
|
|
|
798
1044
|
swarm_spawn_subtask,
|
|
799
1045
|
swarm_complete_subtask,
|
|
800
1046
|
swarm_evaluation_prompt,
|
|
1047
|
+
swarm_broadcast,
|
|
1048
|
+
// Worktree Isolation
|
|
1049
|
+
swarm_worktree_create,
|
|
1050
|
+
swarm_worktree_merge,
|
|
1051
|
+
swarm_worktree_cleanup,
|
|
1052
|
+
swarm_worktree_list,
|
|
1053
|
+
// Structured Review
|
|
1054
|
+
swarm_review,
|
|
1055
|
+
swarm_review_feedback,
|
|
801
1056
|
// Skills
|
|
802
1057
|
skills_list,
|
|
803
1058
|
skills_read,
|
|
@@ -809,6 +1064,17 @@ export const SwarmPlugin: Plugin = async (
|
|
|
809
1064
|
skills_add_script,
|
|
810
1065
|
skills_execute,
|
|
811
1066
|
},
|
|
1067
|
+
|
|
1068
|
+
// Swarm-aware compaction hook - only fires if there's an active swarm
|
|
1069
|
+
"experimental.session.compacting": async (
|
|
1070
|
+
_input: { sessionID: string },
|
|
1071
|
+
output: { context: string[] },
|
|
1072
|
+
) => {
|
|
1073
|
+
const hasSign = await hasSwarmSign();
|
|
1074
|
+
if (hasSign) {
|
|
1075
|
+
output.context.push(SWARM_COMPACTION_CONTEXT);
|
|
1076
|
+
}
|
|
1077
|
+
},
|
|
812
1078
|
};
|
|
813
1079
|
};
|
|
814
1080
|
|