@polpo-ai/drizzle 0.11.0 → 0.12.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/dist/__tests__/migrator-pg.test.js +2 -2
- package/dist/__tests__/migrator-pg.test.js.map +1 -1
- package/dist/__tests__/stores-pg.test.js +43 -109
- package/dist/__tests__/stores-pg.test.js.map +1 -1
- package/dist/__tests__/stores.test.js +48 -264
- package/dist/__tests__/stores.test.js.map +1 -1
- package/dist/index.d.ts +4 -302
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -12
- package/dist/index.js.map +1 -1
- package/dist/migrate.d.ts.map +1 -1
- package/dist/migrate.js +0 -22
- package/dist/migrate.js.map +1 -1
- package/dist/migrator.d.ts.map +1 -1
- package/dist/migrator.js +2 -3
- package/dist/migrator.js.map +1 -1
- package/dist/schema/index.d.ts +0 -2
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +0 -2
- package/dist/schema/index.js.map +1 -1
- package/dist/sqlite-migrator.d.ts +26 -0
- package/dist/sqlite-migrator.d.ts.map +1 -0
- package/dist/sqlite-migrator.js +122 -0
- package/dist/sqlite-migrator.js.map +1 -0
- package/dist/stores/index.d.ts +0 -1
- package/dist/stores/index.d.ts.map +1 -1
- package/dist/stores/index.js +0 -1
- package/dist/stores/index.js.map +1 -1
- package/dist/stores/task-store.d.ts +6 -6
- package/dist/stores/task-store.d.ts.map +1 -1
- package/dist/stores/task-store.js +7 -7
- package/dist/stores/task-store.js.map +1 -1
- package/package.json +3 -3
- package/dist/schema/attachments.d.ts +0 -301
- package/dist/schema/attachments.d.ts.map +0 -1
- package/dist/schema/attachments.js +0 -29
- package/dist/schema/attachments.js.map +0 -1
- package/dist/stores/attachment-store.d.ts +0 -22
- package/dist/stores/attachment-store.d.ts.map +0 -1
- package/dist/stores/attachment-store.js +0 -66
- package/dist/stores/attachment-store.js.map +0 -1
|
@@ -7,6 +7,7 @@ import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
|
7
7
|
import { randomBytes } from "node:crypto";
|
|
8
8
|
import Database from "better-sqlite3";
|
|
9
9
|
import { drizzle } from "drizzle-orm/better-sqlite3";
|
|
10
|
+
import { migrateSqliteSchema } from "../sqlite-migrator.js";
|
|
10
11
|
import { createSqliteStores } from "../index.js";
|
|
11
12
|
// Provide a deterministic vault key for tests (32 bytes hex-encoded)
|
|
12
13
|
process.env.POLPO_VAULT_KEY = randomBytes(32).toString("hex");
|
|
@@ -14,228 +15,11 @@ process.env.POLPO_VAULT_KEY = randomBytes(32).toString("hex");
|
|
|
14
15
|
let sqlite;
|
|
15
16
|
let db;
|
|
16
17
|
let stores;
|
|
17
|
-
|
|
18
|
-
function createTables(raw) {
|
|
19
|
-
raw.exec(`
|
|
20
|
-
CREATE TABLE IF NOT EXISTS tasks (
|
|
21
|
-
id TEXT PRIMARY KEY,
|
|
22
|
-
title TEXT NOT NULL,
|
|
23
|
-
description TEXT NOT NULL,
|
|
24
|
-
assign_to TEXT NOT NULL,
|
|
25
|
-
"group" TEXT,
|
|
26
|
-
mission_id TEXT,
|
|
27
|
-
depends_on TEXT NOT NULL DEFAULT '[]',
|
|
28
|
-
status TEXT NOT NULL DEFAULT 'pending',
|
|
29
|
-
retries INTEGER NOT NULL DEFAULT 0,
|
|
30
|
-
max_retries INTEGER NOT NULL DEFAULT 2,
|
|
31
|
-
max_duration INTEGER,
|
|
32
|
-
retry_policy TEXT,
|
|
33
|
-
expectations TEXT NOT NULL DEFAULT '[]',
|
|
34
|
-
metrics TEXT NOT NULL DEFAULT '[]',
|
|
35
|
-
result TEXT,
|
|
36
|
-
phase TEXT,
|
|
37
|
-
fix_attempts INTEGER NOT NULL DEFAULT 0,
|
|
38
|
-
resolution_attempts INTEGER NOT NULL DEFAULT 0,
|
|
39
|
-
original_description TEXT,
|
|
40
|
-
session_id TEXT,
|
|
41
|
-
notifications TEXT,
|
|
42
|
-
outcomes TEXT,
|
|
43
|
-
expected_outcomes TEXT,
|
|
44
|
-
deadline TEXT,
|
|
45
|
-
priority TEXT,
|
|
46
|
-
side_effects INTEGER,
|
|
47
|
-
revision_count INTEGER,
|
|
48
|
-
"user" TEXT,
|
|
49
|
-
created_at TEXT NOT NULL,
|
|
50
|
-
updated_at TEXT NOT NULL
|
|
51
|
-
);
|
|
52
|
-
CREATE INDEX IF NOT EXISTS idx_tasks_user ON tasks("user");
|
|
53
|
-
CREATE TABLE IF NOT EXISTS missions (
|
|
54
|
-
id TEXT PRIMARY KEY,
|
|
55
|
-
name TEXT NOT NULL UNIQUE,
|
|
56
|
-
data TEXT NOT NULL,
|
|
57
|
-
prompt TEXT,
|
|
58
|
-
status TEXT NOT NULL DEFAULT 'draft',
|
|
59
|
-
schedule TEXT,
|
|
60
|
-
end_date TEXT,
|
|
61
|
-
quality_threshold TEXT,
|
|
62
|
-
deadline TEXT,
|
|
63
|
-
notifications TEXT,
|
|
64
|
-
execution_count INTEGER NOT NULL DEFAULT 0,
|
|
65
|
-
"user" TEXT,
|
|
66
|
-
created_at TEXT NOT NULL,
|
|
67
|
-
updated_at TEXT NOT NULL
|
|
68
|
-
);
|
|
69
|
-
CREATE INDEX IF NOT EXISTS idx_missions_user ON missions("user");
|
|
70
|
-
CREATE TABLE IF NOT EXISTS metadata (
|
|
71
|
-
key TEXT PRIMARY KEY,
|
|
72
|
-
value TEXT NOT NULL
|
|
73
|
-
);
|
|
74
|
-
CREATE TABLE IF NOT EXISTS processes (
|
|
75
|
-
agent_name TEXT NOT NULL,
|
|
76
|
-
pid INTEGER NOT NULL,
|
|
77
|
-
task_id TEXT NOT NULL,
|
|
78
|
-
started_at TEXT NOT NULL,
|
|
79
|
-
alive INTEGER NOT NULL DEFAULT 1,
|
|
80
|
-
activity TEXT NOT NULL DEFAULT '{}'
|
|
81
|
-
);
|
|
82
|
-
CREATE TABLE IF NOT EXISTS runs (
|
|
83
|
-
id TEXT PRIMARY KEY,
|
|
84
|
-
task_id TEXT NOT NULL,
|
|
85
|
-
pid INTEGER NOT NULL DEFAULT 0,
|
|
86
|
-
agent_name TEXT NOT NULL,
|
|
87
|
-
adapter_type TEXT NOT NULL,
|
|
88
|
-
session_id TEXT,
|
|
89
|
-
status TEXT NOT NULL DEFAULT 'running',
|
|
90
|
-
started_at TEXT NOT NULL,
|
|
91
|
-
updated_at TEXT NOT NULL,
|
|
92
|
-
activity TEXT NOT NULL DEFAULT '{}',
|
|
93
|
-
result TEXT,
|
|
94
|
-
outcomes TEXT,
|
|
95
|
-
config TEXT,
|
|
96
|
-
config_path TEXT NOT NULL,
|
|
97
|
-
"user" TEXT
|
|
98
|
-
);
|
|
99
|
-
CREATE INDEX IF NOT EXISTS idx_runs_user ON runs("user");
|
|
100
|
-
CREATE TABLE IF NOT EXISTS sessions (
|
|
101
|
-
id TEXT PRIMARY KEY,
|
|
102
|
-
title TEXT,
|
|
103
|
-
agent TEXT,
|
|
104
|
-
"user" TEXT,
|
|
105
|
-
metadata TEXT,
|
|
106
|
-
created_at TEXT NOT NULL,
|
|
107
|
-
updated_at TEXT NOT NULL
|
|
108
|
-
);
|
|
109
|
-
CREATE INDEX IF NOT EXISTS idx_sessions_user ON sessions("user");
|
|
110
|
-
CREATE TABLE IF NOT EXISTS messages (
|
|
111
|
-
id TEXT PRIMARY KEY,
|
|
112
|
-
session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
113
|
-
role TEXT NOT NULL,
|
|
114
|
-
content TEXT NOT NULL,
|
|
115
|
-
ts TEXT NOT NULL,
|
|
116
|
-
tool_calls TEXT
|
|
117
|
-
);
|
|
118
|
-
CREATE TABLE IF NOT EXISTS notifications (
|
|
119
|
-
id TEXT PRIMARY KEY,
|
|
120
|
-
timestamp TEXT NOT NULL,
|
|
121
|
-
rule_id TEXT NOT NULL,
|
|
122
|
-
rule_name TEXT NOT NULL,
|
|
123
|
-
channel TEXT NOT NULL,
|
|
124
|
-
channel_type TEXT NOT NULL,
|
|
125
|
-
status TEXT NOT NULL,
|
|
126
|
-
error TEXT,
|
|
127
|
-
title TEXT NOT NULL,
|
|
128
|
-
body TEXT NOT NULL,
|
|
129
|
-
severity TEXT NOT NULL,
|
|
130
|
-
source_event TEXT NOT NULL,
|
|
131
|
-
attachment_count INTEGER NOT NULL DEFAULT 0,
|
|
132
|
-
attachment_types TEXT
|
|
133
|
-
);
|
|
134
|
-
CREATE TABLE IF NOT EXISTS log_sessions (
|
|
135
|
-
id TEXT PRIMARY KEY,
|
|
136
|
-
started_at TEXT NOT NULL
|
|
137
|
-
);
|
|
138
|
-
CREATE TABLE IF NOT EXISTS log_entries (
|
|
139
|
-
id TEXT PRIMARY KEY,
|
|
140
|
-
session_id TEXT NOT NULL REFERENCES log_sessions(id) ON DELETE CASCADE,
|
|
141
|
-
ts TEXT NOT NULL,
|
|
142
|
-
event TEXT NOT NULL,
|
|
143
|
-
data TEXT
|
|
144
|
-
);
|
|
145
|
-
CREATE TABLE IF NOT EXISTS approvals (
|
|
146
|
-
id TEXT PRIMARY KEY,
|
|
147
|
-
gate_id TEXT NOT NULL,
|
|
148
|
-
gate_name TEXT NOT NULL,
|
|
149
|
-
task_id TEXT,
|
|
150
|
-
mission_id TEXT,
|
|
151
|
-
status TEXT NOT NULL DEFAULT 'pending',
|
|
152
|
-
payload TEXT,
|
|
153
|
-
requested_at TEXT NOT NULL,
|
|
154
|
-
resolved_at TEXT,
|
|
155
|
-
resolved_by TEXT,
|
|
156
|
-
note TEXT
|
|
157
|
-
);
|
|
158
|
-
CREATE TABLE IF NOT EXISTS memory (
|
|
159
|
-
key TEXT PRIMARY KEY,
|
|
160
|
-
content TEXT NOT NULL DEFAULT ''
|
|
161
|
-
);
|
|
162
|
-
CREATE TABLE IF NOT EXISTS peers (
|
|
163
|
-
id TEXT PRIMARY KEY,
|
|
164
|
-
channel TEXT NOT NULL,
|
|
165
|
-
external_id TEXT NOT NULL,
|
|
166
|
-
display_name TEXT,
|
|
167
|
-
first_seen_at TEXT NOT NULL,
|
|
168
|
-
last_seen_at TEXT NOT NULL,
|
|
169
|
-
linked_to TEXT
|
|
170
|
-
);
|
|
171
|
-
CREATE TABLE IF NOT EXISTS peer_allowlist (
|
|
172
|
-
peer_id TEXT PRIMARY KEY
|
|
173
|
-
);
|
|
174
|
-
CREATE TABLE IF NOT EXISTS pairing_requests (
|
|
175
|
-
id TEXT PRIMARY KEY,
|
|
176
|
-
peer_id TEXT NOT NULL,
|
|
177
|
-
channel TEXT NOT NULL,
|
|
178
|
-
external_id TEXT NOT NULL,
|
|
179
|
-
display_name TEXT,
|
|
180
|
-
code TEXT NOT NULL UNIQUE,
|
|
181
|
-
created_at TEXT NOT NULL,
|
|
182
|
-
expires_at TEXT NOT NULL,
|
|
183
|
-
resolved INTEGER NOT NULL DEFAULT 0
|
|
184
|
-
);
|
|
185
|
-
CREATE TABLE IF NOT EXISTS peer_sessions (
|
|
186
|
-
peer_id TEXT PRIMARY KEY,
|
|
187
|
-
session_id TEXT NOT NULL
|
|
188
|
-
);
|
|
189
|
-
CREATE TABLE IF NOT EXISTS teams (
|
|
190
|
-
name TEXT PRIMARY KEY,
|
|
191
|
-
description TEXT,
|
|
192
|
-
created_at TEXT NOT NULL,
|
|
193
|
-
updated_at TEXT NOT NULL
|
|
194
|
-
);
|
|
195
|
-
CREATE TABLE IF NOT EXISTS agents (
|
|
196
|
-
name TEXT PRIMARY KEY,
|
|
197
|
-
team_name TEXT NOT NULL,
|
|
198
|
-
config TEXT NOT NULL,
|
|
199
|
-
created_at TEXT NOT NULL,
|
|
200
|
-
updated_at TEXT NOT NULL
|
|
201
|
-
);
|
|
202
|
-
CREATE TABLE IF NOT EXISTS vault (
|
|
203
|
-
agent TEXT NOT NULL,
|
|
204
|
-
service TEXT NOT NULL,
|
|
205
|
-
type TEXT NOT NULL,
|
|
206
|
-
label TEXT,
|
|
207
|
-
credentials TEXT NOT NULL,
|
|
208
|
-
created_at TEXT NOT NULL,
|
|
209
|
-
updated_at TEXT NOT NULL,
|
|
210
|
-
PRIMARY KEY (agent, service)
|
|
211
|
-
);
|
|
212
|
-
CREATE TABLE IF NOT EXISTS playbooks (
|
|
213
|
-
name TEXT PRIMARY KEY,
|
|
214
|
-
description TEXT NOT NULL,
|
|
215
|
-
mission TEXT NOT NULL,
|
|
216
|
-
parameters TEXT,
|
|
217
|
-
version TEXT,
|
|
218
|
-
author TEXT,
|
|
219
|
-
tags TEXT,
|
|
220
|
-
created_at TEXT NOT NULL,
|
|
221
|
-
updated_at TEXT NOT NULL
|
|
222
|
-
);
|
|
223
|
-
CREATE TABLE IF NOT EXISTS skills (
|
|
224
|
-
name TEXT PRIMARY KEY,
|
|
225
|
-
description TEXT NOT NULL DEFAULT '',
|
|
226
|
-
source TEXT,
|
|
227
|
-
installed_at TEXT NOT NULL,
|
|
228
|
-
allowed_tools TEXT,
|
|
229
|
-
tags TEXT,
|
|
230
|
-
category TEXT
|
|
231
|
-
);
|
|
232
|
-
PRAGMA foreign_keys = ON;
|
|
233
|
-
`);
|
|
234
|
-
}
|
|
235
|
-
beforeEach(() => {
|
|
18
|
+
beforeEach(async () => {
|
|
236
19
|
sqlite = new Database(":memory:");
|
|
237
|
-
|
|
20
|
+
sqlite.exec("PRAGMA foreign_keys = ON");
|
|
238
21
|
db = drizzle(sqlite);
|
|
22
|
+
await migrateSqliteSchema(db);
|
|
239
23
|
stores = createSqliteStores(db);
|
|
240
24
|
});
|
|
241
25
|
afterEach(() => {
|
|
@@ -245,8 +29,8 @@ afterEach(() => {
|
|
|
245
29
|
// TaskStore
|
|
246
30
|
// ═══════════════════════════════════════════════════════════════════════
|
|
247
31
|
describe("DrizzleTaskStore", () => {
|
|
248
|
-
it("
|
|
249
|
-
const task = await stores.taskStore.
|
|
32
|
+
it("createTask + getTask round-trip", async () => {
|
|
33
|
+
const task = await stores.taskStore.createTask({
|
|
250
34
|
title: "Fix bug",
|
|
251
35
|
description: "Fix the login bug",
|
|
252
36
|
assignTo: "claude",
|
|
@@ -264,8 +48,8 @@ describe("DrizzleTaskStore", () => {
|
|
|
264
48
|
expect(fetched.title).toBe("Fix bug");
|
|
265
49
|
expect(fetched.expectations).toEqual([{ type: "llm_review", criteria: "Login works" }]);
|
|
266
50
|
});
|
|
267
|
-
it("
|
|
268
|
-
const task = await stores.taskStore.
|
|
51
|
+
it("createTask persists OpenAI-compat user identifier", async () => {
|
|
52
|
+
const task = await stores.taskStore.createTask({
|
|
269
53
|
title: "Per-user task",
|
|
270
54
|
description: "Scoped to end-user",
|
|
271
55
|
assignTo: "claude",
|
|
@@ -279,20 +63,20 @@ describe("DrizzleTaskStore", () => {
|
|
|
279
63
|
const fetched = await stores.taskStore.getTask(task.id);
|
|
280
64
|
expect(fetched.user).toBe("u-42");
|
|
281
65
|
});
|
|
282
|
-
it("
|
|
283
|
-
await stores.taskStore.
|
|
66
|
+
it("listTasks returns ordered by createdAt", async () => {
|
|
67
|
+
await stores.taskStore.createTask({
|
|
284
68
|
title: "A", description: "first", assignTo: "claude", dependsOn: [], maxRetries: 2, expectations: [], metrics: [],
|
|
285
69
|
});
|
|
286
|
-
await stores.taskStore.
|
|
70
|
+
await stores.taskStore.createTask({
|
|
287
71
|
title: "B", description: "second", assignTo: "claude", dependsOn: [], maxRetries: 2, expectations: [], metrics: [],
|
|
288
72
|
});
|
|
289
|
-
const all = await stores.taskStore.
|
|
73
|
+
const all = await stores.taskStore.listTasks();
|
|
290
74
|
expect(all).toHaveLength(2);
|
|
291
75
|
expect(all[0].title).toBe("A");
|
|
292
76
|
expect(all[1].title).toBe("B");
|
|
293
77
|
});
|
|
294
78
|
it("updateTask merges fields", async () => {
|
|
295
|
-
const task = await stores.taskStore.
|
|
79
|
+
const task = await stores.taskStore.createTask({
|
|
296
80
|
title: "Original", description: "desc", assignTo: "claude", dependsOn: [], maxRetries: 2, expectations: [], metrics: [],
|
|
297
81
|
});
|
|
298
82
|
const updated = await stores.taskStore.updateTask(task.id, { title: "Updated" });
|
|
@@ -301,30 +85,30 @@ describe("DrizzleTaskStore", () => {
|
|
|
301
85
|
const fetched = await stores.taskStore.getTask(task.id);
|
|
302
86
|
expect(fetched.title).toBe("Updated");
|
|
303
87
|
});
|
|
304
|
-
it("
|
|
305
|
-
const task = await stores.taskStore.
|
|
88
|
+
it("deleteTask deletes by ID", async () => {
|
|
89
|
+
const task = await stores.taskStore.createTask({
|
|
306
90
|
title: "Delete me", description: "d", assignTo: "claude", dependsOn: [], maxRetries: 2, expectations: [], metrics: [],
|
|
307
91
|
});
|
|
308
|
-
const removed = await stores.taskStore.
|
|
92
|
+
const removed = await stores.taskStore.deleteTask(task.id);
|
|
309
93
|
expect(removed).toBe(true);
|
|
310
94
|
const fetched = await stores.taskStore.getTask(task.id);
|
|
311
95
|
expect(fetched).toBeUndefined();
|
|
312
96
|
});
|
|
313
|
-
it("
|
|
314
|
-
await stores.taskStore.
|
|
97
|
+
it("deleteTasks with filter", async () => {
|
|
98
|
+
await stores.taskStore.createTask({
|
|
315
99
|
title: "Keep", description: "d", assignTo: "claude", dependsOn: [], maxRetries: 2, expectations: [], metrics: [],
|
|
316
100
|
});
|
|
317
|
-
await stores.taskStore.
|
|
101
|
+
await stores.taskStore.createTask({
|
|
318
102
|
title: "Remove", description: "d", assignTo: "claude", dependsOn: [], maxRetries: 2, expectations: [], metrics: [], group: "old",
|
|
319
103
|
});
|
|
320
|
-
const count = await stores.taskStore.
|
|
104
|
+
const count = await stores.taskStore.deleteTasks((t) => t.group === "old");
|
|
321
105
|
expect(count).toBe(1);
|
|
322
|
-
const all = await stores.taskStore.
|
|
106
|
+
const all = await stores.taskStore.listTasks();
|
|
323
107
|
expect(all).toHaveLength(1);
|
|
324
108
|
expect(all[0].title).toBe("Keep");
|
|
325
109
|
});
|
|
326
110
|
it("transition validates state machine", async () => {
|
|
327
|
-
const task = await stores.taskStore.
|
|
111
|
+
const task = await stores.taskStore.createTask({
|
|
328
112
|
title: "T", description: "d", assignTo: "claude", dependsOn: [], maxRetries: 2, expectations: [], metrics: [],
|
|
329
113
|
});
|
|
330
114
|
// pending → assigned is valid
|
|
@@ -334,7 +118,7 @@ describe("DrizzleTaskStore", () => {
|
|
|
334
118
|
await expect(stores.taskStore.transition(task.id, "pending")).rejects.toThrow();
|
|
335
119
|
});
|
|
336
120
|
it("transition increments retries on failed→pending", async () => {
|
|
337
|
-
const task = await stores.taskStore.
|
|
121
|
+
const task = await stores.taskStore.createTask({
|
|
338
122
|
title: "T", description: "d", assignTo: "claude", dependsOn: [], maxRetries: 3, expectations: [], metrics: [],
|
|
339
123
|
});
|
|
340
124
|
await stores.taskStore.transition(task.id, "assigned");
|
|
@@ -344,7 +128,7 @@ describe("DrizzleTaskStore", () => {
|
|
|
344
128
|
expect(retried.retries).toBe(1);
|
|
345
129
|
});
|
|
346
130
|
it("unsafeSetStatus bypasses state machine", async () => {
|
|
347
|
-
const task = await stores.taskStore.
|
|
131
|
+
const task = await stores.taskStore.createTask({
|
|
348
132
|
title: "T", description: "d", assignTo: "claude", dependsOn: [], maxRetries: 2, expectations: [], metrics: [],
|
|
349
133
|
});
|
|
350
134
|
// pending → done is not a valid transition, but unsafeSetStatus allows it
|
|
@@ -352,43 +136,43 @@ describe("DrizzleTaskStore", () => {
|
|
|
352
136
|
expect(result.status).toBe("done");
|
|
353
137
|
});
|
|
354
138
|
// ── Missions ────────────────────────────────────────────────────────
|
|
355
|
-
it("
|
|
356
|
-
const mission = await stores.
|
|
139
|
+
it("createMission + getMission round-trip", async () => {
|
|
140
|
+
const mission = await stores.missionStore.createMission({
|
|
357
141
|
name: "mission-1",
|
|
358
142
|
data: '{"tasks":[]}',
|
|
359
143
|
status: "draft",
|
|
360
144
|
});
|
|
361
145
|
expect(mission.id).toBeDefined();
|
|
362
146
|
expect(mission.name).toBe("mission-1");
|
|
363
|
-
const fetched = await stores.
|
|
147
|
+
const fetched = await stores.missionStore.getMission(mission.id);
|
|
364
148
|
expect(fetched).toBeDefined();
|
|
365
149
|
expect(fetched.name).toBe("mission-1");
|
|
366
150
|
});
|
|
367
151
|
it("getMissionByName finds by name", async () => {
|
|
368
|
-
await stores.
|
|
369
|
-
const found = await stores.
|
|
152
|
+
await stores.missionStore.createMission({ name: "deploy-v2", data: "{}", status: "draft" });
|
|
153
|
+
const found = await stores.missionStore.getMissionByName("deploy-v2");
|
|
370
154
|
expect(found).toBeDefined();
|
|
371
155
|
expect(found.name).toBe("deploy-v2");
|
|
372
156
|
});
|
|
373
157
|
it("updateMission merges fields", async () => {
|
|
374
|
-
const m = await stores.
|
|
375
|
-
const updated = await stores.
|
|
158
|
+
const m = await stores.missionStore.createMission({ name: "m-1", data: "{}", status: "draft" });
|
|
159
|
+
const updated = await stores.missionStore.updateMission(m.id, { status: "active" });
|
|
376
160
|
expect(updated.status).toBe("active");
|
|
377
161
|
expect(updated.name).toBe("m-1");
|
|
378
162
|
});
|
|
379
163
|
it("deleteMission removes", async () => {
|
|
380
|
-
const m = await stores.
|
|
381
|
-
const ok = await stores.
|
|
164
|
+
const m = await stores.missionStore.createMission({ name: "m-del", data: "{}", status: "draft" });
|
|
165
|
+
const ok = await stores.missionStore.deleteMission(m.id);
|
|
382
166
|
expect(ok).toBe(true);
|
|
383
|
-
const fetched = await stores.
|
|
167
|
+
const fetched = await stores.missionStore.getMission(m.id);
|
|
384
168
|
expect(fetched).toBeUndefined();
|
|
385
169
|
});
|
|
386
170
|
it("nextMissionName increments", async () => {
|
|
387
|
-
expect(await stores.
|
|
388
|
-
await stores.
|
|
389
|
-
expect(await stores.
|
|
390
|
-
await stores.
|
|
391
|
-
expect(await stores.
|
|
171
|
+
expect(await stores.missionStore.nextMissionName()).toBe("mission-1");
|
|
172
|
+
await stores.missionStore.createMission({ name: "mission-1", data: "{}", status: "draft" });
|
|
173
|
+
expect(await stores.missionStore.nextMissionName()).toBe("mission-2");
|
|
174
|
+
await stores.missionStore.createMission({ name: "mission-5", data: "{}", status: "draft" });
|
|
175
|
+
expect(await stores.missionStore.nextMissionName()).toBe("mission-6");
|
|
392
176
|
});
|
|
393
177
|
// ── State ────────────────────────────────────────────────────────────
|
|
394
178
|
it("setState + getState round-trip", async () => {
|
|
@@ -511,7 +295,7 @@ describe("DrizzleRunStore", () => {
|
|
|
511
295
|
// ═══════════════════════════════════════════════════════════════════════
|
|
512
296
|
describe("DrizzleSessionStore", () => {
|
|
513
297
|
it("create + getSession", async () => {
|
|
514
|
-
const id = await stores.sessionStore.create("My Session");
|
|
298
|
+
const id = await stores.sessionStore.create({ title: "My Session" });
|
|
515
299
|
const session = await stores.sessionStore.getSession(id);
|
|
516
300
|
expect(session).toBeDefined();
|
|
517
301
|
expect(session.title).toBe("My Session");
|
|
@@ -539,10 +323,10 @@ describe("DrizzleSessionStore", () => {
|
|
|
539
323
|
expect(recent[1].content).toBe("3");
|
|
540
324
|
});
|
|
541
325
|
it("listSessions includes messageCount", async () => {
|
|
542
|
-
const s1 = await stores.sessionStore.create("S1");
|
|
326
|
+
const s1 = await stores.sessionStore.create({ title: "S1" });
|
|
543
327
|
await stores.sessionStore.addMessage(s1, "user", "msg1");
|
|
544
328
|
await stores.sessionStore.addMessage(s1, "assistant", "msg2");
|
|
545
|
-
await stores.sessionStore.create("S2");
|
|
329
|
+
await stores.sessionStore.create({ title: "S2" });
|
|
546
330
|
const list = await stores.sessionStore.listSessions();
|
|
547
331
|
expect(list).toHaveLength(2);
|
|
548
332
|
const withMessages = list.find((s) => s.title === "S1");
|
|
@@ -595,14 +379,14 @@ describe("DrizzleSessionStore", () => {
|
|
|
595
379
|
expect(acmeProd[0].title).toBe("Acme-prod");
|
|
596
380
|
});
|
|
597
381
|
it("renameSession updates title", async () => {
|
|
598
|
-
const id = await stores.sessionStore.create("Old");
|
|
382
|
+
const id = await stores.sessionStore.create({ title: "Old" });
|
|
599
383
|
const ok = await stores.sessionStore.renameSession(id, "New");
|
|
600
384
|
expect(ok).toBe(true);
|
|
601
385
|
const session = await stores.sessionStore.getSession(id);
|
|
602
386
|
expect(session.title).toBe("New");
|
|
603
387
|
});
|
|
604
388
|
it("deleteSession cascade-deletes messages", async () => {
|
|
605
|
-
const id = await stores.sessionStore.create("Del");
|
|
389
|
+
const id = await stores.sessionStore.create({ title: "Del" });
|
|
606
390
|
await stores.sessionStore.addMessage(id, "user", "msg");
|
|
607
391
|
const ok = await stores.sessionStore.deleteSession(id);
|
|
608
392
|
expect(ok).toBe(true);
|
|
@@ -610,17 +394,17 @@ describe("DrizzleSessionStore", () => {
|
|
|
610
394
|
expect(await stores.sessionStore.getMessages(id)).toEqual([]);
|
|
611
395
|
});
|
|
612
396
|
it("prune keeps the N most recent sessions", async () => {
|
|
613
|
-
await stores.sessionStore.create("Old");
|
|
614
|
-
await stores.sessionStore.create("New");
|
|
397
|
+
await stores.sessionStore.create({ title: "Old" });
|
|
398
|
+
await stores.sessionStore.create({ title: "New" });
|
|
615
399
|
const pruned = await stores.sessionStore.prune(1);
|
|
616
400
|
expect(pruned).toBe(1);
|
|
617
401
|
const list = await stores.sessionStore.listSessions();
|
|
618
402
|
expect(list).toHaveLength(1);
|
|
619
403
|
});
|
|
620
404
|
it("getLatestSession returns most recently updated", async () => {
|
|
621
|
-
await stores.sessionStore.create("First");
|
|
405
|
+
await stores.sessionStore.create({ title: "First" });
|
|
622
406
|
await new Promise((r) => setTimeout(r, 5));
|
|
623
|
-
const id2 = await stores.sessionStore.create("Second");
|
|
407
|
+
const id2 = await stores.sessionStore.create({ title: "Second" });
|
|
624
408
|
const latest = await stores.sessionStore.getLatestSession();
|
|
625
409
|
expect(latest).toBeDefined();
|
|
626
410
|
expect(latest.id).toBe(id2);
|