@sleep2agi/commhub-server 0.5.0-preview.24 → 0.5.0-preview.26

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/src/tools.ts CHANGED
@@ -45,9 +45,8 @@ export function registerTools(server: McpServer, clientIP?: string, enforceNetwo
45
45
  console.log(`[${ts()}] ${alias} (${resume_id.slice(0, 8)}) → report_status: ${status}${task ? " | " + task.slice(0, 60) : ""}${effectiveNetId ? " [net]" : ""}`);
46
46
  const trimmedOutput = output?.slice(0, 4000);
47
47
 
48
- try {
49
- db.run("BEGIN IMMEDIATE");
50
- // Only delete same-alias sessions within the same network (prevent cross-network alias conflict)
48
+ db.transaction(() => {
49
+ // Only delete same-alias sessions within the same network
51
50
  if (effectiveNetId) {
52
51
  db.run("DELETE FROM sessions WHERE alias = ?1 AND resume_id != ?2 AND network_id = ?3", [alias, resume_id, effectiveNetId]);
53
52
  } else {
@@ -57,33 +56,19 @@ export function registerTools(server: McpServer, clientIP?: string, enforceNetwo
57
56
  `INSERT INTO sessions (resume_id, alias, tmux_name, server, ip, hostname, agent, project_dir, version, status, task, output, progress, score, node_id, session_id, config_path, channels, network_id, last_seen_at, updated_at)
58
57
  VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19, datetime('now'), datetime('now'))
59
58
  ON CONFLICT(resume_id) DO UPDATE SET
60
- alias = COALESCE(?2, sessions.alias),
61
- tmux_name = COALESCE(?3, sessions.tmux_name),
62
- server = COALESCE(?4, sessions.server),
63
- ip = COALESCE(?5, sessions.ip),
64
- hostname = COALESCE(?6, sessions.hostname),
65
- agent = COALESCE(?7, sessions.agent),
66
- project_dir = COALESCE(?8, sessions.project_dir),
67
- version = COALESCE(?9, sessions.version),
68
- status = ?10,
69
- task = COALESCE(?11, sessions.task),
70
- output = COALESCE(?12, sessions.output),
71
- progress = COALESCE(?13, sessions.progress),
72
- score = COALESCE(?14, sessions.score),
73
- node_id = COALESCE(?15, sessions.node_id),
74
- session_id = COALESCE(?16, sessions.session_id),
75
- config_path = COALESCE(?17, sessions.config_path),
76
- channels = COALESCE(?18, sessions.channels),
77
- network_id = COALESCE(?19, sessions.network_id),
78
- last_seen_at = datetime('now'),
79
- updated_at = datetime('now')`,
59
+ alias = COALESCE(?2, sessions.alias), tmux_name = COALESCE(?3, sessions.tmux_name),
60
+ server = COALESCE(?4, sessions.server), ip = COALESCE(?5, sessions.ip),
61
+ hostname = COALESCE(?6, sessions.hostname), agent = COALESCE(?7, sessions.agent),
62
+ project_dir = COALESCE(?8, sessions.project_dir), version = COALESCE(?9, sessions.version),
63
+ status = ?10, task = COALESCE(?11, sessions.task),
64
+ output = COALESCE(?12, sessions.output), progress = COALESCE(?13, sessions.progress),
65
+ score = COALESCE(?14, sessions.score), node_id = COALESCE(?15, sessions.node_id),
66
+ session_id = COALESCE(?16, sessions.session_id), config_path = COALESCE(?17, sessions.config_path),
67
+ channels = COALESCE(?18, sessions.channels), network_id = COALESCE(?19, sessions.network_id),
68
+ last_seen_at = datetime('now'), updated_at = datetime('now')`,
80
69
  [resume_id, alias, tmux ?? null, srv ?? null, clientIP ?? null, hn ?? null, ag ?? null, pd ?? null, ver ?? null, status, task ?? null, trimmedOutput ?? null, progress ?? null, score ?? null, node_id ?? null, session_id ?? null, config_path ?? null, channels ?? null, netId ?? null]
81
70
  );
82
- db.run("COMMIT");
83
- } catch (e) {
84
- try { db.run("ROLLBACK"); } catch {}
85
- throw e;
86
- }
71
+ });
87
72
 
88
73
  // V2: sync tasks table — report_status(working) → tasks.running
89
74
  if (status === "working" && task) {
@@ -95,9 +80,9 @@ export function registerTools(server: McpServer, clientIP?: string, enforceNetwo
95
80
  );
96
81
  if (runResult.changes > 0) {
97
82
  // Find task_id for logging
98
- const t = db.query<{ task_id: string }, [string, string]>(
99
- "SELECT task_id FROM tasks WHERE to_name = ?1 AND content = ?2 AND status = 'running' ORDER BY started_at DESC LIMIT 1"
100
- ).get(alias, task);
83
+ const t = db.get<{ task_id: string }>(
84
+ "SELECT task_id FROM tasks WHERE to_name = ?1 AND content = ?2 AND status = 'running' ORDER BY started_at DESC LIMIT 1",
85
+ alias, task);
101
86
  if (t) logTaskEvent(t.task_id, null, "running", alias);
102
87
  }
103
88
  } catch {}
@@ -127,9 +112,9 @@ export function registerTools(server: McpServer, clientIP?: string, enforceNetwo
127
112
  }
128
113
 
129
114
  // inbox uses alias for routing
130
- const row = db.query<{ cnt: number }, [string]>(
131
- "SELECT COUNT(*) as cnt FROM inbox WHERE session_name = ?1 AND acked = 0"
132
- ).get(alias);
115
+ const row = db.get<{ cnt: number }>(
116
+ "SELECT COUNT(*) as cnt FROM inbox WHERE session_name = ?1 AND acked = 0",
117
+ alias);
133
118
 
134
119
  return {
135
120
  content: [
@@ -161,51 +146,40 @@ export function registerTools(server: McpServer, clientIP?: string, enforceNetwo
161
146
  async ({ alias, task, result, artifacts, score, duration_minutes }) => {
162
147
  console.log(`[${ts()}] ${alias} → report_completion: ${task.slice(0, 60)}`);
163
148
  const id = uuidv4();
164
- try {
165
- db.run("BEGIN IMMEDIATE");
149
+ const taskUpdateChanges = db.transaction(() => {
166
150
  db.run(
167
151
  `INSERT INTO completions (id, session_name, task, result, artifacts, score, duration_minutes)
168
152
  VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)`,
169
153
  [id, alias, task, result, artifacts ? JSON.stringify(artifacts) : null, score ?? null, duration_minutes ?? null]
170
154
  );
171
-
172
155
  db.run(
173
156
  `UPDATE sessions SET status = 'idle', task = NULL, progress = 0, updated_at = datetime('now')
174
157
  WHERE alias = ?1`,
175
158
  [alias]
176
159
  );
177
-
178
160
  // V2: sync tasks table — try by task_id first, then by content
179
- const taskUpdate = db.run(
161
+ const tu = db.run(
180
162
  `UPDATE tasks SET status = 'replied', result = ?1, completed_at = datetime('now')
181
163
  WHERE task_id = ?2 AND status IN ('delivered', 'acked', 'running')`,
182
164
  [result.slice(0, 4000), task]
183
165
  );
184
- if (taskUpdate.changes === 0) {
185
- // fallback: match most recent task by to_name + content (legacy path)
186
- const match = db.query<{ task_id: string }, [string, string]>(
166
+ if (tu.changes === 0) {
167
+ const match = db.get<{ task_id: string }>(
187
168
  `SELECT task_id FROM tasks WHERE to_name = ?1 AND content = ?2
188
- AND status IN ('delivered', 'acked', 'running') ORDER BY created_at DESC LIMIT 1`
189
- ).get(alias, task);
169
+ AND status IN ('delivered', 'acked', 'running') ORDER BY created_at DESC LIMIT 1`,
170
+ alias, task);
190
171
  if (match) {
191
- db.run(
192
- `UPDATE tasks SET status = 'replied', result = ?1, completed_at = datetime('now')
193
- WHERE task_id = ?2`,
194
- [result.slice(0, 4000), match.task_id]
195
- );
172
+ db.run(`UPDATE tasks SET status = 'replied', result = ?1, completed_at = datetime('now') WHERE task_id = ?2`,
173
+ [result.slice(0, 4000), match.task_id]);
196
174
  }
197
175
  }
198
-
199
- db.run("COMMIT");
200
- // Log event after commit
201
- const updatedTaskId = taskUpdate.changes > 0 ? task : (db.query<{ task_id: string }, [string]>(
202
- "SELECT task_id FROM tasks WHERE to_name = ?1 AND status = 'replied' ORDER BY completed_at DESC LIMIT 1"
203
- ).get(alias)?.task_id);
204
- if (updatedTaskId) logTaskEvent(updatedTaskId, null, "replied", alias, "report_completion");
205
- } catch (e) {
206
- try { db.run("ROLLBACK"); } catch {}
207
- throw e;
208
- }
176
+ return tu.changes;
177
+ });
178
+ // Log event after transaction
179
+ const updatedTaskId = taskUpdateChanges > 0 ? task : (db.get<{ task_id: string }>(
180
+ "SELECT task_id FROM tasks WHERE to_name = ?1 AND status = 'replied' ORDER BY completed_at DESC LIMIT 1",
181
+ alias)?.task_id);
182
+ if (updatedTaskId) logTaskEvent(updatedTaskId, null, "replied", alias, "report_completion");
209
183
 
210
184
  return {
211
185
  content: [{ type: "text" as const, text: JSON.stringify({ ok: true, completion_id: id }) }],
@@ -221,16 +195,16 @@ export function registerTools(server: McpServer, clientIP?: string, enforceNetwo
221
195
  limit: z.number().min(1).max(100).optional().default(10),
222
196
  },
223
197
  async ({ alias, limit }) => {
224
- const rows0 = db.query<{ cnt: number }, [string]>(
225
- "SELECT COUNT(*) as cnt FROM inbox WHERE session_name = ?1 AND acked = 0"
226
- ).get(alias);
198
+ const rows0 = db.get<{ cnt: number }>(
199
+ "SELECT COUNT(*) as cnt FROM inbox WHERE session_name = ?1 AND acked = 0",
200
+ alias);
227
201
  console.log(`[${ts()}] ${alias} → get_inbox: ${rows0?.cnt ?? 0} pending messages`);
228
- const rows = db.query<any, [string, number]>(
202
+ const rows = db.all(
229
203
  `SELECT id, type, priority, content, context, from_session, created_at
230
204
  FROM inbox WHERE session_name = ?1 AND acked = 0
231
205
  ORDER BY CASE priority WHEN 'high' THEN 0 WHEN 'normal' THEN 1 ELSE 2 END, created_at
232
- LIMIT ?2`
233
- ).all(alias, limit);
206
+ LIMIT ?2`,
207
+ alias, limit);
234
208
 
235
209
  return {
236
210
  content: [{ type: "text" as const, text: JSON.stringify({ ok: true, messages: rows }) }],
@@ -294,12 +268,11 @@ export function registerTools(server: McpServer, clientIP?: string, enforceNetwo
294
268
  if (filter_status) { sql += " AND status = ?"; params.push(filter_status); }
295
269
  if (filter_server) { sql += " AND server = ?"; params.push(filter_server); }
296
270
  sql += " ORDER BY updated_at DESC";
297
- return db.query(sql).all(...params);
298
- })();
271
+ return db.all(sql, ...params);
272
+ });
299
273
 
300
- const summary = db.query<any, []>(
301
- "SELECT status, COUNT(*) as count FROM sessions GROUP BY status"
302
- ).all();
274
+ const summary = db.all(
275
+ "SELECT status, COUNT(*) as count FROM sessions GROUP BY status");
303
276
 
304
277
  return {
305
278
  content: [
@@ -318,13 +291,13 @@ export function registerTools(server: McpServer, clientIP?: string, enforceNetwo
318
291
  { alias: z.string().min(1).max(200).describe("Session alias") },
319
292
  async ({ alias }) => {
320
293
  console.log(`[${ts()}] hub → get_session_status: ${alias}`);
321
- const session = db.query("SELECT * FROM sessions WHERE alias = ?1").get(alias);
322
- const pending = db.query<{ cnt: number }, [string]>(
323
- "SELECT COUNT(*) as cnt FROM inbox WHERE session_name = ?1 AND acked = 0"
324
- ).get(alias);
325
- const recent = db.query(
326
- "SELECT * FROM completions WHERE session_name = ?1 ORDER BY completed_at DESC LIMIT 5"
327
- ).all(alias);
294
+ const session = db.get("SELECT * FROM sessions WHERE alias = ?1", alias);
295
+ const pending = db.get<{ cnt: number }>(
296
+ "SELECT COUNT(*) as cnt FROM inbox WHERE session_name = ?1 AND acked = 0",
297
+ alias);
298
+ const recent = db.all(
299
+ "SELECT * FROM completions WHERE session_name = ?1 ORDER BY completed_at DESC LIMIT 5",
300
+ alias);
328
301
 
329
302
  return {
330
303
  content: [
@@ -353,7 +326,7 @@ export function registerTools(server: McpServer, clientIP?: string, enforceNetwo
353
326
  const effectiveNetId = getNetworkId(netId);
354
327
 
355
328
  // License check
356
- const license = db.query<any, []>("SELECT type, expires_at FROM licenses ORDER BY created_at LIMIT 1").get();
329
+ const license = db.get<any>("SELECT type, expires_at FROM licenses ORDER BY created_at LIMIT 1");
357
330
  if (license?.expires_at) {
358
331
  const now = new Date().toISOString().replace("T", " ").slice(0, 19);
359
332
  if (license.expires_at < now) {
@@ -367,8 +340,7 @@ export function registerTools(server: McpServer, clientIP?: string, enforceNetwo
367
340
  console.log(`[${ts()}] ${from_session} → send_task → ${alias}: ${task.slice(0, 60)}${priority === "high" ? " [HIGH]" : ""}`);
368
341
  const id = uuidv4();
369
342
  // 事务:inbox + tasks 双写
370
- try {
371
- db.run("BEGIN IMMEDIATE");
343
+ db.transaction(() => {
372
344
  db.run(
373
345
  `INSERT INTO inbox (id, session_name, type, priority, content, context, from_session, requires_response, network_id)
374
346
  VALUES (?1, ?2, 'task', ?3, ?4, ?5, ?6, 'reply', ?7)`,
@@ -379,19 +351,15 @@ export function registerTools(server: McpServer, clientIP?: string, enforceNetwo
379
351
  VALUES (?1, ?2, ?3, ?4, 'delivered', ?5, 'reply', datetime('now'), datetime('now'), datetime('now', ?6), ?7)`,
380
352
  [id, from_session, alias, priority, task, `+${ttl_seconds || 3600} seconds`, effectiveNetId]
381
353
  );
382
- db.run("COMMIT");
383
- logTaskEvent(id, null, "delivered", from_session, `→ ${alias}`);
384
- } catch (e) {
385
- try { db.run("ROLLBACK"); } catch {}
386
- throw e;
387
- }
354
+ });
355
+ logTaskEvent(id, null, "delivered", from_session, `→ ${alias}`);
388
356
 
389
- const session = db.query<any, [string]>("SELECT status FROM sessions WHERE alias = ?1").get(alias);
357
+ const session = db.get<any>("SELECT status FROM sessions WHERE alias = ?1", alias);
390
358
 
391
359
  // SSE push by alias
392
- const pending = db.query<{ cnt: number }, [string]>(
393
- "SELECT COUNT(*) as cnt FROM inbox WHERE session_name = ?1 AND acked = 0"
394
- ).get(alias);
360
+ const pending = db.get<{ cnt: number }>(
361
+ "SELECT COUNT(*) as cnt FROM inbox WHERE session_name = ?1 AND acked = 0",
362
+ alias);
395
363
  pushEvent(alias, { type: "new_task", inbox_count: pending?.cnt ?? 1, priority, from: from_session });
396
364
 
397
365
  return {
@@ -426,7 +394,7 @@ export function registerTools(server: McpServer, clientIP?: string, enforceNetwo
426
394
  [id, alias, message, from_session]
427
395
  );
428
396
 
429
- const session = db.query<any, [string]>("SELECT status FROM sessions WHERE alias = ?1").get(alias);
397
+ const session = db.get<any>("SELECT status FROM sessions WHERE alias = ?1", alias);
430
398
 
431
399
  pushEvent(alias, { type: "new_message", message, from: from_session, message_id: id });
432
400
 
@@ -459,9 +427,7 @@ export function registerTools(server: McpServer, clientIP?: string, enforceNetwo
459
427
  async ({ alias, text, in_reply_to, status: replyStatus, from_session }) => {
460
428
  console.log(`[${ts()}] ${from_session} → send_reply (${replyStatus}) → ${alias}: ${text.slice(0, 60)}`);
461
429
  const id = uuidv4();
462
- let replyLogged = false;
463
- try {
464
- db.run("BEGIN IMMEDIATE");
430
+ const replyLogged = db.transaction(() => {
465
431
  db.run(
466
432
  `INSERT INTO inbox (id, session_name, type, priority, content, from_session, in_reply_to, requires_response)
467
433
  VALUES (?1, ?2, 'reply', 'normal', ?3, ?4, ?5, 'none')`,
@@ -477,20 +443,17 @@ export function registerTools(server: McpServer, clientIP?: string, enforceNetwo
477
443
  );
478
444
  if (result.changes === 0) {
479
445
  console.log(`[${ts()}] ⚠ send_reply: task ${in_reply_to?.slice(0, 8)} not found or already terminal`);
480
- } else {
481
- replyLogged = true;
446
+ return false;
482
447
  }
448
+ return true;
483
449
  }
484
- db.run("COMMIT");
485
- } catch (e) {
486
- try { db.run("ROLLBACK"); } catch {}
487
- throw e;
488
- }
450
+ return false;
451
+ });
489
452
 
490
453
  // Log event after commit (outside transaction)
491
454
  if (replyLogged && in_reply_to) logTaskEvent(in_reply_to, null, replyStatus, from_session, text.slice(0, 200));
492
455
 
493
- const session = db.query<any, [string]>("SELECT status FROM sessions WHERE alias = ?1").get(alias);
456
+ const session = db.get<any>("SELECT status FROM sessions WHERE alias = ?1", alias);
494
457
  pushEvent(alias, { type: "new_reply", from: from_session, message_id: id, in_reply_to, status: replyStatus });
495
458
 
496
459
  return {
@@ -537,17 +500,14 @@ export function registerTools(server: McpServer, clientIP?: string, enforceNetwo
537
500
  async ({ task_id, from_session }) => {
538
501
  console.log(`[${ts()}] ${from_session} → retry_task → ${task_id.slice(0, 8)}`);
539
502
  // Find the original task
540
- const task = db.query<any, [string]>(
541
- "SELECT * FROM tasks WHERE task_id = ?1"
542
- ).get(task_id);
503
+ const task = db.get<any>("SELECT * FROM tasks WHERE task_id = ?1", task_id);
543
504
  if (!task) {
544
505
  return { content: [{ type: "text" as const, text: JSON.stringify({ ok: false, error: "task not found" }) }] };
545
506
  }
546
507
  if (!["failed", "expired", "cancelled"].includes(task.status)) {
547
508
  return { content: [{ type: "text" as const, text: JSON.stringify({ ok: false, error: `task status is ${task.status}, not retryable` }) }] };
548
509
  }
549
- try {
550
- db.run("BEGIN IMMEDIATE");
510
+ db.transaction(() => {
551
511
  // Reset task status
552
512
  db.run(
553
513
  `UPDATE tasks SET status = 'delivered', result = NULL, completed_at = NULL, started_at = NULL, delivered_at = datetime('now'), expires_at = datetime('now', '+1 hour')
@@ -561,12 +521,8 @@ export function registerTools(server: McpServer, clientIP?: string, enforceNetwo
561
521
  VALUES (?1, ?2, 'task', ?3, ?4, ?5, 'reply')`,
562
522
  [retryInboxId, task.to_name, task.priority, task.content, from_session]
563
523
  );
564
- db.run("COMMIT");
565
- logTaskEvent(task_id, task.status, "delivered", from_session, "retry");
566
- } catch (e) {
567
- try { db.run("ROLLBACK"); } catch {}
568
- throw e;
569
- }
524
+ });
525
+ logTaskEvent(task_id, task.status, "delivered", from_session, "retry");
570
526
  // SSE push
571
527
  pushEvent(task.to_name, { type: "new_task", inbox_count: 1, priority: task.priority, from: from_session });
572
528
  return {
@@ -583,7 +539,7 @@ export function registerTools(server: McpServer, clientIP?: string, enforceNetwo
583
539
  task_id: z.string().min(1).max(200).describe("Task ID to query"),
584
540
  },
585
541
  async ({ task_id }) => {
586
- const task = db.query<any, [string]>("SELECT * FROM tasks WHERE task_id = ?1").get(task_id);
542
+ const task = db.get<any>("SELECT * FROM tasks WHERE task_id = ?1", task_id);
587
543
  return {
588
544
  content: [{
589
545
  type: "text" as const,
@@ -614,12 +570,11 @@ export function registerTools(server: McpServer, clientIP?: string, enforceNetwo
614
570
  if (from_name) { sql += ` AND from_name = ?${params.length + 1}`; params.push(from_name); }
615
571
  sql += ` ORDER BY created_at DESC LIMIT ?${params.length + 1}`;
616
572
  params.push(limit);
617
- const tasks = db.query(sql).all(...params);
573
+ const tasks = db.all(sql, ...params);
618
574
 
619
575
  // Stats
620
- const stats = db.query<any, []>(
621
- "SELECT status, COUNT(*) as count FROM tasks GROUP BY status"
622
- ).all();
576
+ const stats = db.all(
577
+ "SELECT status, COUNT(*) as count FROM tasks GROUP BY status");
623
578
 
624
579
  return {
625
580
  content: [{
@@ -668,26 +623,21 @@ export function registerTools(server: McpServer, clientIP?: string, enforceNetwo
668
623
  },
669
624
  async ({ task_id, new_alias, from_session }) => {
670
625
  console.log(`[${ts()}] ${from_session} → reassign_task → ${task_id.slice(0, 8)} → ${new_alias}`);
671
- const task = db.query<any, [string]>("SELECT * FROM tasks WHERE task_id = ?1").get(task_id);
626
+ const task = db.get<any>("SELECT * FROM tasks WHERE task_id = ?1", task_id);
672
627
  if (!task) return { content: [{ type: "text" as const, text: JSON.stringify({ ok: false, error: "task not found" }) }] };
673
628
  if (["replied", "failed", "cancelled", "expired"].includes(task.status)) {
674
629
  return { content: [{ type: "text" as const, text: JSON.stringify({ ok: false, error: `task is terminal (${task.status})` }) }] };
675
630
  }
676
631
  const oldAlias = task.to_name;
677
- try {
678
- db.run("BEGIN IMMEDIATE");
632
+ db.transaction(() => {
679
633
  // Ack old inbox to prevent original agent from picking it up
680
634
  db.run("UPDATE inbox SET acked = 1 WHERE id = ?1 AND acked = 0", [task_id]);
681
635
  db.run("UPDATE tasks SET to_name = ?1, status = 'delivered', started_at = NULL, delivered_at = datetime('now') WHERE task_id = ?2", [new_alias, task_id]);
682
636
  const newInboxId = uuidv4();
683
637
  db.run("INSERT INTO inbox (id, session_name, type, priority, content, from_session, requires_response) VALUES (?1, ?2, 'task', ?3, ?4, ?5, 'reply')",
684
638
  [newInboxId, new_alias, task.priority, task.content, from_session]);
685
- db.run("COMMIT");
686
- logTaskEvent(task_id, task.status, "delivered", from_session, `reassign: ${oldAlias} → ${new_alias}`);
687
- } catch (e) {
688
- try { db.run("ROLLBACK"); } catch {}
689
- throw e;
690
- }
639
+ });
640
+ logTaskEvent(task_id, task.status, "delivered", from_session, `reassign: ${oldAlias} → ${new_alias}`);
691
641
  pushEvent(new_alias, { type: "new_task", inbox_count: 1, priority: task.priority, from: from_session });
692
642
  return { content: [{ type: "text" as const, text: JSON.stringify({ ok: true, task_id, reassigned_from: oldAlias, reassigned_to: new_alias }) }] };
693
643
  }
@@ -710,7 +660,7 @@ export function registerTools(server: McpServer, clientIP?: string, enforceNetwo
710
660
  if (filter_server) { sql += " AND server = ?"; params.push(filter_server); }
711
661
  if (filter_status) { sql += " AND status = ?"; params.push(filter_status); }
712
662
 
713
- const targets = db.query<{ alias: string }, any[]>(sql).all(...params);
663
+ const targets = db.all<{ alias: string }>(sql, ...params);
714
664
  const ids: string[] = [];
715
665
 
716
666
  for (const t of targets) {
@@ -759,7 +709,7 @@ export function registerTools(server: McpServer, clientIP?: string, enforceNetwo
759
709
  sql += ` ORDER BY completed_at DESC LIMIT ?${paramIdx}`;
760
710
  params.push(limit);
761
711
 
762
- const rows = db.query(sql).all(...params);
712
+ const rows = db.all(sql, ...params);
763
713
  return {
764
714
  content: [{ type: "text" as const, text: JSON.stringify({ ok: true, completions: rows }) }],
765
715
  };