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.
Files changed (77) hide show
  1. package/.turbo/turbo-build.log +4 -4
  2. package/CHANGELOG.md +38 -0
  3. package/README.md +43 -46
  4. package/bin/swarm.ts +10 -54
  5. package/dist/compaction-hook.d.ts +57 -0
  6. package/dist/compaction-hook.d.ts.map +1 -0
  7. package/dist/hive.d.ts +741 -0
  8. package/dist/hive.d.ts.map +1 -0
  9. package/dist/index.d.ts +139 -23
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +1353 -350
  12. package/dist/learning.d.ts +9 -9
  13. package/dist/plugin.js +1176 -350
  14. package/dist/schemas/cell-events.d.ts +1352 -0
  15. package/dist/schemas/{bead-events.d.ts.map → cell-events.d.ts.map} +1 -1
  16. package/dist/schemas/{bead.d.ts → cell.d.ts} +173 -29
  17. package/dist/schemas/cell.d.ts.map +1 -0
  18. package/dist/schemas/index.d.ts +11 -7
  19. package/dist/schemas/index.d.ts.map +1 -1
  20. package/dist/structured.d.ts +17 -7
  21. package/dist/structured.d.ts.map +1 -1
  22. package/dist/swarm-decompose.d.ts +5 -5
  23. package/dist/swarm-orchestrate.d.ts +16 -2
  24. package/dist/swarm-orchestrate.d.ts.map +1 -1
  25. package/dist/swarm-prompts.d.ts +9 -9
  26. package/dist/swarm-prompts.d.ts.map +1 -1
  27. package/dist/swarm-review.d.ts +210 -0
  28. package/dist/swarm-review.d.ts.map +1 -0
  29. package/dist/swarm-worktree.d.ts +185 -0
  30. package/dist/swarm-worktree.d.ts.map +1 -0
  31. package/dist/swarm.d.ts +7 -0
  32. package/dist/swarm.d.ts.map +1 -1
  33. package/dist/tool-availability.d.ts +3 -2
  34. package/dist/tool-availability.d.ts.map +1 -1
  35. package/docs/analysis-socratic-planner-pattern.md +1 -1
  36. package/docs/planning/ADR-007-swarm-enhancements-worktree-review.md +168 -0
  37. package/docs/testing/context-recovery-test.md +2 -2
  38. package/evals/README.md +2 -2
  39. package/evals/scorers/index.ts +7 -7
  40. package/examples/commands/swarm.md +21 -23
  41. package/examples/plugin-wrapper-template.ts +310 -44
  42. package/examples/skills/{beads-workflow → hive-workflow}/SKILL.md +40 -40
  43. package/examples/skills/swarm-coordination/SKILL.md +1 -1
  44. package/global-skills/swarm-coordination/SKILL.md +14 -14
  45. package/global-skills/swarm-coordination/references/coordinator-patterns.md +3 -3
  46. package/package.json +2 -2
  47. package/src/compaction-hook.ts +161 -0
  48. package/src/{beads.integration.test.ts → hive.integration.test.ts} +92 -80
  49. package/src/{beads.ts → hive.ts} +378 -219
  50. package/src/index.ts +57 -20
  51. package/src/learning.ts +9 -9
  52. package/src/output-guardrails.test.ts +4 -4
  53. package/src/output-guardrails.ts +9 -9
  54. package/src/planning-guardrails.test.ts +1 -1
  55. package/src/planning-guardrails.ts +1 -1
  56. package/src/schemas/{bead-events.test.ts → cell-events.test.ts} +83 -77
  57. package/src/schemas/cell-events.ts +807 -0
  58. package/src/schemas/{bead.ts → cell.ts} +95 -41
  59. package/src/schemas/evaluation.ts +1 -1
  60. package/src/schemas/index.ts +90 -18
  61. package/src/schemas/swarm-context.ts +2 -2
  62. package/src/structured.test.ts +15 -15
  63. package/src/structured.ts +18 -11
  64. package/src/swarm-decompose.ts +23 -23
  65. package/src/swarm-orchestrate.ts +135 -21
  66. package/src/swarm-prompts.ts +43 -43
  67. package/src/swarm-review.test.ts +702 -0
  68. package/src/swarm-review.ts +696 -0
  69. package/src/swarm-worktree.test.ts +501 -0
  70. package/src/swarm-worktree.ts +575 -0
  71. package/src/swarm.integration.test.ts +12 -12
  72. package/src/tool-availability.ts +36 -3
  73. package/dist/beads.d.ts +0 -386
  74. package/dist/beads.d.ts.map +0 -1
  75. package/dist/schemas/bead-events.d.ts +0 -698
  76. package/dist/schemas/bead.d.ts.map +0 -1
  77. package/src/schemas/bead-events.ts +0 -583
@@ -1,29 +1,29 @@
1
1
  ---
2
- name: beads-workflow
3
- description: Issue tracking and task management using the beads system. Use when creating, updating, or managing work items. Use when you need to track bugs, features, tasks, or epics. Do NOT use for simple one-off questions or explorations.
2
+ name: hive-workflow
3
+ description: Issue tracking and task management using the hive system. Use when creating, updating, or managing work items. Use when you need to track bugs, features, tasks, or epics. Do NOT use for simple one-off questions or explorations.
4
4
  tags:
5
- - beads
5
+ - hive
6
6
  - issues
7
7
  - tracking
8
8
  - workflow
9
9
  tools:
10
- - beads_create
11
- - beads_query
12
- - beads_update
13
- - beads_close
14
- - beads_create_epic
15
- - beads_sync
10
+ - hive_create
11
+ - hive_query
12
+ - hive_update
13
+ - hive_close
14
+ - hive_create_epic
15
+ - hive_sync
16
16
  related_skills:
17
17
  - swarm-coordination
18
18
  ---
19
19
 
20
- # Beads Workflow Skill
20
+ # Hive Workflow Skill
21
21
 
22
- Beads is a local-first issue tracking system designed for AI agents. This skill provides best practices for effective bead management.
22
+ Hive is a local-first issue tracking system designed for AI agents. This skill provides best practices for effective cell management.
23
23
 
24
24
  **NOTE:** For swarm workflows, combine this skill with `swarm-coordination` from global-skills/.
25
25
 
26
- ## Bead Types
26
+ ## Cell Types
27
27
 
28
28
  | Type | When to Use |
29
29
  | --------- | --------------------------------------- |
@@ -33,9 +33,9 @@ Beads is a local-first issue tracking system designed for AI agents. This skill
33
33
  | `chore` | Maintenance, refactoring, dependencies |
34
34
  | `epic` | Large initiative with multiple subtasks |
35
35
 
36
- ## Creating Effective Beads
36
+ ## Creating Effective Cells
37
37
 
38
- ### Good Bead Titles
38
+ ### Good Cell Titles
39
39
 
40
40
  ```text
41
41
  - "Fix null pointer exception in UserService.getProfile()"
@@ -43,7 +43,7 @@ Beads is a local-first issue tracking system designed for AI agents. This skill
43
43
  - "Migrate auth tokens from localStorage to httpOnly cookies"
44
44
  ```
45
45
 
46
- ### Bad Bead Titles
46
+ ### Bad Cell Titles
47
47
 
48
48
  ```text
49
49
  - "Fix bug" (too vague)
@@ -51,7 +51,7 @@ Beads is a local-first issue tracking system designed for AI agents. This skill
51
51
  - "stuff" (meaningless)
52
52
  ```
53
53
 
54
- ### Bead Body Structure
54
+ ### Cell Body Structure
55
55
 
56
56
  ```markdown
57
57
  ## Problem
@@ -93,15 +93,15 @@ open → in_progress → closed
93
93
  ### Open → In Progress
94
94
 
95
95
  ```typescript
96
- beads_update(id: "abc123", state: "in_progress")
96
+ hive_update(id: "hv-abc123", state: "in_progress")
97
97
  ```
98
98
 
99
- Use when you start working on a bead.
99
+ Use when you start working on a cell.
100
100
 
101
101
  ### In Progress → Closed
102
102
 
103
103
  ```typescript
104
- beads_close(id: "abc123", resolution: "Fixed in commit abc1234")
104
+ hive_close(id: "hv-abc123", resolution: "Fixed in commit abc1234")
105
105
  ```
106
106
 
107
107
  Use when work is complete.
@@ -109,29 +109,29 @@ Use when work is complete.
109
109
  ### In Progress → Blocked
110
110
 
111
111
  ```typescript
112
- beads_update(id: "abc123", state: "blocked", body: "Blocked by #xyz789")
112
+ hive_update(id: "hv-abc123", state: "blocked", body: "Blocked by #hv-xyz789")
113
113
  ```
114
114
 
115
115
  Use when you can't proceed due to a dependency.
116
116
 
117
- ## Querying Beads
117
+ ## Querying Cells
118
118
 
119
119
  ### Find Open Work
120
120
 
121
121
  ```typescript
122
- beads_query(state: "open", type: "bug")
122
+ hive_query(state: "open", type: "bug")
123
123
  ```
124
124
 
125
125
  ### Search by Keywords
126
126
 
127
127
  ```typescript
128
- beads_query(search: "authentication")
128
+ hive_query(search: "authentication")
129
129
  ```
130
130
 
131
131
  ### List Recent Activity
132
132
 
133
133
  ```typescript
134
- beads_query(limit: 10, sort: "updated")
134
+ hive_query(limit: 10, sort: "updated")
135
135
  ```
136
136
 
137
137
  ## Epic Management
@@ -150,10 +150,10 @@ Modernize the authentication system
150
150
 
151
151
  ## Subtasks
152
152
 
153
- - [ ] #bead-001: Implement OAuth2 provider
154
- - [ ] #bead-002: Add MFA support
155
- - [ ] #bead-003: Migrate session storage
156
- - [ ] #bead-004: Update login UI
153
+ - [ ] #hv-001: Implement OAuth2 provider
154
+ - [ ] #hv-002: Add MFA support
155
+ - [ ] #hv-003: Migrate session storage
156
+ - [ ] #hv-004: Update login UI
157
157
  ```
158
158
 
159
159
  ### Creating an Epic with Subtasks
@@ -161,32 +161,32 @@ Modernize the authentication system
161
161
  1. Create the epic first:
162
162
 
163
163
  ```typescript
164
- beads_create(type: "epic", title: "User Auth Overhaul", body: "...")
164
+ hive_create(type: "epic", title: "User Auth Overhaul", body: "...")
165
165
  ```
166
166
 
167
167
  2. Create subtasks linked to the epic:
168
168
 
169
169
  ```typescript
170
- beads_create(type: "task", title: "Implement OAuth2", parent: "epic-id")
170
+ hive_create(type: "task", title: "Implement OAuth2", parent: "epic-id")
171
171
  ```
172
172
 
173
173
  ## Best Practices
174
174
 
175
175
  ```text
176
- 1. **One bead per logical unit of work** - Don't combine unrelated fixes
177
- 2. **Update state promptly** - Keep beads reflecting reality
176
+ 1. **One cell per logical unit of work** - Don't combine unrelated fixes
177
+ 2. **Update state promptly** - Keep cells reflecting reality
178
178
  3. **Add context in body** - Future you will thank present you
179
- 4. **Link related beads** - Use `#bead-id` references
179
+ 4. **Link related cells** - Use `#hv-id` references
180
180
  5. **Close with resolution** - Explain how it was resolved
181
181
  6. **Use labels** - `priority:high`, `area:frontend`, etc.
182
182
  ```
183
183
 
184
184
  ## Sync and Collaboration
185
185
 
186
- Beads sync with git:
186
+ Cells sync with git:
187
187
 
188
188
  - Changes tracked locally
189
- - Use `beads_sync()` to commit and push to remote
189
+ - Use `hive_sync()` to commit and push to remote
190
190
 
191
191
  ## Integration with Swarm
192
192
 
@@ -194,15 +194,15 @@ When working in a swarm:
194
194
 
195
195
  ```text
196
196
  1. Load `swarm-coordination` skill with `skills_use(name="swarm-coordination")`
197
- 2. Create epic with `beads_create_epic()` (atomic operation)
198
- 3. Coordinator assigns beads to worker agents
197
+ 2. Create epic with `hive_create_epic()` (atomic operation)
198
+ 3. Coordinator assigns cells to worker agents
199
199
  4. Workers load relevant skills based on subtask type
200
- 5. Close beads as subtasks complete
200
+ 5. Close cells as subtasks complete
201
201
  6. Close epic when all subtasks done
202
- 7. Sync with `beads_sync()` (MANDATORY at session end)
202
+ 7. Sync with `hive_sync()` (MANDATORY at session end)
203
203
  ```
204
204
 
205
- ### Skill Recommendations for Common Bead Types
205
+ ### Skill Recommendations for Common Cell Types
206
206
 
207
207
  ```text
208
208
  - `type: "bug"` → Load `testing-patterns` for regression tests
@@ -36,7 +36,7 @@ Swarm Mail is embedded (no external server needed) and provides:
36
36
 
37
37
  - File reservations to prevent conflicts
38
38
  - Message passing between agents
39
- - Thread-based coordination tied to beads
39
+ - Thread-based coordination tied to cells
40
40
 
41
41
  ## When to Use Swarm Coordination
42
42
 
@@ -13,8 +13,8 @@ tools:
13
13
  - swarm_complete
14
14
  - swarm_status
15
15
  - swarm_progress
16
- - beads_create_epic
17
- - beads_query
16
+ - hive_create_epic
17
+ - hive_query
18
18
  - swarmmail_init
19
19
  - swarmmail_send
20
20
  - swarmmail_inbox
@@ -43,7 +43,7 @@ Swarm Mail is embedded (no external server needed) and provides:
43
43
 
44
44
  - File reservations to prevent conflicts
45
45
  - Message passing between agents
46
- - Thread-based coordination tied to beads
46
+ - Thread-based coordination tied to cells
47
47
 
48
48
  ## When to Swarm
49
49
 
@@ -262,7 +262,7 @@ I'd recommend (${recommendation.letter}) because ${recommendation.reason}. Which
262
262
  **Confirm Only (`--confirm-only`):**
263
263
 
264
264
  - Generate plan silently
265
- - Show final BeadTree
265
+ - Show final CellTree
266
266
  - Get yes/no only
267
267
 
268
268
  **Rules for Socratic Mode:**
@@ -308,7 +308,7 @@ Synthesize findings into `shared_context` for workers.
308
308
  >
309
309
  > **NEVER do planning inline in the coordinator thread.** Decomposition work (file reading, CASS searching, reasoning about task breakdown) consumes massive amounts of context and will exhaust your token budget on long swarms.
310
310
  >
311
- > **ALWAYS delegate planning to a `swarm/planner` subagent** and receive only the structured BeadTree JSON result back.
311
+ > **ALWAYS delegate planning to a `swarm/planner` subagent** and receive only the structured CellTree JSON result back.
312
312
 
313
313
  **❌ Anti-Pattern (Context-Heavy):**
314
314
 
@@ -324,7 +324,7 @@ const validation = await swarm_validate_decomposition({ ... });
324
324
 
325
325
  ```typescript
326
326
  // 1. Create planning bead with full context
327
- await beads_create({
327
+ await hive_create({
328
328
  title: `Plan: ${taskTitle}`,
329
329
  type: "task",
330
330
  description: `Decompose into subtasks. Context: ${synthesizedContext}`,
@@ -335,7 +335,7 @@ const planningResult = await Task({
335
335
  subagent_type: "swarm/planner",
336
336
  description: `Decompose task: ${taskTitle}`,
337
337
  prompt: `
338
- You are a swarm planner. Generate a BeadTree for this task.
338
+ You are a swarm planner. Generate a CellTree for this task.
339
339
 
340
340
  ## Task
341
341
  ${taskDescription}
@@ -346,11 +346,11 @@ ${synthesizedContext}
346
346
  ## Instructions
347
347
  1. Use swarm_plan_prompt(task="...", max_subtasks=5, query_cass=true)
348
348
  2. Reason about decomposition strategy
349
- 3. Generate BeadTree JSON
349
+ 3. Generate CellTree JSON
350
350
  4. Validate with swarm_validate_decomposition
351
- 5. Return ONLY the validated BeadTree JSON (no analysis, no file contents)
351
+ 5. Return ONLY the validated CellTree JSON (no analysis, no file contents)
352
352
 
353
- Output format: Valid BeadTree JSON only.
353
+ Output format: Valid CellTree JSON only.
354
354
  `,
355
355
  });
356
356
 
@@ -358,7 +358,7 @@ Output format: Valid BeadTree JSON only.
358
358
  const beadTree = JSON.parse(planningResult);
359
359
 
360
360
  // 4. Create epic + subtasks atomically
361
- await beads_create_epic({
361
+ await hive_create_epic({
362
362
  epic_title: beadTree.epic.title,
363
363
  epic_description: beadTree.epic.description,
364
364
  subtasks: beadTree.subtasks,
@@ -474,7 +474,7 @@ await swarm_complete({
474
474
  files_touched: [...],
475
475
  });
476
476
  await swarmmail_release(); // Release any remaining reservations
477
- await beads_sync();
477
+ await hive_sync();
478
478
  ```
479
479
 
480
480
  ## Context Survival Patterns (CRITICAL)
@@ -793,7 +793,7 @@ skills_list();
793
793
  // 3. Decompose
794
794
  swarm_plan_prompt({ task });
795
795
  swarm_validate_decomposition();
796
- beads_create_epic();
796
+ hive_create_epic();
797
797
 
798
798
  // 4. Reserve files
799
799
  swarmmail_reserve({ paths, reason, ttl_seconds });
@@ -809,7 +809,7 @@ swarmmail_read_message({ message_id });
809
809
  // 7. Complete
810
810
  swarm_complete();
811
811
  swarmmail_release();
812
- beads_sync();
812
+ hive_sync();
813
813
  ```
814
814
 
815
815
  See `references/coordinator-patterns.md` for detailed patterns.
@@ -35,7 +35,7 @@ After knowledge gathering:
35
35
  1. Select strategy (auto or explicit)
36
36
  2. Generate decomposition with `swarm_plan_prompt` or `swarm_decompose`
37
37
  3. Validate with `swarm_validate_decomposition`
38
- 4. Create beads with `beads_create_epic`
38
+ 4. Create cells with `hive_create_epic`
39
39
 
40
40
  ### 3. Worker Spawning
41
41
 
@@ -48,7 +48,7 @@ For each subtask:
48
48
 
49
49
  ### 4. Progress Monitoring
50
50
 
51
- - Check `beads_query(status="in_progress")` for active work
51
+ - Check `hive_query(status="in_progress")` for active work
52
52
  - Check `swarmmail_inbox()` for worker messages
53
53
  - Intervene on blockers (see Intervention Patterns below)
54
54
 
@@ -97,7 +97,7 @@ For each subtask:
97
97
  - Scope changed fundamentally mid-swarm
98
98
  - Resource exhaustion (context, time, cost)
99
99
 
100
- On abort: Close all beads with reason, summarize partial progress.
100
+ On abort: Close all cells with reason, summarize partial progress.
101
101
 
102
102
  ---
103
103
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm-plugin",
3
- "version": "0.26.1",
3
+ "version": "0.27.2",
4
4
  "description": "Multi-agent swarm coordination for OpenCode with learning capabilities, beads integration, and Agent Mail",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -33,7 +33,7 @@
33
33
  "@opencode-ai/plugin": "^1.0.134",
34
34
  "gray-matter": "^4.0.3",
35
35
  "ioredis": "^5.4.1",
36
- "swarm-mail": "0.2.1",
36
+ "swarm-mail": "0.3.2",
37
37
  "zod": "4.1.8"
38
38
  },
39
39
  "devDependencies": {
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Swarm-Aware Compaction Hook
3
+ *
4
+ * Provides context preservation during OpenCode session compaction.
5
+ * When context is compacted, this hook injects instructions for the summarizer
6
+ * to preserve swarm coordination state and enable seamless resumption.
7
+ *
8
+ * Hook signature (from @opencode-ai/plugin):
9
+ * ```typescript
10
+ * "experimental.session.compacting"?: (
11
+ * input: { sessionID: string },
12
+ * output: { context: string[] }
13
+ * ) => Promise<void>
14
+ * ```
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * import { SWARM_COMPACTION_CONTEXT, createCompactionHook } from "opencode-swarm-plugin";
19
+ *
20
+ * const hooks: Hooks = {
21
+ * "experimental.session.compacting": createCompactionHook(),
22
+ * };
23
+ * ```
24
+ */
25
+
26
+ // ============================================================================
27
+ // Compaction Context
28
+ // ============================================================================
29
+
30
+ /**
31
+ * Swarm-aware compaction context
32
+ *
33
+ * Injected during compaction to keep the swarm cooking. The coordinator should
34
+ * wake up from compaction and immediately resume orchestration - spawning agents,
35
+ * monitoring progress, unblocking work.
36
+ *
37
+ * This is NOT about preserving state for a human - it's about the swarm continuing
38
+ * autonomously after context compression.
39
+ */
40
+ export const SWARM_COMPACTION_CONTEXT = `## 🐝 SWARM ACTIVE - Keep Cooking
41
+
42
+ You are the **COORDINATOR** of an active swarm. Context was compacted but the swarm is still running.
43
+
44
+ **YOUR JOB:** Keep orchestrating. Spawn agents. Monitor progress. Unblock work. Ship it.
45
+
46
+ ### Preserve in Summary
47
+
48
+ Extract from session context:
49
+
50
+ 1. **Epic & Subtasks** - IDs, titles, status, file assignments
51
+ 2. **What's Running** - Which agents are active, what they're working on
52
+ 3. **What's Blocked** - Blockers and what's needed to unblock
53
+ 4. **What's Done** - Completed work and any follow-ups needed
54
+ 5. **What's Next** - Pending subtasks ready to spawn
55
+
56
+ ### Summary Format
57
+
58
+ \`\`\`
59
+ ## 🐝 Swarm State
60
+
61
+ **Epic:** <bd-xxx> - <title>
62
+ **Project:** <path>
63
+ **Progress:** X/Y subtasks complete
64
+
65
+ **Active:**
66
+ - <bd-xxx>: <title> [in_progress] → <agent> working on <files>
67
+
68
+ **Blocked:**
69
+ - <bd-xxx>: <title> - BLOCKED: <reason>
70
+
71
+ **Completed:**
72
+ - <bd-xxx>: <title> ✓
73
+
74
+ **Ready to Spawn:**
75
+ - <bd-xxx>: <title> (files: <...>)
76
+ \`\`\`
77
+
78
+ ### On Resume - IMMEDIATELY
79
+
80
+ 1. \`swarm_status(epic_id="<epic>", project_key="<path>")\` - Get current state
81
+ 2. \`swarmmail_inbox(limit=5)\` - Check for agent messages
82
+ 3. **Spawn ready subtasks** - Don't wait, fire them off
83
+ 4. **Unblock blocked work** - Resolve dependencies, reassign if needed
84
+ 5. **Collect completed work** - Close done subtasks, verify quality
85
+
86
+ ### Keep the Swarm Cooking
87
+
88
+ - **Spawn aggressively** - If a subtask is ready and unblocked, spawn an agent
89
+ - **Monitor actively** - Check status, read messages, respond to blockers
90
+ - **Close the loop** - When all subtasks done, verify and close the epic
91
+ - **Don't stop** - The swarm runs until the epic is closed
92
+
93
+ **You are not waiting for instructions. You are the coordinator. Coordinate.**
94
+ `;
95
+
96
+ // ============================================================================
97
+ // Hook Registration Helper
98
+ // ============================================================================
99
+
100
+ /**
101
+ * Check for swarm sign - evidence a swarm passed through
102
+ *
103
+ * Like deer scat on a trail, we look for traces:
104
+ * - In-progress cells (active work)
105
+ * - Open cells with parent_id (subtasks of an epic)
106
+ * - Unclosed epics
107
+ *
108
+ * Uses the adapter directly to query beads.
109
+ */
110
+ import { getHiveAdapter, getHiveWorkingDirectory } from "./hive";
111
+
112
+ async function hasSwarmSign(): Promise<boolean> {
113
+ try {
114
+ const projectKey = getHiveWorkingDirectory();
115
+ const adapter = await getHiveAdapter(projectKey);
116
+ const cells = await adapter.queryCells(projectKey, {});
117
+
118
+ if (!Array.isArray(cells)) return false;
119
+
120
+ // Look for swarm sign:
121
+ // 1. Any in_progress cells
122
+ // 2. Any open cells with a parent (subtasks)
123
+ // 3. Any epics that aren't closed
124
+ return cells.some(
125
+ (c) =>
126
+ c.status === "in_progress" ||
127
+ (c.status === "open" && c.parent_id) ||
128
+ (c.type === "epic" && c.status !== "closed"),
129
+ );
130
+ } catch {
131
+ return false;
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Create the compaction hook for use in plugin registration
137
+ *
138
+ * Only injects swarm context if there's an active swarm (in-progress beads).
139
+ * This keeps the coordinator cooking after compaction.
140
+ *
141
+ * @example
142
+ * ```typescript
143
+ * import { createCompactionHook } from "opencode-swarm-plugin";
144
+ *
145
+ * export const SwarmPlugin: Plugin = async () => ({
146
+ * tool: { ... },
147
+ * "experimental.session.compacting": createCompactionHook(),
148
+ * });
149
+ * ```
150
+ */
151
+ export function createCompactionHook() {
152
+ return async (
153
+ _input: { sessionID: string },
154
+ output: { context: string[] },
155
+ ): Promise<void> => {
156
+ const hasSign = await hasSwarmSign();
157
+ if (hasSign) {
158
+ output.context.push(SWARM_COMPACTION_CONTEXT);
159
+ }
160
+ };
161
+ }