opencode-swarm-plugin 0.29.0 → 0.30.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 +94 -0
- package/README.md +3 -6
- package/bin/swarm.test.ts +163 -0
- package/bin/swarm.ts +304 -72
- package/dist/hive.d.ts.map +1 -1
- package/dist/index.d.ts +94 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18825 -3469
- package/dist/memory-tools.d.ts +209 -0
- package/dist/memory-tools.d.ts.map +1 -0
- package/dist/memory.d.ts +124 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/plugin.js +18775 -3430
- package/dist/schemas/index.d.ts +7 -0
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/worker-handoff.d.ts +78 -0
- package/dist/schemas/worker-handoff.d.ts.map +1 -0
- package/dist/swarm-orchestrate.d.ts +50 -0
- package/dist/swarm-orchestrate.d.ts.map +1 -1
- package/dist/swarm-prompts.d.ts +1 -1
- package/dist/swarm-prompts.d.ts.map +1 -1
- package/dist/swarm-review.d.ts +4 -0
- package/dist/swarm-review.d.ts.map +1 -1
- package/docs/planning/ADR-008-worker-handoff-protocol.md +293 -0
- package/examples/plugin-wrapper-template.ts +157 -28
- package/package.json +3 -1
- package/src/hive.integration.test.ts +114 -0
- package/src/hive.ts +33 -22
- package/src/index.ts +41 -8
- package/src/memory-tools.test.ts +111 -0
- package/src/memory-tools.ts +273 -0
- package/src/memory.integration.test.ts +266 -0
- package/src/memory.test.ts +334 -0
- package/src/memory.ts +441 -0
- package/src/schemas/index.ts +18 -0
- package/src/schemas/worker-handoff.test.ts +271 -0
- package/src/schemas/worker-handoff.ts +131 -0
- package/src/swarm-orchestrate.ts +262 -24
- package/src/swarm-prompts.ts +48 -5
- package/src/swarm-review.ts +7 -0
- package/src/swarm.integration.test.ts +386 -9
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
$ bun build ./src/index.ts --outdir ./dist --target node --external @electric-sql/pglite --external swarm-mail && bun build ./src/plugin.ts --outfile ./dist/plugin.js --target node --external @electric-sql/pglite --external swarm-mail && tsc
|
|
2
|
-
Bundled
|
|
2
|
+
Bundled 811 modules in 121ms
|
|
3
3
|
|
|
4
|
-
index.js 1.
|
|
4
|
+
index.js 1.71 MB (entry point)
|
|
5
5
|
|
|
6
|
-
Bundled
|
|
6
|
+
Bundled 812 modules in 142ms
|
|
7
7
|
|
|
8
|
-
plugin.js 1.
|
|
8
|
+
plugin.js 1.67 MB (entry point)
|
|
9
9
|
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,99 @@
|
|
|
1
1
|
# opencode-swarm-plugin
|
|
2
2
|
|
|
3
|
+
## 0.30.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`5858148`](https://github.com/joelhooks/swarm-tools/commit/5858148d5785393c0a6993a2595fba275f305707) Thanks [@joelhooks](https://github.com/joelhooks)! - chore: trigger publish workflow
|
|
8
|
+
|
|
9
|
+
## 0.30.1
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [`57d5600`](https://github.com/joelhooks/swarm-tools/commit/57d5600a53e148ce1d1da48b3b5a8723a5552e04) Thanks [@joelhooks](https://github.com/joelhooks)! - ## 🚦 Review Gate UX Fix + Verbose Setup
|
|
14
|
+
|
|
15
|
+
> _"A common mistake that people make when trying to design something completely foolproof is to underestimate the ingenuity of complete fools."_
|
|
16
|
+
> — Douglas Adams, _Mostly Harmless_
|
|
17
|
+
|
|
18
|
+
Two UX improvements that make swarm coordination feel less like shouting into the void.
|
|
19
|
+
|
|
20
|
+
### What Changed
|
|
21
|
+
|
|
22
|
+
**Review Gate Response Fix:**
|
|
23
|
+
|
|
24
|
+
- `swarm_complete` no longer returns `success: false` when code review is pending
|
|
25
|
+
- Now returns `success: true` with `status: "pending_review"` or `status: "needs_changes"`
|
|
26
|
+
- **Why it matters**: The old format made review checkpoints look like errors. Agents would retry unnecessarily or report failures when the workflow was actually working as designed. Review gates are a feature, not a bug.
|
|
27
|
+
|
|
28
|
+
**Setup Command Verbosity:**
|
|
29
|
+
|
|
30
|
+
- Added `p.log.step()` and `p.log.success()` throughout swarm setup
|
|
31
|
+
- Users can now see exactly what's happening: dependency checks, git init, swarm-mail connection
|
|
32
|
+
- **Why it matters**: Silent setup commands feel broken. Explicit progress logs build trust and make debugging easier when setup actually does fail.
|
|
33
|
+
|
|
34
|
+
### Why It Matters
|
|
35
|
+
|
|
36
|
+
**For Agents:**
|
|
37
|
+
|
|
38
|
+
- No more false-negative responses from review gates
|
|
39
|
+
- Clear workflow state (pending vs. needs changes vs. complete)
|
|
40
|
+
- Reduced retry loops and error noise
|
|
41
|
+
|
|
42
|
+
**For Users:**
|
|
43
|
+
|
|
44
|
+
- Setup command shows its work (not a black box)
|
|
45
|
+
- Review process is transparent in logs
|
|
46
|
+
- Easier to diagnose when things actually break
|
|
47
|
+
|
|
48
|
+
**Backward compatible:** Yes. Existing agents checking for `success: false` will still work, they just won't see false errors anymore.
|
|
49
|
+
|
|
50
|
+
## 0.30.0
|
|
51
|
+
|
|
52
|
+
### Minor Changes
|
|
53
|
+
|
|
54
|
+
- [`f3917ad`](https://github.com/joelhooks/swarm-tools/commit/f3917ad911d3c716a2470a01c66bce3500f644f4) Thanks [@joelhooks](https://github.com/joelhooks)! - ## 🐝 The Great bd CLI Purge
|
|
55
|
+
|
|
56
|
+
The `bd` CLI is officially dead. Long live HiveAdapter!
|
|
57
|
+
|
|
58
|
+
**What changed:**
|
|
59
|
+
|
|
60
|
+
### `swarm init` Command Rewritten
|
|
61
|
+
|
|
62
|
+
- No longer shells out to `bd init` or `bd create`
|
|
63
|
+
- Uses `ensureHiveDirectory()` and `getHiveAdapter()` directly
|
|
64
|
+
- Supports `.beads` → `.hive` migration with user prompts
|
|
65
|
+
- Creates cells via HiveAdapter, not CLI
|
|
66
|
+
|
|
67
|
+
### Auto-sync Removed from `index.ts`
|
|
68
|
+
|
|
69
|
+
- Removed `void $\`bd sync\`.quiet().nothrow()`after`hive_close`
|
|
70
|
+
- Users should call `hive_sync` explicitly at session end
|
|
71
|
+
- This was a fire-and-forget that could race with other operations
|
|
72
|
+
|
|
73
|
+
### Plugin Template Updated
|
|
74
|
+
|
|
75
|
+
- `detectSwarm()` now has confidence levels (HIGH/MEDIUM/LOW/NONE)
|
|
76
|
+
- Added `SWARM_DETECTION_FALLBACK` for uncertain cases
|
|
77
|
+
- Compaction hook injects context based on confidence:
|
|
78
|
+
- HIGH/MEDIUM → Full swarm context
|
|
79
|
+
- LOW → Fallback detection prompt
|
|
80
|
+
- NONE → No injection
|
|
81
|
+
|
|
82
|
+
### Error Handling Fixed
|
|
83
|
+
|
|
84
|
+
- `execTool()` now handles both string and object error formats
|
|
85
|
+
- Fixes "Tool execution failed" generic error from `swarm_complete`
|
|
86
|
+
- Actual error messages now propagate to the agent
|
|
87
|
+
|
|
88
|
+
**Why it matters:**
|
|
89
|
+
|
|
90
|
+
- No external CLI dependency for core functionality
|
|
91
|
+
- HiveAdapter is type-safe and testable
|
|
92
|
+
- Plugin works in environments without `bd` installed
|
|
93
|
+
- Better error messages for debugging
|
|
94
|
+
|
|
95
|
+
**Migration:** Run `swarm setup` to update your deployed plugin.
|
|
96
|
+
|
|
3
97
|
## 0.29.0
|
|
4
98
|
|
|
5
99
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -220,7 +220,8 @@ These tools significantly enhance the swarm experience:
|
|
|
220
220
|
|------|---------|---------|
|
|
221
221
|
| [CASS](https://github.com/Dicklesworthstone/coding_agent_session_search) | Historical context - queries past sessions for similar decompositions | See below |
|
|
222
222
|
| [UBS](https://github.com/Dicklesworthstone/ultimate_bug_scanner) | Bug scanning - runs on subtask completion to catch issues | See below |
|
|
223
|
-
|
|
223
|
+
|
|
224
|
+
> **Note:** Semantic memory is now embedded in the plugin. No separate installation needed - just install Ollama for vector embeddings.
|
|
224
225
|
|
|
225
226
|
#### Installing CASS
|
|
226
227
|
|
|
@@ -243,15 +244,11 @@ cd ultimate_bug_scanner
|
|
|
243
244
|
pip install -e .
|
|
244
245
|
```
|
|
245
246
|
|
|
246
|
-
#### Installing semantic-memory
|
|
247
|
-
|
|
248
|
-
The `semantic-memory_check` tool verifies Ollama is ready (see installation steps above).
|
|
249
|
-
|
|
250
247
|
**Why install these?**
|
|
251
248
|
|
|
252
249
|
- **CASS** - When you run `/swarm "Add OAuth"`, the coordinator queries CASS for similar past tasks. Without it, decomposition is based only on the current task description.
|
|
253
250
|
- **UBS** - Every `swarm_complete` runs UBS to scan for bugs. Without it, you lose automatic bug detection.
|
|
254
|
-
- **
|
|
251
|
+
- **Ollama** - Enables vector similarity search for semantic memory. Without it, memory falls back to full-text search (still functional, less semantic).
|
|
255
252
|
|
|
256
253
|
Run `swarm doctor` to check which dependencies are installed.
|
|
257
254
|
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Tests for swarm CLI file operation helpers
|
|
4
|
+
*
|
|
5
|
+
* These tests verify the verbose output helpers used in `swarm setup`:
|
|
6
|
+
* - writeFileWithStatus: logs created/updated/unchanged status
|
|
7
|
+
* - mkdirWithStatus: logs directory creation
|
|
8
|
+
* - rmWithStatus: logs file removal
|
|
9
|
+
*/
|
|
10
|
+
import { describe, test, expect, beforeEach, afterEach } from "bun:test";
|
|
11
|
+
import { mkdirSync, rmSync, writeFileSync, existsSync, readFileSync } from "fs";
|
|
12
|
+
import { join } from "path";
|
|
13
|
+
import { tmpdir } from "os";
|
|
14
|
+
|
|
15
|
+
type FileStatus = "created" | "updated" | "unchanged";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Mock logger for testing (matches @clack/prompts API)
|
|
19
|
+
*/
|
|
20
|
+
class MockLogger {
|
|
21
|
+
logs: Array<{ type: string; message: string }> = [];
|
|
22
|
+
|
|
23
|
+
success(msg: string) {
|
|
24
|
+
this.logs.push({ type: "success", message: msg });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
message(msg: string) {
|
|
28
|
+
this.logs.push({ type: "message", message: msg });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
reset() {
|
|
32
|
+
this.logs = [];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
describe("File operation helpers", () => {
|
|
37
|
+
let testDir: string;
|
|
38
|
+
let logger: MockLogger;
|
|
39
|
+
|
|
40
|
+
beforeEach(() => {
|
|
41
|
+
testDir = join(tmpdir(), `swarm-test-${Date.now()}`);
|
|
42
|
+
mkdirSync(testDir, { recursive: true });
|
|
43
|
+
logger = new MockLogger();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
afterEach(() => {
|
|
47
|
+
if (existsSync(testDir)) {
|
|
48
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe("writeFileWithStatus", () => {
|
|
53
|
+
// Helper that mimics the implementation
|
|
54
|
+
function writeFileWithStatus(path: string, content: string, label: string): FileStatus {
|
|
55
|
+
const exists = existsSync(path);
|
|
56
|
+
|
|
57
|
+
if (exists) {
|
|
58
|
+
const current = readFileSync(path, "utf-8");
|
|
59
|
+
if (current === content) {
|
|
60
|
+
logger.message(` ${label}: ${path} (unchanged)`);
|
|
61
|
+
return "unchanged";
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
writeFileSync(path, content);
|
|
66
|
+
const status: FileStatus = exists ? "updated" : "created";
|
|
67
|
+
logger.success(`${label}: ${path} (${status})`);
|
|
68
|
+
return status;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
test("returns 'created' for new file", () => {
|
|
72
|
+
const filePath = join(testDir, "new.txt");
|
|
73
|
+
const result = writeFileWithStatus(filePath, "content", "Test");
|
|
74
|
+
|
|
75
|
+
expect(result).toBe("created");
|
|
76
|
+
expect(logger.logs[0].type).toBe("success");
|
|
77
|
+
expect(logger.logs[0].message).toContain("(created)");
|
|
78
|
+
expect(existsSync(filePath)).toBe(true);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("returns 'unchanged' if content is same", () => {
|
|
82
|
+
const filePath = join(testDir, "existing.txt");
|
|
83
|
+
writeFileSync(filePath, "same content");
|
|
84
|
+
|
|
85
|
+
const result = writeFileWithStatus(filePath, "same content", "Test");
|
|
86
|
+
|
|
87
|
+
expect(result).toBe("unchanged");
|
|
88
|
+
expect(logger.logs[0].type).toBe("message");
|
|
89
|
+
expect(logger.logs[0].message).toContain("(unchanged)");
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("returns 'updated' if content differs", () => {
|
|
93
|
+
const filePath = join(testDir, "existing.txt");
|
|
94
|
+
writeFileSync(filePath, "old content");
|
|
95
|
+
|
|
96
|
+
const result = writeFileWithStatus(filePath, "new content", "Test");
|
|
97
|
+
|
|
98
|
+
expect(result).toBe("updated");
|
|
99
|
+
expect(logger.logs[0].type).toBe("success");
|
|
100
|
+
expect(logger.logs[0].message).toContain("(updated)");
|
|
101
|
+
expect(readFileSync(filePath, "utf-8")).toBe("new content");
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe("mkdirWithStatus", () => {
|
|
106
|
+
function mkdirWithStatus(path: string): boolean {
|
|
107
|
+
if (!existsSync(path)) {
|
|
108
|
+
mkdirSync(path, { recursive: true });
|
|
109
|
+
logger.message(` Created directory: ${path}`);
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
test("creates directory and logs when it doesn't exist", () => {
|
|
116
|
+
const dirPath = join(testDir, "newdir");
|
|
117
|
+
const result = mkdirWithStatus(dirPath);
|
|
118
|
+
|
|
119
|
+
expect(result).toBe(true);
|
|
120
|
+
expect(existsSync(dirPath)).toBe(true);
|
|
121
|
+
expect(logger.logs[0].type).toBe("message");
|
|
122
|
+
expect(logger.logs[0].message).toContain("Created directory");
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test("returns false when directory already exists", () => {
|
|
126
|
+
const dirPath = join(testDir, "existing");
|
|
127
|
+
mkdirSync(dirPath);
|
|
128
|
+
|
|
129
|
+
const result = mkdirWithStatus(dirPath);
|
|
130
|
+
|
|
131
|
+
expect(result).toBe(false);
|
|
132
|
+
expect(logger.logs.length).toBe(0);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
describe("rmWithStatus", () => {
|
|
137
|
+
function rmWithStatus(path: string, label: string): void {
|
|
138
|
+
if (existsSync(path)) {
|
|
139
|
+
rmSync(path);
|
|
140
|
+
logger.message(` Removed ${label}: ${path}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
test("removes file and logs when it exists", () => {
|
|
145
|
+
const filePath = join(testDir, "todelete.txt");
|
|
146
|
+
writeFileSync(filePath, "content");
|
|
147
|
+
|
|
148
|
+
rmWithStatus(filePath, "test file");
|
|
149
|
+
|
|
150
|
+
expect(existsSync(filePath)).toBe(false);
|
|
151
|
+
expect(logger.logs[0].type).toBe("message");
|
|
152
|
+
expect(logger.logs[0].message).toContain("Removed test file");
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test("does nothing when file doesn't exist", () => {
|
|
156
|
+
const filePath = join(testDir, "nonexistent.txt");
|
|
157
|
+
|
|
158
|
+
rmWithStatus(filePath, "test file");
|
|
159
|
+
|
|
160
|
+
expect(logger.logs.length).toBe(0);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
});
|