opencode-swarm-plugin 0.12.2 → 0.12.6
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/.beads/issues.jsonl +215 -0
- package/README.md +111 -106
- package/bin/swarm.ts +13 -14
- package/dist/index.js +100 -46
- package/dist/plugin.js +68 -33
- package/examples/commands/swarm.md +51 -210
- package/package.json +1 -1
- package/src/agent-mail.ts +26 -11
- package/src/beads.ts +75 -20
- package/src/rate-limiter.ts +12 -6
- package/src/schemas/bead.ts +4 -4
- package/src/schemas/evaluation.ts +2 -2
- package/src/schemas/task.ts +3 -3
- package/src/storage.ts +37 -15
- package/src/swarm.ts +13 -0
- package/examples/agents/swarm-planner.md +0 -138
package/src/storage.ts
CHANGED
|
@@ -73,20 +73,35 @@ async function resolveSemanticMemoryCommand(): Promise<string[]> {
|
|
|
73
73
|
async function execSemanticMemory(
|
|
74
74
|
args: string[],
|
|
75
75
|
): Promise<{ exitCode: number; stdout: Buffer; stderr: Buffer }> {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
// Use Bun.spawn for dynamic command arrays
|
|
80
|
-
const proc = Bun.spawn(fullCmd, {
|
|
81
|
-
stdout: "pipe",
|
|
82
|
-
stderr: "pipe",
|
|
83
|
-
});
|
|
76
|
+
try {
|
|
77
|
+
const cmd = await resolveSemanticMemoryCommand();
|
|
78
|
+
const fullCmd = [...cmd, ...args];
|
|
84
79
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
80
|
+
// Use Bun.spawn for dynamic command arrays
|
|
81
|
+
const proc = Bun.spawn(fullCmd, {
|
|
82
|
+
stdout: "pipe",
|
|
83
|
+
stderr: "pipe",
|
|
84
|
+
});
|
|
88
85
|
|
|
89
|
-
|
|
86
|
+
try {
|
|
87
|
+
const stdout = Buffer.from(await new Response(proc.stdout).arrayBuffer());
|
|
88
|
+
const stderr = Buffer.from(await new Response(proc.stderr).arrayBuffer());
|
|
89
|
+
const exitCode = await proc.exited;
|
|
90
|
+
|
|
91
|
+
return { exitCode, stdout, stderr };
|
|
92
|
+
} finally {
|
|
93
|
+
// Ensure process cleanup
|
|
94
|
+
proc.kill();
|
|
95
|
+
}
|
|
96
|
+
} catch (error) {
|
|
97
|
+
// Return structured error result on exceptions
|
|
98
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
99
|
+
return {
|
|
100
|
+
exitCode: 1,
|
|
101
|
+
stdout: Buffer.from(""),
|
|
102
|
+
stderr: Buffer.from(`Error executing semantic-memory: ${errorMessage}`),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
90
105
|
}
|
|
91
106
|
|
|
92
107
|
/**
|
|
@@ -646,17 +661,22 @@ export async function createStorageWithFallback(
|
|
|
646
661
|
// ============================================================================
|
|
647
662
|
|
|
648
663
|
let globalStorage: LearningStorage | null = null;
|
|
664
|
+
let globalStoragePromise: Promise<LearningStorage> | null = null;
|
|
649
665
|
|
|
650
666
|
/**
|
|
651
667
|
* Get or create the global storage instance
|
|
652
668
|
*
|
|
653
669
|
* Uses semantic-memory by default, with automatic fallback to in-memory.
|
|
670
|
+
* Prevents race conditions by storing the initialization promise.
|
|
654
671
|
*/
|
|
655
672
|
export async function getStorage(): Promise<LearningStorage> {
|
|
656
|
-
if (!
|
|
657
|
-
|
|
673
|
+
if (!globalStoragePromise) {
|
|
674
|
+
globalStoragePromise = createStorageWithFallback().then((storage) => {
|
|
675
|
+
globalStorage = storage;
|
|
676
|
+
return storage;
|
|
677
|
+
});
|
|
658
678
|
}
|
|
659
|
-
return
|
|
679
|
+
return globalStoragePromise;
|
|
660
680
|
}
|
|
661
681
|
|
|
662
682
|
/**
|
|
@@ -666,6 +686,7 @@ export async function getStorage(): Promise<LearningStorage> {
|
|
|
666
686
|
*/
|
|
667
687
|
export function setStorage(storage: LearningStorage): void {
|
|
668
688
|
globalStorage = storage;
|
|
689
|
+
globalStoragePromise = Promise.resolve(storage);
|
|
669
690
|
}
|
|
670
691
|
|
|
671
692
|
/**
|
|
@@ -676,4 +697,5 @@ export async function resetStorage(): Promise<void> {
|
|
|
676
697
|
await globalStorage.close();
|
|
677
698
|
globalStorage = null;
|
|
678
699
|
}
|
|
700
|
+
globalStoragePromise = null;
|
|
679
701
|
}
|
package/src/swarm.ts
CHANGED
|
@@ -1343,6 +1343,19 @@ export const swarm_validate_decomposition = tool({
|
|
|
1343
1343
|
for (let i = 0; i < validated.subtasks.length; i++) {
|
|
1344
1344
|
const deps = validated.subtasks[i].dependencies;
|
|
1345
1345
|
for (const dep of deps) {
|
|
1346
|
+
// Check bounds first
|
|
1347
|
+
if (dep < 0 || dep >= validated.subtasks.length) {
|
|
1348
|
+
return JSON.stringify(
|
|
1349
|
+
{
|
|
1350
|
+
valid: false,
|
|
1351
|
+
error: `Invalid dependency: subtask ${i} depends on ${dep}, but only ${validated.subtasks.length} subtasks exist (indices 0-${validated.subtasks.length - 1})`,
|
|
1352
|
+
hint: "Dependency index is out of bounds",
|
|
1353
|
+
},
|
|
1354
|
+
null,
|
|
1355
|
+
2,
|
|
1356
|
+
);
|
|
1357
|
+
}
|
|
1358
|
+
// Check forward references
|
|
1346
1359
|
if (dep >= i) {
|
|
1347
1360
|
return JSON.stringify(
|
|
1348
1361
|
{
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: swarm-planner
|
|
3
|
-
description: Strategic task decomposition for swarm coordination
|
|
4
|
-
model: claude-sonnet-4-5
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
You are a swarm planner. Your job is to decompose complex tasks into optimal parallel subtasks.
|
|
8
|
-
|
|
9
|
-
## Your Role
|
|
10
|
-
|
|
11
|
-
You analyze tasks and create decomposition plans that:
|
|
12
|
-
|
|
13
|
-
- Maximize parallelization (agents work independently)
|
|
14
|
-
- Minimize conflicts (no file overlap between subtasks)
|
|
15
|
-
- Follow the best strategy for the task type
|
|
16
|
-
|
|
17
|
-
## Workflow
|
|
18
|
-
|
|
19
|
-
1. **Analyze** - Call `swarm_select_strategy` to understand the task
|
|
20
|
-
2. **Plan** - Call `swarm_plan_prompt` to get strategy-specific guidance
|
|
21
|
-
3. **Decompose** - Create a BeadTree following the guidelines
|
|
22
|
-
4. **Validate** - Ensure no file conflicts or circular dependencies
|
|
23
|
-
|
|
24
|
-
## Strategy Selection
|
|
25
|
-
|
|
26
|
-
The plugin auto-selects strategies based on task keywords:
|
|
27
|
-
|
|
28
|
-
| Strategy | Best For | Keywords |
|
|
29
|
-
| ----------------- | -------------------------------------------- | -------------------------------------- |
|
|
30
|
-
| **file-based** | Refactoring, migrations, pattern changes | refactor, migrate, rename, update all |
|
|
31
|
-
| **feature-based** | New features, adding functionality | add, implement, build, create, feature |
|
|
32
|
-
| **risk-based** | Bug fixes, security issues, critical changes | fix, bug, security, critical, urgent |
|
|
33
|
-
|
|
34
|
-
You can override with explicit strategy if the auto-detection is wrong.
|
|
35
|
-
|
|
36
|
-
## Output Format
|
|
37
|
-
|
|
38
|
-
Return ONLY valid JSON matching the BeadTree schema:
|
|
39
|
-
|
|
40
|
-
```json
|
|
41
|
-
{
|
|
42
|
-
"epic": {
|
|
43
|
-
"title": "Epic title for beads tracker",
|
|
44
|
-
"description": "Brief description of the overall goal"
|
|
45
|
-
},
|
|
46
|
-
"subtasks": [
|
|
47
|
-
{
|
|
48
|
-
"title": "What this subtask accomplishes",
|
|
49
|
-
"description": "Detailed instructions for the agent",
|
|
50
|
-
"files": ["src/path/to/file.ts", "src/path/to/file.test.ts"],
|
|
51
|
-
"dependencies": [],
|
|
52
|
-
"estimated_complexity": 2
|
|
53
|
-
}
|
|
54
|
-
]
|
|
55
|
-
}
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
**CRITICAL**: Return ONLY the JSON. No markdown, no explanation, no code blocks.
|
|
59
|
-
|
|
60
|
-
## Decomposition Rules
|
|
61
|
-
|
|
62
|
-
1. **2-7 subtasks** - Too few = not parallel, too many = coordination overhead
|
|
63
|
-
2. **No file overlap** - Each file appears in exactly one subtask
|
|
64
|
-
3. **Include tests** - Put test files with the code they test
|
|
65
|
-
4. **Order by dependency** - If B needs A's output, A comes first (lower index)
|
|
66
|
-
5. **Estimate complexity** - 1 (trivial) to 5 (complex)
|
|
67
|
-
|
|
68
|
-
## Anti-Patterns to Avoid
|
|
69
|
-
|
|
70
|
-
- Don't split tightly coupled files across subtasks
|
|
71
|
-
- Don't create subtasks that can't be tested independently
|
|
72
|
-
- Don't forget shared types/utilities that multiple files depend on
|
|
73
|
-
- Don't make one subtask do everything while others are trivial
|
|
74
|
-
|
|
75
|
-
## Example Decomposition
|
|
76
|
-
|
|
77
|
-
**Task**: "Add user authentication with OAuth"
|
|
78
|
-
|
|
79
|
-
**Strategy**: feature-based (detected from "add" keyword)
|
|
80
|
-
|
|
81
|
-
**Result**:
|
|
82
|
-
|
|
83
|
-
```json
|
|
84
|
-
{
|
|
85
|
-
"epic": {
|
|
86
|
-
"title": "Add user authentication with OAuth",
|
|
87
|
-
"description": "Implement OAuth-based authentication flow with session management"
|
|
88
|
-
},
|
|
89
|
-
"subtasks": [
|
|
90
|
-
{
|
|
91
|
-
"title": "Set up OAuth provider configuration",
|
|
92
|
-
"description": "Configure OAuth provider (Google/GitHub), add environment variables, create auth config",
|
|
93
|
-
"files": ["src/auth/config.ts", "src/auth/providers.ts", ".env.example"],
|
|
94
|
-
"dependencies": [],
|
|
95
|
-
"estimated_complexity": 2
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
"title": "Implement session management",
|
|
99
|
-
"description": "Create session store, JWT handling, cookie management",
|
|
100
|
-
"files": [
|
|
101
|
-
"src/auth/session.ts",
|
|
102
|
-
"src/auth/jwt.ts",
|
|
103
|
-
"src/middleware/auth.ts"
|
|
104
|
-
],
|
|
105
|
-
"dependencies": [0],
|
|
106
|
-
"estimated_complexity": 3
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
"title": "Add protected route wrapper",
|
|
110
|
-
"description": "Create HOC/middleware for protecting routes, redirect logic",
|
|
111
|
-
"files": ["src/components/ProtectedRoute.tsx", "src/hooks/useAuth.ts"],
|
|
112
|
-
"dependencies": [1],
|
|
113
|
-
"estimated_complexity": 2
|
|
114
|
-
},
|
|
115
|
-
{
|
|
116
|
-
"title": "Create login/logout UI",
|
|
117
|
-
"description": "Login page, logout button, auth state display",
|
|
118
|
-
"files": ["src/app/login/page.tsx", "src/components/AuthButton.tsx"],
|
|
119
|
-
"dependencies": [0],
|
|
120
|
-
"estimated_complexity": 2
|
|
121
|
-
}
|
|
122
|
-
]
|
|
123
|
-
}
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
## Usage
|
|
127
|
-
|
|
128
|
-
The coordinator invokes you like this:
|
|
129
|
-
|
|
130
|
-
```
|
|
131
|
-
@swarm-planner "Add user authentication with OAuth"
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
You respond with the BeadTree JSON. The coordinator then:
|
|
135
|
-
|
|
136
|
-
1. Validates with `swarm_validate_decomposition`
|
|
137
|
-
2. Creates beads with `beads_create_epic`
|
|
138
|
-
3. Spawns worker agents for each subtask
|