agent-relay 2.0.23 → 2.0.24

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.
Files changed (168) hide show
  1. package/dist/src/cli/index.js +66 -13
  2. package/package.json +18 -52
  3. package/packages/api-types/package.json +1 -1
  4. package/packages/bridge/package.json +8 -8
  5. package/packages/cli-tester/package.json +1 -1
  6. package/packages/config/package.json +2 -2
  7. package/packages/continuity/package.json +1 -1
  8. package/packages/daemon/package.json +12 -12
  9. package/packages/hooks/package.json +4 -4
  10. package/packages/mcp/package.json +2 -2
  11. package/packages/memory/package.json +2 -2
  12. package/packages/policy/package.json +2 -2
  13. package/packages/protocol/package.json +1 -1
  14. package/packages/resiliency/package.json +1 -1
  15. package/packages/sdk/package.json +2 -2
  16. package/packages/spawner/package.json +1 -1
  17. package/packages/state/package.json +1 -1
  18. package/packages/storage/package.json +2 -2
  19. package/packages/telemetry/package.json +1 -1
  20. package/packages/trajectory/package.json +2 -2
  21. package/packages/user-directory/package.json +2 -2
  22. package/packages/utils/package.json +1 -1
  23. package/packages/wrapper/package.json +6 -6
  24. package/deploy/init-db.sql +0 -5
  25. package/deploy/scripts/setup-fly-workspaces.sh +0 -69
  26. package/deploy/scripts/setup-railway.sh +0 -75
  27. package/dist/src/cloud/index.d.ts +0 -8
  28. package/dist/src/cloud/index.js +0 -8
  29. package/packages/cloud/dist/api/admin.d.ts +0 -8
  30. package/packages/cloud/dist/api/admin.js +0 -225
  31. package/packages/cloud/dist/api/auth.d.ts +0 -20
  32. package/packages/cloud/dist/api/auth.js +0 -138
  33. package/packages/cloud/dist/api/billing.d.ts +0 -7
  34. package/packages/cloud/dist/api/billing.js +0 -564
  35. package/packages/cloud/dist/api/cli-pty-runner.d.ts +0 -53
  36. package/packages/cloud/dist/api/cli-pty-runner.js +0 -175
  37. package/packages/cloud/dist/api/codex-auth-helper.d.ts +0 -21
  38. package/packages/cloud/dist/api/codex-auth-helper.js +0 -327
  39. package/packages/cloud/dist/api/consensus.d.ts +0 -13
  40. package/packages/cloud/dist/api/consensus.js +0 -261
  41. package/packages/cloud/dist/api/coordinators.d.ts +0 -8
  42. package/packages/cloud/dist/api/coordinators.js +0 -750
  43. package/packages/cloud/dist/api/daemons.d.ts +0 -12
  44. package/packages/cloud/dist/api/daemons.js +0 -535
  45. package/packages/cloud/dist/api/email-auth.d.ts +0 -11
  46. package/packages/cloud/dist/api/email-auth.js +0 -347
  47. package/packages/cloud/dist/api/generic-webhooks.d.ts +0 -8
  48. package/packages/cloud/dist/api/generic-webhooks.js +0 -129
  49. package/packages/cloud/dist/api/git.d.ts +0 -8
  50. package/packages/cloud/dist/api/git.js +0 -269
  51. package/packages/cloud/dist/api/github-app.d.ts +0 -11
  52. package/packages/cloud/dist/api/github-app.js +0 -223
  53. package/packages/cloud/dist/api/middleware/planLimits.d.ts +0 -43
  54. package/packages/cloud/dist/api/middleware/planLimits.js +0 -202
  55. package/packages/cloud/dist/api/monitoring.d.ts +0 -11
  56. package/packages/cloud/dist/api/monitoring.js +0 -578
  57. package/packages/cloud/dist/api/nango-auth.d.ts +0 -9
  58. package/packages/cloud/dist/api/nango-auth.js +0 -741
  59. package/packages/cloud/dist/api/onboarding.d.ts +0 -15
  60. package/packages/cloud/dist/api/onboarding.js +0 -679
  61. package/packages/cloud/dist/api/policy.d.ts +0 -8
  62. package/packages/cloud/dist/api/policy.js +0 -229
  63. package/packages/cloud/dist/api/provider-env.d.ts +0 -26
  64. package/packages/cloud/dist/api/provider-env.js +0 -141
  65. package/packages/cloud/dist/api/providers.d.ts +0 -7
  66. package/packages/cloud/dist/api/providers.js +0 -574
  67. package/packages/cloud/dist/api/repos.d.ts +0 -8
  68. package/packages/cloud/dist/api/repos.js +0 -577
  69. package/packages/cloud/dist/api/sessions.d.ts +0 -11
  70. package/packages/cloud/dist/api/sessions.js +0 -302
  71. package/packages/cloud/dist/api/teams.d.ts +0 -7
  72. package/packages/cloud/dist/api/teams.js +0 -281
  73. package/packages/cloud/dist/api/test-helpers.d.ts +0 -10
  74. package/packages/cloud/dist/api/test-helpers.js +0 -745
  75. package/packages/cloud/dist/api/usage.d.ts +0 -7
  76. package/packages/cloud/dist/api/usage.js +0 -111
  77. package/packages/cloud/dist/api/webhooks.d.ts +0 -8
  78. package/packages/cloud/dist/api/webhooks.js +0 -645
  79. package/packages/cloud/dist/api/workspaces.d.ts +0 -25
  80. package/packages/cloud/dist/api/workspaces.js +0 -1799
  81. package/packages/cloud/dist/billing/index.d.ts +0 -9
  82. package/packages/cloud/dist/billing/index.js +0 -9
  83. package/packages/cloud/dist/billing/plans.d.ts +0 -39
  84. package/packages/cloud/dist/billing/plans.js +0 -245
  85. package/packages/cloud/dist/billing/service.d.ts +0 -80
  86. package/packages/cloud/dist/billing/service.js +0 -388
  87. package/packages/cloud/dist/billing/types.d.ts +0 -141
  88. package/packages/cloud/dist/billing/types.js +0 -7
  89. package/packages/cloud/dist/config.d.ts +0 -5
  90. package/packages/cloud/dist/config.js +0 -5
  91. package/packages/cloud/dist/db/bulk-ingest.d.ts +0 -89
  92. package/packages/cloud/dist/db/bulk-ingest.js +0 -268
  93. package/packages/cloud/dist/db/drizzle.d.ts +0 -290
  94. package/packages/cloud/dist/db/drizzle.js +0 -1422
  95. package/packages/cloud/dist/db/index.d.ts +0 -56
  96. package/packages/cloud/dist/db/index.js +0 -70
  97. package/packages/cloud/dist/db/schema.d.ts +0 -5117
  98. package/packages/cloud/dist/db/schema.js +0 -656
  99. package/packages/cloud/dist/index.d.ts +0 -11
  100. package/packages/cloud/dist/index.js +0 -38
  101. package/packages/cloud/dist/provisioner/index.d.ts +0 -207
  102. package/packages/cloud/dist/provisioner/index.js +0 -2118
  103. package/packages/cloud/dist/server.d.ts +0 -17
  104. package/packages/cloud/dist/server.js +0 -2055
  105. package/packages/cloud/dist/services/auto-scaler.d.ts +0 -152
  106. package/packages/cloud/dist/services/auto-scaler.js +0 -439
  107. package/packages/cloud/dist/services/capacity-manager.d.ts +0 -148
  108. package/packages/cloud/dist/services/capacity-manager.js +0 -449
  109. package/packages/cloud/dist/services/ci-agent-spawner.d.ts +0 -49
  110. package/packages/cloud/dist/services/ci-agent-spawner.js +0 -373
  111. package/packages/cloud/dist/services/cloud-message-bus.d.ts +0 -28
  112. package/packages/cloud/dist/services/cloud-message-bus.js +0 -19
  113. package/packages/cloud/dist/services/compute-enforcement.d.ts +0 -57
  114. package/packages/cloud/dist/services/compute-enforcement.js +0 -175
  115. package/packages/cloud/dist/services/coordinator.d.ts +0 -62
  116. package/packages/cloud/dist/services/coordinator.js +0 -389
  117. package/packages/cloud/dist/services/index.d.ts +0 -17
  118. package/packages/cloud/dist/services/index.js +0 -25
  119. package/packages/cloud/dist/services/intro-expiration.d.ts +0 -60
  120. package/packages/cloud/dist/services/intro-expiration.js +0 -252
  121. package/packages/cloud/dist/services/mention-handler.d.ts +0 -65
  122. package/packages/cloud/dist/services/mention-handler.js +0 -405
  123. package/packages/cloud/dist/services/nango.d.ts +0 -219
  124. package/packages/cloud/dist/services/nango.js +0 -424
  125. package/packages/cloud/dist/services/persistence.d.ts +0 -131
  126. package/packages/cloud/dist/services/persistence.js +0 -200
  127. package/packages/cloud/dist/services/planLimits.d.ts +0 -147
  128. package/packages/cloud/dist/services/planLimits.js +0 -335
  129. package/packages/cloud/dist/services/presence-registry.d.ts +0 -56
  130. package/packages/cloud/dist/services/presence-registry.js +0 -91
  131. package/packages/cloud/dist/services/scaling-orchestrator.d.ts +0 -159
  132. package/packages/cloud/dist/services/scaling-orchestrator.js +0 -502
  133. package/packages/cloud/dist/services/scaling-policy.d.ts +0 -121
  134. package/packages/cloud/dist/services/scaling-policy.js +0 -415
  135. package/packages/cloud/dist/services/ssh-security.d.ts +0 -31
  136. package/packages/cloud/dist/services/ssh-security.js +0 -63
  137. package/packages/cloud/dist/services/workspace-keepalive.d.ts +0 -76
  138. package/packages/cloud/dist/services/workspace-keepalive.js +0 -234
  139. package/packages/cloud/dist/shims/consensus.d.ts +0 -23
  140. package/packages/cloud/dist/shims/consensus.js +0 -5
  141. package/packages/cloud/dist/webhooks/index.d.ts +0 -24
  142. package/packages/cloud/dist/webhooks/index.js +0 -29
  143. package/packages/cloud/dist/webhooks/parsers/github.d.ts +0 -8
  144. package/packages/cloud/dist/webhooks/parsers/github.js +0 -234
  145. package/packages/cloud/dist/webhooks/parsers/index.d.ts +0 -23
  146. package/packages/cloud/dist/webhooks/parsers/index.js +0 -30
  147. package/packages/cloud/dist/webhooks/parsers/linear.d.ts +0 -9
  148. package/packages/cloud/dist/webhooks/parsers/linear.js +0 -258
  149. package/packages/cloud/dist/webhooks/parsers/slack.d.ts +0 -9
  150. package/packages/cloud/dist/webhooks/parsers/slack.js +0 -214
  151. package/packages/cloud/dist/webhooks/responders/github.d.ts +0 -8
  152. package/packages/cloud/dist/webhooks/responders/github.js +0 -73
  153. package/packages/cloud/dist/webhooks/responders/index.d.ts +0 -23
  154. package/packages/cloud/dist/webhooks/responders/index.js +0 -30
  155. package/packages/cloud/dist/webhooks/responders/linear.d.ts +0 -9
  156. package/packages/cloud/dist/webhooks/responders/linear.js +0 -149
  157. package/packages/cloud/dist/webhooks/responders/slack.d.ts +0 -20
  158. package/packages/cloud/dist/webhooks/responders/slack.js +0 -178
  159. package/packages/cloud/dist/webhooks/router.d.ts +0 -25
  160. package/packages/cloud/dist/webhooks/router.js +0 -504
  161. package/packages/cloud/dist/webhooks/rules-engine.d.ts +0 -24
  162. package/packages/cloud/dist/webhooks/rules-engine.js +0 -287
  163. package/packages/cloud/dist/webhooks/types.d.ts +0 -186
  164. package/packages/cloud/dist/webhooks/types.js +0 -8
  165. package/packages/cloud/package.json +0 -60
  166. package/scripts/run-migrations.js +0 -43
  167. package/scripts/setup-stripe-products.ts +0 -312
  168. package/scripts/verify-schema.js +0 -134
@@ -1,1422 +0,0 @@
1
- /**
2
- * Agent Relay Cloud - Drizzle Database Client
3
- *
4
- * Type-safe database access using Drizzle ORM.
5
- * Use this instead of the raw pg client for new code.
6
- */
7
- import { drizzle } from 'drizzle-orm/node-postgres';
8
- import { Pool } from 'pg';
9
- import { eq, and, or, sql, desc, lt, isNull, isNotNull, inArray } from 'drizzle-orm';
10
- import * as schema from './schema.js';
11
- import { getConfig } from '../config.js';
12
- import { DEFAULT_POOL_CONFIG } from './bulk-ingest.js';
13
- // Re-export schema for direct table access
14
- export * from './schema.js';
15
- // Initialize pool and drizzle lazily
16
- let pool = null;
17
- let drizzleDb = null;
18
- /**
19
- * Get or create the connection pool with optimized settings.
20
- * Pool configuration:
21
- * - max: 20 connections (up from default 10)
22
- * - idleTimeoutMillis: 30s (close idle connections)
23
- * - connectionTimeoutMillis: 10s (fail fast on connection issues)
24
- */
25
- function getPool() {
26
- if (!pool) {
27
- const config = getConfig();
28
- pool = new Pool({
29
- connectionString: config.databaseUrl,
30
- ...DEFAULT_POOL_CONFIG,
31
- // Allow SSL for cloud databases
32
- ssl: config.databaseUrl?.includes('sslmode=require')
33
- ? { rejectUnauthorized: false }
34
- : undefined,
35
- });
36
- // Log pool errors (connection issues, etc.)
37
- pool.on('error', (err) => {
38
- console.error('[db] Pool error:', err.message);
39
- });
40
- }
41
- return pool;
42
- }
43
- /**
44
- * Get the raw connection pool for bulk operations.
45
- * Use this for optimized bulk inserts that bypass the ORM.
46
- */
47
- export function getRawPool() {
48
- return getPool();
49
- }
50
- export function getDb() {
51
- if (!drizzleDb) {
52
- drizzleDb = drizzle(getPool(), { schema });
53
- }
54
- return drizzleDb;
55
- }
56
- export const userQueries = {
57
- async findById(id) {
58
- const db = getDb();
59
- const result = await db.select().from(schema.users).where(eq(schema.users.id, id));
60
- return result[0] ?? null;
61
- },
62
- async findByGithubId(githubId) {
63
- const db = getDb();
64
- const result = await db.select().from(schema.users).where(eq(schema.users.githubId, githubId));
65
- return result[0] ?? null;
66
- },
67
- async findByGithubUsername(username) {
68
- const db = getDb();
69
- const result = await db.select().from(schema.users).where(eq(schema.users.githubUsername, username));
70
- return result[0] ?? null;
71
- },
72
- async findByEmail(email) {
73
- const db = getDb();
74
- const result = await db.select().from(schema.users).where(eq(schema.users.email, email));
75
- return result[0] ?? null;
76
- },
77
- async findByNangoConnectionId(connectionId) {
78
- const db = getDb();
79
- const result = await db
80
- .select()
81
- .from(schema.users)
82
- .where(eq(schema.users.nangoConnectionId, connectionId));
83
- return result[0] ?? null;
84
- },
85
- async findByIncomingConnectionId(connectionId) {
86
- const db = getDb();
87
- const result = await db.select().from(schema.users).where(eq(schema.users.incomingConnectionId, connectionId));
88
- return result[0] ?? null;
89
- },
90
- async findByPlan(plan) {
91
- const db = getDb();
92
- const result = await db.select().from(schema.users).where(eq(schema.users.plan, plan));
93
- return result;
94
- },
95
- async upsert(data) {
96
- const db = getDb();
97
- const result = await db
98
- .insert(schema.users)
99
- .values(data)
100
- .onConflictDoUpdate({
101
- target: schema.users.githubId,
102
- set: {
103
- githubUsername: data.githubUsername,
104
- email: data.email,
105
- avatarUrl: data.avatarUrl,
106
- updatedAt: new Date(),
107
- },
108
- })
109
- .returning();
110
- return result[0];
111
- },
112
- async completeOnboarding(userId) {
113
- const db = getDb();
114
- await db
115
- .update(schema.users)
116
- .set({ onboardingCompletedAt: new Date(), updatedAt: new Date() })
117
- .where(eq(schema.users.id, userId));
118
- },
119
- async update(id, data) {
120
- const db = getDb();
121
- await db
122
- .update(schema.users)
123
- .set({ ...data, updatedAt: new Date() })
124
- .where(eq(schema.users.id, id));
125
- },
126
- async clearIncomingConnectionId(userId) {
127
- const db = getDb();
128
- await db
129
- .update(schema.users)
130
- .set({ incomingConnectionId: null, updatedAt: new Date() })
131
- .where(eq(schema.users.id, userId));
132
- },
133
- async setPendingInstallationRequest(userId) {
134
- const db = getDb();
135
- await db
136
- .update(schema.users)
137
- .set({ pendingInstallationRequest: new Date(), updatedAt: new Date() })
138
- .where(eq(schema.users.id, userId));
139
- },
140
- async clearPendingInstallationRequest(userId) {
141
- const db = getDb();
142
- await db
143
- .update(schema.users)
144
- .set({ pendingInstallationRequest: null, updatedAt: new Date() })
145
- .where(eq(schema.users.id, userId));
146
- },
147
- async createEmailUser(data) {
148
- const db = getDb();
149
- const result = await db
150
- .insert(schema.users)
151
- .values({
152
- email: data.email,
153
- passwordHash: data.passwordHash,
154
- displayName: data.displayName || null,
155
- emailVerified: false,
156
- })
157
- .returning();
158
- return result[0];
159
- },
160
- async verifyEmail(userId) {
161
- const db = getDb();
162
- await db
163
- .update(schema.users)
164
- .set({
165
- emailVerified: true,
166
- emailVerificationToken: null,
167
- emailVerificationExpires: null,
168
- updatedAt: new Date(),
169
- })
170
- .where(eq(schema.users.id, userId));
171
- },
172
- async setEmailVerificationToken(userId, token, expires) {
173
- const db = getDb();
174
- await db
175
- .update(schema.users)
176
- .set({
177
- emailVerificationToken: token,
178
- emailVerificationExpires: expires,
179
- updatedAt: new Date(),
180
- })
181
- .where(eq(schema.users.id, userId));
182
- },
183
- async findByEmailVerificationToken(token) {
184
- const db = getDb();
185
- const result = await db
186
- .select()
187
- .from(schema.users)
188
- .where(eq(schema.users.emailVerificationToken, token));
189
- return result[0] ?? null;
190
- },
191
- async updatePassword(userId, passwordHash) {
192
- const db = getDb();
193
- await db
194
- .update(schema.users)
195
- .set({ passwordHash, updatedAt: new Date() })
196
- .where(eq(schema.users.id, userId));
197
- },
198
- };
199
- export const userEmailQueries = {
200
- async findByUserId(userId) {
201
- const db = getDb();
202
- return db
203
- .select()
204
- .from(schema.userEmails)
205
- .where(eq(schema.userEmails.userId, userId));
206
- },
207
- async findUserByEmail(email) {
208
- const db = getDb();
209
- // First check user_emails table for linked emails
210
- const linkedEmail = await db
211
- .select({ userId: schema.userEmails.userId })
212
- .from(schema.userEmails)
213
- .where(eq(schema.userEmails.email, email.toLowerCase()))
214
- .limit(1);
215
- if (linkedEmail[0]) {
216
- const user = await db
217
- .select()
218
- .from(schema.users)
219
- .where(eq(schema.users.id, linkedEmail[0].userId));
220
- return user[0] ?? null;
221
- }
222
- // Fall back to checking users.email directly
223
- const user = await db
224
- .select()
225
- .from(schema.users)
226
- .where(eq(schema.users.email, email.toLowerCase()));
227
- return user[0] ?? null;
228
- },
229
- async upsert(data) {
230
- const db = getDb();
231
- const result = await db
232
- .insert(schema.userEmails)
233
- .values({
234
- userId: data.userId,
235
- email: data.email.toLowerCase(),
236
- verified: data.verified,
237
- primary: data.primary,
238
- source: data.source ?? 'github',
239
- })
240
- .onConflictDoUpdate({
241
- target: [schema.userEmails.userId, schema.userEmails.email],
242
- set: {
243
- verified: data.verified,
244
- primary: data.primary,
245
- updatedAt: new Date(),
246
- },
247
- })
248
- .returning();
249
- return result[0];
250
- },
251
- async syncFromGitHub(userId, emails) {
252
- const db = getDb();
253
- // Delete existing GitHub-sourced emails for this user
254
- await db
255
- .delete(schema.userEmails)
256
- .where(and(eq(schema.userEmails.userId, userId), eq(schema.userEmails.source, 'github')));
257
- // Insert all new emails
258
- if (emails.length > 0) {
259
- await db.insert(schema.userEmails).values(emails.map(e => ({
260
- userId,
261
- email: e.email.toLowerCase(),
262
- verified: e.verified,
263
- primary: e.primary,
264
- source: 'github',
265
- })));
266
- }
267
- },
268
- async delete(userId, email) {
269
- const db = getDb();
270
- await db
271
- .delete(schema.userEmails)
272
- .where(and(eq(schema.userEmails.userId, userId), eq(schema.userEmails.email, email.toLowerCase())));
273
- },
274
- async isEmailLinkedToOtherUser(email, excludeUserId) {
275
- const db = getDb();
276
- const result = await db
277
- .select({ userId: schema.userEmails.userId })
278
- .from(schema.userEmails)
279
- .where(and(eq(schema.userEmails.email, email.toLowerCase()), sql `${schema.userEmails.userId} != ${excludeUserId}`))
280
- .limit(1);
281
- return result.length > 0;
282
- },
283
- };
284
- export const githubInstallationQueries = {
285
- async findById(id) {
286
- const db = getDb();
287
- const result = await db.select().from(schema.githubInstallations).where(eq(schema.githubInstallations.id, id));
288
- return result[0] ?? null;
289
- },
290
- async findByInstallationId(installationId) {
291
- const db = getDb();
292
- const result = await db
293
- .select()
294
- .from(schema.githubInstallations)
295
- .where(eq(schema.githubInstallations.installationId, installationId));
296
- return result[0] ?? null;
297
- },
298
- async findByAccountLogin(accountLogin) {
299
- const db = getDb();
300
- const result = await db
301
- .select()
302
- .from(schema.githubInstallations)
303
- .where(eq(schema.githubInstallations.accountLogin, accountLogin));
304
- return result[0] ?? null;
305
- },
306
- async findByInstalledBy(userId) {
307
- const db = getDb();
308
- return db
309
- .select()
310
- .from(schema.githubInstallations)
311
- .where(eq(schema.githubInstallations.installedById, userId));
312
- },
313
- async findAll() {
314
- const db = getDb();
315
- return db.select().from(schema.githubInstallations).orderBy(schema.githubInstallations.accountLogin);
316
- },
317
- async upsert(data) {
318
- const db = getDb();
319
- const result = await db
320
- .insert(schema.githubInstallations)
321
- .values(data)
322
- .onConflictDoUpdate({
323
- target: schema.githubInstallations.installationId,
324
- set: {
325
- accountType: data.accountType,
326
- accountLogin: data.accountLogin,
327
- accountId: data.accountId,
328
- permissions: data.permissions,
329
- events: data.events,
330
- installedById: data.installedById,
331
- updatedAt: new Date(),
332
- },
333
- })
334
- .returning();
335
- return result[0];
336
- },
337
- async updatePermissions(installationId, permissions, events) {
338
- const db = getDb();
339
- await db
340
- .update(schema.githubInstallations)
341
- .set({ permissions, events, updatedAt: new Date() })
342
- .where(eq(schema.githubInstallations.installationId, installationId));
343
- },
344
- async suspend(installationId, suspendedBy) {
345
- const db = getDb();
346
- await db
347
- .update(schema.githubInstallations)
348
- .set({ suspended: true, suspendedAt: new Date(), suspendedBy, updatedAt: new Date() })
349
- .where(eq(schema.githubInstallations.installationId, installationId));
350
- },
351
- async unsuspend(installationId) {
352
- const db = getDb();
353
- await db
354
- .update(schema.githubInstallations)
355
- .set({ suspended: false, suspendedAt: null, suspendedBy: null, updatedAt: new Date() })
356
- .where(eq(schema.githubInstallations.installationId, installationId));
357
- },
358
- async delete(installationId) {
359
- const db = getDb();
360
- await db.delete(schema.githubInstallations).where(eq(schema.githubInstallations.installationId, installationId));
361
- },
362
- };
363
- export const credentialQueries = {
364
- async findByUserId(userId) {
365
- const db = getDb();
366
- return db.select().from(schema.credentials).where(eq(schema.credentials.userId, userId));
367
- },
368
- async findByUserAndWorkspace(userId, workspaceId) {
369
- const db = getDb();
370
- // Return credentials for this workspace OR legacy credentials (NULL workspace_id)
371
- // This ensures backward compatibility with existing credentials
372
- return db
373
- .select()
374
- .from(schema.credentials)
375
- .where(and(eq(schema.credentials.userId, userId), or(eq(schema.credentials.workspaceId, workspaceId), isNull(schema.credentials.workspaceId))));
376
- },
377
- async findByUserWorkspaceAndProvider(userId, workspaceId, provider) {
378
- const db = getDb();
379
- const result = await db
380
- .select()
381
- .from(schema.credentials)
382
- .where(and(eq(schema.credentials.userId, userId), eq(schema.credentials.workspaceId, workspaceId), eq(schema.credentials.provider, provider)));
383
- return result[0] ?? null;
384
- },
385
- async findByUserAndProvider(userId, provider) {
386
- // Legacy: returns first match (any workspace) - use findByUserWorkspaceAndProvider instead
387
- const db = getDb();
388
- const result = await db
389
- .select()
390
- .from(schema.credentials)
391
- .where(and(eq(schema.credentials.userId, userId), eq(schema.credentials.provider, provider)));
392
- return result[0] ?? null;
393
- },
394
- async upsert(data) {
395
- const db = getDb();
396
- const result = await db
397
- .insert(schema.credentials)
398
- .values(data)
399
- .onConflictDoUpdate({
400
- target: [schema.credentials.userId, schema.credentials.provider, schema.credentials.workspaceId],
401
- set: {
402
- scopes: data.scopes,
403
- providerAccountId: data.providerAccountId,
404
- providerAccountEmail: data.providerAccountEmail,
405
- updatedAt: new Date(),
406
- },
407
- })
408
- .returning();
409
- return result[0];
410
- },
411
- async deleteForWorkspace(userId, workspaceId, provider) {
412
- const db = getDb();
413
- await db
414
- .delete(schema.credentials)
415
- .where(and(eq(schema.credentials.userId, userId), eq(schema.credentials.workspaceId, workspaceId), eq(schema.credentials.provider, provider)));
416
- },
417
- async delete(userId, provider) {
418
- // Legacy: deletes all workspace credentials for this provider
419
- const db = getDb();
420
- await db
421
- .delete(schema.credentials)
422
- .where(and(eq(schema.credentials.userId, userId), eq(schema.credentials.provider, provider)));
423
- },
424
- };
425
- export const workspaceQueries = {
426
- async findById(id) {
427
- const db = getDb();
428
- const result = await db.select().from(schema.workspaces).where(eq(schema.workspaces.id, id));
429
- return result[0] ?? null;
430
- },
431
- async findByUserId(userId) {
432
- const db = getDb();
433
- return db
434
- .select()
435
- .from(schema.workspaces)
436
- .where(eq(schema.workspaces.userId, userId))
437
- .orderBy(desc(schema.workspaces.createdAt));
438
- },
439
- async findByCustomDomain(domain) {
440
- const db = getDb();
441
- const result = await db
442
- .select()
443
- .from(schema.workspaces)
444
- .where(eq(schema.workspaces.customDomain, domain));
445
- return result[0] ?? null;
446
- },
447
- async findByRepoFullName(repoFullName) {
448
- const db = getDb();
449
- // Find repository by full name (case-insensitive), then get its workspace
450
- const result = await db
451
- .select({ workspace: schema.workspaces })
452
- .from(schema.repositories)
453
- .innerJoin(schema.workspaces, eq(schema.repositories.workspaceId, schema.workspaces.id))
454
- .where(sql `LOWER(${schema.repositories.githubFullName}) = LOWER(${repoFullName})`)
455
- .limit(1);
456
- return result[0]?.workspace ?? null;
457
- },
458
- async findAll() {
459
- const db = getDb();
460
- return db
461
- .select()
462
- .from(schema.workspaces)
463
- .orderBy(desc(schema.workspaces.createdAt));
464
- },
465
- async create(data) {
466
- const db = getDb();
467
- const result = await db.insert(schema.workspaces).values(data).returning();
468
- return result[0];
469
- },
470
- async update(id, data) {
471
- const db = getDb();
472
- await db
473
- .update(schema.workspaces)
474
- .set({ ...data, updatedAt: new Date() })
475
- .where(eq(schema.workspaces.id, id));
476
- },
477
- async updateStatus(id, status, options) {
478
- const db = getDb();
479
- await db
480
- .update(schema.workspaces)
481
- .set({
482
- status,
483
- computeId: options?.computeId,
484
- publicUrl: options?.publicUrl,
485
- errorMessage: options?.errorMessage,
486
- updatedAt: new Date(),
487
- })
488
- .where(eq(schema.workspaces.id, id));
489
- },
490
- async updateConfig(id, config) {
491
- const db = getDb();
492
- await db
493
- .update(schema.workspaces)
494
- .set({
495
- config,
496
- updatedAt: new Date(),
497
- })
498
- .where(eq(schema.workspaces.id, id));
499
- },
500
- async setCustomDomain(id, customDomain, status = 'pending') {
501
- const db = getDb();
502
- await db
503
- .update(schema.workspaces)
504
- .set({ customDomain, customDomainStatus: status, updatedAt: new Date() })
505
- .where(eq(schema.workspaces.id, id));
506
- },
507
- async updateCustomDomainStatus(id, status) {
508
- const db = getDb();
509
- await db
510
- .update(schema.workspaces)
511
- .set({ customDomainStatus: status, updatedAt: new Date() })
512
- .where(eq(schema.workspaces.id, id));
513
- },
514
- async removeCustomDomain(id) {
515
- const db = getDb();
516
- await db
517
- .update(schema.workspaces)
518
- .set({ customDomain: null, customDomainStatus: null, updatedAt: new Date() })
519
- .where(eq(schema.workspaces.id, id));
520
- },
521
- async delete(id) {
522
- const db = getDb();
523
- await db.delete(schema.workspaces).where(eq(schema.workspaces.id, id));
524
- },
525
- };
526
- export const workspaceMemberQueries = {
527
- async findByWorkspaceId(workspaceId) {
528
- const db = getDb();
529
- return db
530
- .select()
531
- .from(schema.workspaceMembers)
532
- .where(eq(schema.workspaceMembers.workspaceId, workspaceId));
533
- },
534
- async findByUserId(userId) {
535
- const db = getDb();
536
- return db
537
- .select()
538
- .from(schema.workspaceMembers)
539
- .where(and(eq(schema.workspaceMembers.userId, userId), isNotNull(schema.workspaceMembers.acceptedAt)));
540
- },
541
- async findMembership(workspaceId, userId) {
542
- const db = getDb();
543
- const result = await db
544
- .select()
545
- .from(schema.workspaceMembers)
546
- .where(and(eq(schema.workspaceMembers.workspaceId, workspaceId), eq(schema.workspaceMembers.userId, userId)));
547
- return result[0] ?? null;
548
- },
549
- async addMember(data) {
550
- const db = getDb();
551
- const result = await db
552
- .insert(schema.workspaceMembers)
553
- .values({
554
- workspaceId: data.workspaceId,
555
- userId: data.userId,
556
- role: data.role,
557
- invitedBy: data.invitedBy,
558
- })
559
- .returning();
560
- return result[0];
561
- },
562
- async acceptInvite(workspaceId, userId) {
563
- const db = getDb();
564
- await db
565
- .update(schema.workspaceMembers)
566
- .set({ acceptedAt: new Date() })
567
- .where(and(eq(schema.workspaceMembers.workspaceId, workspaceId), eq(schema.workspaceMembers.userId, userId)));
568
- },
569
- async updateRole(workspaceId, userId, role) {
570
- const db = getDb();
571
- await db
572
- .update(schema.workspaceMembers)
573
- .set({ role })
574
- .where(and(eq(schema.workspaceMembers.workspaceId, workspaceId), eq(schema.workspaceMembers.userId, userId)));
575
- },
576
- async removeMember(workspaceId, userId) {
577
- const db = getDb();
578
- await db
579
- .delete(schema.workspaceMembers)
580
- .where(and(eq(schema.workspaceMembers.workspaceId, workspaceId), eq(schema.workspaceMembers.userId, userId)));
581
- },
582
- async getPendingInvites(userId) {
583
- const db = getDb();
584
- return db
585
- .select()
586
- .from(schema.workspaceMembers)
587
- .where(and(eq(schema.workspaceMembers.userId, userId), isNull(schema.workspaceMembers.acceptedAt)));
588
- },
589
- async isOwner(workspaceId, userId) {
590
- const db = getDb();
591
- const result = await db
592
- .select()
593
- .from(schema.workspaceMembers)
594
- .where(and(eq(schema.workspaceMembers.workspaceId, workspaceId), eq(schema.workspaceMembers.userId, userId), eq(schema.workspaceMembers.role, 'owner')));
595
- return result.length > 0;
596
- },
597
- async canEdit(workspaceId, userId) {
598
- const db = getDb();
599
- const result = await db
600
- .select()
601
- .from(schema.workspaceMembers)
602
- .where(and(eq(schema.workspaceMembers.workspaceId, workspaceId), eq(schema.workspaceMembers.userId, userId), isNotNull(schema.workspaceMembers.acceptedAt)));
603
- const member = result[0];
604
- return !!member && ['owner', 'admin', 'member'].includes(member.role);
605
- },
606
- async canView(workspaceId, userId) {
607
- const db = getDb();
608
- const result = await db
609
- .select()
610
- .from(schema.workspaceMembers)
611
- .where(and(eq(schema.workspaceMembers.workspaceId, workspaceId), eq(schema.workspaceMembers.userId, userId), isNotNull(schema.workspaceMembers.acceptedAt)));
612
- return result.length > 0;
613
- },
614
- };
615
- export const linkedDaemonQueries = {
616
- async findById(id) {
617
- const db = getDb();
618
- const result = await db.select().from(schema.linkedDaemons).where(eq(schema.linkedDaemons.id, id));
619
- return result[0] ?? null;
620
- },
621
- async findByUserId(userId) {
622
- const db = getDb();
623
- return db
624
- .select()
625
- .from(schema.linkedDaemons)
626
- .where(eq(schema.linkedDaemons.userId, userId))
627
- .orderBy(desc(schema.linkedDaemons.lastSeenAt));
628
- },
629
- async findByWorkspaceId(workspaceId) {
630
- const db = getDb();
631
- return db
632
- .select()
633
- .from(schema.linkedDaemons)
634
- .where(eq(schema.linkedDaemons.workspaceId, workspaceId))
635
- .orderBy(desc(schema.linkedDaemons.lastSeenAt));
636
- },
637
- async findByMachineId(userId, machineId) {
638
- const db = getDb();
639
- const result = await db
640
- .select()
641
- .from(schema.linkedDaemons)
642
- .where(and(eq(schema.linkedDaemons.userId, userId), eq(schema.linkedDaemons.machineId, machineId)));
643
- return result[0] ?? null;
644
- },
645
- async findByApiKeyHash(apiKeyHash) {
646
- const db = getDb();
647
- const result = await db
648
- .select()
649
- .from(schema.linkedDaemons)
650
- .where(eq(schema.linkedDaemons.apiKeyHash, apiKeyHash));
651
- return result[0] ?? null;
652
- },
653
- async create(data) {
654
- const db = getDb();
655
- const result = await db
656
- .insert(schema.linkedDaemons)
657
- .values({ ...data, lastSeenAt: new Date() })
658
- .returning();
659
- return result[0];
660
- },
661
- async update(id, data) {
662
- const db = getDb();
663
- await db
664
- .update(schema.linkedDaemons)
665
- .set({ ...data, updatedAt: new Date() })
666
- .where(eq(schema.linkedDaemons.id, id));
667
- },
668
- async updateLastSeen(id) {
669
- const db = getDb();
670
- await db
671
- .update(schema.linkedDaemons)
672
- .set({ lastSeenAt: new Date(), status: 'online', updatedAt: new Date() })
673
- .where(eq(schema.linkedDaemons.id, id));
674
- },
675
- async delete(id) {
676
- const db = getDb();
677
- await db.delete(schema.linkedDaemons).where(eq(schema.linkedDaemons.id, id));
678
- },
679
- async markStale() {
680
- const db = getDb();
681
- const twoMinutesAgo = new Date(Date.now() - 2 * 60 * 1000);
682
- const result = await db
683
- .update(schema.linkedDaemons)
684
- .set({ status: 'offline' })
685
- .where(and(eq(schema.linkedDaemons.status, 'online'), lt(schema.linkedDaemons.lastSeenAt, twoMinutesAgo)));
686
- return result.rowCount ?? 0;
687
- },
688
- async getAllAgentsForUser(userId) {
689
- const db = getDb();
690
- const daemons = await db
691
- .select()
692
- .from(schema.linkedDaemons)
693
- .where(eq(schema.linkedDaemons.userId, userId));
694
- return daemons.map((d) => ({
695
- daemonId: d.id,
696
- daemonName: d.name,
697
- machineId: d.machineId,
698
- agents: d.metadata?.agents || [],
699
- }));
700
- },
701
- async getPendingUpdates(id) {
702
- const db = getDb();
703
- const result = await db.select().from(schema.linkedDaemons).where(eq(schema.linkedDaemons.id, id));
704
- const daemon = result[0];
705
- if (!daemon)
706
- return [];
707
- const updates = daemon.pendingUpdates || [];
708
- // Clear after reading
709
- if (updates.length > 0) {
710
- await db
711
- .update(schema.linkedDaemons)
712
- .set({ pendingUpdates: [] })
713
- .where(eq(schema.linkedDaemons.id, id));
714
- }
715
- return updates;
716
- },
717
- async queueUpdate(id, update) {
718
- const db = getDb();
719
- const result = await db.select().from(schema.linkedDaemons).where(eq(schema.linkedDaemons.id, id));
720
- const daemon = result[0];
721
- if (!daemon)
722
- return;
723
- const existing = daemon.pendingUpdates || [];
724
- await db
725
- .update(schema.linkedDaemons)
726
- .set({ pendingUpdates: [...existing, update], updatedAt: new Date() })
727
- .where(eq(schema.linkedDaemons.id, id));
728
- },
729
- async queueMessage(id, message) {
730
- const db = getDb();
731
- const result = await db.select().from(schema.linkedDaemons).where(eq(schema.linkedDaemons.id, id));
732
- const daemon = result[0];
733
- if (!daemon)
734
- return;
735
- const existing = daemon.messageQueue || [];
736
- await db
737
- .update(schema.linkedDaemons)
738
- .set({ messageQueue: [...existing, message], updatedAt: new Date() })
739
- .where(eq(schema.linkedDaemons.id, id));
740
- },
741
- async getQueuedMessages(id) {
742
- const db = getDb();
743
- const result = await db.select().from(schema.linkedDaemons).where(eq(schema.linkedDaemons.id, id));
744
- const daemon = result[0];
745
- return daemon?.messageQueue || [];
746
- },
747
- async clearMessageQueue(id) {
748
- const db = getDb();
749
- await db
750
- .update(schema.linkedDaemons)
751
- .set({ messageQueue: [] })
752
- .where(eq(schema.linkedDaemons.id, id));
753
- },
754
- };
755
- export const projectGroupQueries = {
756
- async findById(id) {
757
- const db = getDb();
758
- const result = await db.select().from(schema.projectGroups).where(eq(schema.projectGroups.id, id));
759
- return result[0] ?? null;
760
- },
761
- async findByUserId(userId) {
762
- const db = getDb();
763
- return db
764
- .select()
765
- .from(schema.projectGroups)
766
- .where(eq(schema.projectGroups.userId, userId))
767
- .orderBy(schema.projectGroups.sortOrder, schema.projectGroups.name);
768
- },
769
- async findByName(userId, name) {
770
- const db = getDb();
771
- const result = await db
772
- .select()
773
- .from(schema.projectGroups)
774
- .where(and(eq(schema.projectGroups.userId, userId), eq(schema.projectGroups.name, name)));
775
- return result[0] ?? null;
776
- },
777
- async create(data) {
778
- const db = getDb();
779
- const result = await db.insert(schema.projectGroups).values(data).returning();
780
- return result[0];
781
- },
782
- async update(id, data) {
783
- const db = getDb();
784
- await db
785
- .update(schema.projectGroups)
786
- .set({ ...data, updatedAt: new Date() })
787
- .where(eq(schema.projectGroups.id, id));
788
- },
789
- async delete(id) {
790
- const db = getDb();
791
- // Repositories in this group will have projectGroupId set to null (ON DELETE SET NULL)
792
- await db.delete(schema.projectGroups).where(eq(schema.projectGroups.id, id));
793
- },
794
- async findWithRepositories(id) {
795
- const db = getDb();
796
- const group = await db.select().from(schema.projectGroups).where(eq(schema.projectGroups.id, id));
797
- if (!group[0])
798
- return null;
799
- const repos = await db
800
- .select()
801
- .from(schema.repositories)
802
- .where(eq(schema.repositories.projectGroupId, id))
803
- .orderBy(schema.repositories.githubFullName);
804
- return { ...group[0], repositories: repos };
805
- },
806
- async findAllWithRepositories(userId) {
807
- const db = getDb();
808
- const groups = await db
809
- .select()
810
- .from(schema.projectGroups)
811
- .where(eq(schema.projectGroups.userId, userId))
812
- .orderBy(schema.projectGroups.sortOrder, schema.projectGroups.name);
813
- // Get repositories for each group
814
- const result = await Promise.all(groups.map(async (group) => {
815
- const repos = await db
816
- .select()
817
- .from(schema.repositories)
818
- .where(eq(schema.repositories.projectGroupId, group.id))
819
- .orderBy(schema.repositories.githubFullName);
820
- return { ...group, repositories: repos };
821
- }));
822
- // Also get ungrouped repositories
823
- const ungroupedRepos = await db
824
- .select()
825
- .from(schema.repositories)
826
- .where(and(eq(schema.repositories.userId, userId), isNull(schema.repositories.projectGroupId)))
827
- .orderBy(schema.repositories.githubFullName);
828
- return { groups: result, ungroupedRepositories: ungroupedRepos };
829
- },
830
- async updateCoordinatorAgent(id, config) {
831
- const db = getDb();
832
- await db
833
- .update(schema.projectGroups)
834
- .set({ coordinatorAgent: config, updatedAt: new Date() })
835
- .where(eq(schema.projectGroups.id, id));
836
- },
837
- async reorder(userId, orderedIds) {
838
- const db = getDb();
839
- // Update sort_order for each group
840
- await Promise.all(orderedIds.map((id, index) => db
841
- .update(schema.projectGroups)
842
- .set({ sortOrder: index, updatedAt: new Date() })
843
- .where(and(eq(schema.projectGroups.id, id), eq(schema.projectGroups.userId, userId)))));
844
- },
845
- };
846
- export const repositoryQueries = {
847
- async findById(id) {
848
- const db = getDb();
849
- const result = await db.select().from(schema.repositories).where(eq(schema.repositories.id, id));
850
- return result[0] ?? null;
851
- },
852
- async findByFullName(fullName) {
853
- const db = getDb();
854
- const result = await db
855
- .select()
856
- .from(schema.repositories)
857
- .where(eq(schema.repositories.githubFullName, fullName));
858
- return result[0] ?? null;
859
- },
860
- async findByGithubFullName(fullName) {
861
- const db = getDb();
862
- // Use case-insensitive match since GitHub repo names are case-insensitive
863
- return db
864
- .select()
865
- .from(schema.repositories)
866
- .where(sql `LOWER(${schema.repositories.githubFullName}) = LOWER(${fullName})`);
867
- },
868
- async findByUserId(userId) {
869
- const db = getDb();
870
- return db
871
- .select()
872
- .from(schema.repositories)
873
- .where(eq(schema.repositories.userId, userId))
874
- .orderBy(schema.repositories.githubFullName);
875
- },
876
- async findByWorkspaceId(workspaceId) {
877
- const db = getDb();
878
- return db
879
- .select()
880
- .from(schema.repositories)
881
- .where(eq(schema.repositories.workspaceId, workspaceId));
882
- },
883
- async findByProjectGroupId(projectGroupId) {
884
- const db = getDb();
885
- return db
886
- .select()
887
- .from(schema.repositories)
888
- .where(eq(schema.repositories.projectGroupId, projectGroupId))
889
- .orderBy(schema.repositories.githubFullName);
890
- },
891
- async upsert(data) {
892
- const db = getDb();
893
- const result = await db
894
- .insert(schema.repositories)
895
- .values(data)
896
- .onConflictDoUpdate({
897
- target: [schema.repositories.userId, schema.repositories.githubFullName],
898
- set: {
899
- githubId: data.githubId,
900
- defaultBranch: data.defaultBranch,
901
- isPrivate: data.isPrivate,
902
- syncStatus: data.syncStatus,
903
- nangoConnectionId: data.nangoConnectionId,
904
- installationId: data.installationId,
905
- lastSyncedAt: data.lastSyncedAt,
906
- updatedAt: new Date(),
907
- },
908
- })
909
- .returning();
910
- return result[0];
911
- },
912
- async assignToWorkspace(repoId, workspaceId) {
913
- const db = getDb();
914
- await db
915
- .update(schema.repositories)
916
- .set({ workspaceId, updatedAt: new Date() })
917
- .where(eq(schema.repositories.id, repoId));
918
- },
919
- async assignToGroup(repoId, projectGroupId) {
920
- const db = getDb();
921
- await db
922
- .update(schema.repositories)
923
- .set({ projectGroupId, updatedAt: new Date() })
924
- .where(eq(schema.repositories.id, repoId));
925
- },
926
- async updateProjectAgent(id, config) {
927
- const db = getDb();
928
- await db
929
- .update(schema.repositories)
930
- .set({ projectAgent: config, updatedAt: new Date() })
931
- .where(eq(schema.repositories.id, id));
932
- },
933
- async updateSyncStatus(id, status, lastSyncedAt) {
934
- const db = getDb();
935
- const updates = { syncStatus: status, updatedAt: new Date() };
936
- if (lastSyncedAt) {
937
- updates.lastSyncedAt = lastSyncedAt;
938
- }
939
- await db
940
- .update(schema.repositories)
941
- .set(updates)
942
- .where(eq(schema.repositories.id, id));
943
- },
944
- async delete(id) {
945
- const db = getDb();
946
- await db.delete(schema.repositories).where(eq(schema.repositories.id, id));
947
- },
948
- };
949
- export const agentSessionQueries = {
950
- async findById(id) {
951
- const db = getDb();
952
- const result = await db.select().from(schema.agentSessions).where(eq(schema.agentSessions.id, id));
953
- return result[0] ?? null;
954
- },
955
- async findByWorkspaceId(workspaceId) {
956
- const db = getDb();
957
- return db
958
- .select()
959
- .from(schema.agentSessions)
960
- .where(eq(schema.agentSessions.workspaceId, workspaceId))
961
- .orderBy(desc(schema.agentSessions.startedAt));
962
- },
963
- async findActiveByWorkspace(workspaceId) {
964
- const db = getDb();
965
- return db
966
- .select()
967
- .from(schema.agentSessions)
968
- .where(and(eq(schema.agentSessions.workspaceId, workspaceId), eq(schema.agentSessions.status, 'active')));
969
- },
970
- async create(data) {
971
- const db = getDb();
972
- const result = await db.insert(schema.agentSessions).values(data).returning();
973
- return result[0];
974
- },
975
- async endSession(id, endMarker) {
976
- const db = getDb();
977
- await db
978
- .update(schema.agentSessions)
979
- .set({
980
- status: 'ended',
981
- endedAt: new Date(),
982
- endMarker: endMarker ?? null,
983
- })
984
- .where(eq(schema.agentSessions.id, id));
985
- },
986
- async delete(id) {
987
- const db = getDb();
988
- await db.delete(schema.agentSessions).where(eq(schema.agentSessions.id, id));
989
- },
990
- };
991
- export const agentSummaryQueries = {
992
- async findBySessionId(sessionId) {
993
- const db = getDb();
994
- return db
995
- .select()
996
- .from(schema.agentSummaries)
997
- .where(eq(schema.agentSummaries.sessionId, sessionId))
998
- .orderBy(schema.agentSummaries.createdAt);
999
- },
1000
- async findLatestByAgent(agentName) {
1001
- const db = getDb();
1002
- const result = await db
1003
- .select()
1004
- .from(schema.agentSummaries)
1005
- .where(eq(schema.agentSummaries.agentName, agentName))
1006
- .orderBy(desc(schema.agentSummaries.createdAt))
1007
- .limit(1);
1008
- return result[0] ?? null;
1009
- },
1010
- async create(data) {
1011
- const db = getDb();
1012
- const result = await db.insert(schema.agentSummaries).values(data).returning();
1013
- return result[0];
1014
- },
1015
- async deleteBySession(sessionId) {
1016
- const db = getDb();
1017
- await db.delete(schema.agentSummaries).where(eq(schema.agentSummaries.sessionId, sessionId));
1018
- },
1019
- };
1020
- export const ciFailureEventQueries = {
1021
- async findById(id) {
1022
- const db = getDb();
1023
- const result = await db.select().from(schema.ciFailureEvents).where(eq(schema.ciFailureEvents.id, id));
1024
- return result[0] ?? null;
1025
- },
1026
- async findByRepository(repository, limit = 50) {
1027
- const db = getDb();
1028
- return db
1029
- .select()
1030
- .from(schema.ciFailureEvents)
1031
- .where(eq(schema.ciFailureEvents.repository, repository))
1032
- .orderBy(desc(schema.ciFailureEvents.createdAt))
1033
- .limit(limit);
1034
- },
1035
- async findByPR(repository, prNumber) {
1036
- const db = getDb();
1037
- return db
1038
- .select()
1039
- .from(schema.ciFailureEvents)
1040
- .where(and(eq(schema.ciFailureEvents.repository, repository), eq(schema.ciFailureEvents.prNumber, prNumber)))
1041
- .orderBy(desc(schema.ciFailureEvents.createdAt));
1042
- },
1043
- async findRecentUnprocessed(limit = 100) {
1044
- const db = getDb();
1045
- return db
1046
- .select()
1047
- .from(schema.ciFailureEvents)
1048
- .where(isNull(schema.ciFailureEvents.processedAt))
1049
- .orderBy(schema.ciFailureEvents.createdAt)
1050
- .limit(limit);
1051
- },
1052
- async create(data) {
1053
- const db = getDb();
1054
- const result = await db.insert(schema.ciFailureEvents).values(data).returning();
1055
- return result[0];
1056
- },
1057
- async markProcessed(id, agentSpawned) {
1058
- const db = getDb();
1059
- await db
1060
- .update(schema.ciFailureEvents)
1061
- .set({ processedAt: new Date(), agentSpawned })
1062
- .where(eq(schema.ciFailureEvents.id, id));
1063
- },
1064
- async delete(id) {
1065
- const db = getDb();
1066
- await db.delete(schema.ciFailureEvents).where(eq(schema.ciFailureEvents.id, id));
1067
- },
1068
- };
1069
- export const ciFixAttemptQueries = {
1070
- async findById(id) {
1071
- const db = getDb();
1072
- const result = await db.select().from(schema.ciFixAttempts).where(eq(schema.ciFixAttempts.id, id));
1073
- return result[0] ?? null;
1074
- },
1075
- async findByFailureEvent(failureEventId) {
1076
- const db = getDb();
1077
- return db
1078
- .select()
1079
- .from(schema.ciFixAttempts)
1080
- .where(eq(schema.ciFixAttempts.failureEventId, failureEventId))
1081
- .orderBy(desc(schema.ciFixAttempts.startedAt));
1082
- },
1083
- async findActiveByRepository(repository) {
1084
- const db = getDb();
1085
- // Find active fix attempts by joining with failure events
1086
- return db
1087
- .select({
1088
- id: schema.ciFixAttempts.id,
1089
- failureEventId: schema.ciFixAttempts.failureEventId,
1090
- agentId: schema.ciFixAttempts.agentId,
1091
- agentName: schema.ciFixAttempts.agentName,
1092
- status: schema.ciFixAttempts.status,
1093
- commitSha: schema.ciFixAttempts.commitSha,
1094
- errorMessage: schema.ciFixAttempts.errorMessage,
1095
- startedAt: schema.ciFixAttempts.startedAt,
1096
- completedAt: schema.ciFixAttempts.completedAt,
1097
- })
1098
- .from(schema.ciFixAttempts)
1099
- .innerJoin(schema.ciFailureEvents, eq(schema.ciFixAttempts.failureEventId, schema.ciFailureEvents.id))
1100
- .where(and(eq(schema.ciFailureEvents.repository, repository), sql `${schema.ciFixAttempts.status} IN ('pending', 'in_progress')`));
1101
- },
1102
- async create(data) {
1103
- const db = getDb();
1104
- const result = await db.insert(schema.ciFixAttempts).values(data).returning();
1105
- return result[0];
1106
- },
1107
- async updateStatus(id, status, errorMessage) {
1108
- const db = getDb();
1109
- const updates = { status };
1110
- if (errorMessage) {
1111
- updates.errorMessage = errorMessage;
1112
- }
1113
- await db
1114
- .update(schema.ciFixAttempts)
1115
- .set(updates)
1116
- .where(eq(schema.ciFixAttempts.id, id));
1117
- },
1118
- async complete(id, status, commitSha, errorMessage) {
1119
- const db = getDb();
1120
- await db
1121
- .update(schema.ciFixAttempts)
1122
- .set({
1123
- status,
1124
- completedAt: new Date(),
1125
- commitSha: commitSha ?? null,
1126
- errorMessage: errorMessage ?? null,
1127
- })
1128
- .where(eq(schema.ciFixAttempts.id, id));
1129
- },
1130
- };
1131
- export const issueAssignmentQueries = {
1132
- async findById(id) {
1133
- const db = getDb();
1134
- const result = await db.select().from(schema.issueAssignments).where(eq(schema.issueAssignments.id, id));
1135
- return result[0] ?? null;
1136
- },
1137
- async findByRepository(repository, limit = 50) {
1138
- const db = getDb();
1139
- return db
1140
- .select()
1141
- .from(schema.issueAssignments)
1142
- .where(eq(schema.issueAssignments.repository, repository))
1143
- .orderBy(desc(schema.issueAssignments.createdAt))
1144
- .limit(limit);
1145
- },
1146
- async findByIssue(repository, issueNumber) {
1147
- const db = getDb();
1148
- const result = await db
1149
- .select()
1150
- .from(schema.issueAssignments)
1151
- .where(and(eq(schema.issueAssignments.repository, repository), eq(schema.issueAssignments.issueNumber, issueNumber)));
1152
- return result[0] ?? null;
1153
- },
1154
- async findByAgent(agentId) {
1155
- const db = getDb();
1156
- return db
1157
- .select()
1158
- .from(schema.issueAssignments)
1159
- .where(eq(schema.issueAssignments.agentId, agentId))
1160
- .orderBy(desc(schema.issueAssignments.createdAt));
1161
- },
1162
- async findPending(limit = 100) {
1163
- const db = getDb();
1164
- return db
1165
- .select()
1166
- .from(schema.issueAssignments)
1167
- .where(eq(schema.issueAssignments.status, 'pending'))
1168
- .orderBy(schema.issueAssignments.createdAt)
1169
- .limit(limit);
1170
- },
1171
- async create(data) {
1172
- const db = getDb();
1173
- const result = await db.insert(schema.issueAssignments).values(data).returning();
1174
- return result[0];
1175
- },
1176
- async assignAgent(id, agentId, agentName) {
1177
- const db = getDb();
1178
- await db
1179
- .update(schema.issueAssignments)
1180
- .set({
1181
- agentId,
1182
- agentName,
1183
- assignedAt: new Date(),
1184
- status: 'assigned',
1185
- updatedAt: new Date(),
1186
- })
1187
- .where(eq(schema.issueAssignments.id, id));
1188
- },
1189
- async updateStatus(id, status, resolution) {
1190
- const db = getDb();
1191
- const updates = { status, updatedAt: new Date() };
1192
- if (resolution) {
1193
- updates.resolution = resolution;
1194
- }
1195
- await db
1196
- .update(schema.issueAssignments)
1197
- .set(updates)
1198
- .where(eq(schema.issueAssignments.id, id));
1199
- },
1200
- async linkPR(id, prNumber) {
1201
- const db = getDb();
1202
- await db
1203
- .update(schema.issueAssignments)
1204
- .set({ linkedPrNumber: prNumber, updatedAt: new Date() })
1205
- .where(eq(schema.issueAssignments.id, id));
1206
- },
1207
- };
1208
- export const commentMentionQueries = {
1209
- async findById(id) {
1210
- const db = getDb();
1211
- const result = await db.select().from(schema.commentMentions).where(eq(schema.commentMentions.id, id));
1212
- return result[0] ?? null;
1213
- },
1214
- async findByRepository(repository, limit = 50) {
1215
- const db = getDb();
1216
- return db
1217
- .select()
1218
- .from(schema.commentMentions)
1219
- .where(eq(schema.commentMentions.repository, repository))
1220
- .orderBy(desc(schema.commentMentions.createdAt))
1221
- .limit(limit);
1222
- },
1223
- async findBySource(sourceType, sourceId) {
1224
- const db = getDb();
1225
- const result = await db
1226
- .select()
1227
- .from(schema.commentMentions)
1228
- .where(and(eq(schema.commentMentions.sourceType, sourceType), eq(schema.commentMentions.sourceId, sourceId)));
1229
- return result[0] ?? null;
1230
- },
1231
- async findPending(limit = 100) {
1232
- const db = getDb();
1233
- return db
1234
- .select()
1235
- .from(schema.commentMentions)
1236
- .where(eq(schema.commentMentions.status, 'pending'))
1237
- .orderBy(schema.commentMentions.createdAt)
1238
- .limit(limit);
1239
- },
1240
- async findByMentionedAgent(mentionedAgent, limit = 50) {
1241
- const db = getDb();
1242
- return db
1243
- .select()
1244
- .from(schema.commentMentions)
1245
- .where(eq(schema.commentMentions.mentionedAgent, mentionedAgent))
1246
- .orderBy(desc(schema.commentMentions.createdAt))
1247
- .limit(limit);
1248
- },
1249
- async create(data) {
1250
- const db = getDb();
1251
- const result = await db.insert(schema.commentMentions).values(data).returning();
1252
- return result[0];
1253
- },
1254
- async markProcessing(id, agentId, agentName) {
1255
- const db = getDb();
1256
- await db
1257
- .update(schema.commentMentions)
1258
- .set({ status: 'processing', agentId, agentName })
1259
- .where(eq(schema.commentMentions.id, id));
1260
- },
1261
- async markResponded(id, responseCommentId, responseBody) {
1262
- const db = getDb();
1263
- await db
1264
- .update(schema.commentMentions)
1265
- .set({
1266
- status: 'responded',
1267
- responseCommentId,
1268
- responseBody,
1269
- respondedAt: new Date(),
1270
- })
1271
- .where(eq(schema.commentMentions.id, id));
1272
- },
1273
- async markIgnored(id) {
1274
- const db = getDb();
1275
- await db
1276
- .update(schema.commentMentions)
1277
- .set({ status: 'ignored' })
1278
- .where(eq(schema.commentMentions.id, id));
1279
- },
1280
- };
1281
- export const channelQueries = {
1282
- async findById(id) {
1283
- const db = getDb();
1284
- const result = await db.select().from(schema.channels).where(eq(schema.channels.id, id));
1285
- return result[0] ?? null;
1286
- },
1287
- async findByWorkspaceId(workspaceId) {
1288
- const db = getDb();
1289
- return db
1290
- .select()
1291
- .from(schema.channels)
1292
- .where(eq(schema.channels.workspaceId, workspaceId))
1293
- .orderBy(desc(schema.channels.lastActivityAt));
1294
- },
1295
- async findByWorkspaceAndChannelId(workspaceId, channelId) {
1296
- const db = getDb();
1297
- const result = await db
1298
- .select()
1299
- .from(schema.channels)
1300
- .where(and(eq(schema.channels.workspaceId, workspaceId), eq(schema.channels.channelId, channelId)));
1301
- return result[0] ?? null;
1302
- },
1303
- async create(channel) {
1304
- const db = getDb();
1305
- const result = await db.insert(schema.channels).values(channel).returning();
1306
- return result[0];
1307
- },
1308
- async update(id, updates) {
1309
- const db = getDb();
1310
- await db
1311
- .update(schema.channels)
1312
- .set({ ...updates, updatedAt: new Date() })
1313
- .where(eq(schema.channels.id, id));
1314
- },
1315
- async archive(id) {
1316
- const db = getDb();
1317
- await db
1318
- .update(schema.channels)
1319
- .set({ status: 'archived', updatedAt: new Date() })
1320
- .where(eq(schema.channels.id, id));
1321
- },
1322
- async unarchive(id) {
1323
- const db = getDb();
1324
- await db
1325
- .update(schema.channels)
1326
- .set({ status: 'active', updatedAt: new Date() })
1327
- .where(eq(schema.channels.id, id));
1328
- },
1329
- async delete(id) {
1330
- const db = getDb();
1331
- await db.delete(schema.channels).where(eq(schema.channels.id, id));
1332
- },
1333
- };
1334
- export const channelMemberQueries = {
1335
- async findByChannelId(channelId) {
1336
- const db = getDb();
1337
- return db
1338
- .select()
1339
- .from(schema.channelMembers)
1340
- .where(eq(schema.channelMembers.channelId, channelId));
1341
- },
1342
- async findByMemberId(memberId) {
1343
- const db = getDb();
1344
- return db
1345
- .select()
1346
- .from(schema.channelMembers)
1347
- .where(eq(schema.channelMembers.memberId, memberId));
1348
- },
1349
- async findMembership(channelId, memberId) {
1350
- const db = getDb();
1351
- const result = await db
1352
- .select()
1353
- .from(schema.channelMembers)
1354
- .where(and(eq(schema.channelMembers.channelId, channelId), eq(schema.channelMembers.memberId, memberId)));
1355
- return result[0] ?? null;
1356
- },
1357
- async addMember(member) {
1358
- const db = getDb();
1359
- const result = await db.insert(schema.channelMembers).values(member).returning();
1360
- return result[0];
1361
- },
1362
- async removeMember(channelId, memberId) {
1363
- const db = getDb();
1364
- await db
1365
- .delete(schema.channelMembers)
1366
- .where(and(eq(schema.channelMembers.channelId, channelId), eq(schema.channelMembers.memberId, memberId)));
1367
- },
1368
- async updateRole(channelId, memberId, role) {
1369
- const db = getDb();
1370
- await db
1371
- .update(schema.channelMembers)
1372
- .set({ role })
1373
- .where(and(eq(schema.channelMembers.channelId, channelId), eq(schema.channelMembers.memberId, memberId)));
1374
- },
1375
- async countByChannelIds(channelIds) {
1376
- if (channelIds.length === 0) {
1377
- return new Map();
1378
- }
1379
- const db = getDb();
1380
- const results = await db
1381
- .select({
1382
- channelId: schema.channelMembers.channelId,
1383
- count: sql `count(*)::int`,
1384
- })
1385
- .from(schema.channelMembers)
1386
- .where(inArray(schema.channelMembers.channelId, channelIds))
1387
- .groupBy(schema.channelMembers.channelId);
1388
- const countMap = new Map();
1389
- for (const row of results) {
1390
- countMap.set(row.channelId, row.count);
1391
- }
1392
- return countMap;
1393
- },
1394
- };
1395
- // ============================================================================
1396
- // Migration helper
1397
- // ============================================================================
1398
- export async function runMigrations() {
1399
- const { migrate } = await import('drizzle-orm/node-postgres/migrator');
1400
- const { fileURLToPath } = await import('node:url');
1401
- const { dirname, join } = await import('node:path');
1402
- // Get migrations folder relative to this file (works in both dev and Docker)
1403
- const __filename = fileURLToPath(import.meta.url);
1404
- const __dirname = dirname(__filename);
1405
- // In dist: packages/cloud/dist/db/drizzle.js -> need to go to packages/cloud/src/db/migrations
1406
- // The migrations are in src/db/migrations, not dist/db/migrations
1407
- const migrationsFolder = join(__dirname, '..', '..', 'src', 'db', 'migrations');
1408
- const db = getDb();
1409
- await migrate(db, { migrationsFolder });
1410
- console.log('Migrations complete');
1411
- }
1412
- // ============================================================================
1413
- // Close connections
1414
- // ============================================================================
1415
- export async function closeDb() {
1416
- if (pool) {
1417
- await pool.end();
1418
- pool = null;
1419
- drizzleDb = null;
1420
- }
1421
- }
1422
- //# sourceMappingURL=drizzle.js.map