@inkeep/agents-core 0.58.13 → 0.58.15

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 (93) hide show
  1. package/dist/auth/auth-schema.d.ts +107 -107
  2. package/dist/auth/auth-validation-schemas.d.ts +152 -152
  3. package/dist/auth/auth.d.ts +9 -9
  4. package/dist/auth/auth.js +17 -45
  5. package/dist/auth/permissions.d.ts +9 -9
  6. package/dist/data-access/index.d.ts +6 -1
  7. package/dist/data-access/index.js +6 -1
  8. package/dist/data-access/manage/agentFull.js +28 -12
  9. package/dist/data-access/manage/agents.d.ts +40 -39
  10. package/dist/data-access/manage/agents.js +33 -33
  11. package/dist/data-access/manage/artifactComponents.d.ts +8 -8
  12. package/dist/data-access/manage/artifactComponents.js +14 -13
  13. package/dist/data-access/manage/audit-queries.d.ts +29 -0
  14. package/dist/data-access/manage/audit-queries.js +30 -0
  15. package/dist/data-access/manage/contextConfigs.d.ts +4 -4
  16. package/dist/data-access/manage/contextConfigs.js +7 -6
  17. package/dist/data-access/manage/credentialReferences.js +12 -11
  18. package/dist/data-access/manage/dataComponents.d.ts +4 -4
  19. package/dist/data-access/manage/dataComponents.js +13 -11
  20. package/dist/data-access/manage/evalConfig.js +42 -41
  21. package/dist/data-access/manage/externalAgents.js +8 -7
  22. package/dist/data-access/manage/functionTools.d.ts +11 -15
  23. package/dist/data-access/manage/functionTools.js +27 -65
  24. package/dist/data-access/manage/functions.js +7 -10
  25. package/dist/data-access/manage/projects.js +37 -36
  26. package/dist/data-access/manage/scheduledTriggers.js +10 -6
  27. package/dist/data-access/manage/scheduledWorkflows.js +3 -2
  28. package/dist/data-access/manage/scope-helpers.d.ts +2 -1
  29. package/dist/data-access/manage/scope-helpers.js +2 -1
  30. package/dist/data-access/manage/skills.d.ts +11 -11
  31. package/dist/data-access/manage/skills.js +14 -9
  32. package/dist/data-access/manage/subAgentExternalAgentRelations.d.ts +12 -12
  33. package/dist/data-access/manage/subAgentRelations.d.ts +18 -18
  34. package/dist/data-access/manage/subAgentRelations.js +28 -26
  35. package/dist/data-access/manage/subAgentTeamAgentRelations.d.ts +12 -12
  36. package/dist/data-access/manage/subAgentTeamAgentRelations.js +16 -16
  37. package/dist/data-access/manage/subAgents.d.ts +21 -21
  38. package/dist/data-access/manage/subAgents.js +8 -7
  39. package/dist/data-access/manage/tools.d.ts +15 -15
  40. package/dist/data-access/manage/tools.js +8 -6
  41. package/dist/data-access/manage/triggers.d.ts +2 -2
  42. package/dist/data-access/manage/triggers.js +12 -8
  43. package/dist/data-access/runtime/apiKeys.d.ts +16 -16
  44. package/dist/data-access/runtime/apiKeys.js +16 -12
  45. package/dist/data-access/runtime/apps.d.ts +6 -6
  46. package/dist/data-access/runtime/apps.js +8 -7
  47. package/dist/data-access/runtime/audit-queries.d.ts +41 -0
  48. package/dist/data-access/runtime/audit-queries.js +37 -0
  49. package/dist/data-access/runtime/auth.d.ts +18 -0
  50. package/dist/data-access/runtime/auth.js +35 -0
  51. package/dist/data-access/runtime/cascade-delete.js +29 -24
  52. package/dist/data-access/runtime/contextCache.d.ts +1 -0
  53. package/dist/data-access/runtime/contextCache.js +9 -8
  54. package/dist/data-access/runtime/conversations.d.ts +16 -16
  55. package/dist/data-access/runtime/conversations.js +8 -12
  56. package/dist/data-access/runtime/evalRuns.js +23 -22
  57. package/dist/data-access/runtime/github-work-app-installations.js +32 -21
  58. package/dist/data-access/runtime/ledgerArtifacts.js +9 -24
  59. package/dist/data-access/runtime/messages.d.ts +21 -21
  60. package/dist/data-access/runtime/messages.js +9 -8
  61. package/dist/data-access/runtime/projects.js +6 -5
  62. package/dist/data-access/runtime/scheduledTriggerInvocations.d.ts +3 -3
  63. package/dist/data-access/runtime/scheduledTriggerInvocations.js +16 -26
  64. package/dist/data-access/runtime/slack-work-app-mcp.js +6 -5
  65. package/dist/data-access/runtime/tasks.d.ts +9 -5
  66. package/dist/data-access/runtime/tasks.js +4 -5
  67. package/dist/data-access/runtime/triggerInvocations.js +4 -8
  68. package/dist/data-access/runtime/workAppSlack.js +21 -14
  69. package/dist/data-reconciliation/audit.d.ts +6 -0
  70. package/dist/data-reconciliation/audit.js +37 -0
  71. package/dist/data-reconciliation/index.d.ts +4 -0
  72. package/dist/data-reconciliation/index.js +5 -0
  73. package/dist/data-reconciliation/reconcile.d.ts +6 -0
  74. package/dist/data-reconciliation/reconcile.js +58 -0
  75. package/dist/data-reconciliation/types.d.ts +116 -0
  76. package/dist/data-reconciliation/types.js +7 -0
  77. package/dist/db/manage/manage-schema.d.ts +453 -453
  78. package/dist/db/runtime/runtime-schema.d.ts +326 -326
  79. package/dist/index.d.ts +12 -2
  80. package/dist/index.js +12 -1
  81. package/dist/retry/index.d.ts +3 -0
  82. package/dist/retry/index.js +4 -0
  83. package/dist/retry/retryable-errors.d.ts +10 -0
  84. package/dist/retry/retryable-errors.js +72 -0
  85. package/dist/retry/withRetry.d.ts +15 -0
  86. package/dist/retry/withRetry.js +37 -0
  87. package/dist/setup/setup.d.ts +1 -0
  88. package/dist/setup/setup.js +25 -8
  89. package/dist/utils/error.d.ts +51 -51
  90. package/dist/validation/drizzle-schema-helpers.d.ts +3 -3
  91. package/dist/validation/schemas.d.ts +1987 -1990
  92. package/dist/validation/schemas.js +5 -1
  93. package/package.json +1 -1
@@ -16,21 +16,21 @@ declare const listConversations: (db: AgentsRunDatabaseClient) => (params: {
16
16
  total: number;
17
17
  }>;
18
18
  declare const createConversation: (db: AgentsRunDatabaseClient) => (params: ConversationInsert) => Promise<{
19
- id: string;
20
19
  tenantId: string;
21
20
  projectId: string;
22
21
  agentId: string | null;
23
- title: string | null;
22
+ id: string;
23
+ metadata: ConversationMetadata | null;
24
24
  createdAt: string;
25
25
  updatedAt: string;
26
- metadata: ConversationMetadata | null;
27
26
  userId: string | null;
27
+ activeSubAgentId: string;
28
28
  ref: {
29
29
  type: "commit" | "tag" | "branch";
30
30
  name: string;
31
31
  hash: string;
32
32
  } | null;
33
- activeSubAgentId: string;
33
+ title: string | null;
34
34
  lastContextResolution: string | null;
35
35
  }>;
36
36
  declare const updateConversation: (db: AgentsRunDatabaseClient) => (params: {
@@ -85,21 +85,21 @@ declare const getConversation: (db: AgentsRunDatabaseClient) => (params: {
85
85
  scopes: ProjectScopeConfig;
86
86
  conversationId: string;
87
87
  }) => Promise<{
88
- id: string;
89
88
  tenantId: string;
90
89
  projectId: string;
91
90
  agentId: string | null;
92
- title: string | null;
91
+ id: string;
92
+ metadata: ConversationMetadata | null;
93
93
  createdAt: string;
94
94
  updatedAt: string;
95
- metadata: ConversationMetadata | null;
96
95
  userId: string | null;
96
+ activeSubAgentId: string;
97
97
  ref: {
98
98
  type: "commit" | "tag" | "branch";
99
99
  name: string;
100
100
  hash: string;
101
101
  } | null;
102
- activeSubAgentId: string;
102
+ title: string | null;
103
103
  lastContextResolution: string | null;
104
104
  } | undefined>;
105
105
  declare const createOrGetConversation: (db: AgentsRunDatabaseClient) => (input: ConversationInsert) => Promise<{
@@ -121,21 +121,21 @@ declare const createOrGetConversation: (db: AgentsRunDatabaseClient) => (input:
121
121
  metadata?: ConversationMetadata | null | undefined;
122
122
  contextConfigId?: string | undefined;
123
123
  } | {
124
- id: string;
125
124
  tenantId: string;
126
125
  projectId: string;
127
126
  agentId: string | null;
128
- title: string | null;
127
+ id: string;
128
+ metadata: ConversationMetadata | null;
129
129
  createdAt: string;
130
130
  updatedAt: string;
131
- metadata: ConversationMetadata | null;
132
131
  userId: string | null;
132
+ activeSubAgentId: string;
133
133
  ref: {
134
134
  type: "commit" | "tag" | "branch";
135
135
  name: string;
136
136
  hash: string;
137
137
  } | null;
138
- activeSubAgentId: string;
138
+ title: string | null;
139
139
  lastContextResolution: string | null;
140
140
  }>;
141
141
  /**
@@ -153,21 +153,21 @@ declare const getActiveAgentForConversation: (db: AgentsRunDatabaseClient) => (p
153
153
  scopes: ProjectScopeConfig;
154
154
  conversationId: string;
155
155
  }) => Promise<{
156
- id: string;
157
156
  tenantId: string;
158
157
  projectId: string;
159
158
  agentId: string | null;
160
- title: string | null;
159
+ id: string;
160
+ metadata: ConversationMetadata | null;
161
161
  createdAt: string;
162
162
  updatedAt: string;
163
- metadata: ConversationMetadata | null;
164
163
  userId: string | null;
164
+ activeSubAgentId: string;
165
165
  ref: {
166
166
  type: "commit" | "tag" | "branch";
167
167
  name: string;
168
168
  hash: string;
169
169
  } | null;
170
- activeSubAgentId: string;
170
+ title: string | null;
171
171
  lastContextResolution: string | null;
172
172
  } | undefined>;
173
173
  /**
@@ -1,5 +1,6 @@
1
1
  import { conversations, messages } from "../../db/runtime/runtime-schema.js";
2
2
  import { getConversationId } from "../../utils/conversations.js";
3
+ import { projectScopedWhere } from "../manage/scope-helpers.js";
3
4
  import { and, count, desc, eq, inArray } from "drizzle-orm";
4
5
 
5
6
  //#region src/data-access/runtime/conversations.ts
@@ -8,7 +9,7 @@ const listConversations = (db) => async (params) => {
8
9
  const page = pagination?.page || 1;
9
10
  const limit = Math.min(pagination?.limit || 20, 200);
10
11
  const offset = (page - 1) * limit;
11
- const whereConditions = [eq(conversations.tenantId, params.scopes.tenantId), eq(conversations.projectId, params.scopes.projectId)];
12
+ const whereConditions = [projectScopedWhere(conversations, params.scopes)];
12
13
  if (userId) whereConditions.push(eq(conversations.userId, userId));
13
14
  const conversationList = await db.select().from(conversations).where(and(...whereConditions)).orderBy(desc(conversations.updatedAt)).limit(limit).offset(offset);
14
15
  const total = (await db.select({ count: count() }).from(conversations).where(and(...whereConditions)))[0]?.count || 0;
@@ -31,13 +32,13 @@ const updateConversation = (db) => async (params) => {
31
32
  const [updated] = await db.update(conversations).set({
32
33
  ...params.data,
33
34
  updatedAt: now
34
- }).where(and(eq(conversations.tenantId, params.scopes.tenantId), eq(conversations.projectId, params.scopes.projectId), eq(conversations.id, params.conversationId))).returning();
35
+ }).where(and(projectScopedWhere(conversations, params.scopes), eq(conversations.id, params.conversationId))).returning();
35
36
  return updated;
36
37
  };
37
38
  const deleteConversation = (db) => async (params) => {
38
39
  try {
39
- await db.delete(messages).where(and(eq(messages.tenantId, params.scopes.tenantId), eq(messages.projectId, params.scopes.projectId), eq(messages.conversationId, params.conversationId)));
40
- await db.delete(conversations).where(and(eq(conversations.tenantId, params.scopes.tenantId), eq(conversations.projectId, params.scopes.projectId), eq(conversations.id, params.conversationId)));
40
+ await db.delete(messages).where(and(projectScopedWhere(messages, params.scopes), eq(messages.conversationId, params.conversationId)));
41
+ await db.delete(conversations).where(and(projectScopedWhere(conversations, params.scopes), eq(conversations.id, params.conversationId)));
41
42
  return true;
42
43
  } catch (error) {
43
44
  console.error("Error deleting conversation:", error);
@@ -52,7 +53,7 @@ const updateConversationActiveSubAgent = (db) => async (params) => {
52
53
  });
53
54
  };
54
55
  const getConversation = (db) => async (params) => {
55
- return await db.query.conversations.findFirst({ where: and(eq(conversations.tenantId, params.scopes.tenantId), eq(conversations.projectId, params.scopes.projectId), eq(conversations.id, params.conversationId)) });
56
+ return await db.query.conversations.findFirst({ where: and(projectScopedWhere(conversations, params.scopes), eq(conversations.id, params.conversationId)) });
56
57
  };
57
58
  const createOrGetConversation = (db) => async (input) => {
58
59
  const conversationId = input.id || getConversationId();
@@ -132,13 +133,8 @@ function applyContextWindowManagement(messageHistory, maxTokens) {
132
133
  */
133
134
  const getConversationHistory = (db) => async (params) => {
134
135
  const { scopes, conversationId, options = {} } = params;
135
- const { tenantId, projectId } = scopes;
136
136
  const { limit = options.limit ?? 50, includeInternal = options.includeInternal ?? false, maxOutputTokens, messageTypes } = options;
137
- const whereConditions = [
138
- eq(messages.tenantId, tenantId),
139
- eq(messages.projectId, projectId),
140
- eq(messages.conversationId, conversationId)
141
- ];
137
+ const whereConditions = [projectScopedWhere(messages, scopes), eq(messages.conversationId, conversationId)];
142
138
  if (!includeInternal) whereConditions.push(eq(messages.visibility, "user-facing"));
143
139
  if (messageTypes && messageTypes.length > 0) whereConditions.push(inArray(messages.messageType, messageTypes));
144
140
  const chronologicalHistory = (await db.select().from(messages).where(and(...whereConditions)).orderBy(desc(messages.createdAt)).limit(limit)).reverse();
@@ -149,7 +145,7 @@ const getConversationHistory = (db) => async (params) => {
149
145
  * Get active agent for a conversation
150
146
  */
151
147
  const getActiveAgentForConversation = (db) => async (params) => {
152
- return await db.query.conversations.findFirst({ where: and(eq(conversations.tenantId, params.scopes.tenantId), eq(conversations.projectId, params.scopes.projectId), eq(conversations.id, params.conversationId)) });
148
+ return await db.query.conversations.findFirst({ where: and(projectScopedWhere(conversations, params.scopes), eq(conversations.id, params.conversationId)) });
153
149
  };
154
150
  /**
155
151
  * Set active agent for a conversation (upsert operation)
@@ -1,15 +1,16 @@
1
1
  import { conversations, datasetRun, datasetRunConversationRelations, evaluationResult, evaluationRun } from "../../db/runtime/runtime-schema.js";
2
+ import { projectScopedWhere } from "../manage/scope-helpers.js";
2
3
  import { and, desc, eq, gte, inArray, lte } from "drizzle-orm";
3
4
 
4
5
  //#region src/data-access/runtime/evalRuns.ts
5
6
  const getDatasetRunById = (db) => async (params) => {
6
- return (await db.select().from(datasetRun).where(and(eq(datasetRun.tenantId, params.scopes.tenantId), eq(datasetRun.projectId, params.scopes.projectId), eq(datasetRun.id, params.scopes.datasetRunId))).limit(1))[0] ?? null;
7
+ return (await db.select().from(datasetRun).where(and(projectScopedWhere(datasetRun, params.scopes), eq(datasetRun.id, params.scopes.datasetRunId))).limit(1))[0] ?? null;
7
8
  };
8
9
  const listDatasetRuns = (db) => async (params) => {
9
- return await db.select().from(datasetRun).where(and(eq(datasetRun.tenantId, params.scopes.tenantId), eq(datasetRun.projectId, params.scopes.projectId))).orderBy(desc(datasetRun.createdAt));
10
+ return await db.select().from(datasetRun).where(projectScopedWhere(datasetRun, params.scopes)).orderBy(desc(datasetRun.createdAt));
10
11
  };
11
12
  const listDatasetRunsByConfig = (db) => async (params) => {
12
- return await db.select().from(datasetRun).where(and(eq(datasetRun.tenantId, params.scopes.tenantId), eq(datasetRun.projectId, params.scopes.projectId), eq(datasetRun.datasetRunConfigId, params.scopes.datasetRunConfigId))).orderBy(desc(datasetRun.createdAt));
13
+ return await db.select().from(datasetRun).where(and(projectScopedWhere(datasetRun, params.scopes), eq(datasetRun.datasetRunConfigId, params.scopes.datasetRunConfigId))).orderBy(desc(datasetRun.createdAt));
13
14
  };
14
15
  const createDatasetRun = (db) => async (data) => {
15
16
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -21,10 +22,10 @@ const createDatasetRun = (db) => async (data) => {
21
22
  return created;
22
23
  };
23
24
  const deleteDatasetRun = (db) => async (params) => {
24
- return (await db.delete(datasetRun).where(and(eq(datasetRun.tenantId, params.scopes.tenantId), eq(datasetRun.projectId, params.scopes.projectId), eq(datasetRun.id, params.scopes.datasetRunId))).returning()).length > 0;
25
+ return (await db.delete(datasetRun).where(and(projectScopedWhere(datasetRun, params.scopes), eq(datasetRun.id, params.scopes.datasetRunId))).returning()).length > 0;
25
26
  };
26
27
  const getDatasetRunConversationRelations = (db) => async (params) => {
27
- return await db.select().from(datasetRunConversationRelations).where(and(eq(datasetRunConversationRelations.tenantId, params.scopes.tenantId), eq(datasetRunConversationRelations.projectId, params.scopes.projectId), eq(datasetRunConversationRelations.datasetRunId, params.scopes.datasetRunId)));
28
+ return await db.select().from(datasetRunConversationRelations).where(and(projectScopedWhere(datasetRunConversationRelations, params.scopes), eq(datasetRunConversationRelations.datasetRunId, params.scopes.datasetRunId)));
28
29
  };
29
30
  const createDatasetRunConversationRelation = (db) => async (data) => {
30
31
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -45,25 +46,25 @@ const createDatasetRunConversationRelations = (db) => async (data) => {
45
46
  return await db.insert(datasetRunConversationRelations).values(values).returning();
46
47
  };
47
48
  const deleteDatasetRunConversationRelation = (db) => async (params) => {
48
- return (await db.delete(datasetRunConversationRelations).where(and(eq(datasetRunConversationRelations.tenantId, params.scopes.tenantId), eq(datasetRunConversationRelations.projectId, params.scopes.projectId), eq(datasetRunConversationRelations.datasetRunId, params.scopes.datasetRunId), eq(datasetRunConversationRelations.conversationId, params.scopes.conversationId))).returning()).length > 0;
49
+ return (await db.delete(datasetRunConversationRelations).where(and(projectScopedWhere(datasetRunConversationRelations, params.scopes), eq(datasetRunConversationRelations.datasetRunId, params.scopes.datasetRunId), eq(datasetRunConversationRelations.conversationId, params.scopes.conversationId))).returning()).length > 0;
49
50
  };
50
51
  const deleteDatasetRunConversationRelationsByRun = (db) => async (params) => {
51
- return (await db.delete(datasetRunConversationRelations).where(and(eq(datasetRunConversationRelations.tenantId, params.scopes.tenantId), eq(datasetRunConversationRelations.projectId, params.scopes.projectId), eq(datasetRunConversationRelations.datasetRunId, params.scopes.datasetRunId))).returning()).length;
52
+ return (await db.delete(datasetRunConversationRelations).where(and(projectScopedWhere(datasetRunConversationRelations, params.scopes), eq(datasetRunConversationRelations.datasetRunId, params.scopes.datasetRunId))).returning()).length;
52
53
  };
53
54
  const getDatasetRunConversationRelationByConversation = (db) => async (params) => {
54
- return (await db.select().from(datasetRunConversationRelations).where(and(eq(datasetRunConversationRelations.tenantId, params.scopes.tenantId), eq(datasetRunConversationRelations.projectId, params.scopes.projectId), eq(datasetRunConversationRelations.conversationId, params.scopes.conversationId))).limit(1))[0] || null;
55
+ return (await db.select().from(datasetRunConversationRelations).where(and(projectScopedWhere(datasetRunConversationRelations, params.scopes), eq(datasetRunConversationRelations.conversationId, params.scopes.conversationId))).limit(1))[0] || null;
55
56
  };
56
57
  const getEvaluationRunById = (db) => async (params) => {
57
- return (await db.select().from(evaluationRun).where(and(eq(evaluationRun.tenantId, params.scopes.tenantId), eq(evaluationRun.projectId, params.scopes.projectId), eq(evaluationRun.id, params.scopes.evaluationRunId))).limit(1))[0] ?? null;
58
+ return (await db.select().from(evaluationRun).where(and(projectScopedWhere(evaluationRun, params.scopes), eq(evaluationRun.id, params.scopes.evaluationRunId))).limit(1))[0] ?? null;
58
59
  };
59
60
  const listEvaluationRuns = (db) => async (params) => {
60
- return await db.select().from(evaluationRun).where(and(eq(evaluationRun.tenantId, params.scopes.tenantId), eq(evaluationRun.projectId, params.scopes.projectId)));
61
+ return await db.select().from(evaluationRun).where(projectScopedWhere(evaluationRun, params.scopes));
61
62
  };
62
63
  const listEvaluationRunsByJobConfigId = (db) => async (params) => {
63
- return await db.select().from(evaluationRun).where(and(eq(evaluationRun.tenantId, params.scopes.tenantId), eq(evaluationRun.projectId, params.scopes.projectId), eq(evaluationRun.evaluationJobConfigId, params.evaluationJobConfigId)));
64
+ return await db.select().from(evaluationRun).where(and(projectScopedWhere(evaluationRun, params.scopes), eq(evaluationRun.evaluationJobConfigId, params.evaluationJobConfigId)));
64
65
  };
65
66
  const getEvaluationRunByJobConfigId = (db) => async (params) => {
66
- return (await db.select().from(evaluationRun).where(and(eq(evaluationRun.tenantId, params.scopes.tenantId), eq(evaluationRun.projectId, params.scopes.projectId), eq(evaluationRun.evaluationJobConfigId, params.evaluationJobConfigId))).limit(1))[0] ?? null;
67
+ return (await db.select().from(evaluationRun).where(and(projectScopedWhere(evaluationRun, params.scopes), eq(evaluationRun.evaluationJobConfigId, params.evaluationJobConfigId))).limit(1))[0] ?? null;
67
68
  };
68
69
  const createEvaluationRun = (db) => async (data) => {
69
70
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -77,23 +78,23 @@ const createEvaluationRun = (db) => async (data) => {
77
78
  const updateEvaluationRun = (db) => async (params) => {
78
79
  const updateData = { updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
79
80
  for (const [key, value] of Object.entries(params.data)) if (value !== void 0) updateData[key] = value;
80
- const [updated] = await db.update(evaluationRun).set(updateData).where(and(eq(evaluationRun.tenantId, params.scopes.tenantId), eq(evaluationRun.projectId, params.scopes.projectId), eq(evaluationRun.id, params.scopes.evaluationRunId))).returning();
81
+ const [updated] = await db.update(evaluationRun).set(updateData).where(and(projectScopedWhere(evaluationRun, params.scopes), eq(evaluationRun.id, params.scopes.evaluationRunId))).returning();
81
82
  return updated ?? null;
82
83
  };
83
84
  const deleteEvaluationRun = (db) => async (params) => {
84
- return (await db.delete(evaluationRun).where(and(eq(evaluationRun.tenantId, params.scopes.tenantId), eq(evaluationRun.projectId, params.scopes.projectId), eq(evaluationRun.id, params.scopes.evaluationRunId))).returning()).length > 0;
85
+ return (await db.delete(evaluationRun).where(and(projectScopedWhere(evaluationRun, params.scopes), eq(evaluationRun.id, params.scopes.evaluationRunId))).returning()).length > 0;
85
86
  };
86
87
  const getEvaluationResultById = (db) => async (params) => {
87
- return await db.query.evaluationResult.findFirst({ where: and(eq(evaluationResult.tenantId, params.scopes.tenantId), eq(evaluationResult.projectId, params.scopes.projectId), eq(evaluationResult.id, params.scopes.evaluationResultId)) }) ?? null;
88
+ return await db.query.evaluationResult.findFirst({ where: and(projectScopedWhere(evaluationResult, params.scopes), eq(evaluationResult.id, params.scopes.evaluationResultId)) }) ?? null;
88
89
  };
89
90
  const listEvaluationResults = (db) => async (params) => {
90
- return await db.query.evaluationResult.findMany({ where: and(eq(evaluationResult.tenantId, params.scopes.tenantId), eq(evaluationResult.projectId, params.scopes.projectId)) });
91
+ return await db.query.evaluationResult.findMany({ where: projectScopedWhere(evaluationResult, params.scopes) });
91
92
  };
92
93
  const listEvaluationResultsByRun = (db) => async (params) => {
93
- return await db.query.evaluationResult.findMany({ where: and(eq(evaluationResult.tenantId, params.scopes.tenantId), eq(evaluationResult.projectId, params.scopes.projectId), eq(evaluationResult.evaluationRunId, params.scopes.evaluationRunId)) });
94
+ return await db.query.evaluationResult.findMany({ where: and(projectScopedWhere(evaluationResult, params.scopes), eq(evaluationResult.evaluationRunId, params.scopes.evaluationRunId)) });
94
95
  };
95
96
  const listEvaluationResultsByConversation = (db) => async (params) => {
96
- return await db.query.evaluationResult.findMany({ where: and(eq(evaluationResult.tenantId, params.scopes.tenantId), eq(evaluationResult.projectId, params.scopes.projectId), eq(evaluationResult.conversationId, params.scopes.conversationId)) });
97
+ return await db.query.evaluationResult.findMany({ where: and(projectScopedWhere(evaluationResult, params.scopes), eq(evaluationResult.conversationId, params.scopes.conversationId)) });
97
98
  };
98
99
  const createEvaluationResult = (db) => async (data) => {
99
100
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -116,14 +117,14 @@ const createEvaluationResults = (db) => async (data) => {
116
117
  const updateEvaluationResult = (db) => async (params) => {
117
118
  const updateData = { updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
118
119
  for (const [key, value] of Object.entries(params.data)) if (value !== void 0) updateData[key] = value;
119
- const [updated] = await db.update(evaluationResult).set(updateData).where(and(eq(evaluationResult.tenantId, params.scopes.tenantId), eq(evaluationResult.projectId, params.scopes.projectId), eq(evaluationResult.id, params.scopes.evaluationResultId))).returning();
120
+ const [updated] = await db.update(evaluationResult).set(updateData).where(and(projectScopedWhere(evaluationResult, params.scopes), eq(evaluationResult.id, params.scopes.evaluationResultId))).returning();
120
121
  return updated ?? null;
121
122
  };
122
123
  const deleteEvaluationResult = (db) => async (params) => {
123
- return (await db.delete(evaluationResult).where(and(eq(evaluationResult.tenantId, params.scopes.tenantId), eq(evaluationResult.projectId, params.scopes.projectId), eq(evaluationResult.id, params.scopes.evaluationResultId))).returning()).length > 0;
124
+ return (await db.delete(evaluationResult).where(and(projectScopedWhere(evaluationResult, params.scopes), eq(evaluationResult.id, params.scopes.evaluationResultId))).returning()).length > 0;
124
125
  };
125
126
  const deleteEvaluationResultsByRun = (db) => async (params) => {
126
- return (await db.delete(evaluationResult).where(and(eq(evaluationResult.tenantId, params.scopes.tenantId), eq(evaluationResult.projectId, params.scopes.projectId), eq(evaluationResult.evaluationRunId, params.scopes.evaluationRunId))).returning()).length;
127
+ return (await db.delete(evaluationResult).where(and(projectScopedWhere(evaluationResult, params.scopes), eq(evaluationResult.evaluationRunId, params.scopes.evaluationRunId))).returning()).length;
127
128
  };
128
129
  /**
129
130
  * Helper to extract plain filter criteria from a Filter wrapper.
@@ -141,7 +142,7 @@ const filterConversationsForJob = (db) => async (params) => {
141
142
  const { scopes, jobFilters: rawJobFilters } = params;
142
143
  const jobFilters = extractPlainFilterCriteria(rawJobFilters);
143
144
  const { tenantId, projectId } = scopes;
144
- const whereConditions = [eq(conversations.tenantId, tenantId), eq(conversations.projectId, projectId)];
145
+ const whereConditions = [projectScopedWhere(conversations, scopes)];
145
146
  if (jobFilters?.conversationIds && Array.isArray(jobFilters.conversationIds) && jobFilters.conversationIds.length > 0) whereConditions.push(inArray(conversations.id, jobFilters.conversationIds));
146
147
  if (jobFilters?.dateRange) {
147
148
  const { startDate, endDate } = jobFilters.dateRange;
@@ -1,5 +1,6 @@
1
1
  import { workAppGitHubInstallations, workAppGitHubMcpToolAccessMode, workAppGitHubMcpToolRepositoryAccess, workAppGitHubProjectAccessMode, workAppGitHubProjectRepositoryAccess, workAppGitHubRepositories } from "../../db/runtime/runtime-schema.js";
2
2
  import { generateId } from "../../utils/conversations.js";
3
+ import { projectScopedWhere, tenantScopedWhere, toolScopedWhere } from "../manage/scope-helpers.js";
3
4
  import { and, count, desc, eq, inArray, ne } from "drizzle-orm";
4
5
 
5
6
  //#region src/data-access/runtime/github-work-app-installations.ts
@@ -25,13 +26,13 @@ const getInstallationByGitHubId = (db) => async (gitHubInstallationId) => {
25
26
  * Get installation by internal ID with tenant validation
26
27
  */
27
28
  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
+ return await db.query.workAppGitHubInstallations.findFirst({ where: and(tenantScopedWhere(workAppGitHubInstallations, { tenantId: params.tenantId }), eq(workAppGitHubInstallations.id, params.id)) }) ?? null;
29
30
  };
30
31
  /**
31
32
  * Get all installations for a tenant
32
33
  */
33
34
  const getInstallationsByTenantId = (db) => async (params) => {
34
- const conditions = [eq(workAppGitHubInstallations.tenantId, params.tenantId)];
35
+ const conditions = [tenantScopedWhere(workAppGitHubInstallations, { tenantId: params.tenantId })];
35
36
  if (!params.includeDisconnected) conditions.push(ne(workAppGitHubInstallations.status, "disconnected"));
36
37
  return await db.select().from(workAppGitHubInstallations).where(and(...conditions)).orderBy(desc(workAppGitHubInstallations.createdAt));
37
38
  };
@@ -43,7 +44,7 @@ const updateInstallationStatus = (db) => async (params) => {
43
44
  const [updated] = await db.update(workAppGitHubInstallations).set({
44
45
  status: params.status,
45
46
  updatedAt: now
46
- }).where(and(eq(workAppGitHubInstallations.tenantId, params.tenantId), eq(workAppGitHubInstallations.id, params.id))).returning();
47
+ }).where(and(tenantScopedWhere(workAppGitHubInstallations, { tenantId: params.tenantId }), eq(workAppGitHubInstallations.id, params.id))).returning();
47
48
  return updated ?? null;
48
49
  };
49
50
  /**
@@ -68,7 +69,7 @@ const disconnectInstallation = (db) => async (params) => {
68
69
  const [updated] = await db.update(workAppGitHubInstallations).set({
69
70
  status: "disconnected",
70
71
  updatedAt: now
71
- }).where(and(eq(workAppGitHubInstallations.tenantId, params.tenantId), eq(workAppGitHubInstallations.id, params.id))).returning();
72
+ }).where(and(tenantScopedWhere(workAppGitHubInstallations, { tenantId: params.tenantId }), eq(workAppGitHubInstallations.id, params.id))).returning();
72
73
  return !!updated;
73
74
  };
74
75
  /**
@@ -76,7 +77,7 @@ const disconnectInstallation = (db) => async (params) => {
76
77
  * Returns the deleted installation if found, null otherwise
77
78
  */
78
79
  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
+ const [deleted] = await db.delete(workAppGitHubInstallations).where(and(tenantScopedWhere(workAppGitHubInstallations, { tenantId: params.tenantId }), eq(workAppGitHubInstallations.id, params.id))).returning();
80
81
  return deleted ?? null;
81
82
  };
82
83
  /**
@@ -188,7 +189,7 @@ const getRepositoriesByTenantId = (db) => async (tenantId) => {
188
189
  createdAt: workAppGitHubRepositories.createdAt,
189
190
  updatedAt: workAppGitHubRepositories.updatedAt,
190
191
  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
+ }).from(workAppGitHubRepositories).innerJoin(workAppGitHubInstallations, eq(workAppGitHubRepositories.installationDbId, workAppGitHubInstallations.id)).where(and(tenantScopedWhere(workAppGitHubInstallations, { tenantId }), ne(workAppGitHubInstallations.status, "disconnected"))).orderBy(workAppGitHubRepositories.repositoryFullName);
192
193
  };
193
194
  /**
194
195
  * Set project repository access (full replacement)
@@ -211,7 +212,10 @@ const setProjectRepositoryAccess = (db) => async (params) => {
211
212
  createdAt: now,
212
213
  updatedAt: now
213
214
  })));
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
+ const toolsWithSelectedMode = await db.select({ toolId: workAppGitHubMcpToolAccessMode.toolId }).from(workAppGitHubMcpToolAccessMode).where(and(projectScopedWhere(workAppGitHubMcpToolAccessMode, {
216
+ tenantId: params.tenantId,
217
+ projectId: params.projectId
218
+ }), eq(workAppGitHubMcpToolAccessMode.mode, "selected")));
215
219
  for (const { toolId } of toolsWithSelectedMode) {
216
220
  const reposToRemove = (await db.select({
217
221
  id: workAppGitHubMcpToolRepositoryAccess.id,
@@ -261,8 +265,11 @@ const getProjectRepositoryAccessWithDetails = (db) => async (params) => {
261
265
  * - Project mode is 'selected' and repository is explicitly in the project's access list
262
266
  */
263
267
  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 {
268
+ if (((await db.select({ mode: workAppGitHubProjectAccessMode.mode }).from(workAppGitHubProjectAccessMode).where(projectScopedWhere(workAppGitHubProjectAccessMode, {
269
+ tenantId: params.tenantId,
270
+ projectId: params.projectId
271
+ })).limit(1))[0]?.mode ?? "selected") === "all") {
272
+ if ((await db.select({ id: workAppGitHubRepositories.id }).from(workAppGitHubRepositories).innerJoin(workAppGitHubInstallations, eq(workAppGitHubRepositories.installationDbId, workAppGitHubInstallations.id)).where(and(eq(workAppGitHubRepositories.repositoryFullName, params.repositoryFullName), tenantScopedWhere(workAppGitHubInstallations, { tenantId: params.tenantId }), ne(workAppGitHubInstallations.status, "disconnected"))).limit(1)).length === 0) return {
266
273
  hasAccess: false,
267
274
  reason: "Repository not found in tenant installations"
268
275
  };
@@ -271,7 +278,7 @@ const checkProjectRepositoryAccess = (db) => async (params) => {
271
278
  reason: "Project has access to all repositories"
272
279
  };
273
280
  }
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 {
281
+ 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), tenantScopedWhere(workAppGitHubInstallations, { tenantId: params.tenantId }), ne(workAppGitHubInstallations.status, "disconnected"))).limit(1)).length === 0) return {
275
282
  hasAccess: false,
276
283
  reason: "Repository not in project access list"
277
284
  };
@@ -292,7 +299,7 @@ const clearProjectRepositoryAccess = (db) => async (projectId) => {
292
299
  */
293
300
  const validateRepositoryOwnership = (db) => async (params) => {
294
301
  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)));
302
+ const validRepos = await db.select({ id: workAppGitHubRepositories.id }).from(workAppGitHubRepositories).innerJoin(workAppGitHubInstallations, eq(workAppGitHubRepositories.installationDbId, workAppGitHubInstallations.id)).where(and(tenantScopedWhere(workAppGitHubInstallations, { tenantId: params.tenantId }), ne(workAppGitHubInstallations.status, "disconnected"), inArray(workAppGitHubRepositories.id, params.repositoryIds)));
296
303
  const validRepoIds = new Set(validRepos.map((r) => r.id));
297
304
  return params.repositoryIds.filter((id) => !validRepoIds.has(id));
298
305
  };
@@ -307,7 +314,7 @@ const getRepositoryCount = (db) => async (installationId) => {
307
314
  * Get repository counts for all installations belonging to a tenant
308
315
  */
309
316
  const getRepositoryCountsByTenantId = (db) => async (params) => {
310
- const conditions = [eq(workAppGitHubInstallations.tenantId, params.tenantId)];
317
+ const conditions = [tenantScopedWhere(workAppGitHubInstallations, { tenantId: params.tenantId })];
311
318
  if (!params.includeDisconnected) conditions.push(ne(workAppGitHubInstallations.status, "disconnected"));
312
319
  const results = await db.select({
313
320
  installationId: workAppGitHubInstallations.id,
@@ -327,7 +334,11 @@ const getRepositoryCountsByTenantId = (db) => async (params) => {
327
334
  */
328
335
  const setMcpToolRepositoryAccess = (db) => async (params) => {
329
336
  const now = (/* @__PURE__ */ new Date()).toISOString();
330
- await db.delete(workAppGitHubMcpToolRepositoryAccess).where(and(eq(workAppGitHubMcpToolRepositoryAccess.tenantId, params.tenantId), eq(workAppGitHubMcpToolRepositoryAccess.projectId, params.projectId), eq(workAppGitHubMcpToolRepositoryAccess.toolId, params.toolId)));
337
+ await db.delete(workAppGitHubMcpToolRepositoryAccess).where(toolScopedWhere(workAppGitHubMcpToolRepositoryAccess, {
338
+ tenantId: params.tenantId,
339
+ projectId: params.projectId,
340
+ toolId: params.toolId
341
+ }));
331
342
  if (params.repositoryIds.length > 0) await db.insert(workAppGitHubMcpToolRepositoryAccess).values(params.repositoryIds.map((repoId) => ({
332
343
  id: generateId(),
333
344
  toolId: params.toolId,
@@ -343,7 +354,7 @@ const setMcpToolRepositoryAccess = (db) => async (params) => {
343
354
  * These entries are used when mode='selected'. Check mode via getMcpToolAccessMode().
344
355
  */
345
356
  const getMcpToolRepositoryAccess = (db) => async (scope) => {
346
- return await db.select().from(workAppGitHubMcpToolRepositoryAccess).where(and(eq(workAppGitHubMcpToolRepositoryAccess.tenantId, scope.tenantId), eq(workAppGitHubMcpToolRepositoryAccess.projectId, scope.projectId), eq(workAppGitHubMcpToolRepositoryAccess.toolId, scope.toolId)));
357
+ return await db.select().from(workAppGitHubMcpToolRepositoryAccess).where(toolScopedWhere(workAppGitHubMcpToolRepositoryAccess, scope));
347
358
  };
348
359
  /**
349
360
  * Get MCP tool repository access with full repository details.
@@ -355,7 +366,7 @@ const getMcpToolRepositoryAccessWithDetails = (db) => async (scope) => {
355
366
  mode: workAppGitHubMcpToolAccessMode.mode,
356
367
  projectId: workAppGitHubMcpToolAccessMode.projectId,
357
368
  tenantId: workAppGitHubMcpToolAccessMode.tenantId
358
- }).from(workAppGitHubMcpToolAccessMode).where(and(eq(workAppGitHubMcpToolAccessMode.tenantId, scope.tenantId), eq(workAppGitHubMcpToolAccessMode.projectId, scope.projectId), eq(workAppGitHubMcpToolAccessMode.toolId, scope.toolId))).limit(1))[0]?.mode === "all") return getProjectRepositoryAccessWithDetails(db)({
369
+ }).from(workAppGitHubMcpToolAccessMode).where(toolScopedWhere(workAppGitHubMcpToolAccessMode, scope)).limit(1))[0]?.mode === "all") return getProjectRepositoryAccessWithDetails(db)({
359
370
  tenantId: scope.tenantId,
360
371
  projectId: scope.projectId
361
372
  });
@@ -371,13 +382,13 @@ const getMcpToolRepositoryAccessWithDetails = (db) => async (scope) => {
371
382
  createdAt: workAppGitHubRepositories.createdAt,
372
383
  updatedAt: workAppGitHubRepositories.updatedAt,
373
384
  installationAccountLogin: workAppGitHubInstallations.accountLogin
374
- }).from(workAppGitHubMcpToolRepositoryAccess).innerJoin(workAppGitHubRepositories, eq(workAppGitHubMcpToolRepositoryAccess.repositoryDbId, workAppGitHubRepositories.id)).innerJoin(workAppGitHubInstallations, eq(workAppGitHubRepositories.installationDbId, workAppGitHubInstallations.id)).where(and(eq(workAppGitHubMcpToolRepositoryAccess.tenantId, scope.tenantId), eq(workAppGitHubMcpToolRepositoryAccess.projectId, scope.projectId), eq(workAppGitHubMcpToolRepositoryAccess.toolId, scope.toolId)));
385
+ }).from(workAppGitHubMcpToolRepositoryAccess).innerJoin(workAppGitHubRepositories, eq(workAppGitHubMcpToolRepositoryAccess.repositoryDbId, workAppGitHubRepositories.id)).innerJoin(workAppGitHubInstallations, eq(workAppGitHubRepositories.installationDbId, workAppGitHubInstallations.id)).where(toolScopedWhere(workAppGitHubMcpToolRepositoryAccess, scope));
375
386
  };
376
387
  /**
377
388
  * Remove all MCP tool repository access for a specific tool
378
389
  */
379
390
  const clearMcpToolRepositoryAccess = (db) => async (scope) => {
380
- return (await db.delete(workAppGitHubMcpToolRepositoryAccess).where(and(eq(workAppGitHubMcpToolRepositoryAccess.tenantId, scope.tenantId), eq(workAppGitHubMcpToolRepositoryAccess.projectId, scope.projectId), eq(workAppGitHubMcpToolRepositoryAccess.toolId, scope.toolId))).returning()).length;
391
+ return (await db.delete(workAppGitHubMcpToolRepositoryAccess).where(toolScopedWhere(workAppGitHubMcpToolRepositoryAccess, scope)).returning()).length;
381
392
  };
382
393
  const isGithubWorkAppTool = (tool) => {
383
394
  return tool.isWorkApp && tool.config.mcp.server.url.includes("/github/mcp");
@@ -408,13 +419,13 @@ const setProjectAccessMode = (db) => async (params) => {
408
419
  * Returns 'selected' if no mode is explicitly set (fail-safe default).
409
420
  */
410
421
  const getProjectAccessMode = (db) => async (params) => {
411
- 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";
422
+ return (await db.select({ mode: workAppGitHubProjectAccessMode.mode }).from(workAppGitHubProjectAccessMode).where(projectScopedWhere(workAppGitHubProjectAccessMode, params)).limit(1))[0]?.mode ?? "selected";
412
423
  };
413
424
  /**
414
425
  * Delete the access mode entry for a project
415
426
  */
416
427
  const deleteProjectAccessMode = (db) => async (params) => {
417
- return (await db.delete(workAppGitHubProjectAccessMode).where(and(eq(workAppGitHubProjectAccessMode.tenantId, params.tenantId), eq(workAppGitHubProjectAccessMode.projectId, params.projectId))).returning()).length > 0;
428
+ return (await db.delete(workAppGitHubProjectAccessMode).where(projectScopedWhere(workAppGitHubProjectAccessMode, params)).returning()).length > 0;
418
429
  };
419
430
  /**
420
431
  * Set the access mode for an MCP tool's GitHub repository access.
@@ -447,13 +458,13 @@ const setMcpToolAccessMode = (db) => async (params) => {
447
458
  * Returns 'selected' if no mode is explicitly set (fail-safe default).
448
459
  */
449
460
  const getMcpToolAccessMode = (db) => async (scope) => {
450
- return (await db.select({ mode: workAppGitHubMcpToolAccessMode.mode }).from(workAppGitHubMcpToolAccessMode).where(and(eq(workAppGitHubMcpToolAccessMode.tenantId, scope.tenantId), eq(workAppGitHubMcpToolAccessMode.projectId, scope.projectId), eq(workAppGitHubMcpToolAccessMode.toolId, scope.toolId))).limit(1))[0]?.mode ?? "selected";
461
+ return (await db.select({ mode: workAppGitHubMcpToolAccessMode.mode }).from(workAppGitHubMcpToolAccessMode).where(toolScopedWhere(workAppGitHubMcpToolAccessMode, scope)).limit(1))[0]?.mode ?? "selected";
451
462
  };
452
463
  /**
453
464
  * Delete the access mode entry for an MCP tool
454
465
  */
455
466
  const deleteMcpToolAccessMode = (db) => async (scope) => {
456
- return (await db.delete(workAppGitHubMcpToolAccessMode).where(and(eq(workAppGitHubMcpToolAccessMode.tenantId, scope.tenantId), eq(workAppGitHubMcpToolAccessMode.projectId, scope.projectId), eq(workAppGitHubMcpToolAccessMode.toolId, scope.toolId))).returning()).length > 0;
467
+ return (await db.delete(workAppGitHubMcpToolAccessMode).where(toolScopedWhere(workAppGitHubMcpToolAccessMode, scope)).returning()).length > 0;
457
468
  };
458
469
 
459
470
  //#endregion
@@ -1,5 +1,7 @@
1
1
  import { ledgerArtifacts } from "../../db/runtime/runtime-schema.js";
2
2
  import { generateId } from "../../utils/conversations.js";
3
+ import { projectScopedWhere } from "../manage/scope-helpers.js";
4
+ import { isRetryableError } from "../../retry/retryable-errors.js";
3
5
  import { and, count, eq, inArray } from "drizzle-orm";
4
6
 
5
7
  //#region src/data-access/runtime/ledgerArtifacts.ts
@@ -114,7 +116,7 @@ const upsertLedgerArtifact = (db) => async (params) => {
114
116
  return { created: true };
115
117
  } catch (error) {
116
118
  if (error.message?.includes("UNIQUE") || error.message?.includes("duplicate")) {
117
- const existing = await db.select().from(ledgerArtifacts).where(and(eq(ledgerArtifacts.tenantId, scopes.tenantId), eq(ledgerArtifacts.projectId, scopes.projectId), eq(ledgerArtifacts.id, artifactRow.id), eq(ledgerArtifacts.taskId, taskId))).limit(1);
119
+ const existing = await db.select().from(ledgerArtifacts).where(and(projectScopedWhere(ledgerArtifacts, scopes), eq(ledgerArtifacts.id, artifactRow.id), eq(ledgerArtifacts.taskId, taskId))).limit(1);
118
120
  if (existing.length > 0) return {
119
121
  created: false,
120
122
  existing: existing[0]
@@ -123,14 +125,6 @@ const upsertLedgerArtifact = (db) => async (params) => {
123
125
  const sanitizedError = /* @__PURE__ */ new Error(`Failed to insert artifact ${artifactRow.id}: ${error.message?.split("\nparams:")[0] || error.message}`);
124
126
  sanitizedError.name = error.name;
125
127
  sanitizedError.cause = error.code || error.errno;
126
- if (artifactRow.id?.includes("compress_")) console.error("COMPRESSION ARTIFACT FULL ERROR:", {
127
- artifactId: artifactRow.id,
128
- errorMessage: error.message,
129
- errorCode: error.code,
130
- errorName: error.name,
131
- errorStack: error.stack,
132
- fullError: error
133
- });
134
128
  throw sanitizedError;
135
129
  }
136
130
  };
@@ -173,7 +167,7 @@ const addLedgerArtifacts = (db) => async (params) => {
173
167
  return;
174
168
  } catch (error) {
175
169
  lastError = error;
176
- if (!(error.cause.code === "40P01" || error.cause.code === "40001" || error.cause.code === "55P03" || error.message?.includes("database is locked") || error.message?.includes("busy") || error.message?.includes("timeout") || error.message?.includes("deadlock") || error.message?.includes("serialization failure")) || attempt === maxRetries) {
170
+ if (!isRetryableError(error) || attempt === maxRetries) {
177
171
  await tryFallbackInsert(db, rows, error);
178
172
  return;
179
173
  }
@@ -183,15 +177,6 @@ const addLedgerArtifacts = (db) => async (params) => {
183
177
  const sanitizedError = /* @__PURE__ */ new Error(`Failed to insert ${rows.length} artifacts after ${maxRetries} attempts: ${lastError?.message?.split("\nparams:")[0] || lastError?.message}`);
184
178
  sanitizedError.name = lastError?.name;
185
179
  sanitizedError.cause = lastError?.code || lastError?.errno;
186
- if (rows.some((row) => row.id?.includes("compress_"))) console.error("COMPRESSION ARTIFACTS BULK INSERT FULL ERROR:", {
187
- artifactCount: rows.length,
188
- compressionArtifacts: rows.filter((row) => row.id?.includes("compress_")).map((row) => row.id),
189
- errorMessage: lastError?.message,
190
- errorCode: lastError?.code,
191
- errorName: lastError?.name,
192
- errorStack: lastError?.stack,
193
- fullError: lastError
194
- });
195
180
  throw sanitizedError;
196
181
  };
197
182
  /**
@@ -203,7 +188,7 @@ const getLedgerArtifacts = (db) => async (params) => {
203
188
  const { scopes, taskId, toolCallId, toolCallIds, artifactId } = params;
204
189
  if (!taskId && !toolCallId && !toolCallIds && !artifactId) throw new Error("At least one of taskId, toolCallId, toolCallIds, or artifactId must be provided");
205
190
  if (toolCallId && toolCallIds) throw new Error("Cannot provide both toolCallId and toolCallIds. Use toolCallIds for batch queries.");
206
- const conditions = [eq(ledgerArtifacts.tenantId, scopes.tenantId), eq(ledgerArtifacts.projectId, scopes.projectId)];
191
+ const conditions = [projectScopedWhere(ledgerArtifacts, scopes)];
207
192
  if (artifactId) conditions.push(eq(ledgerArtifacts.id, artifactId));
208
193
  if (taskId) conditions.push(eq(ledgerArtifacts.taskId, taskId));
209
194
  if (toolCallId) conditions.push(eq(ledgerArtifacts.toolCallId, toolCallId));
@@ -224,25 +209,25 @@ const getLedgerArtifacts = (db) => async (params) => {
224
209
  * Get ledger artifacts by context ID
225
210
  */
226
211
  const getLedgerArtifactsByContext = (db) => async (params) => {
227
- return await db.select().from(ledgerArtifacts).where(and(eq(ledgerArtifacts.tenantId, params.scopes.tenantId), eq(ledgerArtifacts.projectId, params.scopes.projectId), eq(ledgerArtifacts.contextId, params.contextId)));
212
+ return await db.select().from(ledgerArtifacts).where(and(projectScopedWhere(ledgerArtifacts, params.scopes), eq(ledgerArtifacts.contextId, params.contextId)));
228
213
  };
229
214
  /**
230
215
  * Delete ledger artifacts by task ID
231
216
  */
232
217
  const deleteLedgerArtifactsByTask = (db) => async (params) => {
233
- return (await db.delete(ledgerArtifacts).where(and(eq(ledgerArtifacts.tenantId, params.scopes.tenantId), eq(ledgerArtifacts.projectId, params.scopes.projectId), eq(ledgerArtifacts.taskId, params.taskId))).returning()).length > 0;
218
+ return (await db.delete(ledgerArtifacts).where(and(projectScopedWhere(ledgerArtifacts, params.scopes), eq(ledgerArtifacts.taskId, params.taskId))).returning()).length > 0;
234
219
  };
235
220
  /**
236
221
  * Delete ledger artifacts by context ID
237
222
  */
238
223
  const deleteLedgerArtifactsByContext = (db) => async (params) => {
239
- return (await db.delete(ledgerArtifacts).where(and(eq(ledgerArtifacts.tenantId, params.scopes.tenantId), eq(ledgerArtifacts.projectId, params.scopes.projectId), eq(ledgerArtifacts.contextId, params.contextId))).returning()).length > 0;
224
+ return (await db.delete(ledgerArtifacts).where(and(projectScopedWhere(ledgerArtifacts, params.scopes), eq(ledgerArtifacts.contextId, params.contextId))).returning()).length > 0;
240
225
  };
241
226
  /**
242
227
  * Count ledger artifacts by task ID
243
228
  */
244
229
  const countLedgerArtifactsByTask = (db) => async (params) => {
245
- const countValue = (await db.select({ count: count() }).from(ledgerArtifacts).where(and(eq(ledgerArtifacts.tenantId, params.scopes.tenantId), eq(ledgerArtifacts.projectId, params.scopes.projectId), eq(ledgerArtifacts.taskId, params.taskId))))[0]?.count;
230
+ const countValue = (await db.select({ count: count() }).from(ledgerArtifacts).where(and(projectScopedWhere(ledgerArtifacts, params.scopes), eq(ledgerArtifacts.taskId, params.taskId))))[0]?.count;
246
231
  return typeof countValue === "string" ? parseInt(countValue, 10) : countValue || 0;
247
232
  };
248
233