ework-daemon 0.4.6 → 0.4.7
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/package.json +1 -1
- package/src/db.ts +101 -53
- package/src/op.ts +23 -23
- package/src/schema-mysql.sql +8 -8
- package/src/schema-sqlite.sql +8 -8
package/package.json
CHANGED
package/src/db.ts
CHANGED
|
@@ -323,18 +323,24 @@ async function runMigrations(db: AsyncDatabase): Promise<void> {
|
|
|
323
323
|
await db.exec(`ALTER TABLE ${table} ADD COLUMN ${ddl}`);
|
|
324
324
|
};
|
|
325
325
|
|
|
326
|
-
// ── uid:
|
|
326
|
+
// ── id/uid swap: id becomes AUTO_INCREMENT PK, uid holds the UUID ──
|
|
327
327
|
// SQLite cannot ADD PRIMARY KEY via ALTER — must rebuild. Runs before
|
|
328
328
|
// owner_daemon_id etc. so rebuild only copies base columns; ephemeral
|
|
329
329
|
// coordination data (owner_daemon_id, nudge state) is re-added below.
|
|
330
330
|
const tMessages = `${prefix}messages`;
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
331
|
+
|
|
332
|
+
const UID_REBUILDS: {
|
|
333
|
+
table: string;
|
|
334
|
+
sqliteCreate: string;
|
|
335
|
+
mysqlCreate: string;
|
|
336
|
+
oldCols: string;
|
|
337
|
+
newCols: string;
|
|
338
|
+
}[] = [
|
|
339
|
+
{
|
|
340
|
+
table: tIssues,
|
|
341
|
+
sqliteCreate: `CREATE TABLE ${tIssues} (
|
|
342
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
343
|
+
uid TEXT NOT NULL UNIQUE,
|
|
338
344
|
tracker_type TEXT NOT NULL,
|
|
339
345
|
tracker_scope_key TEXT NOT NULL,
|
|
340
346
|
tracker_scope TEXT NOT NULL,
|
|
@@ -345,15 +351,30 @@ async function runMigrations(db: AsyncDatabase): Promise<void> {
|
|
|
345
351
|
updated_at TEXT NOT NULL,
|
|
346
352
|
UNIQUE(tracker_type, tracker_scope_key, tracker_issue_id)
|
|
347
353
|
)`,
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
354
|
+
mysqlCreate: `CREATE TABLE ${tIssues} (
|
|
355
|
+
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
356
|
+
uid VARCHAR(36) NOT NULL UNIQUE,
|
|
357
|
+
tracker_type VARCHAR(64) NOT NULL,
|
|
358
|
+
tracker_scope_key VARCHAR(255) NOT NULL,
|
|
359
|
+
tracker_scope TEXT NOT NULL,
|
|
360
|
+
tracker_issue_id VARCHAR(64) NOT NULL,
|
|
361
|
+
state VARCHAR(16) NOT NULL DEFAULT 'created',
|
|
362
|
+
title VARCHAR(512) NOT NULL DEFAULT '',
|
|
363
|
+
created_at VARCHAR(40) NOT NULL,
|
|
364
|
+
updated_at VARCHAR(40) NOT NULL,
|
|
365
|
+
UNIQUE (tracker_type, tracker_scope_key, tracker_issue_id)
|
|
366
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4`,
|
|
367
|
+
oldCols:
|
|
368
|
+
"id, tracker_type, tracker_scope_key, tracker_scope, tracker_issue_id, state, title, created_at, updated_at",
|
|
369
|
+
newCols:
|
|
370
|
+
"uid, tracker_type, tracker_scope_key, tracker_scope, tracker_issue_id, state, title, created_at, updated_at",
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
table: tSessions,
|
|
374
|
+
sqliteCreate: `CREATE TABLE ${tSessions} (
|
|
375
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
376
|
+
uid TEXT NOT NULL UNIQUE,
|
|
377
|
+
issue_id TEXT NOT NULL REFERENCES ${tIssues}(uid) ON DELETE CASCADE,
|
|
357
378
|
name TEXT NOT NULL,
|
|
358
379
|
state TEXT NOT NULL DEFAULT 'idle',
|
|
359
380
|
opencode_session_id TEXT,
|
|
@@ -366,15 +387,33 @@ async function runMigrations(db: AsyncDatabase): Promise<void> {
|
|
|
366
387
|
current_prompt TEXT,
|
|
367
388
|
UNIQUE(issue_id, name)
|
|
368
389
|
)`,
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
390
|
+
mysqlCreate: `CREATE TABLE ${tSessions} (
|
|
391
|
+
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
392
|
+
uid VARCHAR(36) NOT NULL UNIQUE,
|
|
393
|
+
issue_id VARCHAR(36) NOT NULL,
|
|
394
|
+
name VARCHAR(64) NOT NULL,
|
|
395
|
+
state VARCHAR(16) NOT NULL DEFAULT 'idle',
|
|
396
|
+
opencode_session_id VARCHAR(64),
|
|
397
|
+
opencode_pid BIGINT,
|
|
398
|
+
workdir VARCHAR(1024),
|
|
399
|
+
created_at VARCHAR(40) NOT NULL,
|
|
400
|
+
started_at BIGINT,
|
|
401
|
+
progress_comment_id VARCHAR(64),
|
|
402
|
+
reaction_comment_id VARCHAR(64),
|
|
403
|
+
current_prompt TEXT,
|
|
404
|
+
UNIQUE (issue_id, name)
|
|
405
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4`,
|
|
406
|
+
oldCols:
|
|
407
|
+
"id, issue_id, name, state, opencode_session_id, opencode_pid, workdir, created_at, started_at, progress_comment_id, reaction_comment_id, current_prompt",
|
|
408
|
+
newCols:
|
|
409
|
+
"uid, issue_id, name, state, opencode_session_id, opencode_pid, workdir, created_at, started_at, progress_comment_id, reaction_comment_id, current_prompt",
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
table: tMessages,
|
|
413
|
+
sqliteCreate: `CREATE TABLE ${tMessages} (
|
|
414
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
415
|
+
uid TEXT NOT NULL UNIQUE,
|
|
416
|
+
session_id TEXT NOT NULL REFERENCES ${tSessions}(uid) ON DELETE CASCADE,
|
|
378
417
|
content TEXT NOT NULL,
|
|
379
418
|
source_comment_id TEXT,
|
|
380
419
|
reaction_comment_id TEXT,
|
|
@@ -384,46 +423,55 @@ async function runMigrations(db: AsyncDatabase): Promise<void> {
|
|
|
384
423
|
created_at TEXT NOT NULL,
|
|
385
424
|
updated_at TEXT NOT NULL
|
|
386
425
|
)`,
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
426
|
+
mysqlCreate: `CREATE TABLE ${tMessages} (
|
|
427
|
+
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
428
|
+
uid VARCHAR(36) NOT NULL UNIQUE,
|
|
429
|
+
session_id VARCHAR(36) NOT NULL,
|
|
430
|
+
content LONGTEXT NOT NULL,
|
|
431
|
+
source_comment_id VARCHAR(64),
|
|
432
|
+
reaction_comment_id VARCHAR(64),
|
|
433
|
+
status VARCHAR(16) NOT NULL DEFAULT 'pending',
|
|
434
|
+
attempts INT NOT NULL DEFAULT 0,
|
|
435
|
+
error TEXT,
|
|
436
|
+
created_at VARCHAR(40) NOT NULL,
|
|
437
|
+
updated_at VARCHAR(40) NOT NULL
|
|
438
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4`,
|
|
439
|
+
oldCols:
|
|
440
|
+
"id, session_id, content, source_comment_id, reaction_comment_id, status, attempts, error, created_at, updated_at",
|
|
441
|
+
newCols:
|
|
442
|
+
"uid, session_id, content, source_comment_id, reaction_comment_id, status, attempts, error, created_at, updated_at",
|
|
443
|
+
},
|
|
444
|
+
];
|
|
391
445
|
|
|
392
|
-
|
|
393
|
-
|
|
446
|
+
for (const { table, sqliteCreate, mysqlCreate, oldCols, newCols } of UID_REBUILDS) {
|
|
447
|
+
if (await hasColumn(table, "uid")) continue;
|
|
448
|
+
if (sqlite) {
|
|
394
449
|
const exists = await db.get<{ cnt: number }>(
|
|
395
450
|
`SELECT COUNT(*) AS cnt FROM sqlite_master WHERE type='table' AND name='${table}'`
|
|
396
451
|
);
|
|
397
452
|
if (Number(exists?.cnt ?? 0) === 0) continue;
|
|
398
|
-
|
|
399
453
|
await db.exec("PRAGMA foreign_keys = OFF");
|
|
400
454
|
try {
|
|
401
455
|
await db.transaction(async () => {
|
|
402
|
-
await db.exec(`ALTER TABLE ${table} RENAME TO ${table}
|
|
403
|
-
await db.exec(
|
|
404
|
-
await db.exec(
|
|
405
|
-
|
|
406
|
-
);
|
|
407
|
-
await db.exec(`INSERT INTO ${table} (${dataCols}) SELECT ${dataCols} FROM ${table}__old_uid`);
|
|
408
|
-
await db.exec(`DROP TABLE ${table}__old_uid`);
|
|
456
|
+
await db.exec(`ALTER TABLE ${table} RENAME TO ${table}__old_id`);
|
|
457
|
+
await db.exec(sqliteCreate);
|
|
458
|
+
await db.exec(`INSERT INTO ${table} (${newCols}) SELECT ${oldCols} FROM ${table}__old_id`);
|
|
459
|
+
await db.exec(`DROP TABLE ${table}__old_id`);
|
|
409
460
|
});
|
|
410
461
|
} finally {
|
|
411
462
|
await db.exec("PRAGMA foreign_keys = ON");
|
|
412
463
|
}
|
|
413
|
-
}
|
|
414
|
-
} else {
|
|
415
|
-
const uidMySqlTables = [tIssues, tSessions, tMessages];
|
|
416
|
-
for (const tbl of uidMySqlTables) {
|
|
417
|
-
if (await hasColumn(tbl, "uid")) continue;
|
|
464
|
+
} else {
|
|
418
465
|
try {
|
|
419
|
-
await db.exec(
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
466
|
+
await db.exec("SET FOREIGN_KEY_CHECKS = 0");
|
|
467
|
+
await db.transaction(async () => {
|
|
468
|
+
await db.exec(`ALTER TABLE ${table} RENAME TO ${table}__old_id`);
|
|
469
|
+
await db.exec(mysqlCreate);
|
|
470
|
+
await db.exec(`INSERT INTO ${table} (${newCols}) SELECT ${oldCols} FROM ${table}__old_id`);
|
|
471
|
+
await db.exec(`DROP TABLE ${table}__old_id`);
|
|
472
|
+
});
|
|
473
|
+
} finally {
|
|
474
|
+
await db.exec("SET FOREIGN_KEY_CHECKS = 1");
|
|
427
475
|
}
|
|
428
476
|
}
|
|
429
477
|
}
|
package/src/op.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { TrackerRef, Issue, IssueState, OpSession, SessionState, Message }
|
|
|
5
5
|
// ─── Row Types ───
|
|
6
6
|
|
|
7
7
|
interface IssueRow {
|
|
8
|
-
|
|
8
|
+
uid: string;
|
|
9
9
|
tracker_type: string;
|
|
10
10
|
tracker_scope_key: string;
|
|
11
11
|
tracker_scope: string;
|
|
@@ -18,7 +18,7 @@ interface IssueRow {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
interface SessionRow {
|
|
21
|
-
|
|
21
|
+
uid: string;
|
|
22
22
|
issue_id: string;
|
|
23
23
|
name: string;
|
|
24
24
|
state: string;
|
|
@@ -37,7 +37,7 @@ interface SessionRow {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
interface MessageRow {
|
|
40
|
-
|
|
40
|
+
uid: string;
|
|
41
41
|
session_id: string;
|
|
42
42
|
content: string;
|
|
43
43
|
source_comment_id: string | null;
|
|
@@ -55,7 +55,7 @@ function rowToIssue(row: IssueRow): Issue {
|
|
|
55
55
|
let scope: Record<string, string>;
|
|
56
56
|
try { scope = JSON.parse(row.tracker_scope); } catch { scope = {}; }
|
|
57
57
|
return {
|
|
58
|
-
id: row.
|
|
58
|
+
id: row.uid,
|
|
59
59
|
trackerType: row.tracker_type,
|
|
60
60
|
trackerScope: scope,
|
|
61
61
|
trackerScopeKey: row.tracker_scope_key,
|
|
@@ -70,7 +70,7 @@ function rowToIssue(row: IssueRow): Issue {
|
|
|
70
70
|
|
|
71
71
|
function rowToSession(row: SessionRow): OpSession {
|
|
72
72
|
return {
|
|
73
|
-
id: row.
|
|
73
|
+
id: row.uid,
|
|
74
74
|
issueId: row.issue_id,
|
|
75
75
|
name: row.name,
|
|
76
76
|
state: row.state as SessionState,
|
|
@@ -91,7 +91,7 @@ function rowToSession(row: SessionRow): OpSession {
|
|
|
91
91
|
|
|
92
92
|
function rowToMessage(row: MessageRow): Message {
|
|
93
93
|
return {
|
|
94
|
-
id: row.
|
|
94
|
+
id: row.uid,
|
|
95
95
|
sessionId: row.session_id,
|
|
96
96
|
content: row.content,
|
|
97
97
|
sourceCommentId: row.source_comment_id ?? undefined,
|
|
@@ -121,7 +121,7 @@ export class Store {
|
|
|
121
121
|
// ─── Issues ───
|
|
122
122
|
|
|
123
123
|
async getIssue(id: string): Promise<Issue | undefined> {
|
|
124
|
-
const row = await getDB().get<IssueRow>("SELECT * FROM {{issues}} WHERE
|
|
124
|
+
const row = await getDB().get<IssueRow>("SELECT * FROM {{issues}} WHERE uid = ?", [id]);
|
|
125
125
|
return row ? rowToIssue(row) : undefined;
|
|
126
126
|
}
|
|
127
127
|
|
|
@@ -137,7 +137,7 @@ export class Store {
|
|
|
137
137
|
const existing = await this.findIssue(ref.trackerType, scopeKey, ref.issueId);
|
|
138
138
|
if (existing) {
|
|
139
139
|
if (title && existing.title !== title) {
|
|
140
|
-
await getDB().run("UPDATE {{issues}} SET title = ?, updated_at = ? WHERE
|
|
140
|
+
await getDB().run("UPDATE {{issues}} SET title = ?, updated_at = ? WHERE uid = ?", [
|
|
141
141
|
title,
|
|
142
142
|
new Date().toISOString(),
|
|
143
143
|
existing.id,
|
|
@@ -150,7 +150,7 @@ export class Store {
|
|
|
150
150
|
const now = new Date();
|
|
151
151
|
const id = crypto.randomUUID();
|
|
152
152
|
await getDB().run(
|
|
153
|
-
"INSERT OR IGNORE INTO {{issues}} (
|
|
153
|
+
"INSERT OR IGNORE INTO {{issues}} (uid, tracker_type, tracker_scope_key, tracker_scope, tracker_issue_id, state, title, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
|
154
154
|
[id, ref.trackerType, scopeKey, JSON.stringify(ref.scope), ref.issueId, "created", title, now.toISOString(), now.toISOString()]
|
|
155
155
|
);
|
|
156
156
|
|
|
@@ -166,7 +166,7 @@ export class Store {
|
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
async updateIssueState(id: string, state: IssueState): Promise<void> {
|
|
169
|
-
await getDB().run("UPDATE {{issues}} SET state = ?, updated_at = ? WHERE
|
|
169
|
+
await getDB().run("UPDATE {{issues}} SET state = ?, updated_at = ? WHERE uid = ?", [
|
|
170
170
|
state,
|
|
171
171
|
new Date().toISOString(),
|
|
172
172
|
id,
|
|
@@ -186,7 +186,7 @@ export class Store {
|
|
|
186
186
|
// ─── OpSessions ───
|
|
187
187
|
|
|
188
188
|
async getSession(id: string): Promise<OpSession | undefined> {
|
|
189
|
-
const row = await getDB().get<SessionRow>("SELECT * FROM {{op_sessions}} WHERE
|
|
189
|
+
const row = await getDB().get<SessionRow>("SELECT * FROM {{op_sessions}} WHERE uid = ?", [id]);
|
|
190
190
|
return row ? rowToSession(row) : undefined;
|
|
191
191
|
}
|
|
192
192
|
|
|
@@ -218,14 +218,14 @@ export class Store {
|
|
|
218
218
|
createdAt: new Date(),
|
|
219
219
|
};
|
|
220
220
|
await getDB().run(
|
|
221
|
-
"INSERT OR IGNORE INTO {{op_sessions}} (
|
|
221
|
+
"INSERT OR IGNORE INTO {{op_sessions}} (uid, issue_id, name, state, opencode_session_id, opencode_pid, workdir, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
|
222
222
|
[session.id, session.issueId, session.name, session.state, null, null, null, session.createdAt.toISOString()]
|
|
223
223
|
);
|
|
224
224
|
return session;
|
|
225
225
|
}
|
|
226
226
|
|
|
227
227
|
async updateSession(id: string, patch: Partial<OpSession>): Promise<OpSession | undefined> {
|
|
228
|
-
const row = await getDB().get<SessionRow>("SELECT * FROM {{op_sessions}} WHERE
|
|
228
|
+
const row = await getDB().get<SessionRow>("SELECT * FROM {{op_sessions}} WHERE uid = ?", [id]);
|
|
229
229
|
if (!row) return undefined;
|
|
230
230
|
const existing = rowToSession(row);
|
|
231
231
|
const updated = { ...existing, ...patch };
|
|
@@ -233,7 +233,7 @@ export class Store {
|
|
|
233
233
|
await getDB().run(
|
|
234
234
|
`UPDATE {{op_sessions}} SET state = ?, opencode_session_id = ?, opencode_pid = ?, workdir = ?,
|
|
235
235
|
started_at = ?, progress_comment_id = ?, reaction_comment_id = ?, current_prompt = ?,
|
|
236
|
-
last_output_at = ?, nudge_rounds = ?, stuck_nudge_rounds = ?, generation = ? WHERE
|
|
236
|
+
last_output_at = ?, nudge_rounds = ?, stuck_nudge_rounds = ?, generation = ? WHERE uid = ?`,
|
|
237
237
|
[
|
|
238
238
|
updated.state,
|
|
239
239
|
updated.opencodeSessionId ?? null,
|
|
@@ -275,7 +275,7 @@ export class Store {
|
|
|
275
275
|
const now = new Date().toISOString();
|
|
276
276
|
const id = crypto.randomUUID();
|
|
277
277
|
await getDB().run(
|
|
278
|
-
"INSERT OR IGNORE INTO {{messages}} (
|
|
278
|
+
"INSERT OR IGNORE INTO {{messages}} (uid, session_id, content, source_comment_id, reaction_comment_id, status, attempts, error, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
|
279
279
|
[id, sessionId, content, sourceCommentId ?? null, reactionCommentId ?? null, "pending", 0, null, now, now]
|
|
280
280
|
);
|
|
281
281
|
return {
|
|
@@ -287,7 +287,7 @@ export class Store {
|
|
|
287
287
|
}
|
|
288
288
|
|
|
289
289
|
async getMessage(id: string): Promise<Message | undefined> {
|
|
290
|
-
const row = await getDB().get<MessageRow>("SELECT * FROM {{messages}} WHERE
|
|
290
|
+
const row = await getDB().get<MessageRow>("SELECT * FROM {{messages}} WHERE uid = ?", [id]);
|
|
291
291
|
return row ? rowToMessage(row) : undefined;
|
|
292
292
|
}
|
|
293
293
|
|
|
@@ -300,10 +300,10 @@ export class Store {
|
|
|
300
300
|
}
|
|
301
301
|
|
|
302
302
|
async updateMessageStatus(id: string, status: Message["status"], error?: string): Promise<void> {
|
|
303
|
-
const row = await getDB().get<MessageRow>("SELECT * FROM {{messages}} WHERE
|
|
303
|
+
const row = await getDB().get<MessageRow>("SELECT * FROM {{messages}} WHERE uid = ?", [id]);
|
|
304
304
|
const attempts = row ? row.attempts + (status === "failed" ? 1 : 0) : 0;
|
|
305
305
|
await getDB().run(
|
|
306
|
-
"UPDATE {{messages}} SET status = ?, attempts = ?, error = ?, updated_at = ? WHERE
|
|
306
|
+
"UPDATE {{messages}} SET status = ?, attempts = ?, error = ?, updated_at = ? WHERE uid = ?",
|
|
307
307
|
[status, attempts, error ?? null, new Date().toISOString(), id]
|
|
308
308
|
);
|
|
309
309
|
}
|
|
@@ -436,7 +436,7 @@ export class Store {
|
|
|
436
436
|
*/
|
|
437
437
|
async claimIssue(issueId: string, daemonId: number): Promise<boolean> {
|
|
438
438
|
const res = await getDB().run(
|
|
439
|
-
"UPDATE {{issues}} SET owner_daemon_id = ? WHERE
|
|
439
|
+
"UPDATE {{issues}} SET owner_daemon_id = ? WHERE uid = ? AND owner_daemon_id IS NULL",
|
|
440
440
|
[daemonId, issueId]
|
|
441
441
|
);
|
|
442
442
|
return res.changes === 1;
|
|
@@ -454,7 +454,7 @@ export class Store {
|
|
|
454
454
|
/** Atomic message claim: pending → running. False = lost or already done. */
|
|
455
455
|
async claimMessage(messageId: string): Promise<boolean> {
|
|
456
456
|
const res = await getDB().run(
|
|
457
|
-
"UPDATE {{messages}} SET status = 'running', updated_at = ? WHERE
|
|
457
|
+
"UPDATE {{messages}} SET status = 'running', updated_at = ? WHERE uid = ? AND status = 'pending'",
|
|
458
458
|
[new Date().toISOString(), messageId]
|
|
459
459
|
);
|
|
460
460
|
return res.changes === 1;
|
|
@@ -471,7 +471,7 @@ export class Store {
|
|
|
471
471
|
async listOwnedSessions(daemonId: number): Promise<OpSession[]> {
|
|
472
472
|
const rows = await getDB().all<SessionRow>(
|
|
473
473
|
`SELECT s.* FROM {{op_sessions}} s
|
|
474
|
-
INNER JOIN {{issues}} i ON i.
|
|
474
|
+
INNER JOIN {{issues}} i ON i.uid = s.issue_id
|
|
475
475
|
WHERE i.owner_daemon_id = ?
|
|
476
476
|
ORDER BY s.created_at`,
|
|
477
477
|
[daemonId]
|
|
@@ -483,8 +483,8 @@ export class Store {
|
|
|
483
483
|
async getOwnedPendingOrRunningMessages(daemonId: number): Promise<Message[]> {
|
|
484
484
|
const rows = await getDB().all<MessageRow>(
|
|
485
485
|
`SELECT m.* FROM {{messages}} m
|
|
486
|
-
INNER JOIN {{op_sessions}} s ON s.
|
|
487
|
-
INNER JOIN {{issues}} i ON i.
|
|
486
|
+
INNER JOIN {{op_sessions}} s ON s.uid = m.session_id
|
|
487
|
+
INNER JOIN {{issues}} i ON i.uid = s.issue_id
|
|
488
488
|
WHERE i.owner_daemon_id = ? AND m.status IN ('pending', 'running')
|
|
489
489
|
ORDER BY m.created_at ASC`,
|
|
490
490
|
[daemonId]
|
package/src/schema-mysql.sql
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
-- tables InnoDB + utf8mb4 for FK CASCADE + full Unicode (emoji).
|
|
9
9
|
|
|
10
10
|
CREATE TABLE IF NOT EXISTS {{issues}} (
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
12
|
+
uid VARCHAR(36) NOT NULL UNIQUE,
|
|
13
13
|
tracker_type VARCHAR(64) NOT NULL,
|
|
14
14
|
tracker_scope_key VARCHAR(255) NOT NULL,
|
|
15
15
|
tracker_scope TEXT NOT NULL,
|
|
@@ -22,8 +22,8 @@ CREATE TABLE IF NOT EXISTS {{issues}} (
|
|
|
22
22
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
23
23
|
|
|
24
24
|
CREATE TABLE IF NOT EXISTS {{op_sessions}} (
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
26
|
+
uid VARCHAR(36) NOT NULL UNIQUE,
|
|
27
27
|
issue_id VARCHAR(36) NOT NULL,
|
|
28
28
|
name VARCHAR(64) NOT NULL,
|
|
29
29
|
state VARCHAR(16) NOT NULL DEFAULT 'idle',
|
|
@@ -36,15 +36,15 @@ CREATE TABLE IF NOT EXISTS {{op_sessions}} (
|
|
|
36
36
|
reaction_comment_id VARCHAR(64),
|
|
37
37
|
current_prompt TEXT,
|
|
38
38
|
UNIQUE (issue_id, name),
|
|
39
|
-
CONSTRAINT {{fk_sessions_issue}} FOREIGN KEY (issue_id) REFERENCES {{issues}}(
|
|
39
|
+
CONSTRAINT {{fk_sessions_issue}} FOREIGN KEY (issue_id) REFERENCES {{issues}}(uid) ON DELETE CASCADE
|
|
40
40
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
41
41
|
-- UNIQUE(issue_id, name) above creates a composite index whose leftmost
|
|
42
42
|
-- prefix (issue_id) satisfies the FK's index requirement, so no separate
|
|
43
43
|
-- idx_sessions_issue is needed on MySQL.
|
|
44
44
|
|
|
45
45
|
CREATE TABLE IF NOT EXISTS {{messages}} (
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
47
|
+
uid VARCHAR(36) NOT NULL UNIQUE,
|
|
48
48
|
session_id VARCHAR(36) NOT NULL,
|
|
49
49
|
content LONGTEXT NOT NULL,
|
|
50
50
|
source_comment_id VARCHAR(64),
|
|
@@ -54,7 +54,7 @@ CREATE TABLE IF NOT EXISTS {{messages}} (
|
|
|
54
54
|
error TEXT,
|
|
55
55
|
created_at VARCHAR(40) NOT NULL,
|
|
56
56
|
updated_at VARCHAR(40) NOT NULL,
|
|
57
|
-
CONSTRAINT {{fk_messages_session}} FOREIGN KEY (session_id) REFERENCES {{op_sessions}}(
|
|
57
|
+
CONSTRAINT {{fk_messages_session}} FOREIGN KEY (session_id) REFERENCES {{op_sessions}}(uid) ON DELETE CASCADE
|
|
58
58
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
59
59
|
CREATE INDEX idx_messages_session ON {{messages}} (session_id);
|
|
60
60
|
CREATE INDEX idx_messages_status ON {{messages}} (status);
|
package/src/schema-sqlite.sql
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
-- share one DB across multiple daemon instances.
|
|
5
5
|
|
|
6
6
|
CREATE TABLE IF NOT EXISTS {{issues}} (
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
8
|
+
uid TEXT NOT NULL UNIQUE,
|
|
9
9
|
tracker_type TEXT NOT NULL,
|
|
10
10
|
tracker_scope_key TEXT NOT NULL,
|
|
11
11
|
tracker_scope TEXT NOT NULL,
|
|
@@ -18,9 +18,9 @@ CREATE TABLE IF NOT EXISTS {{issues}} (
|
|
|
18
18
|
);
|
|
19
19
|
|
|
20
20
|
CREATE TABLE IF NOT EXISTS {{op_sessions}} (
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
issue_id TEXT NOT NULL REFERENCES {{issues}}(
|
|
21
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
22
|
+
uid TEXT NOT NULL UNIQUE,
|
|
23
|
+
issue_id TEXT NOT NULL REFERENCES {{issues}}(uid) ON DELETE CASCADE,
|
|
24
24
|
name TEXT NOT NULL,
|
|
25
25
|
state TEXT NOT NULL DEFAULT 'idle',
|
|
26
26
|
opencode_session_id TEXT,
|
|
@@ -35,9 +35,9 @@ CREATE TABLE IF NOT EXISTS {{op_sessions}} (
|
|
|
35
35
|
);
|
|
36
36
|
|
|
37
37
|
CREATE TABLE IF NOT EXISTS {{messages}} (
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
session_id TEXT NOT NULL REFERENCES {{op_sessions}}(
|
|
38
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
39
|
+
uid TEXT NOT NULL UNIQUE,
|
|
40
|
+
session_id TEXT NOT NULL REFERENCES {{op_sessions}}(uid) ON DELETE CASCADE,
|
|
41
41
|
content TEXT NOT NULL,
|
|
42
42
|
source_comment_id TEXT,
|
|
43
43
|
reaction_comment_id TEXT,
|