@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.
- package/dist/auth/auth.d.ts +4 -2
- package/dist/auth/auth.js +4 -3
- package/dist/auth/authz/client.d.ts +0 -1
- package/dist/auth/authz/client.js +0 -1
- package/dist/auth/authz/config.d.ts +1 -7
- package/dist/auth/authz/config.js +1 -9
- package/dist/auth/authz/index.d.ts +3 -3
- package/dist/auth/authz/index.js +3 -3
- package/dist/auth/authz/permissions.d.ts +16 -1
- package/dist/auth/authz/permissions.js +30 -9
- package/dist/auth/authz/sync.js +1 -11
- package/dist/auth/init.d.ts +1 -0
- package/dist/auth/init.js +115 -0
- package/dist/client-exports.d.ts +2 -6
- package/dist/client-exports.js +3 -7
- package/dist/constants/otel-attributes.d.ts +6 -0
- package/dist/constants/otel-attributes.js +9 -3
- package/dist/constants/signoz-queries.d.ts +1 -0
- package/dist/constants/signoz-queries.js +2 -1
- package/dist/data-access/index.d.ts +4 -3
- package/dist/data-access/index.js +6 -5
- package/dist/data-access/manage/agentFull.js +42 -1
- package/dist/data-access/manage/agents.d.ts +27 -10
- package/dist/data-access/manage/agents.js +33 -2
- package/dist/data-access/manage/artifactComponents.d.ts +4 -4
- package/dist/data-access/manage/artifactComponents.js +1 -1
- package/dist/data-access/manage/contextConfigs.d.ts +12 -12
- package/dist/data-access/manage/dataComponents.d.ts +4 -4
- package/dist/data-access/manage/dataComponents.js +1 -1
- package/dist/data-access/manage/functionTools.d.ts +4 -4
- package/dist/data-access/manage/subAgentExternalAgentRelations.d.ts +12 -12
- package/dist/data-access/manage/subAgentRelations.d.ts +18 -18
- package/dist/data-access/manage/subAgentTeamAgentRelations.d.ts +12 -12
- package/dist/data-access/manage/subAgents.d.ts +3 -3
- package/dist/data-access/manage/tools.d.ts +20 -15
- package/dist/data-access/manage/tools.js +20 -1
- package/dist/data-access/runtime/apiKeys.d.ts +4 -4
- package/dist/data-access/runtime/cascade-delete.d.ts +48 -1
- package/dist/data-access/runtime/cascade-delete.js +52 -2
- package/dist/data-access/runtime/conversations.d.ts +19 -19
- package/dist/data-access/runtime/github-work-app-installations.d.ts +261 -0
- package/dist/data-access/runtime/github-work-app-installations.js +457 -0
- package/dist/data-access/runtime/messages.d.ts +6 -6
- package/dist/data-access/runtime/organizations.js +2 -2
- package/dist/data-access/runtime/tasks.d.ts +4 -4
- package/dist/db/manage/manage-schema.d.ts +17 -0
- package/dist/db/manage/manage-schema.js +1 -0
- package/dist/db/runtime/runtime-schema.d.ts +1009 -165
- package/dist/db/runtime/runtime-schema.js +173 -5
- package/dist/dolt/ref-middleware.js +1 -1
- package/dist/env.d.ts +6 -4
- package/dist/env.js +11 -10
- package/dist/index.d.ts +10 -11
- package/dist/index.js +22 -23
- package/dist/types/entities.d.ts +9 -2
- package/dist/types/index.d.ts +3 -3
- package/dist/types/utility.d.ts +16 -2
- package/dist/utils/temp-jwt.d.ts +2 -1
- package/dist/utils/temp-jwt.js +3 -2
- package/dist/validation/agentFull.js +1 -1
- package/dist/validation/dolt-schemas.d.ts +1 -1
- package/dist/validation/drizzle-schema-helpers.d.ts +1 -20
- package/dist/validation/drizzle-schema-helpers.js +3 -30
- package/dist/validation/index.d.ts +2 -4
- package/dist/validation/index.js +4 -6
- package/dist/validation/schemas.d.ts +3021 -1228
- package/dist/validation/schemas.js +164 -79
- package/drizzle/manage/0006_fixed_umar.sql +1 -0
- package/drizzle/manage/meta/0006_snapshot.json +3148 -0
- package/drizzle/manage/meta/_journal.json +7 -0
- package/drizzle/runtime/0010_previous_black_knight.sql +84 -0
- package/drizzle/runtime/meta/0010_snapshot.json +3066 -0
- package/drizzle/runtime/meta/_journal.json +7 -0
- package/package.json +4 -2
- package/dist/validation/id-validation.d.ts +0 -24
- 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: "
|
|
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
|
-
|
|
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: "
|
|
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: [
|