@inkeep/agents-core 0.43.0 → 0.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/dist/auth/auth.d.ts +4 -2
  2. package/dist/auth/auth.js +4 -3
  3. package/dist/auth/authz/client.d.ts +0 -1
  4. package/dist/auth/authz/client.js +0 -1
  5. package/dist/auth/authz/config.d.ts +1 -7
  6. package/dist/auth/authz/config.js +1 -9
  7. package/dist/auth/authz/index.d.ts +3 -3
  8. package/dist/auth/authz/index.js +3 -3
  9. package/dist/auth/authz/permissions.d.ts +16 -1
  10. package/dist/auth/authz/permissions.js +30 -9
  11. package/dist/auth/authz/sync.js +1 -11
  12. package/dist/auth/init.d.ts +1 -0
  13. package/dist/auth/init.js +115 -0
  14. package/dist/client-exports.d.ts +2 -6
  15. package/dist/client-exports.js +3 -7
  16. package/dist/constants/otel-attributes.d.ts +6 -0
  17. package/dist/constants/otel-attributes.js +9 -3
  18. package/dist/constants/signoz-queries.d.ts +1 -0
  19. package/dist/constants/signoz-queries.js +2 -1
  20. package/dist/data-access/index.d.ts +4 -3
  21. package/dist/data-access/index.js +6 -5
  22. package/dist/data-access/manage/agentFull.js +42 -1
  23. package/dist/data-access/manage/agents.d.ts +27 -10
  24. package/dist/data-access/manage/agents.js +33 -2
  25. package/dist/data-access/manage/artifactComponents.d.ts +4 -4
  26. package/dist/data-access/manage/artifactComponents.js +1 -1
  27. package/dist/data-access/manage/contextConfigs.d.ts +12 -12
  28. package/dist/data-access/manage/dataComponents.d.ts +4 -4
  29. package/dist/data-access/manage/dataComponents.js +1 -1
  30. package/dist/data-access/manage/functionTools.d.ts +4 -4
  31. package/dist/data-access/manage/subAgentExternalAgentRelations.d.ts +12 -12
  32. package/dist/data-access/manage/subAgentRelations.d.ts +18 -18
  33. package/dist/data-access/manage/subAgentTeamAgentRelations.d.ts +12 -12
  34. package/dist/data-access/manage/subAgents.d.ts +3 -3
  35. package/dist/data-access/manage/tools.d.ts +20 -15
  36. package/dist/data-access/manage/tools.js +20 -1
  37. package/dist/data-access/runtime/apiKeys.d.ts +4 -4
  38. package/dist/data-access/runtime/cascade-delete.d.ts +48 -1
  39. package/dist/data-access/runtime/cascade-delete.js +52 -2
  40. package/dist/data-access/runtime/conversations.d.ts +19 -19
  41. package/dist/data-access/runtime/github-work-app-installations.d.ts +261 -0
  42. package/dist/data-access/runtime/github-work-app-installations.js +457 -0
  43. package/dist/data-access/runtime/messages.d.ts +6 -6
  44. package/dist/data-access/runtime/organizations.js +2 -2
  45. package/dist/data-access/runtime/tasks.d.ts +4 -4
  46. package/dist/db/manage/manage-schema.d.ts +17 -0
  47. package/dist/db/manage/manage-schema.js +1 -0
  48. package/dist/db/runtime/runtime-schema.d.ts +1009 -165
  49. package/dist/db/runtime/runtime-schema.js +173 -5
  50. package/dist/dolt/ref-middleware.js +1 -1
  51. package/dist/env.d.ts +6 -4
  52. package/dist/env.js +11 -10
  53. package/dist/index.d.ts +10 -11
  54. package/dist/index.js +22 -23
  55. package/dist/types/entities.d.ts +9 -2
  56. package/dist/types/index.d.ts +3 -3
  57. package/dist/types/utility.d.ts +16 -2
  58. package/dist/utils/temp-jwt.d.ts +2 -1
  59. package/dist/utils/temp-jwt.js +3 -2
  60. package/dist/validation/agentFull.js +1 -1
  61. package/dist/validation/dolt-schemas.d.ts +1 -1
  62. package/dist/validation/drizzle-schema-helpers.d.ts +1 -20
  63. package/dist/validation/drizzle-schema-helpers.js +3 -30
  64. package/dist/validation/index.d.ts +2 -4
  65. package/dist/validation/index.js +4 -6
  66. package/dist/validation/schemas.d.ts +3021 -1228
  67. package/dist/validation/schemas.js +164 -79
  68. package/drizzle/manage/0006_fixed_umar.sql +1 -0
  69. package/drizzle/manage/meta/0006_snapshot.json +3148 -0
  70. package/drizzle/manage/meta/_journal.json +7 -0
  71. package/drizzle/runtime/0010_previous_black_knight.sql +84 -0
  72. package/drizzle/runtime/meta/0010_snapshot.json +3066 -0
  73. package/drizzle/runtime/meta/_journal.json +7 -0
  74. package/package.json +4 -2
  75. package/dist/validation/id-validation.d.ts +0 -24
  76. package/dist/validation/id-validation.js +0 -52
@@ -0,0 +1,457 @@
1
+ import { workAppGitHubInstallations, workAppGitHubMcpToolAccessMode, workAppGitHubMcpToolRepositoryAccess, workAppGitHubProjectAccessMode, workAppGitHubProjectRepositoryAccess, workAppGitHubRepositories } from "../../db/runtime/runtime-schema.js";
2
+ import { generateId } from "../../utils/conversations.js";
3
+ import { and, count, desc, eq, inArray, ne } from "drizzle-orm";
4
+
5
+ //#region src/data-access/runtime/github-work-app-installations.ts
6
+ /**
7
+ * Create a new GitHub App installation record
8
+ */
9
+ const createInstallation = (db) => async (input) => {
10
+ const now = (/* @__PURE__ */ new Date()).toISOString();
11
+ const [created] = await db.insert(workAppGitHubInstallations).values({
12
+ ...input,
13
+ createdAt: now,
14
+ updatedAt: now
15
+ }).returning();
16
+ return created;
17
+ };
18
+ /**
19
+ * Get installation by GitHub installation ID
20
+ */
21
+ const getInstallationByGitHubId = (db) => async (gitHubInstallationId) => {
22
+ return await db.query.workAppGitHubInstallations.findFirst({ where: eq(workAppGitHubInstallations.installationId, gitHubInstallationId) }) ?? null;
23
+ };
24
+ /**
25
+ * Get installation by internal ID with tenant validation
26
+ */
27
+ const getInstallationById = (db) => async (params) => {
28
+ return await db.query.workAppGitHubInstallations.findFirst({ where: and(eq(workAppGitHubInstallations.tenantId, params.tenantId), eq(workAppGitHubInstallations.id, params.id)) }) ?? null;
29
+ };
30
+ /**
31
+ * Get all installations for a tenant
32
+ */
33
+ const getInstallationsByTenantId = (db) => async (params) => {
34
+ const conditions = [eq(workAppGitHubInstallations.tenantId, params.tenantId)];
35
+ if (!params.includeDisconnected) conditions.push(ne(workAppGitHubInstallations.status, "disconnected"));
36
+ return await db.select().from(workAppGitHubInstallations).where(and(...conditions)).orderBy(desc(workAppGitHubInstallations.createdAt));
37
+ };
38
+ /**
39
+ * Update installation status
40
+ */
41
+ const updateInstallationStatus = (db) => async (params) => {
42
+ const now = (/* @__PURE__ */ new Date()).toISOString();
43
+ const [updated] = await db.update(workAppGitHubInstallations).set({
44
+ status: params.status,
45
+ updatedAt: now
46
+ }).where(and(eq(workAppGitHubInstallations.tenantId, params.tenantId), eq(workAppGitHubInstallations.id, params.id))).returning();
47
+ return updated ?? null;
48
+ };
49
+ /**
50
+ * Update installation status by GitHub installation ID (for webhook handlers)
51
+ */
52
+ const updateInstallationStatusByGitHubId = (db) => async (params) => {
53
+ const now = (/* @__PURE__ */ new Date()).toISOString();
54
+ const [updated] = await db.update(workAppGitHubInstallations).set({
55
+ status: params.status,
56
+ updatedAt: now
57
+ }).where(eq(workAppGitHubInstallations.installationId, params.gitHubInstallationId)).returning();
58
+ return updated ?? null;
59
+ };
60
+ /**
61
+ * Soft delete an installation (set status to 'disconnected')
62
+ * Also removes all project repository access for this installation's repositories
63
+ */
64
+ const disconnectInstallation = (db) => async (params) => {
65
+ const now = (/* @__PURE__ */ new Date()).toISOString();
66
+ const repoIds = (await db.select({ id: workAppGitHubRepositories.id }).from(workAppGitHubRepositories).where(eq(workAppGitHubRepositories.installationDbId, params.id))).map((r) => r.id);
67
+ if (repoIds.length > 0) await db.delete(workAppGitHubProjectRepositoryAccess).where(inArray(workAppGitHubProjectRepositoryAccess.repositoryDbId, repoIds));
68
+ const [updated] = await db.update(workAppGitHubInstallations).set({
69
+ status: "disconnected",
70
+ updatedAt: now
71
+ }).where(and(eq(workAppGitHubInstallations.tenantId, params.tenantId), eq(workAppGitHubInstallations.id, params.id))).returning();
72
+ return !!updated;
73
+ };
74
+ /**
75
+ * Delete an installation (hard delete)
76
+ * Returns the deleted installation if found, null otherwise
77
+ */
78
+ const deleteInstallation = (db) => async (params) => {
79
+ const [deleted] = await db.delete(workAppGitHubInstallations).where(and(eq(workAppGitHubInstallations.tenantId, params.tenantId), eq(workAppGitHubInstallations.id, params.id))).returning();
80
+ return deleted ?? null;
81
+ };
82
+ /**
83
+ * Sync repositories for an installation
84
+ * Adds new repos, removes missing repos, updates existing
85
+ */
86
+ const syncRepositories = (db) => async (params) => {
87
+ const now = (/* @__PURE__ */ new Date()).toISOString();
88
+ const existingRepos = await db.select().from(workAppGitHubRepositories).where(eq(workAppGitHubRepositories.installationDbId, params.installationId));
89
+ const existingRepoIds = new Set(existingRepos.map((r) => r.repositoryId));
90
+ const newRepoIds = new Set(params.repositories.map((r) => r.repositoryId));
91
+ const toAdd = params.repositories.filter((r) => !existingRepoIds.has(r.repositoryId));
92
+ const toRemove = existingRepos.filter((r) => !newRepoIds.has(r.repositoryId));
93
+ const toUpdate = params.repositories.filter((r) => existingRepoIds.has(r.repositoryId));
94
+ if (toRemove.length > 0) {
95
+ const removeIds = toRemove.map((r) => r.id);
96
+ await db.delete(workAppGitHubProjectRepositoryAccess).where(inArray(workAppGitHubProjectRepositoryAccess.repositoryDbId, removeIds));
97
+ await db.delete(workAppGitHubRepositories).where(inArray(workAppGitHubRepositories.id, removeIds));
98
+ }
99
+ if (toAdd.length > 0) await db.insert(workAppGitHubRepositories).values(toAdd.map((repo) => ({
100
+ id: generateId(),
101
+ installationDbId: params.installationId,
102
+ repositoryId: repo.repositoryId,
103
+ repositoryName: repo.repositoryName,
104
+ repositoryFullName: repo.repositoryFullName,
105
+ private: repo.private,
106
+ createdAt: now,
107
+ updatedAt: now
108
+ })));
109
+ let updatedCount = 0;
110
+ for (const repo of toUpdate) {
111
+ const existing = existingRepos.find((e) => e.repositoryId === repo.repositoryId);
112
+ if (existing && (existing.repositoryName !== repo.repositoryName || existing.repositoryFullName !== repo.repositoryFullName || existing.private !== repo.private)) {
113
+ await db.update(workAppGitHubRepositories).set({
114
+ repositoryName: repo.repositoryName,
115
+ repositoryFullName: repo.repositoryFullName,
116
+ private: repo.private,
117
+ updatedAt: now
118
+ }).where(eq(workAppGitHubRepositories.id, existing.id));
119
+ updatedCount++;
120
+ }
121
+ }
122
+ return {
123
+ added: toAdd.length,
124
+ removed: toRemove.length,
125
+ updated: updatedCount
126
+ };
127
+ };
128
+ /**
129
+ * Add repositories to an installation (for webhook 'added' events)
130
+ */
131
+ const addRepositories = (db) => async (params) => {
132
+ const now = (/* @__PURE__ */ new Date()).toISOString();
133
+ if (params.repositories.length === 0) return [];
134
+ await db.insert(workAppGitHubRepositories).values(params.repositories.map((repo) => ({
135
+ id: generateId(),
136
+ installationDbId: params.installationId,
137
+ repositoryId: repo.repositoryId,
138
+ repositoryName: repo.repositoryName,
139
+ repositoryFullName: repo.repositoryFullName,
140
+ private: repo.private,
141
+ createdAt: now,
142
+ updatedAt: now
143
+ }))).onConflictDoNothing().returning();
144
+ const insertedRepoIds = params.repositories.map((r) => r.repositoryId);
145
+ return await db.select().from(workAppGitHubRepositories).where(and(eq(workAppGitHubRepositories.installationDbId, params.installationId), inArray(workAppGitHubRepositories.repositoryId, insertedRepoIds)));
146
+ };
147
+ /**
148
+ * Remove repositories from an installation (for webhook 'removed' events)
149
+ * Also removes associated project repository access entries
150
+ */
151
+ const removeRepositories = (db) => async (params) => {
152
+ if (params.repositoryIds.length === 0) return 0;
153
+ const repoIds = (await db.select({ id: workAppGitHubRepositories.id }).from(workAppGitHubRepositories).where(and(eq(workAppGitHubRepositories.installationDbId, params.installationId), inArray(workAppGitHubRepositories.repositoryId, params.repositoryIds)))).map((r) => r.id);
154
+ if (repoIds.length === 0) return 0;
155
+ await db.delete(workAppGitHubProjectRepositoryAccess).where(inArray(workAppGitHubProjectRepositoryAccess.repositoryDbId, repoIds));
156
+ return (await db.delete(workAppGitHubRepositories).where(inArray(workAppGitHubRepositories.id, repoIds)).returning()).length;
157
+ };
158
+ /**
159
+ * Get all repositories for an installation
160
+ */
161
+ const getRepositoriesByInstallationId = (db) => async (installationId) => {
162
+ return await db.select().from(workAppGitHubRepositories).where(eq(workAppGitHubRepositories.installationDbId, installationId)).orderBy(workAppGitHubRepositories.repositoryFullName);
163
+ };
164
+ /**
165
+ * Get repository by full name (e.g., "org/repo")
166
+ */
167
+ const getRepositoryByFullName = (db) => async (repositoryFullName) => {
168
+ return (await db.select().from(workAppGitHubRepositories).where(eq(workAppGitHubRepositories.repositoryFullName, repositoryFullName)).limit(1))[0] ?? null;
169
+ };
170
+ /**
171
+ * Get repository by internal ID
172
+ */
173
+ const getRepositoryById = (db) => async (id) => {
174
+ return await db.query.workAppGitHubRepositories.findFirst({ where: eq(workAppGitHubRepositories.id, id) }) ?? null;
175
+ };
176
+ /**
177
+ * Get all repositories for a tenant (across all installations)
178
+ */
179
+ const getRepositoriesByTenantId = (db) => async (tenantId) => {
180
+ return await db.select({
181
+ id: workAppGitHubRepositories.id,
182
+ installationDbId: workAppGitHubRepositories.installationDbId,
183
+ installationId: workAppGitHubInstallations.installationId,
184
+ repositoryId: workAppGitHubRepositories.repositoryId,
185
+ repositoryName: workAppGitHubRepositories.repositoryName,
186
+ repositoryFullName: workAppGitHubRepositories.repositoryFullName,
187
+ private: workAppGitHubRepositories.private,
188
+ createdAt: workAppGitHubRepositories.createdAt,
189
+ updatedAt: workAppGitHubRepositories.updatedAt,
190
+ installationAccountLogin: workAppGitHubInstallations.accountLogin
191
+ }).from(workAppGitHubRepositories).innerJoin(workAppGitHubInstallations, eq(workAppGitHubRepositories.installationDbId, workAppGitHubInstallations.id)).where(and(eq(workAppGitHubInstallations.tenantId, tenantId), ne(workAppGitHubInstallations.status, "disconnected"))).orderBy(workAppGitHubRepositories.repositoryFullName);
192
+ };
193
+ /**
194
+ * Set project repository access (full replacement)
195
+ * Used when mode='selected' to specify which repositories the project can access.
196
+ * Pass empty array to clear all access entries.
197
+ *
198
+ * Also cascades changes to MCP tools: any MCP tool in this project with mode='selected'
199
+ * will have its selected repositories filtered to only include repos that remain
200
+ * in the project's access list.
201
+ */
202
+ const setProjectRepositoryAccess = (db) => async (params) => {
203
+ const now = (/* @__PURE__ */ new Date()).toISOString();
204
+ const newRepoIdSet = new Set(params.repositoryIds);
205
+ await db.delete(workAppGitHubProjectRepositoryAccess).where(eq(workAppGitHubProjectRepositoryAccess.projectId, params.projectId));
206
+ if (params.repositoryIds.length > 0) await db.insert(workAppGitHubProjectRepositoryAccess).values(params.repositoryIds.map((repoId) => ({
207
+ id: generateId(),
208
+ tenantId: params.tenantId,
209
+ projectId: params.projectId,
210
+ repositoryDbId: repoId,
211
+ createdAt: now,
212
+ updatedAt: now
213
+ })));
214
+ const toolsWithSelectedMode = await db.select({ toolId: workAppGitHubMcpToolAccessMode.toolId }).from(workAppGitHubMcpToolAccessMode).where(and(eq(workAppGitHubMcpToolAccessMode.tenantId, params.tenantId), eq(workAppGitHubMcpToolAccessMode.projectId, params.projectId), eq(workAppGitHubMcpToolAccessMode.mode, "selected")));
215
+ for (const { toolId } of toolsWithSelectedMode) {
216
+ const reposToRemove = (await db.select({
217
+ id: workAppGitHubMcpToolRepositoryAccess.id,
218
+ repositoryDbId: workAppGitHubMcpToolRepositoryAccess.repositoryDbId
219
+ }).from(workAppGitHubMcpToolRepositoryAccess).where(eq(workAppGitHubMcpToolRepositoryAccess.toolId, toolId))).filter((r) => !newRepoIdSet.has(r.repositoryDbId));
220
+ if (reposToRemove.length > 0) await db.delete(workAppGitHubMcpToolRepositoryAccess).where(inArray(workAppGitHubMcpToolRepositoryAccess.id, reposToRemove.map((r) => r.id)));
221
+ }
222
+ };
223
+ /**
224
+ * Get project repository access entries
225
+ * These entries are used when mode='selected'. Check mode via getProjectAccessMode().
226
+ */
227
+ const getProjectRepositoryAccess = (db) => async (projectId) => {
228
+ return await db.select().from(workAppGitHubProjectRepositoryAccess).where(eq(workAppGitHubProjectRepositoryAccess.projectId, projectId));
229
+ };
230
+ /**
231
+ * Get project repository access with full repository details.
232
+ * If project access mode is 'all', returns all tenant repositories.
233
+ * If mode is 'selected' (or not set), returns only explicitly granted repositories.
234
+ */
235
+ const getProjectRepositoryAccessWithDetails = (db) => async (params) => {
236
+ if (await getProjectAccessMode(db)({
237
+ tenantId: params.tenantId,
238
+ projectId: params.projectId
239
+ }) === "all") return (await getRepositoriesByTenantId(db)(params.tenantId)).map((repo) => ({
240
+ accessId: repo.id,
241
+ ...repo
242
+ }));
243
+ return await db.select({
244
+ accessId: workAppGitHubProjectRepositoryAccess.id,
245
+ id: workAppGitHubRepositories.id,
246
+ installationDbId: workAppGitHubRepositories.installationDbId,
247
+ installationId: workAppGitHubInstallations.installationId,
248
+ repositoryId: workAppGitHubRepositories.repositoryId,
249
+ repositoryName: workAppGitHubRepositories.repositoryName,
250
+ repositoryFullName: workAppGitHubRepositories.repositoryFullName,
251
+ private: workAppGitHubRepositories.private,
252
+ createdAt: workAppGitHubRepositories.createdAt,
253
+ updatedAt: workAppGitHubRepositories.updatedAt,
254
+ installationAccountLogin: workAppGitHubInstallations.accountLogin
255
+ }).from(workAppGitHubProjectRepositoryAccess).innerJoin(workAppGitHubRepositories, eq(workAppGitHubProjectRepositoryAccess.repositoryDbId, workAppGitHubRepositories.id)).innerJoin(workAppGitHubInstallations, eq(workAppGitHubRepositories.installationDbId, workAppGitHubInstallations.id)).where(eq(workAppGitHubProjectRepositoryAccess.projectId, params.projectId));
256
+ };
257
+ /**
258
+ * Check if a project has access to a specific repository
259
+ * Returns true if:
260
+ * - Project mode is 'all' and repository belongs to tenant installations
261
+ * - Project mode is 'selected' and repository is explicitly in the project's access list
262
+ */
263
+ const checkProjectRepositoryAccess = (db) => async (params) => {
264
+ if (((await db.select({ mode: workAppGitHubProjectAccessMode.mode }).from(workAppGitHubProjectAccessMode).where(and(eq(workAppGitHubProjectAccessMode.tenantId, params.tenantId), eq(workAppGitHubProjectAccessMode.projectId, params.projectId))).limit(1))[0]?.mode ?? "selected") === "all") {
265
+ if ((await db.select({ id: workAppGitHubRepositories.id }).from(workAppGitHubRepositories).innerJoin(workAppGitHubInstallations, eq(workAppGitHubRepositories.installationDbId, workAppGitHubInstallations.id)).where(and(eq(workAppGitHubRepositories.repositoryFullName, params.repositoryFullName), eq(workAppGitHubInstallations.tenantId, params.tenantId), ne(workAppGitHubInstallations.status, "disconnected"))).limit(1)).length === 0) return {
266
+ hasAccess: false,
267
+ reason: "Repository not found in tenant installations"
268
+ };
269
+ return {
270
+ hasAccess: true,
271
+ reason: "Project has access to all repositories"
272
+ };
273
+ }
274
+ if ((await db.select({ id: workAppGitHubProjectRepositoryAccess.id }).from(workAppGitHubProjectRepositoryAccess).innerJoin(workAppGitHubRepositories, eq(workAppGitHubProjectRepositoryAccess.repositoryDbId, workAppGitHubRepositories.id)).innerJoin(workAppGitHubInstallations, eq(workAppGitHubRepositories.installationDbId, workAppGitHubInstallations.id)).where(and(eq(workAppGitHubProjectRepositoryAccess.projectId, params.projectId), eq(workAppGitHubRepositories.repositoryFullName, params.repositoryFullName), eq(workAppGitHubInstallations.tenantId, params.tenantId), ne(workAppGitHubInstallations.status, "disconnected"))).limit(1)).length === 0) return {
275
+ hasAccess: false,
276
+ reason: "Repository not in project access list"
277
+ };
278
+ return {
279
+ hasAccess: true,
280
+ reason: "Repository explicitly allowed for project"
281
+ };
282
+ };
283
+ /**
284
+ * Remove all project repository access for a specific project
285
+ */
286
+ const clearProjectRepositoryAccess = (db) => async (projectId) => {
287
+ return (await db.delete(workAppGitHubProjectRepositoryAccess).where(eq(workAppGitHubProjectRepositoryAccess.projectId, projectId)).returning()).length;
288
+ };
289
+ /**
290
+ * Validate that all repository IDs belong to installations owned by a tenant
291
+ * Returns list of invalid repository IDs
292
+ */
293
+ const validateRepositoryOwnership = (db) => async (params) => {
294
+ if (params.repositoryIds.length === 0) return [];
295
+ const validRepos = await db.select({ id: workAppGitHubRepositories.id }).from(workAppGitHubRepositories).innerJoin(workAppGitHubInstallations, eq(workAppGitHubRepositories.installationDbId, workAppGitHubInstallations.id)).where(and(eq(workAppGitHubInstallations.tenantId, params.tenantId), ne(workAppGitHubInstallations.status, "disconnected"), inArray(workAppGitHubRepositories.id, params.repositoryIds)));
296
+ const validRepoIds = new Set(validRepos.map((r) => r.id));
297
+ return params.repositoryIds.filter((id) => !validRepoIds.has(id));
298
+ };
299
+ /**
300
+ * Get repository count for an installation
301
+ */
302
+ const getRepositoryCount = (db) => async (installationId) => {
303
+ const total = (await db.select({ count: count() }).from(workAppGitHubRepositories).where(eq(workAppGitHubRepositories.installationDbId, installationId)))[0]?.count ?? 0;
304
+ return typeof total === "string" ? Number.parseInt(total, 10) : total;
305
+ };
306
+ /**
307
+ * Get repository counts for all installations belonging to a tenant
308
+ */
309
+ const getRepositoryCountsByTenantId = (db) => async (params) => {
310
+ const conditions = [eq(workAppGitHubInstallations.tenantId, params.tenantId)];
311
+ if (!params.includeDisconnected) conditions.push(ne(workAppGitHubInstallations.status, "disconnected"));
312
+ const results = await db.select({
313
+ installationId: workAppGitHubInstallations.id,
314
+ count: count(workAppGitHubRepositories.id)
315
+ }).from(workAppGitHubInstallations).leftJoin(workAppGitHubRepositories, eq(workAppGitHubRepositories.installationDbId, workAppGitHubInstallations.id)).where(and(...conditions)).groupBy(workAppGitHubInstallations.id);
316
+ const countsMap = /* @__PURE__ */ new Map();
317
+ for (const row of results) {
318
+ const total = typeof row.count === "string" ? Number.parseInt(row.count, 10) : row.count;
319
+ countsMap.set(row.installationId, total);
320
+ }
321
+ return countsMap;
322
+ };
323
+ /**
324
+ * Set MCP tool repository access (full replacement)
325
+ * Used when mode='selected' to specify which repositories the tool can access.
326
+ * Pass empty array to clear all access entries.
327
+ */
328
+ const setMcpToolRepositoryAccess = (db) => async (params) => {
329
+ const now = (/* @__PURE__ */ new Date()).toISOString();
330
+ await db.delete(workAppGitHubMcpToolRepositoryAccess).where(eq(workAppGitHubMcpToolRepositoryAccess.toolId, params.toolId));
331
+ if (params.repositoryIds.length > 0) await db.insert(workAppGitHubMcpToolRepositoryAccess).values(params.repositoryIds.map((repoId) => ({
332
+ id: generateId(),
333
+ toolId: params.toolId,
334
+ tenantId: params.tenantId,
335
+ projectId: params.projectId,
336
+ repositoryDbId: repoId,
337
+ createdAt: now,
338
+ updatedAt: now
339
+ })));
340
+ };
341
+ /**
342
+ * Get MCP tool repository access entries
343
+ * These entries are used when mode='selected'. Check mode via getMcpToolAccessMode().
344
+ */
345
+ const getMcpToolRepositoryAccess = (db) => async (toolId) => {
346
+ return await db.select().from(workAppGitHubMcpToolRepositoryAccess).where(eq(workAppGitHubMcpToolRepositoryAccess.toolId, toolId));
347
+ };
348
+ /**
349
+ * Get MCP tool repository access with full repository details.
350
+ * If the tool's access mode is 'all', returns all repositories the project has access to.
351
+ * If mode is 'selected' (or not set), returns only explicitly granted repositories.
352
+ */
353
+ const getMcpToolRepositoryAccessWithDetails = (db) => async (toolId) => {
354
+ const accessMode = (await db.select({
355
+ mode: workAppGitHubMcpToolAccessMode.mode,
356
+ projectId: workAppGitHubMcpToolAccessMode.projectId,
357
+ tenantId: workAppGitHubMcpToolAccessMode.tenantId
358
+ }).from(workAppGitHubMcpToolAccessMode).where(eq(workAppGitHubMcpToolAccessMode.toolId, toolId)).limit(1))[0];
359
+ if (accessMode?.mode === "all") return getProjectRepositoryAccessWithDetails(db)({
360
+ tenantId: accessMode.tenantId,
361
+ projectId: accessMode.projectId
362
+ });
363
+ return await db.select({
364
+ accessId: workAppGitHubMcpToolRepositoryAccess.id,
365
+ id: workAppGitHubRepositories.id,
366
+ installationDbId: workAppGitHubRepositories.installationDbId,
367
+ installationId: workAppGitHubInstallations.installationId,
368
+ repositoryId: workAppGitHubRepositories.repositoryId,
369
+ repositoryName: workAppGitHubRepositories.repositoryName,
370
+ repositoryFullName: workAppGitHubRepositories.repositoryFullName,
371
+ private: workAppGitHubRepositories.private,
372
+ createdAt: workAppGitHubRepositories.createdAt,
373
+ updatedAt: workAppGitHubRepositories.updatedAt,
374
+ installationAccountLogin: workAppGitHubInstallations.accountLogin
375
+ }).from(workAppGitHubMcpToolRepositoryAccess).innerJoin(workAppGitHubRepositories, eq(workAppGitHubMcpToolRepositoryAccess.repositoryDbId, workAppGitHubRepositories.id)).innerJoin(workAppGitHubInstallations, eq(workAppGitHubRepositories.installationDbId, workAppGitHubInstallations.id)).where(eq(workAppGitHubMcpToolRepositoryAccess.toolId, toolId));
376
+ };
377
+ /**
378
+ * Remove all MCP tool repository access for a specific tool
379
+ */
380
+ const clearMcpToolRepositoryAccess = (db) => async (toolId) => {
381
+ return (await db.delete(workAppGitHubMcpToolRepositoryAccess).where(eq(workAppGitHubMcpToolRepositoryAccess.toolId, toolId)).returning()).length;
382
+ };
383
+ const isGithubWorkAppTool = (tool) => {
384
+ return tool.isWorkApp && tool.config.mcp.server.url.includes("/github/mcp");
385
+ };
386
+ /**
387
+ * Set the access mode for a project's GitHub repository access.
388
+ * - 'all': Project has access to all repositories from tenant GitHub installations
389
+ * - 'selected': Project only has access to repositories listed in work_app_github_project_repository_access
390
+ */
391
+ const setProjectAccessMode = (db) => async (params) => {
392
+ const now = (/* @__PURE__ */ new Date()).toISOString();
393
+ await db.insert(workAppGitHubProjectAccessMode).values({
394
+ tenantId: params.tenantId,
395
+ projectId: params.projectId,
396
+ mode: params.mode,
397
+ createdAt: now,
398
+ updatedAt: now
399
+ }).onConflictDoUpdate({
400
+ target: [workAppGitHubProjectAccessMode.tenantId, workAppGitHubProjectAccessMode.projectId],
401
+ set: {
402
+ mode: params.mode,
403
+ updatedAt: now
404
+ }
405
+ });
406
+ };
407
+ /**
408
+ * Get the access mode for a project's GitHub repository access.
409
+ * Returns 'selected' if no mode is explicitly set (fail-safe default).
410
+ */
411
+ const getProjectAccessMode = (db) => async (params) => {
412
+ return (await db.select({ mode: workAppGitHubProjectAccessMode.mode }).from(workAppGitHubProjectAccessMode).where(and(eq(workAppGitHubProjectAccessMode.tenantId, params.tenantId), eq(workAppGitHubProjectAccessMode.projectId, params.projectId))).limit(1))[0]?.mode ?? "selected";
413
+ };
414
+ /**
415
+ * Delete the access mode entry for a project
416
+ */
417
+ const deleteProjectAccessMode = (db) => async (params) => {
418
+ return (await db.delete(workAppGitHubProjectAccessMode).where(and(eq(workAppGitHubProjectAccessMode.tenantId, params.tenantId), eq(workAppGitHubProjectAccessMode.projectId, params.projectId))).returning()).length > 0;
419
+ };
420
+ /**
421
+ * Set the access mode for an MCP tool's GitHub repository access.
422
+ * - 'all': Tool has access to all repositories the project has access to
423
+ * - 'selected': Tool only has access to repositories listed in work_app_github_mcp_tool_repository_access
424
+ */
425
+ const setMcpToolAccessMode = (db) => async (params) => {
426
+ const now = (/* @__PURE__ */ new Date()).toISOString();
427
+ await db.insert(workAppGitHubMcpToolAccessMode).values({
428
+ toolId: params.toolId,
429
+ tenantId: params.tenantId,
430
+ projectId: params.projectId,
431
+ mode: params.mode,
432
+ createdAt: now,
433
+ updatedAt: now
434
+ }).onConflictDoUpdate({
435
+ target: [workAppGitHubMcpToolAccessMode.toolId],
436
+ set: {
437
+ mode: params.mode,
438
+ updatedAt: now
439
+ }
440
+ });
441
+ };
442
+ /**
443
+ * Get the access mode for an MCP tool's GitHub repository access.
444
+ * Returns 'selected' if no mode is explicitly set (fail-safe default).
445
+ */
446
+ const getMcpToolAccessMode = (db) => async (toolId) => {
447
+ return (await db.select({ mode: workAppGitHubMcpToolAccessMode.mode }).from(workAppGitHubMcpToolAccessMode).where(eq(workAppGitHubMcpToolAccessMode.toolId, toolId)).limit(1))[0]?.mode ?? "selected";
448
+ };
449
+ /**
450
+ * Delete the access mode entry for an MCP tool
451
+ */
452
+ const deleteMcpToolAccessMode = (db) => async (toolId) => {
453
+ return (await db.delete(workAppGitHubMcpToolAccessMode).where(eq(workAppGitHubMcpToolAccessMode.toolId, toolId)).returning()).length > 0;
454
+ };
455
+
456
+ //#endregion
457
+ export { addRepositories, checkProjectRepositoryAccess, clearMcpToolRepositoryAccess, clearProjectRepositoryAccess, createInstallation, deleteInstallation, deleteMcpToolAccessMode, deleteProjectAccessMode, disconnectInstallation, getInstallationByGitHubId, getInstallationById, getInstallationsByTenantId, getMcpToolAccessMode, getMcpToolRepositoryAccess, getMcpToolRepositoryAccessWithDetails, getProjectAccessMode, getProjectRepositoryAccess, getProjectRepositoryAccessWithDetails, getRepositoriesByInstallationId, getRepositoriesByTenantId, getRepositoryByFullName, getRepositoryById, getRepositoryCount, getRepositoryCountsByTenantId, isGithubWorkAppTool, removeRepositories, setMcpToolAccessMode, setMcpToolRepositoryAccess, setProjectAccessMode, setProjectRepositoryAccess, syncRepositories, updateInstallationStatus, updateInstallationStatusByGitHubId, validateRepositoryOwnership };
@@ -14,8 +14,9 @@ declare const getMessageById: (db: AgentsRunDatabaseClient) => (params: {
14
14
  updatedAt: string;
15
15
  metadata: MessageMetadata | null;
16
16
  role: string;
17
- tenantId: string;
18
17
  projectId: string;
18
+ tenantId: string;
19
+ content: MessageContent;
19
20
  conversationId: string;
20
21
  fromSubAgentId: string | null;
21
22
  toSubAgentId: string | null;
@@ -23,7 +24,6 @@ declare const getMessageById: (db: AgentsRunDatabaseClient) => (params: {
23
24
  toExternalAgentId: string | null;
24
25
  fromTeamAgentId: string | null;
25
26
  toTeamAgentId: string | null;
26
- content: MessageContent;
27
27
  visibility: string;
28
28
  messageType: string;
29
29
  taskId: string | null;
@@ -145,8 +145,9 @@ declare const createMessage: (db: AgentsRunDatabaseClient) => (params: MessageIn
145
145
  updatedAt: string;
146
146
  metadata: MessageMetadata | null;
147
147
  role: string;
148
- tenantId: string;
149
148
  projectId: string;
149
+ tenantId: string;
150
+ content: MessageContent;
150
151
  conversationId: string;
151
152
  fromSubAgentId: string | null;
152
153
  toSubAgentId: string | null;
@@ -154,7 +155,6 @@ declare const createMessage: (db: AgentsRunDatabaseClient) => (params: MessageIn
154
155
  toExternalAgentId: string | null;
155
156
  fromTeamAgentId: string | null;
156
157
  toTeamAgentId: string | null;
157
- content: MessageContent;
158
158
  visibility: string;
159
159
  messageType: string;
160
160
  taskId: string | null;
@@ -198,8 +198,9 @@ declare const deleteMessage: (db: AgentsRunDatabaseClient) => (params: {
198
198
  updatedAt: string;
199
199
  metadata: MessageMetadata | null;
200
200
  role: string;
201
- tenantId: string;
202
201
  projectId: string;
202
+ tenantId: string;
203
+ content: MessageContent;
203
204
  conversationId: string;
204
205
  fromSubAgentId: string | null;
205
206
  toSubAgentId: string | null;
@@ -207,7 +208,6 @@ declare const deleteMessage: (db: AgentsRunDatabaseClient) => (params: {
207
208
  toExternalAgentId: string | null;
208
209
  fromTeamAgentId: string | null;
209
210
  toTeamAgentId: string | null;
210
- content: MessageContent;
211
211
  visibility: string;
212
212
  messageType: string;
213
213
  taskId: string | null;
@@ -1,5 +1,5 @@
1
1
  import { invitation, member, organization } from "../../auth/auth-schema.js";
2
- import { and, desc, eq } from "drizzle-orm";
2
+ import { and, desc, eq, or } from "drizzle-orm";
3
3
 
4
4
  //#region src/data-access/runtime/organizations.ts
5
5
  /**
@@ -59,7 +59,7 @@ const addUserToOrganization = (db) => async (data) => {
59
59
  });
60
60
  };
61
61
  const upsertOrganization = (db) => async (data) => {
62
- if ((await db.select().from(organization).where(eq(organization.id, data.organizationId)).limit(1)).length > 0) return { created: false };
62
+ if ((await db.select().from(organization).where(or(eq(organization.id, data.organizationId), eq(organization.slug, data.slug))).limit(1)).length > 0) return { created: false };
63
63
  await db.insert(organization).values({
64
64
  id: data.organizationId,
65
65
  name: data.name,
@@ -10,17 +10,17 @@ declare const createTask: (db: AgentsRunDatabaseClient) => (params: TaskInsert)
10
10
  createdAt: string;
11
11
  updatedAt: string;
12
12
  ref: {
13
- type: "commit" | "tag" | "branch";
13
+ type: "tag" | "commit" | "branch";
14
14
  name: string;
15
15
  hash: string;
16
16
  } | null;
17
17
  metadata: TaskMetadataConfig | null;
18
18
  status: string;
19
- tenantId: string;
20
19
  agentId: string;
21
20
  projectId: string;
22
- contextId: string;
21
+ tenantId: string;
23
22
  subAgentId: string;
23
+ contextId: string;
24
24
  }>;
25
25
  declare const getTask: (db: AgentsRunDatabaseClient) => (params: {
26
26
  id: string;
@@ -36,7 +36,7 @@ declare const updateTask: (db: AgentsRunDatabaseClient) => (params: {
36
36
  updatedAt: string;
37
37
  contextId: string;
38
38
  ref: {
39
- type: "commit" | "tag" | "branch";
39
+ type: "tag" | "commit" | "branch";
40
40
  name: string;
41
41
  hash: string;
42
42
  } | null;
@@ -2430,6 +2430,23 @@ declare const tools: drizzle_orm_pg_core208.PgTableWithColumns<{
2430
2430
  identity: undefined;
2431
2431
  generated: undefined;
2432
2432
  }, {}, {}>;
2433
+ isWorkApp: drizzle_orm_pg_core208.PgColumn<{
2434
+ name: "is_work_app";
2435
+ tableName: "tools";
2436
+ dataType: "boolean";
2437
+ columnType: "PgBoolean";
2438
+ data: boolean;
2439
+ driverParam: boolean;
2440
+ notNull: true;
2441
+ hasDefault: true;
2442
+ isPrimaryKey: false;
2443
+ isAutoincrement: false;
2444
+ hasRuntimeDefault: false;
2445
+ enumValues: undefined;
2446
+ baseColumn: never;
2447
+ identity: undefined;
2448
+ generated: undefined;
2449
+ }, {}, {}>;
2433
2450
  projectId: drizzle_orm_pg_core208.PgColumn<{
2434
2451
  name: "project_id";
2435
2452
  tableName: "tools";
@@ -367,6 +367,7 @@ const tools = pgTable("tools", {
367
367
  imageUrl: text("image_url"),
368
368
  capabilities: jsonb("capabilities").$type(),
369
369
  lastError: text("last_error"),
370
+ isWorkApp: boolean("is_work_app").notNull().default(false),
370
371
  ...timestamps
371
372
  }, (table) => [
372
373
  primaryKey({ columns: [