opencode-swarm-plugin 0.26.0 → 0.27.0
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 +37 -0
- package/README.md +43 -46
- package/bin/swarm.ts +8 -8
- package/dist/compaction-hook.d.ts +57 -0
- package/dist/compaction-hook.d.ts.map +1 -0
- package/dist/hive.d.ts +741 -0
- package/dist/hive.d.ts.map +1 -0
- package/dist/index.d.ts +139 -23
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1418 -387
- package/dist/learning.d.ts +9 -9
- package/dist/plugin.js +1240 -386
- package/dist/schemas/cell-events.d.ts +1352 -0
- package/dist/schemas/{bead-events.d.ts.map → cell-events.d.ts.map} +1 -1
- package/dist/schemas/{bead.d.ts → cell.d.ts} +173 -29
- package/dist/schemas/cell.d.ts.map +1 -0
- package/dist/schemas/index.d.ts +11 -7
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/structured.d.ts +17 -7
- package/dist/structured.d.ts.map +1 -1
- package/dist/swarm-decompose.d.ts +5 -5
- package/dist/swarm-orchestrate.d.ts +16 -2
- package/dist/swarm-orchestrate.d.ts.map +1 -1
- package/dist/swarm-prompts.d.ts +9 -9
- package/dist/swarm-prompts.d.ts.map +1 -1
- package/dist/swarm-review.d.ts +210 -0
- package/dist/swarm-review.d.ts.map +1 -0
- package/dist/swarm-worktree.d.ts +185 -0
- package/dist/swarm-worktree.d.ts.map +1 -0
- package/dist/swarm.d.ts +7 -0
- package/dist/swarm.d.ts.map +1 -1
- package/dist/tool-availability.d.ts +3 -2
- package/dist/tool-availability.d.ts.map +1 -1
- package/docs/analysis-socratic-planner-pattern.md +1 -1
- package/docs/planning/ADR-007-swarm-enhancements-worktree-review.md +168 -0
- package/docs/testing/context-recovery-test.md +2 -2
- package/evals/README.md +2 -2
- package/evals/scorers/index.ts +7 -7
- package/examples/commands/swarm.md +21 -23
- package/examples/plugin-wrapper-template.ts +310 -44
- package/examples/skills/{beads-workflow → hive-workflow}/SKILL.md +40 -40
- package/examples/skills/swarm-coordination/SKILL.md +1 -1
- package/global-skills/swarm-coordination/SKILL.md +14 -14
- package/global-skills/swarm-coordination/references/coordinator-patterns.md +3 -3
- package/package.json +2 -2
- package/src/compaction-hook.ts +161 -0
- package/src/{beads.integration.test.ts → hive.integration.test.ts} +92 -80
- package/src/hive.ts +1017 -0
- package/src/index.ts +57 -20
- package/src/learning.ts +9 -9
- package/src/output-guardrails.test.ts +4 -4
- package/src/output-guardrails.ts +9 -9
- package/src/planning-guardrails.test.ts +1 -1
- package/src/planning-guardrails.ts +1 -1
- package/src/schemas/{bead-events.test.ts → cell-events.test.ts} +83 -77
- package/src/schemas/cell-events.ts +807 -0
- package/src/schemas/{bead.ts → cell.ts} +95 -41
- package/src/schemas/evaluation.ts +1 -1
- package/src/schemas/index.ts +90 -18
- package/src/schemas/swarm-context.ts +2 -2
- package/src/structured.test.ts +15 -15
- package/src/structured.ts +18 -11
- package/src/swarm-decompose.ts +23 -23
- package/src/swarm-orchestrate.ts +135 -21
- package/src/swarm-prompts.ts +43 -43
- package/src/swarm-review.test.ts +702 -0
- package/src/swarm-review.ts +696 -0
- package/src/swarm-worktree.test.ts +501 -0
- package/src/swarm-worktree.ts +575 -0
- package/src/swarm.integration.test.ts +12 -12
- package/src/tool-availability.ts +36 -3
- package/dist/beads.d.ts +0 -383
- package/dist/beads.d.ts.map +0 -1
- package/dist/schemas/bead-events.d.ts +0 -698
- package/dist/schemas/bead.d.ts.map +0 -1
- package/src/beads.ts +0 -800
- package/src/schemas/bead-events.ts +0 -583
|
@@ -1,27 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Hive Integration Tests
|
|
3
3
|
*
|
|
4
|
-
* These tests exercise the
|
|
5
|
-
* They validate the tool wrappers work correctly with actual
|
|
4
|
+
* These tests exercise the HiveAdapter-based tools directly.
|
|
5
|
+
* They validate the tool wrappers work correctly with actual hive operations.
|
|
6
6
|
*
|
|
7
|
-
* Run with: bun test src/
|
|
7
|
+
* Run with: bun test src/hive.integration.test.ts
|
|
8
8
|
*/
|
|
9
9
|
import { describe, it, expect, beforeAll, beforeEach, afterAll } from "vitest";
|
|
10
10
|
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
11
|
+
hive_create,
|
|
12
|
+
hive_create_epic,
|
|
13
|
+
hive_query,
|
|
14
|
+
hive_update,
|
|
15
|
+
hive_close,
|
|
16
|
+
hive_start,
|
|
17
|
+
hive_ready,
|
|
18
|
+
hive_link_thread,
|
|
19
|
+
HiveError,
|
|
20
|
+
getHiveAdapter,
|
|
21
|
+
setHiveWorkingDirectory,
|
|
22
|
+
// Legacy aliases for backward compatibility tests
|
|
23
|
+
hive_create,
|
|
24
|
+
hive_create_epic,
|
|
25
|
+
hive_query,
|
|
26
|
+
hive_update,
|
|
27
|
+
hive_close,
|
|
28
|
+
hive_start,
|
|
29
|
+
hive_ready,
|
|
18
30
|
beads_link_thread,
|
|
19
31
|
BeadError,
|
|
20
32
|
getBeadsAdapter,
|
|
21
33
|
setBeadsWorkingDirectory,
|
|
22
|
-
} from "./
|
|
23
|
-
import type { Bead, EpicCreateResult } from "./schemas";
|
|
24
|
-
import type {
|
|
34
|
+
} from "./hive";
|
|
35
|
+
import type { Cell, Bead, EpicCreateResult } from "./schemas";
|
|
36
|
+
import type { HiveAdapter } from "swarm-mail";
|
|
25
37
|
|
|
26
38
|
/**
|
|
27
39
|
* Mock tool context for execute functions
|
|
@@ -54,7 +66,7 @@ const TEST_PROJECT_KEY = `/tmp/beads-integration-test-${Date.now()}`;
|
|
|
54
66
|
/**
|
|
55
67
|
* Adapter instance for verification
|
|
56
68
|
*/
|
|
57
|
-
let adapter:
|
|
69
|
+
let adapter: HiveAdapter;
|
|
58
70
|
|
|
59
71
|
/**
|
|
60
72
|
* Cleanup helper - close all created beads after tests
|
|
@@ -62,7 +74,7 @@ let adapter: BeadsAdapter;
|
|
|
62
74
|
async function cleanupBeads() {
|
|
63
75
|
for (const id of createdBeadIds) {
|
|
64
76
|
try {
|
|
65
|
-
await
|
|
77
|
+
await hive_close.execute({ id, reason: "Test cleanup" }, mockContext);
|
|
66
78
|
} catch {
|
|
67
79
|
// Ignore cleanup errors - bead may already be closed
|
|
68
80
|
}
|
|
@@ -84,9 +96,9 @@ describe("beads integration", () => {
|
|
|
84
96
|
await cleanupBeads();
|
|
85
97
|
});
|
|
86
98
|
|
|
87
|
-
describe("
|
|
99
|
+
describe("hive_create", () => {
|
|
88
100
|
it("creates a bead with minimal args (title only)", async () => {
|
|
89
|
-
const result = await
|
|
101
|
+
const result = await hive_create.execute(
|
|
90
102
|
{ title: "Test bead minimal" },
|
|
91
103
|
mockContext,
|
|
92
104
|
);
|
|
@@ -102,7 +114,7 @@ describe("beads integration", () => {
|
|
|
102
114
|
});
|
|
103
115
|
|
|
104
116
|
it("creates a bead with all options", async () => {
|
|
105
|
-
const result = await
|
|
117
|
+
const result = await hive_create.execute(
|
|
106
118
|
{
|
|
107
119
|
title: "Test bug with priority",
|
|
108
120
|
type: "bug",
|
|
@@ -122,7 +134,7 @@ describe("beads integration", () => {
|
|
|
122
134
|
});
|
|
123
135
|
|
|
124
136
|
it("creates a feature type bead", async () => {
|
|
125
|
-
const result = await
|
|
137
|
+
const result = await hive_create.execute(
|
|
126
138
|
{ title: "New feature request", type: "feature", priority: 1 },
|
|
127
139
|
mockContext,
|
|
128
140
|
);
|
|
@@ -135,7 +147,7 @@ describe("beads integration", () => {
|
|
|
135
147
|
});
|
|
136
148
|
|
|
137
149
|
it("creates a chore type bead", async () => {
|
|
138
|
-
const result = await
|
|
150
|
+
const result = await hive_create.execute(
|
|
139
151
|
{ title: "Cleanup task", type: "chore", priority: 3 },
|
|
140
152
|
mockContext,
|
|
141
153
|
);
|
|
@@ -148,12 +160,12 @@ describe("beads integration", () => {
|
|
|
148
160
|
});
|
|
149
161
|
});
|
|
150
162
|
|
|
151
|
-
describe("
|
|
163
|
+
describe("hive_query", () => {
|
|
152
164
|
let testBeadId: string;
|
|
153
165
|
|
|
154
166
|
beforeEach(async () => {
|
|
155
167
|
// Create a test bead for query tests
|
|
156
|
-
const result = await
|
|
168
|
+
const result = await hive_create.execute(
|
|
157
169
|
{ title: "Query test bead", type: "task" },
|
|
158
170
|
mockContext,
|
|
159
171
|
);
|
|
@@ -163,7 +175,7 @@ describe("beads integration", () => {
|
|
|
163
175
|
});
|
|
164
176
|
|
|
165
177
|
it("queries all open beads", async () => {
|
|
166
|
-
const result = await
|
|
178
|
+
const result = await hive_query.execute({ status: "open" }, mockContext);
|
|
167
179
|
|
|
168
180
|
const beads = parseResponse<Bead[]>(result);
|
|
169
181
|
|
|
@@ -173,7 +185,7 @@ describe("beads integration", () => {
|
|
|
173
185
|
});
|
|
174
186
|
|
|
175
187
|
it("queries beads by type", async () => {
|
|
176
|
-
const result = await
|
|
188
|
+
const result = await hive_query.execute({ type: "task" }, mockContext);
|
|
177
189
|
|
|
178
190
|
const beads = parseResponse<Bead[]>(result);
|
|
179
191
|
|
|
@@ -182,7 +194,7 @@ describe("beads integration", () => {
|
|
|
182
194
|
});
|
|
183
195
|
|
|
184
196
|
it("queries ready beads (unblocked)", async () => {
|
|
185
|
-
const result = await
|
|
197
|
+
const result = await hive_query.execute({ ready: true }, mockContext);
|
|
186
198
|
|
|
187
199
|
const beads = parseResponse<Bead[]>(result);
|
|
188
200
|
|
|
@@ -196,7 +208,7 @@ describe("beads integration", () => {
|
|
|
196
208
|
it("limits results", async () => {
|
|
197
209
|
// Create multiple beads first
|
|
198
210
|
for (let i = 0; i < 5; i++) {
|
|
199
|
-
const result = await
|
|
211
|
+
const result = await hive_create.execute(
|
|
200
212
|
{ title: `Limit test bead ${i}` },
|
|
201
213
|
mockContext,
|
|
202
214
|
);
|
|
@@ -204,14 +216,14 @@ describe("beads integration", () => {
|
|
|
204
216
|
createdBeadIds.push(bead.id);
|
|
205
217
|
}
|
|
206
218
|
|
|
207
|
-
const result = await
|
|
219
|
+
const result = await hive_query.execute({ limit: 3 }, mockContext);
|
|
208
220
|
|
|
209
221
|
const beads = parseResponse<Bead[]>(result);
|
|
210
222
|
expect(beads.length).toBeLessThanOrEqual(3);
|
|
211
223
|
});
|
|
212
224
|
|
|
213
225
|
it("combines filters", async () => {
|
|
214
|
-
const result = await
|
|
226
|
+
const result = await hive_query.execute(
|
|
215
227
|
{ status: "open", type: "task", limit: 5 },
|
|
216
228
|
mockContext,
|
|
217
229
|
);
|
|
@@ -227,11 +239,11 @@ describe("beads integration", () => {
|
|
|
227
239
|
});
|
|
228
240
|
});
|
|
229
241
|
|
|
230
|
-
describe("
|
|
242
|
+
describe("hive_update", () => {
|
|
231
243
|
let testBeadId: string;
|
|
232
244
|
|
|
233
245
|
beforeEach(async () => {
|
|
234
|
-
const result = await
|
|
246
|
+
const result = await hive_create.execute(
|
|
235
247
|
{ title: "Update test bead", description: "Original description" },
|
|
236
248
|
mockContext,
|
|
237
249
|
);
|
|
@@ -241,7 +253,7 @@ describe("beads integration", () => {
|
|
|
241
253
|
});
|
|
242
254
|
|
|
243
255
|
it("updates bead status", async () => {
|
|
244
|
-
const result = await
|
|
256
|
+
const result = await hive_update.execute(
|
|
245
257
|
{ id: testBeadId, status: "in_progress" },
|
|
246
258
|
mockContext,
|
|
247
259
|
);
|
|
@@ -251,7 +263,7 @@ describe("beads integration", () => {
|
|
|
251
263
|
});
|
|
252
264
|
|
|
253
265
|
it("updates bead description", async () => {
|
|
254
|
-
const result = await
|
|
266
|
+
const result = await hive_update.execute(
|
|
255
267
|
{ id: testBeadId, description: "Updated description" },
|
|
256
268
|
mockContext,
|
|
257
269
|
);
|
|
@@ -261,7 +273,7 @@ describe("beads integration", () => {
|
|
|
261
273
|
});
|
|
262
274
|
|
|
263
275
|
it("updates bead priority", async () => {
|
|
264
|
-
const result = await
|
|
276
|
+
const result = await hive_update.execute(
|
|
265
277
|
{ id: testBeadId, priority: 0 },
|
|
266
278
|
mockContext,
|
|
267
279
|
);
|
|
@@ -271,7 +283,7 @@ describe("beads integration", () => {
|
|
|
271
283
|
});
|
|
272
284
|
|
|
273
285
|
it("updates multiple fields at once", async () => {
|
|
274
|
-
const result = await
|
|
286
|
+
const result = await hive_update.execute(
|
|
275
287
|
{
|
|
276
288
|
id: testBeadId,
|
|
277
289
|
status: "blocked",
|
|
@@ -289,7 +301,7 @@ describe("beads integration", () => {
|
|
|
289
301
|
|
|
290
302
|
it("throws BeadError for invalid bead ID", async () => {
|
|
291
303
|
await expect(
|
|
292
|
-
|
|
304
|
+
hive_update.execute(
|
|
293
305
|
{ id: "nonexistent-bead-xyz", status: "closed" },
|
|
294
306
|
mockContext,
|
|
295
307
|
),
|
|
@@ -297,17 +309,17 @@ describe("beads integration", () => {
|
|
|
297
309
|
});
|
|
298
310
|
});
|
|
299
311
|
|
|
300
|
-
describe("
|
|
312
|
+
describe("hive_close", () => {
|
|
301
313
|
it("closes a bead with reason", async () => {
|
|
302
314
|
// Create a fresh bead to close
|
|
303
|
-
const createResult = await
|
|
315
|
+
const createResult = await hive_create.execute(
|
|
304
316
|
{ title: "Bead to close" },
|
|
305
317
|
mockContext,
|
|
306
318
|
);
|
|
307
319
|
const created = parseResponse<Bead>(createResult);
|
|
308
320
|
// Don't add to cleanup since we're closing it
|
|
309
321
|
|
|
310
|
-
const result = await
|
|
322
|
+
const result = await hive_close.execute(
|
|
311
323
|
{ id: created.id, reason: "Task completed successfully" },
|
|
312
324
|
mockContext,
|
|
313
325
|
);
|
|
@@ -316,14 +328,14 @@ describe("beads integration", () => {
|
|
|
316
328
|
expect(result).toContain(created.id);
|
|
317
329
|
|
|
318
330
|
// Verify it's actually closed using adapter
|
|
319
|
-
const closedBead = await adapter.
|
|
331
|
+
const closedBead = await adapter.getCell(TEST_PROJECT_KEY, created.id);
|
|
320
332
|
expect(closedBead).toBeDefined();
|
|
321
333
|
expect(closedBead!.status).toBe("closed");
|
|
322
334
|
});
|
|
323
335
|
|
|
324
336
|
it("throws BeadError for invalid bead ID", async () => {
|
|
325
337
|
await expect(
|
|
326
|
-
|
|
338
|
+
hive_close.execute(
|
|
327
339
|
{ id: "nonexistent-bead-xyz", reason: "Test" },
|
|
328
340
|
mockContext,
|
|
329
341
|
),
|
|
@@ -331,10 +343,10 @@ describe("beads integration", () => {
|
|
|
331
343
|
});
|
|
332
344
|
});
|
|
333
345
|
|
|
334
|
-
describe("
|
|
346
|
+
describe("hive_start", () => {
|
|
335
347
|
it("marks a bead as in_progress", async () => {
|
|
336
348
|
// Create a fresh bead
|
|
337
|
-
const createResult = await
|
|
349
|
+
const createResult = await hive_create.execute(
|
|
338
350
|
{ title: "Bead to start" },
|
|
339
351
|
mockContext,
|
|
340
352
|
);
|
|
@@ -343,35 +355,35 @@ describe("beads integration", () => {
|
|
|
343
355
|
|
|
344
356
|
expect(created.status).toBe("open");
|
|
345
357
|
|
|
346
|
-
const result = await
|
|
358
|
+
const result = await hive_start.execute({ id: created.id }, mockContext);
|
|
347
359
|
|
|
348
360
|
expect(result).toContain("Started");
|
|
349
361
|
expect(result).toContain(created.id);
|
|
350
362
|
|
|
351
363
|
// Verify status changed using adapter
|
|
352
|
-
const startedBead = await adapter.
|
|
364
|
+
const startedBead = await adapter.getCell(TEST_PROJECT_KEY, created.id);
|
|
353
365
|
expect(startedBead).toBeDefined();
|
|
354
366
|
expect(startedBead!.status).toBe("in_progress");
|
|
355
367
|
});
|
|
356
368
|
|
|
357
369
|
it("throws BeadError for invalid bead ID", async () => {
|
|
358
370
|
await expect(
|
|
359
|
-
|
|
371
|
+
hive_start.execute({ id: "nonexistent-bead-xyz" }, mockContext),
|
|
360
372
|
).rejects.toThrow(BeadError);
|
|
361
373
|
});
|
|
362
374
|
});
|
|
363
375
|
|
|
364
|
-
describe("
|
|
376
|
+
describe("hive_ready", () => {
|
|
365
377
|
it("returns the highest priority unblocked bead", async () => {
|
|
366
378
|
// Create a high priority bead
|
|
367
|
-
const createResult = await
|
|
379
|
+
const createResult = await hive_create.execute(
|
|
368
380
|
{ title: "High priority ready bead", priority: 0 },
|
|
369
381
|
mockContext,
|
|
370
382
|
);
|
|
371
383
|
const created = parseResponse<Bead>(createResult);
|
|
372
384
|
createdBeadIds.push(created.id);
|
|
373
385
|
|
|
374
|
-
const result = await
|
|
386
|
+
const result = await hive_ready.execute({}, mockContext);
|
|
375
387
|
|
|
376
388
|
// Should return a bead (or "No ready beads" message)
|
|
377
389
|
if (result !== "No ready beads") {
|
|
@@ -385,7 +397,7 @@ describe("beads integration", () => {
|
|
|
385
397
|
it("returns no ready beads message when all are closed", async () => {
|
|
386
398
|
// This test depends on the state of the beads database
|
|
387
399
|
// It may return a bead if there are open ones
|
|
388
|
-
const result = await
|
|
400
|
+
const result = await hive_ready.execute({}, mockContext);
|
|
389
401
|
|
|
390
402
|
expect(typeof result).toBe("string");
|
|
391
403
|
// Either a JSON bead or "No ready beads"
|
|
@@ -398,9 +410,9 @@ describe("beads integration", () => {
|
|
|
398
410
|
});
|
|
399
411
|
});
|
|
400
412
|
|
|
401
|
-
describe("
|
|
413
|
+
describe("hive_create_epic", () => {
|
|
402
414
|
it("creates an epic with subtasks", async () => {
|
|
403
|
-
const result = await
|
|
415
|
+
const result = await hive_create_epic.execute(
|
|
404
416
|
{
|
|
405
417
|
epic_title: "Integration test epic",
|
|
406
418
|
epic_description: "Testing epic creation",
|
|
@@ -427,14 +439,14 @@ describe("beads integration", () => {
|
|
|
427
439
|
// Subtasks should have parent_id pointing to epic
|
|
428
440
|
// Verify via adapter since parent_id may not be in the output schema
|
|
429
441
|
for (const subtask of epicResult.subtasks) {
|
|
430
|
-
const subtaskBead = await adapter.
|
|
442
|
+
const subtaskBead = await adapter.getCell(TEST_PROJECT_KEY, subtask.id);
|
|
431
443
|
expect(subtaskBead).toBeDefined();
|
|
432
444
|
expect(subtaskBead!.parent_id).toBe(epicResult.epic.id);
|
|
433
445
|
}
|
|
434
446
|
});
|
|
435
447
|
|
|
436
448
|
it("creates an epic with files metadata in subtasks", async () => {
|
|
437
|
-
const result = await
|
|
449
|
+
const result = await hive_create_epic.execute(
|
|
438
450
|
{
|
|
439
451
|
epic_title: "Epic with file references",
|
|
440
452
|
subtasks: [
|
|
@@ -460,7 +472,7 @@ describe("beads integration", () => {
|
|
|
460
472
|
});
|
|
461
473
|
|
|
462
474
|
it("creates epic with single subtask", async () => {
|
|
463
|
-
const result = await
|
|
475
|
+
const result = await hive_create_epic.execute(
|
|
464
476
|
{
|
|
465
477
|
epic_title: "Single subtask epic",
|
|
466
478
|
subtasks: [{ title: "Only task", priority: 1 }],
|
|
@@ -478,7 +490,7 @@ describe("beads integration", () => {
|
|
|
478
490
|
|
|
479
491
|
it("preserves subtask order", async () => {
|
|
480
492
|
const titles = ["First", "Second", "Third", "Fourth"];
|
|
481
|
-
const result = await
|
|
493
|
+
const result = await hive_create_epic.execute(
|
|
482
494
|
{
|
|
483
495
|
epic_title: "Ordered subtasks epic",
|
|
484
496
|
subtasks: titles.map((title, i) => ({ title, priority: 2 })),
|
|
@@ -504,7 +516,7 @@ describe("beads integration", () => {
|
|
|
504
516
|
let testBeadId: string;
|
|
505
517
|
|
|
506
518
|
beforeEach(async () => {
|
|
507
|
-
const result = await
|
|
519
|
+
const result = await hive_create.execute(
|
|
508
520
|
{ title: "Thread link test bead" },
|
|
509
521
|
mockContext,
|
|
510
522
|
);
|
|
@@ -516,7 +528,7 @@ describe("beads integration", () => {
|
|
|
516
528
|
it("links a bead to an Agent Mail thread", async () => {
|
|
517
529
|
const threadId = "test-thread-123";
|
|
518
530
|
const result = await beads_link_thread.execute(
|
|
519
|
-
{
|
|
531
|
+
{ cell_id: testBeadId, thread_id: threadId },
|
|
520
532
|
mockContext,
|
|
521
533
|
);
|
|
522
534
|
|
|
@@ -525,7 +537,7 @@ describe("beads integration", () => {
|
|
|
525
537
|
expect(result).toContain(threadId);
|
|
526
538
|
|
|
527
539
|
// Verify the thread marker is in the description using adapter
|
|
528
|
-
const linkedBead = await adapter.
|
|
540
|
+
const linkedBead = await adapter.getCell(TEST_PROJECT_KEY, testBeadId);
|
|
529
541
|
expect(linkedBead).toBeDefined();
|
|
530
542
|
expect(linkedBead!.description).toContain(`[thread:${threadId}]`);
|
|
531
543
|
});
|
|
@@ -535,13 +547,13 @@ describe("beads integration", () => {
|
|
|
535
547
|
|
|
536
548
|
// Link once
|
|
537
549
|
await beads_link_thread.execute(
|
|
538
|
-
{
|
|
550
|
+
{ cell_id: testBeadId, thread_id: threadId },
|
|
539
551
|
mockContext,
|
|
540
552
|
);
|
|
541
553
|
|
|
542
554
|
// Try to link again
|
|
543
555
|
const result = await beads_link_thread.execute(
|
|
544
|
-
{
|
|
556
|
+
{ cell_id: testBeadId, thread_id: threadId },
|
|
545
557
|
mockContext,
|
|
546
558
|
);
|
|
547
559
|
|
|
@@ -550,19 +562,19 @@ describe("beads integration", () => {
|
|
|
550
562
|
|
|
551
563
|
it("preserves existing description when linking", async () => {
|
|
552
564
|
// Update bead with a description first
|
|
553
|
-
await
|
|
565
|
+
await hive_update.execute(
|
|
554
566
|
{ id: testBeadId, description: "Important context here" },
|
|
555
567
|
mockContext,
|
|
556
568
|
);
|
|
557
569
|
|
|
558
570
|
const threadId = "test-thread-789";
|
|
559
571
|
await beads_link_thread.execute(
|
|
560
|
-
{
|
|
572
|
+
{ cell_id: testBeadId, thread_id: threadId },
|
|
561
573
|
mockContext,
|
|
562
574
|
);
|
|
563
575
|
|
|
564
576
|
// Verify both original description and thread marker exist using adapter
|
|
565
|
-
const linkedBead = await adapter.
|
|
577
|
+
const linkedBead = await adapter.getCell(TEST_PROJECT_KEY, testBeadId);
|
|
566
578
|
expect(linkedBead).toBeDefined();
|
|
567
579
|
expect(linkedBead!.description).toContain("Important context here");
|
|
568
580
|
expect(linkedBead!.description).toContain(`[thread:${threadId}]`);
|
|
@@ -571,7 +583,7 @@ describe("beads integration", () => {
|
|
|
571
583
|
it("throws BeadError for invalid bead ID", async () => {
|
|
572
584
|
await expect(
|
|
573
585
|
beads_link_thread.execute(
|
|
574
|
-
{
|
|
586
|
+
{ cell_id: "nonexistent-bead-xyz", thread_id: "thread-123" },
|
|
575
587
|
mockContext,
|
|
576
588
|
),
|
|
577
589
|
).rejects.toThrow(BeadError);
|
|
@@ -581,14 +593,14 @@ describe("beads integration", () => {
|
|
|
581
593
|
describe("error handling", () => {
|
|
582
594
|
it("throws BeadError with command info on adapter failure", async () => {
|
|
583
595
|
try {
|
|
584
|
-
await
|
|
596
|
+
await hive_update.execute(
|
|
585
597
|
{ id: "definitely-not-a-real-bead-id", status: "closed" },
|
|
586
598
|
mockContext,
|
|
587
599
|
);
|
|
588
600
|
expect.fail("Should have thrown");
|
|
589
601
|
} catch (error) {
|
|
590
602
|
expect(error).toBeInstanceOf(BeadError);
|
|
591
|
-
const beadError = error as BeadError
|
|
603
|
+
const beadError = error as InstanceType<typeof BeadError>;
|
|
592
604
|
expect(beadError.command).toBeDefined();
|
|
593
605
|
}
|
|
594
606
|
});
|
|
@@ -597,7 +609,7 @@ describe("beads integration", () => {
|
|
|
597
609
|
describe("workflow integration", () => {
|
|
598
610
|
it("complete bead lifecycle: create -> start -> update -> close", async () => {
|
|
599
611
|
// 1. Create
|
|
600
|
-
const createResult = await
|
|
612
|
+
const createResult = await hive_create.execute(
|
|
601
613
|
{ title: "Lifecycle test bead", type: "task", priority: 2 },
|
|
602
614
|
mockContext,
|
|
603
615
|
);
|
|
@@ -605,14 +617,14 @@ describe("beads integration", () => {
|
|
|
605
617
|
expect(bead.status).toBe("open");
|
|
606
618
|
|
|
607
619
|
// 2. Start (in_progress)
|
|
608
|
-
const startResult = await
|
|
620
|
+
const startResult = await hive_start.execute(
|
|
609
621
|
{ id: bead.id },
|
|
610
622
|
mockContext,
|
|
611
623
|
);
|
|
612
624
|
expect(startResult).toContain("Started");
|
|
613
625
|
|
|
614
626
|
// 3. Update (add progress note)
|
|
615
|
-
const updateResult = await
|
|
627
|
+
const updateResult = await hive_update.execute(
|
|
616
628
|
{ id: bead.id, description: "50% complete" },
|
|
617
629
|
mockContext,
|
|
618
630
|
);
|
|
@@ -620,21 +632,21 @@ describe("beads integration", () => {
|
|
|
620
632
|
expect(updated.description).toContain("50%");
|
|
621
633
|
|
|
622
634
|
// 4. Close
|
|
623
|
-
const closeResult = await
|
|
635
|
+
const closeResult = await hive_close.execute(
|
|
624
636
|
{ id: bead.id, reason: "Completed successfully" },
|
|
625
637
|
mockContext,
|
|
626
638
|
);
|
|
627
639
|
expect(closeResult).toContain("Closed");
|
|
628
640
|
|
|
629
641
|
// Verify final state using adapter
|
|
630
|
-
const finalBead = await adapter.
|
|
642
|
+
const finalBead = await adapter.getCell(TEST_PROJECT_KEY, bead.id);
|
|
631
643
|
expect(finalBead).toBeDefined();
|
|
632
644
|
expect(finalBead!.status).toBe("closed");
|
|
633
645
|
});
|
|
634
646
|
|
|
635
647
|
it("epic workflow: create epic -> start subtasks -> close subtasks -> close epic", async () => {
|
|
636
648
|
// 1. Create epic with subtasks
|
|
637
|
-
const epicResult = await
|
|
649
|
+
const epicResult = await hive_create_epic.execute(
|
|
638
650
|
{
|
|
639
651
|
epic_title: "Workflow test epic",
|
|
640
652
|
subtasks: [
|
|
@@ -648,32 +660,32 @@ describe("beads integration", () => {
|
|
|
648
660
|
expect(epic.success).toBe(true);
|
|
649
661
|
|
|
650
662
|
// 2. Start and complete first subtask
|
|
651
|
-
await
|
|
652
|
-
await
|
|
663
|
+
await hive_start.execute({ id: epic.subtasks[0].id }, mockContext);
|
|
664
|
+
await hive_close.execute(
|
|
653
665
|
{ id: epic.subtasks[0].id, reason: "Step 1 done" },
|
|
654
666
|
mockContext,
|
|
655
667
|
);
|
|
656
668
|
|
|
657
669
|
// 3. Start and complete second subtask
|
|
658
|
-
await
|
|
659
|
-
await
|
|
670
|
+
await hive_start.execute({ id: epic.subtasks[1].id }, mockContext);
|
|
671
|
+
await hive_close.execute(
|
|
660
672
|
{ id: epic.subtasks[1].id, reason: "Step 2 done" },
|
|
661
673
|
mockContext,
|
|
662
674
|
);
|
|
663
675
|
|
|
664
676
|
// 4. Close the epic
|
|
665
|
-
await
|
|
677
|
+
await hive_close.execute(
|
|
666
678
|
{ id: epic.epic.id, reason: "All subtasks completed" },
|
|
667
679
|
mockContext,
|
|
668
680
|
);
|
|
669
681
|
|
|
670
682
|
// Verify all are closed using adapter
|
|
671
|
-
const epicClosed = await adapter.
|
|
683
|
+
const epicClosed = await adapter.getCell(TEST_PROJECT_KEY, epic.epic.id);
|
|
672
684
|
expect(epicClosed).toBeDefined();
|
|
673
685
|
expect(epicClosed!.status).toBe("closed");
|
|
674
686
|
|
|
675
687
|
for (const subtask of epic.subtasks) {
|
|
676
|
-
const subtaskClosed = await adapter.
|
|
688
|
+
const subtaskClosed = await adapter.getCell(TEST_PROJECT_KEY, subtask.id);
|
|
677
689
|
expect(subtaskClosed).toBeDefined();
|
|
678
690
|
expect(subtaskClosed!.status).toBe("closed");
|
|
679
691
|
}
|