@iletai/nzb 1.7.0 → 1.7.3

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/daemon.js CHANGED
@@ -26,6 +26,7 @@ function isProcessAlive(pid) {
26
26
  return true;
27
27
  }
28
28
  catch {
29
+ // Expected: process.kill(0) throws when process doesn't exist
29
30
  return false;
30
31
  }
31
32
  }
@@ -64,8 +65,8 @@ function releasePidLock() {
64
65
  }
65
66
  }
66
67
  }
67
- catch {
68
- /* best effort */
68
+ catch (err) {
69
+ console.error("[nzb] PID lock cleanup:", err instanceof Error ? err.message : err);
69
70
  }
70
71
  }
71
72
  async function main() {
@@ -197,8 +198,8 @@ async function shutdown() {
197
198
  try {
198
199
  await stopBot();
199
200
  }
200
- catch {
201
- /* best effort */
201
+ catch (err) {
202
+ console.error("[nzb] stopBot during shutdown:", err instanceof Error ? err.message : err);
202
203
  }
203
204
  }
204
205
  // Destroy all active worker sessions to free memory
@@ -207,8 +208,8 @@ async function shutdown() {
207
208
  try {
208
209
  await stopClient();
209
210
  }
210
- catch {
211
- /* best effort */
211
+ catch (err) {
212
+ console.error("[nzb] stopClient during shutdown:", err instanceof Error ? err.message : err);
212
213
  }
213
214
  closeDb();
214
215
  releasePidLock();
@@ -229,8 +230,8 @@ export async function restartDaemon() {
229
230
  try {
230
231
  await stopBot();
231
232
  }
232
- catch {
233
- /* best effort */
233
+ catch (err) {
234
+ console.error("[nzb] stopBot during restart:", err instanceof Error ? err.message : err);
234
235
  }
235
236
  }
236
237
  // Destroy all active worker sessions to free memory
@@ -239,8 +240,8 @@ export async function restartDaemon() {
239
240
  try {
240
241
  await stopClient();
241
242
  }
242
- catch {
243
- /* best effort */
243
+ catch (err) {
244
+ console.error("[nzb] stopClient during restart:", err instanceof Error ? err.message : err);
244
245
  }
245
246
  closeDb();
246
247
  releasePidLock();
package/dist/setup.js CHANGED
@@ -28,14 +28,15 @@ async function fetchModels() {
28
28
  });
29
29
  }
30
30
  catch {
31
+ // Expected: Copilot CLI may not be authenticated yet
31
32
  return [];
32
33
  }
33
34
  finally {
34
35
  try {
35
36
  await client?.stop();
36
37
  }
37
- catch {
38
- /* best-effort */
38
+ catch (err) {
39
+ console.error("[nzb] CopilotClient stop:", err instanceof Error ? err.message : err);
39
40
  }
40
41
  }
41
42
  }
@@ -0,0 +1,96 @@
1
+ import { getDb } from "./db.js";
2
+ // Lazy per-connection prepared statement cache
3
+ let cachedDb;
4
+ let stmtCache;
5
+ function ensureStmtCache() {
6
+ const db = getDb();
7
+ if (db !== cachedDb) {
8
+ cachedDb = db;
9
+ stmtCache = {
10
+ logConversation: db.prepare(`INSERT INTO conversation_log (role, content, source, telegram_msg_id) VALUES (?, ?, ?, ?)`),
11
+ pruneConversation: db.prepare(`DELETE FROM conversation_log WHERE id NOT IN (SELECT id FROM conversation_log ORDER BY id DESC LIMIT 200)`),
12
+ getConversationByMsgId: db.prepare(`SELECT id FROM conversation_log WHERE telegram_msg_id = ? LIMIT 1`),
13
+ };
14
+ }
15
+ return stmtCache;
16
+ }
17
+ /** Log a conversation turn (user, assistant, or system) with optional Telegram message ID. Returns the row ID. */
18
+ export function logConversation(role, content, source, telegramMsgId) {
19
+ const cache = ensureStmtCache();
20
+ const result = cache.logConversation.run(role, content, source, telegramMsgId ?? null);
21
+ // Prune every ~50 inserts using rowid (crash-safe, no in-memory counter)
22
+ const rowId = result.lastInsertRowid;
23
+ if (rowId % 50 === 0) {
24
+ try {
25
+ cache.pruneConversation.run();
26
+ }
27
+ catch (err) {
28
+ console.error("[nzb] Conversation prune failed:", err instanceof Error ? err.message : err);
29
+ }
30
+ }
31
+ return rowId;
32
+ }
33
+ /** Get conversation context around a Telegram message ID (±4 rows using proper subquery). */
34
+ export function getConversationContext(telegramMsgId) {
35
+ const db = getDb();
36
+ const cache = ensureStmtCache();
37
+ const row = cache.getConversationByMsgId.get(telegramMsgId);
38
+ if (!row)
39
+ return undefined;
40
+ // Fetch 4 rows before + the target + 4 rows after (handles ID gaps from pruning)
41
+ const rows = db
42
+ .prepare(`
43
+ SELECT role, content, source, ts FROM (
44
+ SELECT * FROM conversation_log WHERE id < ? ORDER BY id DESC LIMIT 4
45
+ )
46
+ UNION ALL
47
+ SELECT role, content, source, ts FROM conversation_log WHERE id = ?
48
+ UNION ALL
49
+ SELECT role, content, source, ts FROM (
50
+ SELECT * FROM conversation_log WHERE id > ? ORDER BY id ASC LIMIT 4
51
+ )
52
+ `)
53
+ .all(row.id, row.id, row.id);
54
+ if (rows.length === 0)
55
+ return undefined;
56
+ return rows
57
+ .map((r) => {
58
+ const tag = r.role === "user" ? "You" : r.role === "assistant" ? "NZB" : "System";
59
+ const content = r.content.length > 400 ? r.content.slice(0, 400) + "…" : r.content;
60
+ return `${tag}: ${content}`;
61
+ })
62
+ .join("\n");
63
+ }
64
+ /** Set Telegram message ID on a specific conversation_log row (race-free). */
65
+ export function setConversationTelegramMsgId(rowId, telegramMsgId) {
66
+ const db = getDb();
67
+ db.prepare(`UPDATE conversation_log SET telegram_msg_id = ? WHERE id = ?`).run(telegramMsgId, rowId);
68
+ }
69
+ /** Look up conversation content by Telegram message ID. Returns the message content or undefined. */
70
+ export function getConversationByTelegramMsgId(telegramMsgId) {
71
+ const db = getDb();
72
+ const row = db
73
+ .prepare(`SELECT content FROM conversation_log WHERE telegram_msg_id = ? LIMIT 1`)
74
+ .get(telegramMsgId);
75
+ return row?.content;
76
+ }
77
+ /** Get recent conversation history formatted for injection into system message. */
78
+ export function getRecentConversation(limit = 20) {
79
+ const db = getDb();
80
+ const rows = db
81
+ .prepare(`SELECT role, content, source, ts FROM conversation_log ORDER BY id DESC LIMIT ?`)
82
+ .all(limit);
83
+ if (rows.length === 0)
84
+ return "";
85
+ // Reverse so oldest is first (chronological order)
86
+ rows.reverse();
87
+ return rows
88
+ .map((r) => {
89
+ const tag = r.role === "user" ? `[${r.source}] User` : r.role === "system" ? `[${r.source}] System` : "NZB";
90
+ // Truncate long messages to keep context manageable
91
+ const content = r.content.length > 500 ? r.content.slice(0, 500) + "…" : r.content;
92
+ return `${tag}: ${content}`;
93
+ })
94
+ .join("\n\n");
95
+ }
96
+ //# sourceMappingURL=conversation.js.map
package/dist/store/db.js CHANGED
@@ -1,8 +1,7 @@
1
1
  import Database from "better-sqlite3";
2
2
  import { DB_PATH, ensureNZBHome } from "../paths.js";
3
3
  let db;
4
- let logInsertCount = 0;
5
- // Cached prepared statements for hot-path queries (created lazily after DB init)
4
+ // Cached prepared statements for state operations (created lazily after DB init)
6
5
  let stmtCache;
7
6
  export function getDb() {
8
7
  if (!db) {
@@ -115,17 +114,11 @@ export function getDb() {
115
114
  // FTS5 may not be available — will fall back to LIKE
116
115
  console.log("[nzb] FTS5 not available, using LIKE fallback for memory search");
117
116
  }
118
- // Initialize cached prepared statements for hot-path operations
117
+ // Initialize cached prepared statements for state operations
119
118
  stmtCache = {
120
119
  getState: db.prepare(`SELECT value FROM nzb_state WHERE key = ?`),
121
120
  setState: db.prepare(`INSERT OR REPLACE INTO nzb_state (key, value) VALUES (?, ?)`),
122
121
  deleteState: db.prepare(`DELETE FROM nzb_state WHERE key = ?`),
123
- logConversation: db.prepare(`INSERT INTO conversation_log (role, content, source, telegram_msg_id) VALUES (?, ?, ?, ?)`),
124
- pruneConversation: db.prepare(`DELETE FROM conversation_log WHERE id NOT IN (SELECT id FROM conversation_log ORDER BY id DESC LIMIT 200)`),
125
- addMemory: db.prepare(`INSERT INTO memories (category, content, source) VALUES (?, ?, ?)`),
126
- removeMemory: db.prepare(`DELETE FROM memories WHERE id = ?`),
127
- memorySummary: db.prepare(`SELECT id, category, content FROM memories ORDER BY category, last_accessed DESC`),
128
- getConversationByMsgId: db.prepare(`SELECT id FROM conversation_log WHERE telegram_msg_id = ? LIMIT 1`),
129
122
  };
130
123
  }
131
124
  return db;
@@ -144,203 +137,6 @@ export function deleteState(key) {
144
137
  getDb(); // ensure init
145
138
  stmtCache.deleteState.run(key);
146
139
  }
147
- /** Log a conversation turn (user, assistant, or system) with optional Telegram message ID. Returns the row ID. */
148
- export function logConversation(role, content, source, telegramMsgId) {
149
- getDb(); // ensure init
150
- const result = stmtCache.logConversation.run(role, content, source, telegramMsgId ?? null);
151
- // Keep last 200 entries to support context recovery after session loss
152
- logInsertCount++;
153
- if (logInsertCount % 50 === 0) {
154
- stmtCache.pruneConversation.run();
155
- }
156
- return result.lastInsertRowid;
157
- }
158
- /** Get conversation context around a Telegram message ID (±4 rows using proper subquery). */
159
- export function getConversationContext(telegramMsgId) {
160
- const db = getDb();
161
- const row = stmtCache.getConversationByMsgId.get(telegramMsgId);
162
- if (!row)
163
- return undefined;
164
- // Fetch 4 rows before + the target + 4 rows after (handles ID gaps from pruning)
165
- const rows = db
166
- .prepare(`
167
- SELECT role, content, source, ts FROM (
168
- SELECT * FROM conversation_log WHERE id < ? ORDER BY id DESC LIMIT 4
169
- )
170
- UNION ALL
171
- SELECT role, content, source, ts FROM conversation_log WHERE id = ?
172
- UNION ALL
173
- SELECT role, content, source, ts FROM (
174
- SELECT * FROM conversation_log WHERE id > ? ORDER BY id ASC LIMIT 4
175
- )
176
- `)
177
- .all(row.id, row.id, row.id);
178
- if (rows.length === 0)
179
- return undefined;
180
- return rows
181
- .map((r) => {
182
- const tag = r.role === "user" ? "You" : r.role === "assistant" ? "NZB" : "System";
183
- const content = r.content.length > 400 ? r.content.slice(0, 400) + "…" : r.content;
184
- return `${tag}: ${content}`;
185
- })
186
- .join("\n");
187
- }
188
- /** Set Telegram message ID on a specific conversation_log row (race-free). */
189
- export function setConversationTelegramMsgId(rowId, telegramMsgId) {
190
- const db = getDb();
191
- db.prepare(`UPDATE conversation_log SET telegram_msg_id = ? WHERE id = ?`).run(telegramMsgId, rowId);
192
- }
193
- /** Look up conversation content by Telegram message ID. Returns the message content or undefined. */
194
- export function getConversationByTelegramMsgId(telegramMsgId) {
195
- const db = getDb();
196
- const row = db
197
- .prepare(`SELECT content FROM conversation_log WHERE telegram_msg_id = ? LIMIT 1`)
198
- .get(telegramMsgId);
199
- return row?.content;
200
- }
201
- /** Get recent conversation history formatted for injection into system message. */
202
- export function getRecentConversation(limit = 20) {
203
- const db = getDb();
204
- const rows = db
205
- .prepare(`SELECT role, content, source, ts FROM conversation_log ORDER BY id DESC LIMIT ?`)
206
- .all(limit);
207
- if (rows.length === 0)
208
- return "";
209
- // Reverse so oldest is first (chronological order)
210
- rows.reverse();
211
- return rows
212
- .map((r) => {
213
- const tag = r.role === "user" ? `[${r.source}] User` : r.role === "system" ? `[${r.source}] System` : "NZB";
214
- // Truncate long messages to keep context manageable
215
- const content = r.content.length > 500 ? r.content.slice(0, 500) + "…" : r.content;
216
- return `${tag}: ${content}`;
217
- })
218
- .join("\n\n");
219
- }
220
- /** Add a memory to long-term storage. */
221
- export function addMemory(category, content, source = "user") {
222
- getDb(); // ensure init
223
- const result = stmtCache.addMemory.run(category, content, source);
224
- return result.lastInsertRowid;
225
- }
226
- /** Search memories by keyword and/or category. Uses FTS5 when available, falls back to LIKE. */
227
- export function searchMemories(keyword, category, limit = 20) {
228
- const db = getDb();
229
- // Try FTS5 first for keyword search (much faster than LIKE)
230
- if (keyword) {
231
- try {
232
- const catFilter = category ? `AND m.category = ?` : "";
233
- const params = [keyword + "*"];
234
- if (category)
235
- params.push(category);
236
- params.push(limit);
237
- const rows = db
238
- .prepare(`SELECT m.id, m.category, m.content, m.source, m.created_at
239
- FROM memories_fts f
240
- JOIN memories m ON f.rowid = m.id
241
- WHERE memories_fts MATCH ? ${catFilter}
242
- ORDER BY rank LIMIT ?`)
243
- .all(...params);
244
- return rows;
245
- }
246
- catch {
247
- // FTS5 not available — fall through to LIKE
248
- }
249
- }
250
- // Fallback: LIKE-based search
251
- const conditions = [];
252
- const params = [];
253
- if (keyword) {
254
- conditions.push(`content LIKE ?`);
255
- params.push(`%${keyword}%`);
256
- }
257
- if (category) {
258
- conditions.push(`category = ?`);
259
- params.push(category);
260
- }
261
- const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
262
- params.push(limit);
263
- const rows = db
264
- .prepare(`SELECT id, category, content, source, created_at FROM memories ${where} ORDER BY last_accessed DESC LIMIT ?`)
265
- .all(...params);
266
- // Update last_accessed only when explicitly requested, not on every search
267
- // (removed automatic last_accessed update to avoid write side effects on reads)
268
- return rows;
269
- }
270
- /** Remove a memory by ID. */
271
- export function removeMemory(id) {
272
- getDb(); // ensure init
273
- const result = stmtCache.removeMemory.run(id);
274
- return result.changes > 0;
275
- }
276
- /** Get a compact summary of all memories for injection into system message. */
277
- export function getMemorySummary() {
278
- getDb(); // ensure init
279
- const rows = stmtCache.memorySummary.all();
280
- if (rows.length === 0)
281
- return "";
282
- // Group by category
283
- const grouped = {};
284
- for (const r of rows) {
285
- if (!grouped[r.category])
286
- grouped[r.category] = [];
287
- grouped[r.category].push({ id: r.id, content: r.content });
288
- }
289
- const sections = Object.entries(grouped).map(([cat, items]) => {
290
- const lines = items.map((i) => ` - [#${i.id}] ${i.content}`).join("\n");
291
- return `**${cat}**:\n${lines}`;
292
- });
293
- return sections.join("\n");
294
- }
295
- // ── Agent Teams CRUD ──────────────────────────────────────────
296
- export function createTeam(id, taskDescription, originChannel) {
297
- const db = getDb();
298
- db.prepare(`INSERT INTO agent_teams (id, task_description, origin_channel) VALUES (?, ?, ?)`).run(id, taskDescription, originChannel ?? null);
299
- }
300
- export function addTeamMember(teamId, workerName, role) {
301
- const db = getDb();
302
- db.prepare(`INSERT INTO team_members (team_id, worker_name, role, status) VALUES (?, ?, ?, 'pending')`).run(teamId, workerName, role);
303
- db.prepare(`UPDATE agent_teams SET member_count = member_count + 1 WHERE id = ?`).run(teamId);
304
- }
305
- export function updateTeamMemberResult(teamId, workerName, result, status) {
306
- const db = getDb();
307
- db.prepare(`UPDATE team_members SET result = ?, status = ?, completed_at = CURRENT_TIMESTAMP WHERE team_id = ? AND worker_name = ?`).run(result, status, teamId, workerName);
308
- if (status === "completed" || status === "error") {
309
- db.prepare(`UPDATE agent_teams SET completed_count = completed_count + 1 WHERE id = ?`).run(teamId);
310
- }
311
- }
312
- export function getTeam(id) {
313
- const db = getDb();
314
- return db.prepare(`SELECT * FROM agent_teams WHERE id = ?`).get(id);
315
- }
316
- export function getTeamMembers(teamId) {
317
- const db = getDb();
318
- return db
319
- .prepare(`SELECT worker_name, role, status, result FROM team_members WHERE team_id = ? ORDER BY id`)
320
- .all(teamId);
321
- }
322
- export function completeTeam(teamId, aggregatedResult, status = "completed") {
323
- const db = getDb();
324
- db.prepare(`UPDATE agent_teams SET status = ?, aggregated_result = ?, completed_at = CURRENT_TIMESTAMP WHERE id = ?`).run(status, aggregatedResult, teamId);
325
- }
326
- export function getActiveTeams() {
327
- const db = getDb();
328
- return db
329
- .prepare(`SELECT id, status, task_description, member_count, completed_count, created_at FROM agent_teams WHERE status = 'active' ORDER BY created_at DESC`)
330
- .all();
331
- }
332
- export function getTeamByWorkerName(workerName) {
333
- const db = getDb();
334
- const row = db
335
- .prepare(`SELECT team_id FROM team_members WHERE worker_name = ? AND status IN ('pending', 'running') LIMIT 1`)
336
- .get(workerName);
337
- return row?.team_id;
338
- }
339
- export function cleanupTeam(teamId) {
340
- const db = getDb();
341
- db.prepare(`DELETE FROM team_members WHERE team_id = ?`).run(teamId);
342
- db.prepare(`DELETE FROM agent_teams WHERE id = ?`).run(teamId);
343
- }
344
140
  export function closeDb() {
345
141
  if (db) {
346
142
  stmtCache = undefined;
@@ -348,4 +144,8 @@ export function closeDb() {
348
144
  db = undefined;
349
145
  }
350
146
  }
147
+ // Re-export for backward compatibility
148
+ export { logConversation, getConversationContext, setConversationTelegramMsgId, getConversationByTelegramMsgId, getRecentConversation, } from "./conversation.js";
149
+ export { addMemory, searchMemories, removeMemory, getMemorySummary } from "./memory.js";
150
+ export { createTeam, addTeamMember, updateTeamMemberResult, getTeam, getTeamMembers, completeTeam, getActiveTeams, getTeamByWorkerName, cleanupTeam, } from "./team-store.js";
351
151
  //# sourceMappingURL=db.js.map
@@ -0,0 +1,90 @@
1
+ import { getDb } from "./db.js";
2
+ // Lazy per-connection prepared statement cache
3
+ let cachedDb;
4
+ let stmtCache;
5
+ function ensureStmtCache() {
6
+ const db = getDb();
7
+ if (db !== cachedDb) {
8
+ cachedDb = db;
9
+ stmtCache = {
10
+ addMemory: db.prepare(`INSERT INTO memories (category, content, source) VALUES (?, ?, ?)`),
11
+ removeMemory: db.prepare(`DELETE FROM memories WHERE id = ?`),
12
+ memorySummary: db.prepare(`SELECT id, category, content FROM memories ORDER BY category, last_accessed DESC`),
13
+ };
14
+ }
15
+ return stmtCache;
16
+ }
17
+ /** Add a memory to long-term storage. */
18
+ export function addMemory(category, content, source = "user") {
19
+ const cache = ensureStmtCache();
20
+ const result = cache.addMemory.run(category, content, source);
21
+ return result.lastInsertRowid;
22
+ }
23
+ /** Search memories by keyword and/or category. Uses FTS5 when available, falls back to LIKE. */
24
+ export function searchMemories(keyword, category, limit = 20) {
25
+ const db = getDb();
26
+ // Try FTS5 first for keyword search (much faster than LIKE)
27
+ if (keyword) {
28
+ try {
29
+ const catFilter = category ? `AND m.category = ?` : "";
30
+ const params = [keyword + "*"];
31
+ if (category)
32
+ params.push(category);
33
+ params.push(limit);
34
+ const rows = db
35
+ .prepare(`SELECT m.id, m.category, m.content, m.source, m.created_at
36
+ FROM memories_fts f
37
+ JOIN memories m ON f.rowid = m.id
38
+ WHERE memories_fts MATCH ? ${catFilter}
39
+ ORDER BY rank LIMIT ?`)
40
+ .all(...params);
41
+ return rows;
42
+ }
43
+ catch {
44
+ // FTS5 not available — fall through to LIKE
45
+ }
46
+ }
47
+ // Fallback: LIKE-based search
48
+ const conditions = [];
49
+ const params = [];
50
+ if (keyword) {
51
+ conditions.push(`content LIKE ?`);
52
+ params.push(`%${keyword}%`);
53
+ }
54
+ if (category) {
55
+ conditions.push(`category = ?`);
56
+ params.push(category);
57
+ }
58
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
59
+ params.push(limit);
60
+ const rows = db
61
+ .prepare(`SELECT id, category, content, source, created_at FROM memories ${where} ORDER BY last_accessed DESC LIMIT ?`)
62
+ .all(...params);
63
+ return rows;
64
+ }
65
+ /** Remove a memory by ID. */
66
+ export function removeMemory(id) {
67
+ const cache = ensureStmtCache();
68
+ const result = cache.removeMemory.run(id);
69
+ return result.changes > 0;
70
+ }
71
+ /** Get a compact summary of all memories for injection into system message. */
72
+ export function getMemorySummary() {
73
+ const cache = ensureStmtCache();
74
+ const rows = cache.memorySummary.all();
75
+ if (rows.length === 0)
76
+ return "";
77
+ // Group by category
78
+ const grouped = {};
79
+ for (const r of rows) {
80
+ if (!grouped[r.category])
81
+ grouped[r.category] = [];
82
+ grouped[r.category].push({ id: r.id, content: r.content });
83
+ }
84
+ const sections = Object.entries(grouped).map(([cat, items]) => {
85
+ const lines = items.map((i) => ` - [#${i.id}] ${i.content}`).join("\n");
86
+ return `**${cat}**:\n${lines}`;
87
+ });
88
+ return sections.join("\n");
89
+ }
90
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +1,51 @@
1
+ import { getDb } from "./db.js";
2
+ // ── Agent Teams CRUD ──────────────────────────────────────────
3
+ export function createTeam(id, taskDescription, originChannel) {
4
+ const db = getDb();
5
+ db.prepare(`INSERT INTO agent_teams (id, task_description, origin_channel) VALUES (?, ?, ?)`).run(id, taskDescription, originChannel ?? null);
6
+ }
7
+ export function addTeamMember(teamId, workerName, role) {
8
+ const db = getDb();
9
+ db.prepare(`INSERT INTO team_members (team_id, worker_name, role, status) VALUES (?, ?, ?, 'pending')`).run(teamId, workerName, role);
10
+ db.prepare(`UPDATE agent_teams SET member_count = member_count + 1 WHERE id = ?`).run(teamId);
11
+ }
12
+ export function updateTeamMemberResult(teamId, workerName, result, status) {
13
+ const db = getDb();
14
+ db.prepare(`UPDATE team_members SET result = ?, status = ?, completed_at = CURRENT_TIMESTAMP WHERE team_id = ? AND worker_name = ?`).run(result, status, teamId, workerName);
15
+ if (status === "completed" || status === "error") {
16
+ db.prepare(`UPDATE agent_teams SET completed_count = completed_count + 1 WHERE id = ?`).run(teamId);
17
+ }
18
+ }
19
+ export function getTeam(id) {
20
+ const db = getDb();
21
+ return db.prepare(`SELECT * FROM agent_teams WHERE id = ?`).get(id);
22
+ }
23
+ export function getTeamMembers(teamId) {
24
+ const db = getDb();
25
+ return db
26
+ .prepare(`SELECT worker_name, role, status, result FROM team_members WHERE team_id = ? ORDER BY id`)
27
+ .all(teamId);
28
+ }
29
+ export function completeTeam(teamId, aggregatedResult, status = "completed") {
30
+ const db = getDb();
31
+ db.prepare(`UPDATE agent_teams SET status = ?, aggregated_result = ?, completed_at = CURRENT_TIMESTAMP WHERE id = ?`).run(status, aggregatedResult, teamId);
32
+ }
33
+ export function getActiveTeams() {
34
+ const db = getDb();
35
+ return db
36
+ .prepare(`SELECT id, status, task_description, member_count, completed_count, created_at FROM agent_teams WHERE status = 'active' ORDER BY created_at DESC`)
37
+ .all();
38
+ }
39
+ export function getTeamByWorkerName(workerName) {
40
+ const db = getDb();
41
+ const row = db
42
+ .prepare(`SELECT team_id FROM team_members WHERE worker_name = ? AND status IN ('pending', 'running') LIMIT 1`)
43
+ .get(workerName);
44
+ return row?.team_id;
45
+ }
46
+ export function cleanupTeam(teamId) {
47
+ const db = getDb();
48
+ db.prepare(`DELETE FROM team_members WHERE team_id = ?`).run(teamId);
49
+ db.prepare(`DELETE FROM agent_teams WHERE id = ?`).run(teamId);
50
+ }
51
+ //# sourceMappingURL=team-store.js.map