opencode-swarm-plugin 0.31.7 → 0.32.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 +10 -9
- package/.turbo/turbo-test.log +319 -317
- package/CHANGELOG.md +134 -0
- package/README.md +7 -4
- package/bin/swarm.ts +388 -128
- package/dist/compaction-hook.d.ts +1 -1
- package/dist/compaction-hook.d.ts.map +1 -1
- package/dist/hive.d.ts.map +1 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +123 -134
- package/dist/memory-tools.d.ts.map +1 -1
- package/dist/memory.d.ts +5 -4
- package/dist/memory.d.ts.map +1 -1
- package/dist/plugin.js +118 -131
- package/dist/swarm-orchestrate.d.ts +29 -5
- package/dist/swarm-orchestrate.d.ts.map +1 -1
- package/dist/swarm-prompts.d.ts +7 -0
- package/dist/swarm-prompts.d.ts.map +1 -1
- package/dist/swarm.d.ts +0 -2
- package/dist/swarm.d.ts.map +1 -1
- package/evals/lib/{data-loader.test.ts → data-loader.evalite-test.ts} +7 -6
- package/evals/lib/data-loader.ts +1 -1
- package/evals/scorers/{outcome-scorers.test.ts → outcome-scorers.evalite-test.ts} +1 -1
- package/examples/plugin-wrapper-template.ts +19 -4
- package/global-skills/swarm-coordination/SKILL.md +118 -8
- package/package.json +2 -2
- package/src/compaction-hook.ts +5 -3
- package/src/hive.integration.test.ts +83 -1
- package/src/hive.ts +37 -12
- package/src/mandate-storage.integration.test.ts +601 -0
- package/src/memory-tools.ts +6 -4
- package/src/memory.integration.test.ts +117 -49
- package/src/memory.test.ts +41 -217
- package/src/memory.ts +12 -8
- package/src/repo-crawl.integration.test.ts +441 -0
- package/src/skills.integration.test.ts +1056 -0
- package/src/structured.integration.test.ts +817 -0
- package/src/swarm-deferred.integration.test.ts +157 -0
- package/src/swarm-deferred.test.ts +38 -0
- package/src/swarm-mail.integration.test.ts +15 -19
- package/src/swarm-orchestrate.integration.test.ts +282 -0
- package/src/swarm-orchestrate.ts +96 -201
- package/src/swarm-prompts.test.ts +92 -0
- package/src/swarm-prompts.ts +69 -0
- package/src/swarm-review.integration.test.ts +290 -0
- package/src/swarm.integration.test.ts +23 -20
- package/src/tool-adapter.integration.test.ts +1221 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration tests for swarm review feedback flow
|
|
3
|
+
*
|
|
4
|
+
* Tests the coordinator review feedback workflow with real HiveAdapter and swarm-mail.
|
|
5
|
+
* Verifies that review approval/rejection properly updates state and sends messages.
|
|
6
|
+
*
|
|
7
|
+
* **STATUS**: URL_INVALID bug FIXED by commit 7bf9385 (libSQL URL normalization).
|
|
8
|
+
* Tests now execute without URL errors. sendSwarmMessage successfully creates adapters.
|
|
9
|
+
*
|
|
10
|
+
* **REMAINING ISSUE**: Message retrieval not working. getInbox returns empty even though
|
|
11
|
+
* sendSwarmMessage succeeds. Possible causes:
|
|
12
|
+
* - Database adapter instance mismatch (sendSwarmMessage creates new adapter each call)
|
|
13
|
+
* - Message projection not materializing from events
|
|
14
|
+
* - Database path resolution issue between send and receive
|
|
15
|
+
*
|
|
16
|
+
* Tests currently SKIPPED pending message retrieval fix.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
20
|
+
import { join } from "node:path";
|
|
21
|
+
import { mkdirSync, rmSync } from "node:fs";
|
|
22
|
+
import { tmpdir } from "node:os";
|
|
23
|
+
import {
|
|
24
|
+
type SwarmMailAdapter,
|
|
25
|
+
clearAdapterCache,
|
|
26
|
+
getSwarmMailLibSQL,
|
|
27
|
+
} from "swarm-mail";
|
|
28
|
+
import {
|
|
29
|
+
getHiveAdapter,
|
|
30
|
+
hive_create,
|
|
31
|
+
setHiveWorkingDirectory,
|
|
32
|
+
} from "./hive";
|
|
33
|
+
import { swarm_review, swarm_review_feedback } from "./swarm-review";
|
|
34
|
+
|
|
35
|
+
const mockContext = {
|
|
36
|
+
sessionID: `test-review-integration-${Date.now()}`,
|
|
37
|
+
messageID: `test-message-${Date.now()}`,
|
|
38
|
+
agent: "test-coordinator",
|
|
39
|
+
abort: new AbortController().signal,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
describe("swarm_review integration", () => {
|
|
43
|
+
let testProjectPath: string;
|
|
44
|
+
let swarmMail: SwarmMailAdapter;
|
|
45
|
+
|
|
46
|
+
beforeEach(async () => {
|
|
47
|
+
// Create temp project directory
|
|
48
|
+
testProjectPath = join(tmpdir(), `swarm-review-test-${Date.now()}`);
|
|
49
|
+
mkdirSync(testProjectPath, { recursive: true });
|
|
50
|
+
|
|
51
|
+
// Initialize swarm-mail with file-based database
|
|
52
|
+
// (in-memory doesn't work with sendSwarmMessage's auto-adapter creation)
|
|
53
|
+
swarmMail = await getSwarmMailLibSQL(testProjectPath);
|
|
54
|
+
|
|
55
|
+
// Set hive working directory so hive tools work
|
|
56
|
+
setHiveWorkingDirectory(testProjectPath);
|
|
57
|
+
|
|
58
|
+
// Register coordinator and worker agents
|
|
59
|
+
await swarmMail.registerAgent(testProjectPath, "coordinator", {
|
|
60
|
+
program: "test",
|
|
61
|
+
model: "test-model",
|
|
62
|
+
});
|
|
63
|
+
await swarmMail.registerAgent(testProjectPath, "TestWorker", {
|
|
64
|
+
program: "test",
|
|
65
|
+
model: "test-model",
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
afterEach(async () => {
|
|
70
|
+
// Clean up
|
|
71
|
+
await swarmMail.close();
|
|
72
|
+
clearAdapterCache();
|
|
73
|
+
rmSync(testProjectPath, { recursive: true, force: true });
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("review approved flow", async () => {
|
|
77
|
+
// Setup: create epic + subtask via hive tools
|
|
78
|
+
const epicResult = await hive_create.execute(
|
|
79
|
+
{
|
|
80
|
+
title: "Test Epic",
|
|
81
|
+
type: "epic",
|
|
82
|
+
priority: 1,
|
|
83
|
+
},
|
|
84
|
+
mockContext
|
|
85
|
+
);
|
|
86
|
+
const epic = JSON.parse(epicResult);
|
|
87
|
+
|
|
88
|
+
const subtaskResult = await hive_create.execute(
|
|
89
|
+
{
|
|
90
|
+
title: "Test Subtask",
|
|
91
|
+
type: "task",
|
|
92
|
+
priority: 2,
|
|
93
|
+
parent_id: epic.id,
|
|
94
|
+
},
|
|
95
|
+
mockContext
|
|
96
|
+
);
|
|
97
|
+
const subtask = JSON.parse(subtaskResult);
|
|
98
|
+
|
|
99
|
+
// Call swarm_review to generate review prompt
|
|
100
|
+
const reviewResult = await swarm_review.execute(
|
|
101
|
+
{
|
|
102
|
+
project_key: testProjectPath,
|
|
103
|
+
epic_id: epic.id,
|
|
104
|
+
task_id: subtask.id,
|
|
105
|
+
files_touched: ["test.ts"],
|
|
106
|
+
},
|
|
107
|
+
mockContext
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
const reviewParsed = JSON.parse(reviewResult);
|
|
111
|
+
expect(reviewParsed).toHaveProperty("review_prompt");
|
|
112
|
+
expect(reviewParsed.context.epic_id).toBe(epic.id);
|
|
113
|
+
expect(reviewParsed.context.task_id).toBe(subtask.id);
|
|
114
|
+
expect(reviewParsed.context.remaining_attempts).toBe(3);
|
|
115
|
+
|
|
116
|
+
// Call swarm_review_feedback with status="approved"
|
|
117
|
+
const feedbackResult = await swarm_review_feedback.execute(
|
|
118
|
+
{
|
|
119
|
+
project_key: testProjectPath,
|
|
120
|
+
task_id: subtask.id,
|
|
121
|
+
worker_id: "TestWorker",
|
|
122
|
+
status: "approved",
|
|
123
|
+
summary: "Looks good, clean implementation",
|
|
124
|
+
},
|
|
125
|
+
mockContext
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
const feedbackParsed = JSON.parse(feedbackResult);
|
|
129
|
+
expect(feedbackParsed.success).toBe(true);
|
|
130
|
+
expect(feedbackParsed.status).toBe("approved");
|
|
131
|
+
expect(feedbackParsed.task_id).toBe(subtask.id);
|
|
132
|
+
|
|
133
|
+
// Verify message was sent to worker
|
|
134
|
+
const messages = await swarmMail.getInbox(
|
|
135
|
+
testProjectPath,
|
|
136
|
+
"TestWorker",
|
|
137
|
+
{ limit: 10 }
|
|
138
|
+
);
|
|
139
|
+
expect(messages.length).toBeGreaterThan(0);
|
|
140
|
+
|
|
141
|
+
const approvalMessage = messages.find((m) =>
|
|
142
|
+
m.subject.includes("APPROVED")
|
|
143
|
+
);
|
|
144
|
+
expect(approvalMessage).toBeDefined();
|
|
145
|
+
expect(approvalMessage?.subject).toContain(subtask.id);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test("review needs_changes flow", async () => {
|
|
149
|
+
// Setup: create epic + subtask
|
|
150
|
+
const epicResult = await hive_create.execute(
|
|
151
|
+
{
|
|
152
|
+
title: "Test Epic",
|
|
153
|
+
type: "epic",
|
|
154
|
+
priority: 1,
|
|
155
|
+
},
|
|
156
|
+
mockContext
|
|
157
|
+
);
|
|
158
|
+
const epic = JSON.parse(epicResult);
|
|
159
|
+
|
|
160
|
+
const subtaskResult = await hive_create.execute(
|
|
161
|
+
{
|
|
162
|
+
title: "Test Subtask",
|
|
163
|
+
type: "task",
|
|
164
|
+
priority: 2,
|
|
165
|
+
parent_id: epic.id,
|
|
166
|
+
},
|
|
167
|
+
mockContext
|
|
168
|
+
);
|
|
169
|
+
const subtask = JSON.parse(subtaskResult);
|
|
170
|
+
|
|
171
|
+
// Call swarm_review_feedback with status="needs_changes"
|
|
172
|
+
const issues = [
|
|
173
|
+
{
|
|
174
|
+
file: "src/auth.ts",
|
|
175
|
+
line: 42,
|
|
176
|
+
issue: "Missing null check",
|
|
177
|
+
suggestion: "Add if (!token) return null",
|
|
178
|
+
},
|
|
179
|
+
];
|
|
180
|
+
|
|
181
|
+
const feedbackResult = await swarm_review_feedback.execute(
|
|
182
|
+
{
|
|
183
|
+
project_key: testProjectPath,
|
|
184
|
+
task_id: subtask.id,
|
|
185
|
+
worker_id: "TestWorker",
|
|
186
|
+
status: "needs_changes",
|
|
187
|
+
issues: JSON.stringify(issues),
|
|
188
|
+
},
|
|
189
|
+
mockContext
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
const feedbackParsed = JSON.parse(feedbackResult);
|
|
193
|
+
expect(feedbackParsed.success).toBe(true);
|
|
194
|
+
expect(feedbackParsed.status).toBe("needs_changes");
|
|
195
|
+
expect(feedbackParsed.attempt).toBe(1);
|
|
196
|
+
expect(feedbackParsed.remaining_attempts).toBe(2);
|
|
197
|
+
|
|
198
|
+
// Verify retry count incremented
|
|
199
|
+
expect(feedbackParsed.attempt).toBe(1);
|
|
200
|
+
|
|
201
|
+
// Verify message was sent with issues
|
|
202
|
+
const messages = await swarmMail.getInbox(
|
|
203
|
+
testProjectPath,
|
|
204
|
+
"TestWorker",
|
|
205
|
+
{ limit: 10 }
|
|
206
|
+
);
|
|
207
|
+
expect(messages.length).toBeGreaterThan(0);
|
|
208
|
+
|
|
209
|
+
const needsChangesMessage = messages.find((m) =>
|
|
210
|
+
m.subject.includes("NEEDS CHANGES")
|
|
211
|
+
);
|
|
212
|
+
expect(needsChangesMessage).toBeDefined();
|
|
213
|
+
expect(needsChangesMessage?.subject).toContain(subtask.id);
|
|
214
|
+
expect(needsChangesMessage?.subject).toContain("attempt 1/3");
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
test("3-strike rule: task marked blocked after 3 rejections", async () => {
|
|
218
|
+
// Setup: create epic + subtask
|
|
219
|
+
const epicResult = await hive_create.execute(
|
|
220
|
+
{
|
|
221
|
+
title: "Test Epic",
|
|
222
|
+
type: "epic",
|
|
223
|
+
priority: 1,
|
|
224
|
+
},
|
|
225
|
+
mockContext
|
|
226
|
+
);
|
|
227
|
+
const epic = JSON.parse(epicResult);
|
|
228
|
+
|
|
229
|
+
const subtaskResult = await hive_create.execute(
|
|
230
|
+
{
|
|
231
|
+
title: "Test Subtask",
|
|
232
|
+
type: "task",
|
|
233
|
+
priority: 2,
|
|
234
|
+
parent_id: epic.id,
|
|
235
|
+
},
|
|
236
|
+
mockContext
|
|
237
|
+
);
|
|
238
|
+
const subtask = JSON.parse(subtaskResult);
|
|
239
|
+
|
|
240
|
+
const issues = [
|
|
241
|
+
{
|
|
242
|
+
file: "src/test.ts",
|
|
243
|
+
issue: "Still broken",
|
|
244
|
+
},
|
|
245
|
+
];
|
|
246
|
+
|
|
247
|
+
// Exhaust all 3 attempts
|
|
248
|
+
for (let i = 1; i <= 3; i++) {
|
|
249
|
+
const feedbackResult = await swarm_review_feedback.execute(
|
|
250
|
+
{
|
|
251
|
+
project_key: testProjectPath,
|
|
252
|
+
task_id: subtask.id,
|
|
253
|
+
worker_id: "TestWorker",
|
|
254
|
+
status: "needs_changes",
|
|
255
|
+
issues: JSON.stringify(issues),
|
|
256
|
+
},
|
|
257
|
+
mockContext
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
const feedbackParsed = JSON.parse(feedbackResult);
|
|
261
|
+
expect(feedbackParsed.success).toBe(true);
|
|
262
|
+
expect(feedbackParsed.status).toBe("needs_changes");
|
|
263
|
+
expect(feedbackParsed.attempt).toBe(i);
|
|
264
|
+
expect(feedbackParsed.remaining_attempts).toBe(3 - i);
|
|
265
|
+
|
|
266
|
+
if (i === 3) {
|
|
267
|
+
// Last attempt should mark task as failed
|
|
268
|
+
expect(feedbackParsed.task_failed).toBe(true);
|
|
269
|
+
expect(feedbackParsed.remaining_attempts).toBe(0);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Verify task was marked as blocked in hive
|
|
274
|
+
const hive = await getHiveAdapter(testProjectPath);
|
|
275
|
+
const updatedCell = await hive.getCell(testProjectPath, subtask.id);
|
|
276
|
+
expect(updatedCell?.status).toBe("blocked");
|
|
277
|
+
|
|
278
|
+
// Verify final failure message was sent
|
|
279
|
+
const messages = await swarmMail.getInbox(
|
|
280
|
+
testProjectPath,
|
|
281
|
+
"TestWorker",
|
|
282
|
+
{ limit: 10 }
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
const failedMessage = messages.find((m) => m.subject.includes("FAILED"));
|
|
286
|
+
expect(failedMessage).toBeDefined();
|
|
287
|
+
expect(failedMessage?.subject).toContain("max review attempts reached");
|
|
288
|
+
expect(failedMessage?.importance).toBe("urgent");
|
|
289
|
+
});
|
|
290
|
+
});
|
|
@@ -90,7 +90,7 @@ describe("swarm_decompose", () => {
|
|
|
90
90
|
expect(parsed).toHaveProperty("expected_schema", "CellTree");
|
|
91
91
|
expect(parsed).toHaveProperty("schema_hint");
|
|
92
92
|
expect(parsed.prompt).toContain("Add user authentication with OAuth");
|
|
93
|
-
expect(parsed.prompt).toContain("
|
|
93
|
+
expect(parsed.prompt).toContain("as many as needed");
|
|
94
94
|
});
|
|
95
95
|
|
|
96
96
|
it("includes context in prompt when provided", async () => {
|
|
@@ -120,8 +120,8 @@ describe("swarm_decompose", () => {
|
|
|
120
120
|
|
|
121
121
|
const parsed = JSON.parse(result);
|
|
122
122
|
|
|
123
|
-
//
|
|
124
|
-
expect(parsed.prompt).toContain("
|
|
123
|
+
// Prompt should say "as many as needed" (max_subtasks no longer in template)
|
|
124
|
+
expect(parsed.prompt).toContain("as many as needed");
|
|
125
125
|
});
|
|
126
126
|
});
|
|
127
127
|
|
|
@@ -398,7 +398,7 @@ describe("swarm_plan_prompt", () => {
|
|
|
398
398
|
);
|
|
399
399
|
const parsed = JSON.parse(result);
|
|
400
400
|
|
|
401
|
-
expect(parsed.prompt).toContain("
|
|
401
|
+
expect(parsed.prompt).toContain("as many as needed");
|
|
402
402
|
});
|
|
403
403
|
});
|
|
404
404
|
|
|
@@ -1790,8 +1790,9 @@ describe("Checkpoint/Recovery Flow (integration)", () => {
|
|
|
1790
1790
|
const sessionID = `checkpoint-session-${Date.now()}`;
|
|
1791
1791
|
|
|
1792
1792
|
// Initialize swarm-mail database directly (no Agent Mail needed)
|
|
1793
|
-
const {
|
|
1794
|
-
const
|
|
1793
|
+
const { getSwarmMailLibSQL, closeSwarmMailLibSQL } = await import("swarm-mail");
|
|
1794
|
+
const swarmMail = await getSwarmMailLibSQL(uniqueProjectKey);
|
|
1795
|
+
const db = await swarmMail.getDatabase();
|
|
1795
1796
|
|
|
1796
1797
|
try {
|
|
1797
1798
|
const ctx = {
|
|
@@ -1842,8 +1843,8 @@ describe("Checkpoint/Recovery Flow (integration)", () => {
|
|
|
1842
1843
|
}>(
|
|
1843
1844
|
`SELECT id, epic_id, bead_id, strategy, files, recovery
|
|
1844
1845
|
FROM swarm_contexts
|
|
1845
|
-
WHERE bead_id = $
|
|
1846
|
-
[beadId],
|
|
1846
|
+
WHERE project_key = $1 AND bead_id = $2`,
|
|
1847
|
+
[uniqueProjectKey, beadId],
|
|
1847
1848
|
);
|
|
1848
1849
|
|
|
1849
1850
|
expect(dbResult.rows.length).toBe(1);
|
|
@@ -1865,7 +1866,7 @@ describe("Checkpoint/Recovery Flow (integration)", () => {
|
|
|
1865
1866
|
expect(recovery.files_modified).toEqual(["src/test.ts", "src/test2.ts"]);
|
|
1866
1867
|
expect(recovery).toHaveProperty("last_checkpoint");
|
|
1867
1868
|
} finally {
|
|
1868
|
-
await
|
|
1869
|
+
await closeSwarmMailLibSQL(uniqueProjectKey);
|
|
1869
1870
|
}
|
|
1870
1871
|
});
|
|
1871
1872
|
|
|
@@ -1873,8 +1874,9 @@ describe("Checkpoint/Recovery Flow (integration)", () => {
|
|
|
1873
1874
|
const uniqueProjectKey = `${TEST_PROJECT_PATH}-checkpoint-error-${Date.now()}`;
|
|
1874
1875
|
const sessionID = `checkpoint-error-session-${Date.now()}`;
|
|
1875
1876
|
|
|
1876
|
-
const {
|
|
1877
|
-
const
|
|
1877
|
+
const { getSwarmMailLibSQL, closeSwarmMailLibSQL } = await import("swarm-mail");
|
|
1878
|
+
const swarmMail = await getSwarmMailLibSQL(uniqueProjectKey);
|
|
1879
|
+
const db = await swarmMail.getDatabase();
|
|
1878
1880
|
|
|
1879
1881
|
try {
|
|
1880
1882
|
const ctx = {
|
|
@@ -1901,8 +1903,8 @@ describe("Checkpoint/Recovery Flow (integration)", () => {
|
|
|
1901
1903
|
|
|
1902
1904
|
// Verify error_context was stored
|
|
1903
1905
|
const dbResult = await db.query<{ recovery: string }>(
|
|
1904
|
-
`SELECT recovery FROM swarm_contexts WHERE bead_id = $
|
|
1905
|
-
["bd-error-test.1"],
|
|
1906
|
+
`SELECT recovery FROM swarm_contexts WHERE project_key = $1 AND bead_id = $2`,
|
|
1907
|
+
[uniqueProjectKey, "bd-error-test.1"],
|
|
1906
1908
|
);
|
|
1907
1909
|
|
|
1908
1910
|
const recoveryRaw = dbResult.rows[0].recovery;
|
|
@@ -1912,7 +1914,7 @@ describe("Checkpoint/Recovery Flow (integration)", () => {
|
|
|
1912
1914
|
"Hit type error on line 42, need to add explicit types",
|
|
1913
1915
|
);
|
|
1914
1916
|
} finally {
|
|
1915
|
-
await
|
|
1917
|
+
await closeSwarmMailLibSQL(uniqueProjectKey);
|
|
1916
1918
|
}
|
|
1917
1919
|
});
|
|
1918
1920
|
});
|
|
@@ -1922,8 +1924,9 @@ describe("Checkpoint/Recovery Flow (integration)", () => {
|
|
|
1922
1924
|
const uniqueProjectKey = `${TEST_PROJECT_PATH}-recover-${Date.now()}`;
|
|
1923
1925
|
const sessionID = `recover-session-${Date.now()}`;
|
|
1924
1926
|
|
|
1925
|
-
const {
|
|
1926
|
-
const
|
|
1927
|
+
const { getSwarmMailLibSQL, closeSwarmMailLibSQL } = await import("swarm-mail");
|
|
1928
|
+
const swarmMail = await getSwarmMailLibSQL(uniqueProjectKey);
|
|
1929
|
+
const db = await swarmMail.getDatabase();
|
|
1927
1930
|
|
|
1928
1931
|
try {
|
|
1929
1932
|
const ctx = {
|
|
@@ -1983,7 +1986,7 @@ describe("Checkpoint/Recovery Flow (integration)", () => {
|
|
|
1983
1986
|
"swarm-coordination",
|
|
1984
1987
|
]);
|
|
1985
1988
|
} finally {
|
|
1986
|
-
await
|
|
1989
|
+
await closeSwarmMailLibSQL(uniqueProjectKey);
|
|
1987
1990
|
}
|
|
1988
1991
|
});
|
|
1989
1992
|
|
|
@@ -1991,8 +1994,8 @@ describe("Checkpoint/Recovery Flow (integration)", () => {
|
|
|
1991
1994
|
const uniqueProjectKey = `${TEST_PROJECT_PATH}-recover-notfound-${Date.now()}`;
|
|
1992
1995
|
const sessionID = `recover-notfound-session-${Date.now()}`;
|
|
1993
1996
|
|
|
1994
|
-
const {
|
|
1995
|
-
await
|
|
1997
|
+
const { getSwarmMailLibSQL, closeSwarmMailLibSQL } = await import("swarm-mail");
|
|
1998
|
+
await getSwarmMailLibSQL(uniqueProjectKey);
|
|
1996
1999
|
|
|
1997
2000
|
try {
|
|
1998
2001
|
const ctx = {
|
|
@@ -2015,7 +2018,7 @@ describe("Checkpoint/Recovery Flow (integration)", () => {
|
|
|
2015
2018
|
expect(parsed.message).toContain("No checkpoint found");
|
|
2016
2019
|
expect(parsed.epic_id).toBe("bd-nonexistent-epic");
|
|
2017
2020
|
} finally {
|
|
2018
|
-
await
|
|
2021
|
+
await closeSwarmMailLibSQL(uniqueProjectKey);
|
|
2019
2022
|
}
|
|
2020
2023
|
});
|
|
2021
2024
|
});
|