opencode-swarm-plugin 0.44.0 → 0.44.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 (215) hide show
  1. package/bin/swarm.serve.test.ts +6 -4
  2. package/bin/swarm.ts +18 -12
  3. package/dist/compaction-prompt-scoring.js +139 -0
  4. package/dist/eval-capture.js +12811 -0
  5. package/dist/hive.d.ts.map +1 -1
  6. package/dist/hive.js +14834 -0
  7. package/dist/index.d.ts +18 -0
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +7743 -62593
  10. package/dist/plugin.js +24052 -78907
  11. package/dist/swarm-orchestrate.d.ts.map +1 -1
  12. package/dist/swarm-prompts.d.ts.map +1 -1
  13. package/dist/swarm-prompts.js +39407 -0
  14. package/dist/swarm-review.d.ts.map +1 -1
  15. package/dist/swarm-validation.d.ts +127 -0
  16. package/dist/swarm-validation.d.ts.map +1 -0
  17. package/dist/validators/index.d.ts +7 -0
  18. package/dist/validators/index.d.ts.map +1 -0
  19. package/dist/validators/schema-validator.d.ts +58 -0
  20. package/dist/validators/schema-validator.d.ts.map +1 -0
  21. package/package.json +17 -5
  22. package/.changeset/swarm-insights-data-layer.md +0 -63
  23. package/.hive/analysis/eval-failure-analysis-2025-12-25.md +0 -331
  24. package/.hive/analysis/session-data-quality-audit.md +0 -320
  25. package/.hive/eval-results.json +0 -483
  26. package/.hive/issues.jsonl +0 -138
  27. package/.hive/memories.jsonl +0 -729
  28. package/.opencode/eval-history.jsonl +0 -327
  29. package/.turbo/turbo-build.log +0 -9
  30. package/CHANGELOG.md +0 -2286
  31. package/SCORER-ANALYSIS.md +0 -598
  32. package/docs/analysis/subagent-coordination-patterns.md +0 -902
  33. package/docs/analysis-socratic-planner-pattern.md +0 -504
  34. package/docs/planning/ADR-001-monorepo-structure.md +0 -171
  35. package/docs/planning/ADR-002-package-extraction.md +0 -393
  36. package/docs/planning/ADR-003-performance-improvements.md +0 -451
  37. package/docs/planning/ADR-004-message-queue-features.md +0 -187
  38. package/docs/planning/ADR-005-devtools-observability.md +0 -202
  39. package/docs/planning/ADR-007-swarm-enhancements-worktree-review.md +0 -168
  40. package/docs/planning/ADR-008-worker-handoff-protocol.md +0 -293
  41. package/docs/planning/ADR-009-oh-my-opencode-patterns.md +0 -353
  42. package/docs/planning/ADR-010-cass-inhousing.md +0 -1215
  43. package/docs/planning/ROADMAP.md +0 -368
  44. package/docs/semantic-memory-cli-syntax.md +0 -123
  45. package/docs/swarm-mail-architecture.md +0 -1147
  46. package/docs/testing/context-recovery-test.md +0 -470
  47. package/evals/ARCHITECTURE.md +0 -1189
  48. package/evals/README.md +0 -768
  49. package/evals/compaction-prompt.eval.ts +0 -149
  50. package/evals/compaction-resumption.eval.ts +0 -289
  51. package/evals/coordinator-behavior.eval.ts +0 -307
  52. package/evals/coordinator-session.eval.ts +0 -154
  53. package/evals/evalite.config.ts.bak +0 -15
  54. package/evals/example.eval.ts +0 -31
  55. package/evals/fixtures/cass-baseline.ts +0 -217
  56. package/evals/fixtures/compaction-cases.ts +0 -350
  57. package/evals/fixtures/compaction-prompt-cases.ts +0 -311
  58. package/evals/fixtures/coordinator-sessions.ts +0 -328
  59. package/evals/fixtures/decomposition-cases.ts +0 -105
  60. package/evals/lib/compaction-loader.test.ts +0 -248
  61. package/evals/lib/compaction-loader.ts +0 -320
  62. package/evals/lib/data-loader.evalite-test.ts +0 -289
  63. package/evals/lib/data-loader.test.ts +0 -345
  64. package/evals/lib/data-loader.ts +0 -281
  65. package/evals/lib/llm.ts +0 -115
  66. package/evals/scorers/compaction-prompt-scorers.ts +0 -145
  67. package/evals/scorers/compaction-scorers.ts +0 -305
  68. package/evals/scorers/coordinator-discipline.evalite-test.ts +0 -539
  69. package/evals/scorers/coordinator-discipline.ts +0 -325
  70. package/evals/scorers/index.test.ts +0 -146
  71. package/evals/scorers/index.ts +0 -328
  72. package/evals/scorers/outcome-scorers.evalite-test.ts +0 -27
  73. package/evals/scorers/outcome-scorers.ts +0 -349
  74. package/evals/swarm-decomposition.eval.ts +0 -121
  75. package/examples/commands/swarm.md +0 -745
  76. package/examples/plugin-wrapper-template.ts +0 -2515
  77. package/examples/skills/hive-workflow/SKILL.md +0 -212
  78. package/examples/skills/skill-creator/SKILL.md +0 -223
  79. package/examples/skills/swarm-coordination/SKILL.md +0 -292
  80. package/global-skills/cli-builder/SKILL.md +0 -344
  81. package/global-skills/cli-builder/references/advanced-patterns.md +0 -244
  82. package/global-skills/learning-systems/SKILL.md +0 -644
  83. package/global-skills/skill-creator/LICENSE.txt +0 -202
  84. package/global-skills/skill-creator/SKILL.md +0 -352
  85. package/global-skills/skill-creator/references/output-patterns.md +0 -82
  86. package/global-skills/skill-creator/references/workflows.md +0 -28
  87. package/global-skills/swarm-coordination/SKILL.md +0 -995
  88. package/global-skills/swarm-coordination/references/coordinator-patterns.md +0 -235
  89. package/global-skills/swarm-coordination/references/strategies.md +0 -138
  90. package/global-skills/system-design/SKILL.md +0 -213
  91. package/global-skills/testing-patterns/SKILL.md +0 -430
  92. package/global-skills/testing-patterns/references/dependency-breaking-catalog.md +0 -586
  93. package/opencode-swarm-plugin-0.30.7.tgz +0 -0
  94. package/opencode-swarm-plugin-0.31.0.tgz +0 -0
  95. package/scripts/cleanup-test-memories.ts +0 -346
  96. package/scripts/init-skill.ts +0 -222
  97. package/scripts/migrate-unknown-sessions.ts +0 -349
  98. package/scripts/validate-skill.ts +0 -204
  99. package/src/agent-mail.ts +0 -1724
  100. package/src/anti-patterns.test.ts +0 -1167
  101. package/src/anti-patterns.ts +0 -448
  102. package/src/compaction-capture.integration.test.ts +0 -257
  103. package/src/compaction-hook.test.ts +0 -838
  104. package/src/compaction-hook.ts +0 -1204
  105. package/src/compaction-observability.integration.test.ts +0 -139
  106. package/src/compaction-observability.test.ts +0 -187
  107. package/src/compaction-observability.ts +0 -324
  108. package/src/compaction-prompt-scorers.test.ts +0 -475
  109. package/src/compaction-prompt-scoring.ts +0 -300
  110. package/src/contributor-tools.test.ts +0 -133
  111. package/src/contributor-tools.ts +0 -201
  112. package/src/dashboard.test.ts +0 -611
  113. package/src/dashboard.ts +0 -462
  114. package/src/error-enrichment.test.ts +0 -403
  115. package/src/error-enrichment.ts +0 -219
  116. package/src/eval-capture.test.ts +0 -1015
  117. package/src/eval-capture.ts +0 -929
  118. package/src/eval-gates.test.ts +0 -306
  119. package/src/eval-gates.ts +0 -218
  120. package/src/eval-history.test.ts +0 -508
  121. package/src/eval-history.ts +0 -214
  122. package/src/eval-learning.test.ts +0 -378
  123. package/src/eval-learning.ts +0 -360
  124. package/src/eval-runner.test.ts +0 -223
  125. package/src/eval-runner.ts +0 -402
  126. package/src/export-tools.test.ts +0 -476
  127. package/src/export-tools.ts +0 -257
  128. package/src/hive.integration.test.ts +0 -2241
  129. package/src/hive.ts +0 -1628
  130. package/src/index.ts +0 -940
  131. package/src/learning.integration.test.ts +0 -1815
  132. package/src/learning.ts +0 -1079
  133. package/src/logger.test.ts +0 -189
  134. package/src/logger.ts +0 -135
  135. package/src/mandate-promotion.test.ts +0 -473
  136. package/src/mandate-promotion.ts +0 -239
  137. package/src/mandate-storage.integration.test.ts +0 -601
  138. package/src/mandate-storage.test.ts +0 -578
  139. package/src/mandate-storage.ts +0 -794
  140. package/src/mandates.ts +0 -540
  141. package/src/memory-tools.test.ts +0 -195
  142. package/src/memory-tools.ts +0 -344
  143. package/src/memory.integration.test.ts +0 -334
  144. package/src/memory.test.ts +0 -158
  145. package/src/memory.ts +0 -527
  146. package/src/model-selection.test.ts +0 -188
  147. package/src/model-selection.ts +0 -68
  148. package/src/observability-tools.test.ts +0 -359
  149. package/src/observability-tools.ts +0 -871
  150. package/src/output-guardrails.test.ts +0 -438
  151. package/src/output-guardrails.ts +0 -381
  152. package/src/pattern-maturity.test.ts +0 -1160
  153. package/src/pattern-maturity.ts +0 -525
  154. package/src/planning-guardrails.test.ts +0 -491
  155. package/src/planning-guardrails.ts +0 -438
  156. package/src/plugin.ts +0 -23
  157. package/src/post-compaction-tracker.test.ts +0 -251
  158. package/src/post-compaction-tracker.ts +0 -237
  159. package/src/query-tools.test.ts +0 -636
  160. package/src/query-tools.ts +0 -324
  161. package/src/rate-limiter.integration.test.ts +0 -466
  162. package/src/rate-limiter.ts +0 -774
  163. package/src/replay-tools.test.ts +0 -496
  164. package/src/replay-tools.ts +0 -240
  165. package/src/repo-crawl.integration.test.ts +0 -441
  166. package/src/repo-crawl.ts +0 -610
  167. package/src/schemas/cell-events.test.ts +0 -347
  168. package/src/schemas/cell-events.ts +0 -807
  169. package/src/schemas/cell.ts +0 -257
  170. package/src/schemas/evaluation.ts +0 -166
  171. package/src/schemas/index.test.ts +0 -199
  172. package/src/schemas/index.ts +0 -286
  173. package/src/schemas/mandate.ts +0 -232
  174. package/src/schemas/swarm-context.ts +0 -115
  175. package/src/schemas/task.ts +0 -161
  176. package/src/schemas/worker-handoff.test.ts +0 -302
  177. package/src/schemas/worker-handoff.ts +0 -131
  178. package/src/sessions/agent-discovery.test.ts +0 -137
  179. package/src/sessions/agent-discovery.ts +0 -112
  180. package/src/sessions/index.ts +0 -15
  181. package/src/skills.integration.test.ts +0 -1192
  182. package/src/skills.test.ts +0 -643
  183. package/src/skills.ts +0 -1549
  184. package/src/storage.integration.test.ts +0 -341
  185. package/src/storage.ts +0 -884
  186. package/src/structured.integration.test.ts +0 -817
  187. package/src/structured.test.ts +0 -1046
  188. package/src/structured.ts +0 -762
  189. package/src/swarm-decompose.test.ts +0 -188
  190. package/src/swarm-decompose.ts +0 -1302
  191. package/src/swarm-deferred.integration.test.ts +0 -157
  192. package/src/swarm-deferred.test.ts +0 -38
  193. package/src/swarm-insights.test.ts +0 -214
  194. package/src/swarm-insights.ts +0 -459
  195. package/src/swarm-mail.integration.test.ts +0 -970
  196. package/src/swarm-mail.ts +0 -739
  197. package/src/swarm-orchestrate.integration.test.ts +0 -282
  198. package/src/swarm-orchestrate.test.ts +0 -548
  199. package/src/swarm-orchestrate.ts +0 -3084
  200. package/src/swarm-prompts.test.ts +0 -1270
  201. package/src/swarm-prompts.ts +0 -2077
  202. package/src/swarm-research.integration.test.ts +0 -701
  203. package/src/swarm-research.test.ts +0 -698
  204. package/src/swarm-research.ts +0 -472
  205. package/src/swarm-review.integration.test.ts +0 -285
  206. package/src/swarm-review.test.ts +0 -879
  207. package/src/swarm-review.ts +0 -709
  208. package/src/swarm-strategies.ts +0 -407
  209. package/src/swarm-worktree.test.ts +0 -501
  210. package/src/swarm-worktree.ts +0 -575
  211. package/src/swarm.integration.test.ts +0 -2377
  212. package/src/swarm.ts +0 -38
  213. package/src/tool-adapter.integration.test.ts +0 -1221
  214. package/src/tool-availability.ts +0 -461
  215. package/tsconfig.json +0 -28
@@ -1,1302 +0,0 @@
1
- /**
2
- * Swarm Decompose Module - Task decomposition and validation
3
- *
4
- * Handles breaking tasks into parallelizable subtasks with file assignments,
5
- * validates decomposition structure, and detects conflicts.
6
- *
7
- * Key responsibilities:
8
- * - Decomposition prompt generation
9
- * - CellTree validation
10
- * - File conflict detection
11
- * - Instruction conflict detection
12
- * - Delegation to planner subagents
13
- */
14
-
15
- import { tool } from "@opencode-ai/plugin";
16
- import { z } from "zod";
17
- import { CellTreeSchema } from "./schemas";
18
- import {
19
- POSITIVE_MARKERS,
20
- NEGATIVE_MARKERS,
21
- type DecompositionStrategy,
22
- } from "./swarm-strategies";
23
- import { captureCoordinatorEvent } from "./eval-capture.js";
24
-
25
- // ============================================================================
26
- // Decomposition Prompt (temporary - will be moved to swarm-prompts.ts)
27
- // ============================================================================
28
-
29
- /**
30
- * Prompt for decomposing a task into parallelizable subtasks.
31
- *
32
- * Used by swarm_decompose to instruct the agent on how to break down work.
33
- * The agent responds with a CellTree that gets validated.
34
- */
35
- const DECOMPOSITION_PROMPT = `You are decomposing a task into parallelizable subtasks for a swarm of agents.
36
-
37
- ## Task
38
- {task}
39
-
40
- {context_section}
41
-
42
- ## MANDATORY: Beads Issue Tracking
43
-
44
- **Every subtask MUST become a bead.** This is non-negotiable.
45
-
46
- After decomposition, the coordinator will:
47
- 1. Create an epic bead for the overall task
48
- 2. Create child cells for each subtask
49
- 3. Track progress through bead status updates
50
- 4. Close cells with summaries when complete
51
-
52
- Agents MUST update their bead status as they work. No silent progress.
53
-
54
- ## Requirements
55
-
56
- 1. **Break into independent subtasks** that can run in parallel (as many as needed)
57
- 2. **Assign files** - each subtask must specify which files it will modify
58
- 3. **No file overlap** - files cannot appear in multiple subtasks (they get exclusive locks)
59
- 4. **Order by dependency** - if subtask B needs subtask A's output, A must come first in the array
60
- 5. **Estimate complexity** - 1 (trivial) to 5 (complex)
61
- 6. **Plan aggressively** - break down more than you think necessary, smaller is better
62
-
63
- ## Response Format
64
-
65
- Respond with a JSON object matching this schema:
66
-
67
- \`\`\`typescript
68
- {
69
- epic: {
70
- title: string, // Epic title for the hive tracker
71
- description?: string // Brief description of the overall goal
72
- },
73
- subtasks: [
74
- {
75
- title: string, // What this subtask accomplishes
76
- description?: string, // Detailed instructions for the agent
77
- files: string[], // Files this subtask will modify (globs allowed)
78
- dependencies: number[], // Indices of subtasks this depends on (0-indexed)
79
- estimated_complexity: 1-5 // Effort estimate
80
- },
81
- // ... more subtasks
82
- ]
83
- }
84
- \`\`\`
85
-
86
- ## Guidelines
87
-
88
- - **Plan aggressively** - when in doubt, split further. 3 small tasks > 1 medium task
89
- - **Prefer smaller, focused subtasks** over large complex ones
90
- - **Include test files** in the same subtask as the code they test
91
- - **Consider shared types** - if multiple files share types, handle that first
92
- - **Think about imports** - changes to exported APIs affect downstream files
93
- - **Explicit > implicit** - spell out what each subtask should do, don't assume
94
-
95
- ## File Assignment Examples
96
-
97
- - Schema change: \`["src/schemas/user.ts", "src/schemas/index.ts"]\`
98
- - Component + test: \`["src/components/Button.tsx", "src/components/Button.test.tsx"]\`
99
- - API route: \`["src/app/api/users/route.ts"]\`
100
-
101
- Now decompose the task:`;
102
-
103
- /**
104
- * Strategy-specific decomposition prompt template
105
- */
106
- const STRATEGY_DECOMPOSITION_PROMPT = `You are decomposing a task into parallelizable subtasks for a swarm of agents.
107
-
108
- ## Task
109
- {task}
110
-
111
- {strategy_guidelines}
112
-
113
- {context_section}
114
-
115
- {cass_history}
116
-
117
- {skills_context}
118
-
119
- ## MANDATORY: Beads Issue Tracking
120
-
121
- **Every subtask MUST become a bead.** This is non-negotiable.
122
-
123
- After decomposition, the coordinator will:
124
- 1. Create an epic bead for the overall task
125
- 2. Create child cells for each subtask
126
- 3. Track progress through bead status updates
127
- 4. Close cells with summaries when complete
128
-
129
- Agents MUST update their bead status as they work. No silent progress.
130
-
131
- ## Requirements
132
-
133
- 1. **Break into independent subtasks** that can run in parallel (as many as needed)
134
- 2. **Assign files** - each subtask must specify which files it will modify
135
- 3. **No file overlap** - files cannot appear in multiple subtasks (they get exclusive locks)
136
- 4. **Order by dependency** - if subtask B needs subtask A's output, A must come first in the array
137
- 5. **Estimate complexity** - 1 (trivial) to 5 (complex)
138
- 6. **Plan aggressively** - break down more than you think necessary, smaller is better
139
-
140
- ## Response Format
141
-
142
- Respond with a JSON object matching this schema:
143
-
144
- \`\`\`typescript
145
- {
146
- epic: {
147
- title: string, // Epic title for the hive tracker
148
- description?: string // Brief description of the overall goal
149
- },
150
- subtasks: [
151
- {
152
- title: string, // What this subtask accomplishes
153
- description?: string, // Detailed instructions for the agent
154
- files: string[], // Files this subtask will modify (globs allowed)
155
- dependencies: number[], // Indices of subtasks this depends on (0-indexed)
156
- estimated_complexity: 1-5 // Effort estimate
157
- },
158
- // ... more subtasks
159
- ]
160
- }
161
- \`\`\`
162
-
163
- Now decompose the task:`;
164
-
165
- // ============================================================================
166
- // Conflict Detection
167
- // ============================================================================
168
-
169
- /**
170
- * A detected conflict between subtask instructions
171
- */
172
- export interface InstructionConflict {
173
- subtask_a: number;
174
- subtask_b: number;
175
- directive_a: string;
176
- directive_b: string;
177
- conflict_type: "positive_negative" | "contradictory";
178
- description: string;
179
- }
180
-
181
- /**
182
- * Extract directives from text based on marker words
183
- */
184
- function extractDirectives(text: string): {
185
- positive: string[];
186
- negative: string[];
187
- } {
188
- const sentences = text.split(/[.!?\n]+/).map((s) => s.trim().toLowerCase());
189
- const positive: string[] = [];
190
- const negative: string[] = [];
191
-
192
- for (const sentence of sentences) {
193
- if (!sentence) continue;
194
-
195
- const hasPositive = POSITIVE_MARKERS.some((m) => sentence.includes(m));
196
- const hasNegative = NEGATIVE_MARKERS.some((m) => sentence.includes(m));
197
-
198
- if (hasPositive && !hasNegative) {
199
- positive.push(sentence);
200
- } else if (hasNegative) {
201
- negative.push(sentence);
202
- }
203
- }
204
-
205
- return { positive, negative };
206
- }
207
-
208
- /**
209
- * Check if two directives conflict
210
- *
211
- * Simple heuristic: look for common subjects with opposite polarity
212
- */
213
- function directivesConflict(positive: string, negative: string): boolean {
214
- // Extract key nouns/concepts (simple word overlap check)
215
- const positiveWords = new Set(
216
- positive.split(/\s+/).filter((w) => w.length > 3),
217
- );
218
- const negativeWords = negative.split(/\s+/).filter((w) => w.length > 3);
219
-
220
- // If they share significant words, they might conflict
221
- const overlap = negativeWords.filter((w) => positiveWords.has(w));
222
- return overlap.length >= 2;
223
- }
224
-
225
- /**
226
- * Detect conflicts between subtask instructions
227
- *
228
- * Looks for cases where one subtask says "always use X" and another says "avoid X".
229
- *
230
- * @param subtasks - Array of subtask descriptions
231
- * @returns Array of detected conflicts
232
- *
233
- * @see https://github.com/Dicklesworthstone/cass_memory_system/blob/main/src/curate.ts#L36-L89
234
- */
235
- export function detectInstructionConflicts(
236
- subtasks: Array<{ title: string; description?: string }>,
237
- ): InstructionConflict[] {
238
- const conflicts: InstructionConflict[] = [];
239
-
240
- // Extract directives from each subtask
241
- const subtaskDirectives = subtasks.map((s, i) => ({
242
- index: i,
243
- title: s.title,
244
- ...extractDirectives(`${s.title} ${s.description || ""}`),
245
- }));
246
-
247
- // Compare each pair of subtasks
248
- for (let i = 0; i < subtaskDirectives.length; i++) {
249
- for (let j = i + 1; j < subtaskDirectives.length; j++) {
250
- const a = subtaskDirectives[i];
251
- const b = subtaskDirectives[j];
252
-
253
- // Check if A's positive conflicts with B's negative
254
- for (const posA of a.positive) {
255
- for (const negB of b.negative) {
256
- if (directivesConflict(posA, negB)) {
257
- conflicts.push({
258
- subtask_a: i,
259
- subtask_b: j,
260
- directive_a: posA,
261
- directive_b: negB,
262
- conflict_type: "positive_negative",
263
- description: `Subtask ${i} says "${posA}" but subtask ${j} says "${negB}"`,
264
- });
265
- }
266
- }
267
- }
268
-
269
- // Check if B's positive conflicts with A's negative
270
- for (const posB of b.positive) {
271
- for (const negA of a.negative) {
272
- if (directivesConflict(posB, negA)) {
273
- conflicts.push({
274
- subtask_a: j,
275
- subtask_b: i,
276
- directive_a: posB,
277
- directive_b: negA,
278
- conflict_type: "positive_negative",
279
- description: `Subtask ${j} says "${posB}" but subtask ${i} says "${negA}"`,
280
- });
281
- }
282
- }
283
- }
284
- }
285
- }
286
-
287
- return conflicts;
288
- }
289
-
290
- /**
291
- * Detect file conflicts in a bead tree
292
- *
293
- * @param subtasks - Array of subtasks with file assignments
294
- * @returns Array of files that appear in multiple subtasks
295
- */
296
- export function detectFileConflicts(
297
- subtasks: Array<{ files: string[] }>,
298
- ): string[] {
299
- const allFiles = new Map<string, number>();
300
- const conflicts: string[] = [];
301
-
302
- for (const subtask of subtasks) {
303
- for (const file of subtask.files) {
304
- const count = allFiles.get(file) || 0;
305
- allFiles.set(file, count + 1);
306
- if (count === 1) {
307
- // Second occurrence - it's a conflict
308
- conflicts.push(file);
309
- }
310
- }
311
- }
312
-
313
- return conflicts;
314
- }
315
-
316
- // ============================================================================
317
- // CASS History Integration
318
- // ============================================================================
319
-
320
- /**
321
- * CASS search result from similar past tasks
322
- */
323
- interface CassSearchResult {
324
- query: string;
325
- results: Array<{
326
- source_path: string;
327
- line: number;
328
- agent: string;
329
- preview: string;
330
- score: number;
331
- }>;
332
- }
333
-
334
- /**
335
- * CASS query result with status
336
- */
337
- type CassQueryResult =
338
- | { status: "unavailable" }
339
- | { status: "failed"; error?: string }
340
- | { status: "empty"; query: string }
341
- | { status: "success"; data: CassSearchResult };
342
-
343
- /**
344
- * Query CASS for similar past tasks
345
- *
346
- * @param task - Task description to search for
347
- * @param limit - Maximum results to return
348
- * @returns Structured result with status indicator
349
- */
350
- async function queryCassHistory(
351
- task: string,
352
- limit: number = 3,
353
- ): Promise<CassQueryResult> {
354
- // Check if CASS is available
355
- try {
356
- const result = await Bun.$`cass search ${task} --limit ${limit} --json`
357
- .quiet()
358
- .nothrow();
359
-
360
- if (result.exitCode !== 0) {
361
- const error = result.stderr.toString();
362
- console.warn(
363
- `[swarm] CASS search failed (exit ${result.exitCode}):`,
364
- error,
365
- );
366
- return { status: "failed", error };
367
- }
368
-
369
- const output = result.stdout.toString();
370
- if (!output.trim()) {
371
- return { status: "empty", query: task };
372
- }
373
-
374
- try {
375
- const parsed = JSON.parse(output);
376
- const searchResult: CassSearchResult = {
377
- query: task,
378
- results: Array.isArray(parsed) ? parsed : parsed.results || [],
379
- };
380
-
381
- if (searchResult.results.length === 0) {
382
- return { status: "empty", query: task };
383
- }
384
-
385
- return { status: "success", data: searchResult };
386
- } catch (error) {
387
- console.warn(`[swarm] Failed to parse CASS output:`, error);
388
- return { status: "failed", error: String(error) };
389
- }
390
- } catch (error) {
391
- console.error(`[swarm] CASS query error:`, error);
392
- return { status: "unavailable" };
393
- }
394
- }
395
-
396
- /**
397
- * Format CASS history for inclusion in decomposition prompt
398
- */
399
- function formatCassHistoryForPrompt(history: CassSearchResult): string {
400
- if (history.results.length === 0) {
401
- return "";
402
- }
403
-
404
- const lines = [
405
- "## Similar Past Tasks",
406
- "",
407
- "These similar tasks were found in agent history:",
408
- "",
409
- ...history.results.slice(0, 3).map((r, i) => {
410
- const preview = r.preview.slice(0, 200).replace(/\n/g, " ");
411
- return `${i + 1}. [${r.agent}] ${preview}...`;
412
- }),
413
- "",
414
- "Consider patterns that worked in these past tasks.",
415
- "",
416
- ];
417
-
418
- return lines.join("\n");
419
- }
420
-
421
- // ============================================================================
422
- // Tool Definitions
423
- // ============================================================================
424
-
425
- /**
426
- * Decompose a task into a bead tree
427
- *
428
- * This is a PROMPT tool - it returns a prompt for the agent to respond to.
429
- * The agent's response (JSON) should be validated with CellTreeSchema.
430
- *
431
- * Optionally queries CASS for similar past tasks to inform decomposition.
432
- */
433
- export const swarm_decompose = tool({
434
- description:
435
- "Generate decomposition prompt for breaking task into parallelizable subtasks. Optionally queries CASS for similar past tasks.",
436
- args: {
437
- task: tool.schema.string().min(1).describe("Task description to decompose"),
438
- context: tool.schema
439
- .string()
440
- .optional()
441
- .describe("Additional context (codebase info, constraints, etc.)"),
442
- query_cass: tool.schema
443
- .boolean()
444
- .optional()
445
- .describe("Query CASS for similar past tasks (default: true)"),
446
- cass_limit: tool.schema
447
- .number()
448
- .int()
449
- .min(1)
450
- .optional()
451
- .describe("Max CASS results to include (default: 3)"),
452
- },
453
- async execute(args) {
454
- // Import needed modules
455
- const { formatMemoryQueryForDecomposition } = await import("./learning");
456
-
457
- // Query CASS for similar past tasks
458
- let cassContext = "";
459
- let cassResultInfo: {
460
- queried: boolean;
461
- results_found?: number;
462
- included_in_context?: boolean;
463
- reason?: string;
464
- };
465
-
466
- if (args.query_cass !== false) {
467
- const cassResult = await queryCassHistory(
468
- args.task,
469
- args.cass_limit ?? 3,
470
- );
471
- if (cassResult.status === "success") {
472
- cassContext = formatCassHistoryForPrompt(cassResult.data);
473
- cassResultInfo = {
474
- queried: true,
475
- results_found: cassResult.data.results.length,
476
- included_in_context: true,
477
- };
478
- } else {
479
- cassResultInfo = {
480
- queried: true,
481
- results_found: 0,
482
- included_in_context: false,
483
- reason: cassResult.status,
484
- };
485
- }
486
- } else {
487
- cassResultInfo = { queried: false, reason: "disabled" };
488
- }
489
-
490
- // Combine user context with CASS history
491
- const fullContext = [args.context, cassContext]
492
- .filter(Boolean)
493
- .join("\n\n");
494
-
495
- // Format the decomposition prompt
496
- const contextSection = fullContext
497
- ? `## Additional Context\n${fullContext}`
498
- : "## Additional Context\n(none provided)";
499
-
500
- const prompt = DECOMPOSITION_PROMPT.replace("{task}", args.task)
501
- .replace("{context_section}", contextSection);
502
-
503
- // Return the prompt and schema info for the caller
504
- return JSON.stringify(
505
- {
506
- prompt,
507
- expected_schema: "CellTree",
508
- schema_hint: {
509
- epic: { title: "string", description: "string?" },
510
- subtasks: [
511
- {
512
- title: "string",
513
- description: "string?",
514
- files: "string[]",
515
- dependencies: "number[]",
516
- estimated_complexity: "1-5",
517
- },
518
- ],
519
- },
520
- validation_note:
521
- "Parse agent response as JSON and validate with CellTreeSchema from schemas/bead.ts",
522
- cass_history: cassResultInfo,
523
- // Add semantic-memory query instruction
524
- memory_query: formatMemoryQueryForDecomposition(args.task, 3),
525
- },
526
- null,
527
- 2,
528
- );
529
- },
530
- });
531
-
532
- /**
533
- * Validate a decomposition response from an agent
534
- *
535
- * Use this after the agent responds to swarm:decompose to validate the structure.
536
- */
537
- export const swarm_validate_decomposition = tool({
538
- description: "Validate a decomposition response against CellTreeSchema and capture for eval",
539
- args: {
540
- response: tool.schema
541
- .string()
542
- .describe("JSON response from agent (CellTree format)"),
543
- project_path: tool.schema
544
- .string()
545
- .optional()
546
- .describe("Project path for eval capture"),
547
- task: tool.schema
548
- .string()
549
- .optional()
550
- .describe("Original task description for eval capture"),
551
- context: tool.schema
552
- .string()
553
- .optional()
554
- .describe("Context provided for decomposition"),
555
- strategy: tool.schema
556
- .enum(["file-based", "feature-based", "risk-based", "auto"])
557
- .optional()
558
- .describe("Decomposition strategy used"),
559
- epic_id: tool.schema
560
- .string()
561
- .optional()
562
- .describe("Epic ID for eval capture"),
563
- },
564
- async execute(args) {
565
- try {
566
- const parsed = JSON.parse(args.response);
567
- const validated = CellTreeSchema.parse(parsed);
568
-
569
- // Additional validation: check for file conflicts
570
- const conflicts = detectFileConflicts(validated.subtasks);
571
-
572
- if (conflicts.length > 0) {
573
- return JSON.stringify(
574
- {
575
- valid: false,
576
- error: `File conflicts detected: ${conflicts.join(", ")}`,
577
- hint: "Each file can only be assigned to one subtask",
578
- },
579
- null,
580
- 2,
581
- );
582
- }
583
-
584
- // Check dependency indices are valid
585
- for (let i = 0; i < validated.subtasks.length; i++) {
586
- const deps = validated.subtasks[i].dependencies;
587
- for (const dep of deps) {
588
- // Check bounds first
589
- if (dep < 0 || dep >= validated.subtasks.length) {
590
- return JSON.stringify(
591
- {
592
- valid: false,
593
- error: `Invalid dependency: subtask ${i} depends on ${dep}, but only ${validated.subtasks.length} subtasks exist (indices 0-${validated.subtasks.length - 1})`,
594
- hint: "Dependency index is out of bounds",
595
- },
596
- null,
597
- 2,
598
- );
599
- }
600
- // Check forward references
601
- if (dep >= i) {
602
- return JSON.stringify(
603
- {
604
- valid: false,
605
- error: `Invalid dependency: subtask ${i} depends on ${dep}, but dependencies must be earlier in the array`,
606
- hint: "Reorder subtasks so dependencies come before dependents",
607
- },
608
- null,
609
- 2,
610
- );
611
- }
612
- }
613
- }
614
-
615
- // Check for instruction conflicts between subtasks
616
- const instructionConflicts = detectInstructionConflicts(
617
- validated.subtasks,
618
- );
619
-
620
- // Capture decomposition for eval if all required params provided
621
- if (
622
- args.project_path &&
623
- args.task &&
624
- args.strategy &&
625
- args.epic_id
626
- ) {
627
- try {
628
- const { captureDecomposition } = await import("./eval-capture.js");
629
- captureDecomposition({
630
- epicId: args.epic_id,
631
- projectPath: args.project_path,
632
- task: args.task,
633
- context: args.context,
634
- strategy: args.strategy,
635
- epicTitle: validated.epic.title,
636
- epicDescription: validated.epic.description,
637
- subtasks: validated.subtasks.map((s) => ({
638
- title: s.title,
639
- description: s.description,
640
- files: s.files,
641
- dependencies: s.dependencies,
642
- estimated_complexity: s.estimated_complexity,
643
- })),
644
- });
645
- } catch (error) {
646
- // Non-fatal - don't block validation if capture fails
647
- console.warn("[swarm_validate_decomposition] Failed to capture decomposition:", error);
648
- }
649
- }
650
-
651
- return JSON.stringify(
652
- {
653
- valid: true,
654
- cell_tree: validated,
655
- stats: {
656
- subtask_count: validated.subtasks.length,
657
- total_files: new Set(validated.subtasks.flatMap((s) => s.files))
658
- .size,
659
- total_complexity: validated.subtasks.reduce(
660
- (sum, s) => sum + s.estimated_complexity,
661
- 0,
662
- ),
663
- },
664
- // Include conflicts as warnings (not blocking)
665
- warnings:
666
- instructionConflicts.length > 0
667
- ? {
668
- instruction_conflicts: instructionConflicts,
669
- hint: "Review these potential conflicts between subtask instructions",
670
- }
671
- : undefined,
672
- },
673
- null,
674
- 2,
675
- );
676
- } catch (error) {
677
- if (error instanceof z.ZodError) {
678
- return JSON.stringify(
679
- {
680
- valid: false,
681
- error: "Schema validation failed",
682
- details: error.issues,
683
- },
684
- null,
685
- 2,
686
- );
687
- }
688
- if (error instanceof SyntaxError) {
689
- return JSON.stringify(
690
- {
691
- valid: false,
692
- error: "Invalid JSON",
693
- details: error.message,
694
- },
695
- null,
696
- 2,
697
- );
698
- }
699
- throw error;
700
- }
701
- },
702
- });
703
-
704
- /**
705
- * Delegate task decomposition to a swarm/planner subagent
706
- *
707
- * Returns a prompt for spawning a planner agent that will handle all decomposition
708
- * reasoning. This keeps the coordinator context lean by offloading:
709
- * - Strategy selection
710
- * - CASS queries
711
- * - Skills discovery
712
- * - File analysis
713
- * - CellTree generation
714
- *
715
- * The planner returns ONLY structured CellTree JSON, which the coordinator
716
- * validates and uses to create cells.
717
- *
718
- * @example
719
- * ```typescript
720
- * // Coordinator workflow:
721
- * const delegateResult = await swarm_delegate_planning({
722
- * task: "Add user authentication",
723
- * context: "Next.js 14 app",
724
- * });
725
- *
726
- * // Parse the result
727
- * const { prompt, subagent_type } = JSON.parse(delegateResult);
728
- *
729
- * // Spawn subagent using Task tool
730
- * const plannerResponse = await Task(prompt, subagent_type);
731
- *
732
- * // Validate the response
733
- * await swarm_validate_decomposition({ response: plannerResponse });
734
- * ```
735
- */
736
- export const swarm_delegate_planning = tool({
737
- description:
738
- "Delegate task decomposition to a swarm/planner subagent. Returns a prompt to spawn the planner. Use this to keep coordinator context lean - all planning reasoning happens in the subagent.",
739
- args: {
740
- task: tool.schema.string().min(1).describe("The task to decompose"),
741
- context: tool.schema
742
- .string()
743
- .optional()
744
- .describe("Additional context to include"),
745
- strategy: tool.schema
746
- .enum(["auto", "file-based", "feature-based", "risk-based"])
747
- .optional()
748
- .default("auto")
749
- .describe("Decomposition strategy (default: auto-detect)"),
750
- query_cass: tool.schema
751
- .boolean()
752
- .optional()
753
- .default(true)
754
- .describe("Query CASS for similar past tasks (default: true)"),
755
- },
756
- async execute(args, _ctx) {
757
- // Import needed modules
758
- const { selectStrategy, formatStrategyGuidelines } =
759
- await import("./swarm-strategies");
760
- const { formatMemoryQueryForDecomposition } = await import("./learning");
761
- const { listSkills, getSkillsContextForSwarm, findRelevantSkills } =
762
- await import("./skills");
763
-
764
- // Select strategy
765
- let selectedStrategy: Exclude<DecompositionStrategy, "auto">;
766
- let strategyReasoning: string;
767
-
768
- if (args.strategy && args.strategy !== "auto") {
769
- selectedStrategy = args.strategy;
770
- strategyReasoning = `User-specified strategy: ${selectedStrategy}`;
771
- } else {
772
- const selection = selectStrategy(args.task);
773
- selectedStrategy = selection.strategy;
774
- strategyReasoning = selection.reasoning;
775
- }
776
-
777
- // Capture strategy selection decision
778
- try {
779
- captureCoordinatorEvent({
780
- session_id: _ctx.sessionID || "unknown",
781
- epic_id: "planning", // No epic ID yet - this is pre-decomposition
782
- timestamp: new Date().toISOString(),
783
- event_type: "DECISION",
784
- decision_type: "strategy_selected",
785
- payload: {
786
- strategy: selectedStrategy,
787
- reasoning: strategyReasoning,
788
- task_preview: args.task.slice(0, 100),
789
- },
790
- });
791
- } catch (error) {
792
- // Non-fatal - don't block planning if capture fails
793
- console.warn("[swarm_delegate_planning] Failed to capture strategy_selected:", error);
794
- }
795
-
796
- // Query CASS for similar past tasks
797
- let cassContext = "";
798
- let cassResultInfo: {
799
- queried: boolean;
800
- results_found?: number;
801
- included_in_context?: boolean;
802
- reason?: string;
803
- };
804
-
805
- if (args.query_cass !== false) {
806
- const cassResult = await queryCassHistory(args.task, 3);
807
- if (cassResult.status === "success") {
808
- cassContext = formatCassHistoryForPrompt(cassResult.data);
809
- cassResultInfo = {
810
- queried: true,
811
- results_found: cassResult.data.results.length,
812
- included_in_context: true,
813
- };
814
- } else {
815
- cassResultInfo = {
816
- queried: true,
817
- results_found: 0,
818
- included_in_context: false,
819
- reason: cassResult.status,
820
- };
821
- }
822
- } else {
823
- cassResultInfo = { queried: false, reason: "disabled" };
824
- }
825
-
826
- // Fetch skills context
827
- let skillsContext = "";
828
- let skillsInfo: { included: boolean; count?: number; relevant?: string[] } =
829
- {
830
- included: false,
831
- };
832
-
833
- const allSkills = await listSkills();
834
- if (allSkills.length > 0) {
835
- skillsContext = await getSkillsContextForSwarm();
836
- const relevantSkills = await findRelevantSkills(args.task);
837
- skillsInfo = {
838
- included: true,
839
- count: allSkills.length,
840
- relevant: relevantSkills,
841
- };
842
-
843
- // Add suggestion for relevant skills
844
- if (relevantSkills.length > 0) {
845
- skillsContext += `\n\n**Suggested skills for this task**: ${relevantSkills.join(", ")}`;
846
- }
847
- }
848
-
849
- // Format strategy guidelines
850
- const strategyGuidelines = formatStrategyGuidelines(selectedStrategy);
851
-
852
- // Combine user context
853
- const contextSection = args.context
854
- ? `## Additional Context\n${args.context}`
855
- : "## Additional Context\n(none provided)";
856
-
857
- // Build the planning prompt with clear instructions for JSON-only output
858
- const planningPrompt = STRATEGY_DECOMPOSITION_PROMPT.replace(
859
- "{task}",
860
- args.task,
861
- )
862
- .replace("{strategy_guidelines}", strategyGuidelines)
863
- .replace("{context_section}", contextSection)
864
- .replace("{cass_history}", cassContext || "")
865
- .replace("{skills_context}", skillsContext || "");
866
-
867
- // Add strict JSON-only instructions for the subagent
868
- const subagentInstructions = `
869
- ## CRITICAL: Output Format
870
-
871
- You are a planner subagent. Your ONLY output must be valid JSON matching the CellTree schema.
872
-
873
- DO NOT include:
874
- - Explanatory text before or after the JSON
875
- - Markdown code fences (\`\`\`json)
876
- - Commentary or reasoning
877
-
878
- OUTPUT ONLY the raw JSON object.
879
-
880
- ## Example Output
881
-
882
- {
883
- "epic": {
884
- "title": "Add user authentication",
885
- "description": "Implement OAuth-based authentication system"
886
- },
887
- "subtasks": [
888
- {
889
- "title": "Set up OAuth provider",
890
- "description": "Configure OAuth client credentials and redirect URLs",
891
- "files": ["src/auth/oauth.ts", "src/config/auth.ts"],
892
- "dependencies": [],
893
- "estimated_complexity": 2
894
- },
895
- {
896
- "title": "Create auth routes",
897
- "description": "Implement login, logout, and callback routes",
898
- "files": ["src/app/api/auth/[...nextauth]/route.ts"],
899
- "dependencies": [0],
900
- "estimated_complexity": 3
901
- }
902
- ]
903
- }
904
-
905
- Now generate the CellTree for the given task.`;
906
-
907
- const fullPrompt = `${planningPrompt}\n\n${subagentInstructions}`;
908
-
909
- // Return structured output for coordinator
910
- return JSON.stringify(
911
- {
912
- prompt: fullPrompt,
913
- subagent_type: "swarm/planner",
914
- description: "Task decomposition planning",
915
- strategy: {
916
- selected: selectedStrategy,
917
- reasoning: strategyReasoning,
918
- },
919
- expected_output: "CellTree JSON (raw JSON, no markdown)",
920
- next_steps: [
921
- "1. Spawn subagent with Task tool using returned prompt",
922
- "2. Parse subagent response as JSON",
923
- "3. Validate with swarm_validate_decomposition",
924
- "4. Create cells with hive_create_epic",
925
- ],
926
- cass_history: cassResultInfo,
927
- skills: skillsInfo,
928
- // Add semantic-memory query instruction
929
- memory_query: formatMemoryQueryForDecomposition(args.task, 3),
930
- },
931
- null,
932
- 2,
933
- );
934
- },
935
- });
936
-
937
- // ============================================================================
938
- // Errors
939
- // ============================================================================
940
-
941
- export class SwarmError extends Error {
942
- constructor(
943
- message: string,
944
- public readonly operation: string,
945
- public readonly details?: unknown,
946
- ) {
947
- super(message);
948
- this.name = "SwarmError";
949
- }
950
- }
951
-
952
- export class DecompositionError extends SwarmError {
953
- constructor(
954
- message: string,
955
- public readonly zodError?: z.ZodError,
956
- ) {
957
- super(message, "decompose", zodError?.issues);
958
- }
959
- }
960
-
961
- /**
962
- * Planning phase state machine for Socratic planning
963
- */
964
- type PlanningPhase = "questioning" | "alternatives" | "recommendation" | "ready";
965
-
966
- /**
967
- * Planning mode that determines interaction level
968
- */
969
- type PlanningMode = "socratic" | "fast" | "auto" | "confirm-only";
970
-
971
- /**
972
- * Socratic planning output structure
973
- */
974
- interface SocraticPlanOutput {
975
- mode: PlanningMode;
976
- phase: PlanningPhase;
977
- questions?: Array<{ question: string; options?: string[] }>;
978
- alternatives?: Array<{
979
- name: string;
980
- description: string;
981
- tradeoffs: string;
982
- }>;
983
- recommendation?: { approach: string; reasoning: string };
984
- memory_context?: string;
985
- codebase_context?: {
986
- git_status?: string;
987
- relevant_files?: string[];
988
- };
989
- ready_to_decompose: boolean;
990
- next_action?: string;
991
- }
992
-
993
- /**
994
- * Interactive planning tool with Socratic questioning
995
- *
996
- * Implements a planning phase BEFORE decomposition that:
997
- * 1. Gathers context (git, files, semantic memory)
998
- * 2. Asks clarifying questions (socratic mode)
999
- * 3. Explores alternatives with tradeoffs
1000
- * 4. Recommends an approach with reasoning
1001
- * 5. Confirms before proceeding to decomposition
1002
- *
1003
- * Modes:
1004
- * - socratic: Full interactive planning with questions, alternatives, recommendations
1005
- * - fast: Skip brainstorming, go straight to decomposition with memory context
1006
- * - auto: Auto-select best approach based on task keywords, minimal interaction
1007
- * - confirm-only: Show decomposition, wait for yes/no confirmation
1008
- *
1009
- * Based on the Socratic Planner Pattern from obra/superpowers.
1010
- *
1011
- * @see docs/analysis-socratic-planner-pattern.md
1012
- */
1013
- export const swarm_plan_interactive = tool({
1014
- description:
1015
- "Interactive planning phase with Socratic questioning before decomposition. Supports multiple modes from full interactive to auto-proceed.",
1016
- args: {
1017
- task: tool.schema.string().min(1).describe("The task to plan"),
1018
- mode: tool.schema
1019
- .enum(["socratic", "fast", "auto", "confirm-only"])
1020
- .default("socratic")
1021
- .describe("Planning mode: socratic (full), fast (skip questions), auto (minimal), confirm-only (single yes/no)"),
1022
- context: tool.schema
1023
- .string()
1024
- .optional()
1025
- .describe("Optional additional context about the task"),
1026
- user_response: tool.schema
1027
- .string()
1028
- .optional()
1029
- .describe("User's response to a previous question (for multi-turn socratic mode)"),
1030
- phase: tool.schema
1031
- .enum(["questioning", "alternatives", "recommendation", "ready"])
1032
- .optional()
1033
- .describe("Current planning phase (for resuming multi-turn interaction)"),
1034
- },
1035
- async execute(args): Promise<string> {
1036
- // Import needed modules
1037
- const { selectStrategy, formatStrategyGuidelines, STRATEGIES } =
1038
- await import("./swarm-strategies");
1039
- const { formatMemoryQueryForDecomposition } = await import("./learning");
1040
-
1041
- // Determine current phase
1042
- const currentPhase: PlanningPhase = args.phase || "questioning";
1043
- const mode: PlanningMode = args.mode || "socratic";
1044
-
1045
- // Gather context - always do this regardless of mode
1046
- let memoryContext = "";
1047
- let codebaseContext: { git_status?: string; relevant_files?: string[] } = {};
1048
-
1049
- // Generate semantic memory query instruction
1050
- // Note: Semantic memory is accessed via OpenCode's global tools, not as a direct import
1051
- // The coordinator should call semantic-memory_find before calling this tool
1052
- // and pass results in the context parameter
1053
- try {
1054
- const memoryQuery = formatMemoryQueryForDecomposition(args.task, 3);
1055
- memoryContext = `[Memory Query Instruction]\n${memoryQuery.instruction}\nQuery: "${memoryQuery.query}"\nLimit: ${memoryQuery.limit}`;
1056
- } catch (error) {
1057
- console.warn("[swarm_plan_interactive] Memory query formatting failed:", error);
1058
- }
1059
-
1060
- // Get git context for codebase awareness
1061
- try {
1062
- const gitResult = await Bun.$`git status --short`.quiet().nothrow();
1063
- if (gitResult.exitCode === 0) {
1064
- codebaseContext.git_status = gitResult.stdout.toString().trim();
1065
- }
1066
- } catch (error) {
1067
- // Git not available or not in a git repo - continue without it
1068
- }
1069
-
1070
- // Fast mode: Skip to recommendation
1071
- if (mode === "fast") {
1072
- const strategyResult = selectStrategy(args.task);
1073
- const guidelines = formatStrategyGuidelines(strategyResult.strategy);
1074
-
1075
- const output: SocraticPlanOutput = {
1076
- mode: "fast",
1077
- phase: "ready",
1078
- recommendation: {
1079
- approach: strategyResult.strategy,
1080
- reasoning: `${strategyResult.reasoning}\n\n${guidelines}`,
1081
- },
1082
- memory_context: memoryContext || undefined,
1083
- codebase_context: Object.keys(codebaseContext).length > 0 ? codebaseContext : undefined,
1084
- ready_to_decompose: true,
1085
- next_action: "Proceed to swarm_decompose or swarm_delegate_planning",
1086
- };
1087
-
1088
- return JSON.stringify(output, null, 2);
1089
- }
1090
-
1091
- // Auto mode: Auto-select and proceed
1092
- if (mode === "auto") {
1093
- const strategyResult = selectStrategy(args.task);
1094
-
1095
- const output: SocraticPlanOutput = {
1096
- mode: "auto",
1097
- phase: "ready",
1098
- recommendation: {
1099
- approach: strategyResult.strategy,
1100
- reasoning: `Auto-selected based on task keywords: ${strategyResult.reasoning}`,
1101
- },
1102
- memory_context: memoryContext || undefined,
1103
- codebase_context: Object.keys(codebaseContext).length > 0 ? codebaseContext : undefined,
1104
- ready_to_decompose: true,
1105
- next_action: "Auto-proceeding to decomposition",
1106
- };
1107
-
1108
- return JSON.stringify(output, null, 2);
1109
- }
1110
-
1111
- // Confirm-only mode: Generate decomposition, show it, wait for yes/no
1112
- if (mode === "confirm-only") {
1113
- // This mode will be handled by calling swarm_delegate_planning
1114
- // and then asking for confirmation on the result
1115
- const output: SocraticPlanOutput = {
1116
- mode: "confirm-only",
1117
- phase: "ready",
1118
- recommendation: {
1119
- approach: "Will generate decomposition for your review",
1120
- reasoning: "Use swarm_delegate_planning to generate the plan, then present it for yes/no confirmation",
1121
- },
1122
- memory_context: memoryContext || undefined,
1123
- codebase_context: Object.keys(codebaseContext).length > 0 ? codebaseContext : undefined,
1124
- ready_to_decompose: false,
1125
- next_action: "Call swarm_delegate_planning, then show result and ask for confirmation",
1126
- };
1127
-
1128
- return JSON.stringify(output, null, 2);
1129
- }
1130
-
1131
- // Socratic mode: Full interactive planning
1132
- // Phase 1: Questioning
1133
- if (currentPhase === "questioning") {
1134
- // Analyze task to identify what needs clarification
1135
- const taskLower = args.task.toLowerCase();
1136
- const questions: Array<{ question: string; options?: string[] }> = [];
1137
-
1138
- // Check for vague task signals from skill
1139
- const isVague = {
1140
- noFiles: !taskLower.includes("src/") && !taskLower.includes("file"),
1141
- vagueVerb:
1142
- taskLower.includes("improve") ||
1143
- taskLower.includes("fix") ||
1144
- taskLower.includes("update") ||
1145
- taskLower.includes("make better"),
1146
- noSuccessCriteria: !taskLower.includes("test") && !taskLower.includes("verify"),
1147
- };
1148
-
1149
- // Generate clarifying questions (one at a time)
1150
- if (isVague.noFiles) {
1151
- questions.push({
1152
- question: "Which part of the codebase should this change affect?",
1153
- options: [
1154
- "Core functionality (src/)",
1155
- "UI components (components/)",
1156
- "API routes (app/api/)",
1157
- "Configuration and tooling",
1158
- "Tests",
1159
- ],
1160
- });
1161
- } else if (isVague.vagueVerb) {
1162
- questions.push({
1163
- question: "What specific change are you looking for?",
1164
- options: [
1165
- "Add new functionality",
1166
- "Modify existing behavior",
1167
- "Remove/deprecate something",
1168
- "Refactor without behavior change",
1169
- "Fix a bug",
1170
- ],
1171
- });
1172
- } else if (isVague.noSuccessCriteria) {
1173
- questions.push({
1174
- question: "How will we know this task is complete?",
1175
- options: [
1176
- "All tests pass",
1177
- "Feature works as demonstrated",
1178
- "Code review approved",
1179
- "Documentation updated",
1180
- "Performance target met",
1181
- ],
1182
- });
1183
- }
1184
-
1185
- // If task seems clear, move to alternatives phase
1186
- if (questions.length === 0) {
1187
- const output: SocraticPlanOutput = {
1188
- mode: "socratic",
1189
- phase: "alternatives",
1190
- memory_context: memoryContext || undefined,
1191
- codebase_context: Object.keys(codebaseContext).length > 0 ? codebaseContext : undefined,
1192
- ready_to_decompose: false,
1193
- next_action: "Task is clear. Call again with phase=alternatives to explore approaches",
1194
- };
1195
- return JSON.stringify(output, null, 2);
1196
- }
1197
-
1198
- // Return first question only (Socratic principle: one at a time)
1199
- const output: SocraticPlanOutput = {
1200
- mode: "socratic",
1201
- phase: "questioning",
1202
- questions: [questions[0]],
1203
- memory_context: memoryContext || undefined,
1204
- codebase_context: Object.keys(codebaseContext).length > 0 ? codebaseContext : undefined,
1205
- ready_to_decompose: false,
1206
- next_action: "User should answer this question, then call again with user_response",
1207
- };
1208
-
1209
- return JSON.stringify(output, null, 2);
1210
- }
1211
-
1212
- // Phase 2: Alternatives
1213
- if (currentPhase === "alternatives") {
1214
- const strategyResult = selectStrategy(args.task);
1215
-
1216
- // Build 2-3 alternative approaches
1217
- const alternatives: Array<{
1218
- name: string;
1219
- description: string;
1220
- tradeoffs: string;
1221
- }> = [];
1222
-
1223
- // Primary recommendation
1224
- alternatives.push({
1225
- name: strategyResult.strategy,
1226
- description: strategyResult.reasoning,
1227
- tradeoffs: `Confidence: ${(strategyResult.confidence * 100).toFixed(0)}%. ${STRATEGIES[strategyResult.strategy].description}`,
1228
- });
1229
-
1230
- // Add top 2 alternatives
1231
- for (let i = 0; i < Math.min(2, strategyResult.alternatives.length); i++) {
1232
- const alt = strategyResult.alternatives[i];
1233
- alternatives.push({
1234
- name: alt.strategy,
1235
- description: STRATEGIES[alt.strategy].description,
1236
- tradeoffs: `Match score: ${alt.score}. ${STRATEGIES[alt.strategy].antiPatterns[0] || "Consider trade-offs carefully"}`,
1237
- });
1238
- }
1239
-
1240
- const output: SocraticPlanOutput = {
1241
- mode: "socratic",
1242
- phase: "alternatives",
1243
- alternatives,
1244
- memory_context: memoryContext || undefined,
1245
- codebase_context: Object.keys(codebaseContext).length > 0 ? codebaseContext : undefined,
1246
- ready_to_decompose: false,
1247
- next_action: "User should choose an approach, then call again with phase=recommendation",
1248
- };
1249
-
1250
- return JSON.stringify(output, null, 2);
1251
- }
1252
-
1253
- // Phase 3: Recommendation
1254
- if (currentPhase === "recommendation") {
1255
- const strategyResult = selectStrategy(args.task);
1256
- const guidelines = formatStrategyGuidelines(strategyResult.strategy);
1257
-
1258
- const output: SocraticPlanOutput = {
1259
- mode: "socratic",
1260
- phase: "recommendation",
1261
- recommendation: {
1262
- approach: strategyResult.strategy,
1263
- reasoning: `Based on your input and task analysis:\n\n${strategyResult.reasoning}\n\n${guidelines}`,
1264
- },
1265
- memory_context: memoryContext || undefined,
1266
- codebase_context: Object.keys(codebaseContext).length > 0 ? codebaseContext : undefined,
1267
- ready_to_decompose: false,
1268
- next_action: "User should confirm to proceed. Then call again with phase=ready",
1269
- };
1270
-
1271
- return JSON.stringify(output, null, 2);
1272
- }
1273
-
1274
- // Phase 4: Ready
1275
- if (currentPhase === "ready") {
1276
- const output: SocraticPlanOutput = {
1277
- mode: "socratic",
1278
- phase: "ready",
1279
- recommendation: {
1280
- approach: "Confirmed by user",
1281
- reasoning: "Ready to proceed with decomposition",
1282
- },
1283
- memory_context: memoryContext || undefined,
1284
- codebase_context: Object.keys(codebaseContext).length > 0 ? codebaseContext : undefined,
1285
- ready_to_decompose: true,
1286
- next_action: "Proceed to swarm_decompose or swarm_delegate_planning",
1287
- };
1288
-
1289
- return JSON.stringify(output, null, 2);
1290
- }
1291
-
1292
- // Should never reach here
1293
- throw new Error(`Invalid planning phase: ${currentPhase}`);
1294
- },
1295
- });
1296
-
1297
- export const decomposeTools = {
1298
- swarm_decompose,
1299
- swarm_validate_decomposition,
1300
- swarm_delegate_planning,
1301
- swarm_plan_interactive,
1302
- };