@agentforge-ai/cli 0.5.0 → 0.5.1

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 (35) hide show
  1. package/dist/default/convex/agents.ts +8 -8
  2. package/dist/default/convex/apiKeys.ts +7 -7
  3. package/dist/default/convex/cronJobs.ts +12 -12
  4. package/dist/default/convex/files.ts +7 -7
  5. package/dist/default/convex/folders.ts +11 -11
  6. package/dist/default/convex/heartbeat.ts +18 -18
  7. package/dist/default/convex/mastraIntegration.ts +2 -1
  8. package/dist/default/convex/mcpConnections.ts +5 -5
  9. package/dist/default/convex/messages.ts +4 -4
  10. package/dist/default/convex/projects.ts +10 -10
  11. package/dist/default/convex/schema.ts +150 -83
  12. package/dist/default/convex/sessions.ts +12 -12
  13. package/dist/default/convex/settings.ts +3 -3
  14. package/dist/default/convex/skills.ts +8 -8
  15. package/dist/default/convex/threads.ts +9 -9
  16. package/dist/default/convex/usage.ts +16 -16
  17. package/dist/default/convex/vault.ts +47 -33
  18. package/package.json +1 -1
  19. package/templates/default/convex/agents.ts +8 -8
  20. package/templates/default/convex/apiKeys.ts +7 -7
  21. package/templates/default/convex/cronJobs.ts +12 -12
  22. package/templates/default/convex/files.ts +7 -7
  23. package/templates/default/convex/folders.ts +11 -11
  24. package/templates/default/convex/heartbeat.ts +18 -18
  25. package/templates/default/convex/mastraIntegration.ts +2 -1
  26. package/templates/default/convex/mcpConnections.ts +5 -5
  27. package/templates/default/convex/messages.ts +4 -4
  28. package/templates/default/convex/projects.ts +10 -10
  29. package/templates/default/convex/schema.ts +150 -83
  30. package/templates/default/convex/sessions.ts +12 -12
  31. package/templates/default/convex/settings.ts +3 -3
  32. package/templates/default/convex/skills.ts +8 -8
  33. package/templates/default/convex/threads.ts +9 -9
  34. package/templates/default/convex/usage.ts +16 -16
  35. package/templates/default/convex/vault.ts +47 -33
@@ -1,5 +1,5 @@
1
1
  import { v } from "convex/values";
2
- import { mutation, query, action } from "./_generated/server";
2
+ import { mutation, query, internalMutation } from "./_generated/server";
3
3
 
4
4
  // ============================================================
5
5
  // SECURE VAULT - Encrypted secrets management
@@ -35,10 +35,20 @@ function maskSecret(value: string): string {
35
35
  return value.substring(0, 6) + "..." + value.substring(value.length - 4);
36
36
  }
37
37
 
38
- // Simple XOR-based encoding (in production, use proper AES-256-GCM with a KMS)
39
- // This provides a layer of obfuscation in the database
38
+ // Encryption key from Convex environment variable.
39
+ // Set VAULT_ENCRYPTION_KEY in your Convex dashboard under Settings > Environment Variables.
40
+ // If not set, a default key is used (NOT SECURE for production).
41
+ function getEncryptionKey(): string {
42
+ return process.env.VAULT_ENCRYPTION_KEY ?? "agentforge-default-key-set-env-var";
43
+ }
44
+
45
+ // XOR-based encoding with per-entry IV for database obfuscation.
46
+ // For production deployments with sensitive data, consider integrating
47
+ // with a proper KMS (e.g., AWS KMS, Cloudflare Workers Secrets).
40
48
  function encodeSecret(value: string, key: string): { encrypted: string; iv: string } {
41
- const iv = Array.from({ length: 16 }, () => Math.floor(Math.random() * 256).toString(16).padStart(2, "0")).join("");
49
+ const iv = Array.from({ length: 16 }, () =>
50
+ Math.floor(Math.random() * 256).toString(16).padStart(2, "0")
51
+ ).join("");
42
52
  const combined = key + iv;
43
53
  let encrypted = "";
44
54
  for (let i = 0; i < value.length; i++) {
@@ -52,15 +62,14 @@ function decodeSecret(encrypted: string, iv: string, key: string): string {
52
62
  const combined = key + iv;
53
63
  let decoded = "";
54
64
  for (let i = 0; i < encrypted.length; i += 4) {
55
- const charCode = parseInt(encrypted.substring(i, i + 4), 16) ^ combined.charCodeAt((i / 4) % combined.length);
65
+ const charCode =
66
+ parseInt(encrypted.substring(i, i + 4), 16) ^
67
+ combined.charCodeAt((i / 4) % combined.length);
56
68
  decoded += String.fromCharCode(charCode);
57
69
  }
58
70
  return decoded;
59
71
  }
60
72
 
61
- // The encryption key should come from environment variables in production
62
- const VAULT_ENCRYPTION_KEY = "agentforge-vault-key-change-in-production-2026";
63
-
64
73
  // ---- Queries ----
65
74
 
66
75
  export const list = query({
@@ -69,11 +78,21 @@ export const list = query({
69
78
  category: v.optional(v.string()),
70
79
  },
71
80
  handler: async (ctx, args) => {
72
- let q = ctx.db.query("vault");
81
+ let entries;
73
82
  if (args.userId) {
74
- q = ctx.db.query("vault").withIndex("byUserId", (q) => q.eq("userId", args.userId));
83
+ entries = await ctx.db
84
+ .query("vault")
85
+ .withIndex("byUserId", (q) => q.eq("userId", args.userId!))
86
+ .order("desc")
87
+ .collect();
88
+ } else {
89
+ entries = await ctx.db.query("vault").order("desc").collect();
75
90
  }
76
- const entries = await q.order("desc").take(100);
91
+
92
+ if (args.category) {
93
+ entries = entries.filter((e) => e.category === args.category);
94
+ }
95
+
77
96
  // Never return encrypted values - only masked
78
97
  return entries.map((entry) => ({
79
98
  _id: entry._id,
@@ -99,13 +118,13 @@ export const getAuditLog = query({
99
118
  handler: async (ctx, args) => {
100
119
  const limit = args.limit ?? 50;
101
120
  if (args.vaultEntryId) {
102
- return ctx.db
121
+ return await ctx.db
103
122
  .query("vaultAuditLog")
104
123
  .withIndex("byVaultEntryId", (q) => q.eq("vaultEntryId", args.vaultEntryId!))
105
124
  .order("desc")
106
125
  .take(limit);
107
126
  }
108
- return ctx.db.query("vaultAuditLog").order("desc").take(limit);
127
+ return await ctx.db.query("vaultAuditLog").order("desc").take(limit);
109
128
  },
110
129
  });
111
130
 
@@ -116,12 +135,13 @@ export const store = mutation({
116
135
  name: v.string(),
117
136
  category: v.string(),
118
137
  provider: v.optional(v.string()),
119
- value: v.string(), // Raw secret value - will be encrypted before storage
138
+ value: v.string(),
120
139
  userId: v.optional(v.string()),
121
140
  expiresAt: v.optional(v.number()),
122
141
  },
123
142
  handler: async (ctx, args) => {
124
- const { encrypted, iv } = encodeSecret(args.value, VAULT_ENCRYPTION_KEY);
143
+ const key = getEncryptionKey();
144
+ const { encrypted, iv } = encodeSecret(args.value, key);
125
145
  const masked = maskSecret(args.value);
126
146
  const now = Date.now();
127
147
 
@@ -134,14 +154,12 @@ export const store = mutation({
134
154
  maskedValue: masked,
135
155
  isActive: true,
136
156
  expiresAt: args.expiresAt,
137
- lastAccessedAt: undefined,
138
157
  accessCount: 0,
139
158
  userId: args.userId,
140
159
  createdAt: now,
141
160
  updatedAt: now,
142
161
  });
143
162
 
144
- // Audit log
145
163
  await ctx.db.insert("vaultAuditLog", {
146
164
  vaultEntryId: id,
147
165
  action: "created",
@@ -163,7 +181,8 @@ export const storeFromChat = mutation({
163
181
  userId: v.optional(v.string()),
164
182
  },
165
183
  handler: async (ctx, args) => {
166
- const { encrypted, iv } = encodeSecret(args.value, VAULT_ENCRYPTION_KEY);
184
+ const key = getEncryptionKey();
185
+ const { encrypted, iv } = encodeSecret(args.value, key);
167
186
  const masked = maskSecret(args.value);
168
187
  const now = Date.now();
169
188
 
@@ -181,7 +200,6 @@ export const storeFromChat = mutation({
181
200
  updatedAt: now,
182
201
  });
183
202
 
184
- // Audit log with auto_captured source
185
203
  await ctx.db.insert("vaultAuditLog", {
186
204
  vaultEntryId: id,
187
205
  action: "auto_captured",
@@ -207,14 +225,15 @@ export const update = mutation({
207
225
  const existing = await ctx.db.get(args.id);
208
226
  if (!existing) throw new Error("Vault entry not found");
209
227
 
210
- const updates: any = { updatedAt: Date.now() };
228
+ const updates: Record<string, unknown> = { updatedAt: Date.now() };
211
229
 
212
230
  if (args.name !== undefined) updates.name = args.name;
213
231
  if (args.isActive !== undefined) updates.isActive = args.isActive;
214
232
  if (args.expiresAt !== undefined) updates.expiresAt = args.expiresAt;
215
233
 
216
234
  if (args.value) {
217
- const { encrypted, iv } = encodeSecret(args.value, VAULT_ENCRYPTION_KEY);
235
+ const key = getEncryptionKey();
236
+ const { encrypted, iv } = encodeSecret(args.value, key);
218
237
  updates.encryptedValue = encrypted;
219
238
  updates.iv = iv;
220
239
  updates.maskedValue = maskSecret(args.value);
@@ -241,7 +260,6 @@ export const remove = mutation({
241
260
  const existing = await ctx.db.get(args.id);
242
261
  if (!existing) throw new Error("Vault entry not found");
243
262
 
244
- // Log deletion before removing
245
263
  await ctx.db.insert("vaultAuditLog", {
246
264
  vaultEntryId: args.id,
247
265
  action: "deleted",
@@ -254,8 +272,8 @@ export const remove = mutation({
254
272
  },
255
273
  });
256
274
 
257
- // Retrieve decrypted value (for internal agent use only - never expose to frontend)
258
- export const retrieveSecret = mutation({
275
+ // Internal-only: Retrieve decrypted value (only callable from other Convex functions)
276
+ export const retrieveSecret = internalMutation({
259
277
  args: {
260
278
  id: v.id("vault"),
261
279
  userId: v.optional(v.string()),
@@ -265,13 +283,11 @@ export const retrieveSecret = mutation({
265
283
  if (!entry) throw new Error("Vault entry not found");
266
284
  if (!entry.isActive) throw new Error("Vault entry is disabled");
267
285
 
268
- // Update access tracking
269
286
  await ctx.db.patch(args.id, {
270
287
  lastAccessedAt: Date.now(),
271
288
  accessCount: entry.accessCount + 1,
272
289
  });
273
290
 
274
- // Audit log
275
291
  await ctx.db.insert("vaultAuditLog", {
276
292
  vaultEntryId: args.id,
277
293
  action: "accessed",
@@ -280,14 +296,13 @@ export const retrieveSecret = mutation({
280
296
  timestamp: Date.now(),
281
297
  });
282
298
 
283
- // Decrypt and return
284
- const decrypted = decodeSecret(entry.encryptedValue, entry.iv, VAULT_ENCRYPTION_KEY);
299
+ const key = getEncryptionKey();
300
+ const decrypted = decodeSecret(entry.encryptedValue, entry.iv, key);
285
301
  return decrypted;
286
302
  },
287
303
  });
288
304
 
289
305
  // ---- Secret Detection Utility ----
290
- // This is exported for use by the chat message handler
291
306
 
292
307
  export const detectSecrets = query({
293
308
  args: { text: v.string() },
@@ -329,7 +344,7 @@ export const censorMessage = mutation({
329
344
  },
330
345
  handler: async (ctx, args) => {
331
346
  let censoredText = args.text;
332
- const storedSecrets: Array<{ name: string; masked: string; id: any }> = [];
347
+ const storedSecrets: Array<{ name: string; masked: string; id: unknown }> = [];
333
348
 
334
349
  for (const { pattern, category, provider, name } of SECRET_PATTERNS) {
335
350
  const regex = new RegExp(pattern, "g");
@@ -338,12 +353,11 @@ export const censorMessage = mutation({
338
353
  const secretValue = match[0];
339
354
  const masked = maskSecret(secretValue);
340
355
 
341
- // Replace in censored text
342
356
  censoredText = censoredText.replace(secretValue, `[REDACTED: ${masked}]`);
343
357
 
344
- // Auto-store if enabled
345
358
  if (args.autoStore !== false) {
346
- const { encrypted, iv } = encodeSecret(secretValue, VAULT_ENCRYPTION_KEY);
359
+ const key = getEncryptionKey();
360
+ const { encrypted, iv } = encodeSecret(secretValue, key);
347
361
  const now = Date.now();
348
362
 
349
363
  const id = await ctx.db.insert("vault", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentforge-ai/cli",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "CLI tool for creating, running, and managing AgentForge projects",
5
5
  "type": "module",
6
6
  "bin": {
@@ -11,10 +11,10 @@ export const list = query({
11
11
  if (args.userId) {
12
12
  return await ctx.db
13
13
  .query("agents")
14
- .withIndex("byUserId", (q) => q.eq("userId", args.userId))
15
- .take(100).collect();
14
+ .withIndex("byUserId", (q) => q.eq("userId", args.userId!))
15
+ .collect();
16
16
  }
17
- return await ctx.db.query("agents").take(100).collect();
17
+ return await ctx.db.query("agents").collect();
18
18
  },
19
19
  });
20
20
 
@@ -24,7 +24,7 @@ export const get = query({
24
24
  handler: async (ctx, args) => {
25
25
  return await ctx.db
26
26
  .query("agents")
27
- .withIndex("byAgentId", (q) => q.eq("id", args.id))
27
+ .withIndex("byAgentId", (q) => q.eq("id", args.id!))
28
28
  .first();
29
29
  },
30
30
  });
@@ -35,11 +35,11 @@ export const listActive = query({
35
35
  userId: v.optional(v.string()),
36
36
  },
37
37
  handler: async (ctx, args) => {
38
- let query = ctx.db
38
+ const activeQuery = ctx.db
39
39
  .query("agents")
40
40
  .withIndex("byIsActive", (q) => q.eq("isActive", true));
41
41
 
42
- const agents = await query.take(100).collect();
42
+ const agents = await activeQuery.collect();
43
43
 
44
44
  if (args.userId) {
45
45
  return agents.filter((agent) => agent.userId === args.userId);
@@ -117,7 +117,7 @@ export const remove = mutation({
117
117
  handler: async (ctx, args) => {
118
118
  const agent = await ctx.db
119
119
  .query("agents")
120
- .withIndex("byAgentId", (q) => q.eq("id", args.id))
120
+ .withIndex("byAgentId", (q) => q.eq("id", args.id!))
121
121
  .first();
122
122
 
123
123
  if (!agent) {
@@ -135,7 +135,7 @@ export const toggleActive = mutation({
135
135
  handler: async (ctx, args) => {
136
136
  const agent = await ctx.db
137
137
  .query("agents")
138
- .withIndex("byAgentId", (q) => q.eq("id", args.id))
138
+ .withIndex("byAgentId", (q) => q.eq("id", args.id!))
139
139
  .first();
140
140
 
141
141
  if (!agent) {
@@ -11,8 +11,8 @@ export const list = query({
11
11
  if (args.provider) {
12
12
  const keys = await ctx.db
13
13
  .query("apiKeys")
14
- .withIndex("byProvider", (q) => q.eq("provider", args.provider))
15
- .take(100).collect();
14
+ .withIndex("byProvider", (q) => q.eq("provider", args.provider!))
15
+ .collect();
16
16
 
17
17
  if (args.userId) {
18
18
  return keys.filter((k) => k.userId === args.userId);
@@ -23,11 +23,11 @@ export const list = query({
23
23
  if (args.userId) {
24
24
  return await ctx.db
25
25
  .query("apiKeys")
26
- .withIndex("byUserId", (q) => q.eq("userId", args.userId))
27
- .take(100).collect();
26
+ .withIndex("byUserId", (q) => q.eq("userId", args.userId!))
27
+ .collect();
28
28
  }
29
29
 
30
- return await ctx.db.query("apiKeys").take(100).collect();
30
+ return await ctx.db.query("apiKeys").collect();
31
31
  },
32
32
  });
33
33
 
@@ -48,8 +48,8 @@ export const getActiveForProvider = query({
48
48
  handler: async (ctx, args) => {
49
49
  const keys = await ctx.db
50
50
  .query("apiKeys")
51
- .withIndex("byProvider", (q) => q.eq("provider", args.provider))
52
- .take(100).collect();
51
+ .withIndex("byProvider", (q) => q.eq("provider", args.provider!))
52
+ .collect();
53
53
 
54
54
  const activeKeys = keys.filter((k) => k.isActive);
55
55
 
@@ -12,8 +12,8 @@ export const list = query({
12
12
  if (args.isEnabled !== undefined) {
13
13
  const jobs = await ctx.db
14
14
  .query("cronJobs")
15
- .withIndex("byIsEnabled", (q) => q.eq("isEnabled", args.isEnabled))
16
- .take(100).collect();
15
+ .withIndex("byIsEnabled", (q) => q.eq("isEnabled", args.isEnabled!))
16
+ .collect();
17
17
 
18
18
  if (args.userId) {
19
19
  return jobs.filter((j) => j.userId === args.userId);
@@ -27,18 +27,18 @@ export const list = query({
27
27
  if (args.agentId) {
28
28
  return await ctx.db
29
29
  .query("cronJobs")
30
- .withIndex("byAgentId", (q) => q.eq("agentId", args.agentId))
31
- .take(100).collect();
30
+ .withIndex("byAgentId", (q) => q.eq("agentId", args.agentId!))
31
+ .collect();
32
32
  }
33
33
 
34
34
  if (args.userId) {
35
35
  return await ctx.db
36
36
  .query("cronJobs")
37
- .withIndex("byUserId", (q) => q.eq("userId", args.userId))
38
- .take(100).collect();
37
+ .withIndex("byUserId", (q) => q.eq("userId", args.userId!))
38
+ .collect();
39
39
  }
40
40
 
41
- return await ctx.db.query("cronJobs").take(100).collect();
41
+ return await ctx.db.query("cronJobs").collect();
42
42
  },
43
43
  });
44
44
 
@@ -58,7 +58,7 @@ export const getDueJobs = query({
58
58
  const jobs = await ctx.db
59
59
  .query("cronJobs")
60
60
  .withIndex("byNextRun")
61
- .take(100).collect();
61
+ .collect();
62
62
 
63
63
  return jobs.filter((j) => j.isEnabled && j.nextRun && j.nextRun <= now);
64
64
  },
@@ -162,8 +162,8 @@ export const remove = mutation({
162
162
  // Delete all run history
163
163
  const runs = await ctx.db
164
164
  .query("cronJobRuns")
165
- .withIndex("byCronJobId", (q) => q.eq("cronJobId", args.id))
166
- .take(100).collect();
165
+ .withIndex("byCronJobId", (q) => q.eq("cronJobId", args.id!))
166
+ .collect();
167
167
 
168
168
  for (const run of runs) {
169
169
  await ctx.db.delete(run._id);
@@ -209,8 +209,8 @@ export const getRunHistory = query({
209
209
  handler: async (ctx, args) => {
210
210
  const runs = await ctx.db
211
211
  .query("cronJobRuns")
212
- .withIndex("byCronJobId", (q) => q.eq("cronJobId", args.cronJobId))
213
- .take(100).collect();
212
+ .withIndex("byCronJobId", (q) => q.eq("cronJobId", args.cronJobId!))
213
+ .collect();
214
214
 
215
215
  // Sort by startedAt descending
216
216
  runs.sort((a, b) => b.startedAt - a.startedAt);
@@ -12,25 +12,25 @@ export const list = query({
12
12
  if (args.folderId) {
13
13
  return await ctx.db
14
14
  .query("files")
15
- .withIndex("byFolderId", (q) => q.eq("folderId", args.folderId))
16
- .take(100).collect();
15
+ .withIndex("byFolderId", (q) => q.eq("folderId", args.folderId!))
16
+ .collect();
17
17
  }
18
18
 
19
19
  if (args.projectId) {
20
20
  return await ctx.db
21
21
  .query("files")
22
- .withIndex("byProjectId", (q) => q.eq("projectId", args.projectId))
23
- .take(100).collect();
22
+ .withIndex("byProjectId", (q) => q.eq("projectId", args.projectId!))
23
+ .collect();
24
24
  }
25
25
 
26
26
  if (args.userId) {
27
27
  return await ctx.db
28
28
  .query("files")
29
- .withIndex("byUserId", (q) => q.eq("userId", args.userId))
30
- .take(100).collect();
29
+ .withIndex("byUserId", (q) => q.eq("userId", args.userId!))
30
+ .collect();
31
31
  }
32
32
 
33
- return await ctx.db.query("files").take(100).collect();
33
+ return await ctx.db.query("files").collect();
34
34
  },
35
35
  });
36
36
 
@@ -12,25 +12,25 @@ export const list = query({
12
12
  if (args.projectId) {
13
13
  return await ctx.db
14
14
  .query("folders")
15
- .withIndex("byProjectId", (q) => q.eq("projectId", args.projectId))
16
- .take(100).collect();
15
+ .withIndex("byProjectId", (q) => q.eq("projectId", args.projectId!))
16
+ .collect();
17
17
  }
18
18
 
19
19
  if (args.parentId) {
20
20
  return await ctx.db
21
21
  .query("folders")
22
- .withIndex("byParentId", (q) => q.eq("parentId", args.parentId))
23
- .take(100).collect();
22
+ .withIndex("byParentId", (q) => q.eq("parentId", args.parentId!))
23
+ .collect();
24
24
  }
25
25
 
26
26
  if (args.userId) {
27
27
  return await ctx.db
28
28
  .query("folders")
29
- .withIndex("byUserId", (q) => q.eq("userId", args.userId))
30
- .take(100).collect();
29
+ .withIndex("byUserId", (q) => q.eq("userId", args.userId!))
30
+ .collect();
31
31
  }
32
32
 
33
- return await ctx.db.query("folders").take(100).collect();
33
+ return await ctx.db.query("folders").collect();
34
34
  },
35
35
  });
36
36
 
@@ -85,8 +85,8 @@ export const remove = mutation({
85
85
  // Delete all files in the folder
86
86
  const files = await ctx.db
87
87
  .query("files")
88
- .withIndex("byFolderId", (q) => q.eq("folderId", args.id))
89
- .take(100).collect();
88
+ .withIndex("byFolderId", (q) => q.eq("folderId", args.id!))
89
+ .collect();
90
90
 
91
91
  for (const file of files) {
92
92
  await ctx.db.delete(file._id);
@@ -95,8 +95,8 @@ export const remove = mutation({
95
95
  // Delete all subfolders recursively
96
96
  const subfolders = await ctx.db
97
97
  .query("folders")
98
- .withIndex("byParentId", (q) => q.eq("parentId", args.id))
99
- .take(100).collect();
98
+ .withIndex("byParentId", (q) => q.eq("parentId", args.id!))
99
+ .collect();
100
100
 
101
101
  for (const subfolder of subfolders) {
102
102
  // Recursive delete (will be called via mutation)
@@ -37,8 +37,8 @@ export const get = query({
37
37
  handler: async (ctx, args) => {
38
38
  const heartbeats = await ctx.db
39
39
  .query("heartbeats")
40
- .withIndex("byAgentId", (q) => q.eq("agentId", args.agentId))
41
- .take(100).collect();
40
+ .withIndex("byAgentId", (q) => q.eq("agentId", args.agentId!))
41
+ .collect();
42
42
 
43
43
  if (args.threadId) {
44
44
  return heartbeats.find((h) => h.threadId === args.threadId);
@@ -57,14 +57,14 @@ export const listActive = query({
57
57
  const heartbeats = await ctx.db
58
58
  .query("heartbeats")
59
59
  .withIndex("byStatus", (q) => q.eq("status", "active"))
60
- .take(100).collect();
60
+ .collect();
61
61
 
62
62
  if (args.userId) {
63
63
  // Filter by userId if provided
64
64
  const userAgents = await ctx.db
65
65
  .query("agents")
66
- .withIndex("byUserId", (q) => q.eq("userId", args.userId))
67
- .take(100).collect();
66
+ .withIndex("byUserId", (q) => q.eq("userId", args.userId!))
67
+ .collect();
68
68
 
69
69
  const userAgentIds = new Set(userAgents.map((a) => a.id));
70
70
  return heartbeats.filter((h) => userAgentIds.has(h.agentId));
@@ -82,7 +82,7 @@ export const getDueForCheck = query({
82
82
  const heartbeats = await ctx.db
83
83
  .query("heartbeats")
84
84
  .withIndex("byNextCheck")
85
- .take(100).collect();
85
+ .collect();
86
86
 
87
87
  return heartbeats.filter((h) => h.nextCheck <= now && h.status === "active");
88
88
  },
@@ -107,10 +107,10 @@ export const upsert = mutation({
107
107
  // Check if heartbeat exists
108
108
  const existing = await ctx.db
109
109
  .query("heartbeats")
110
- .withIndex("byAgentId", (q) => q.eq("agentId", args.agentId))
110
+ .withIndex("byAgentId", (q) => q.eq("agentId", args.agentId!))
111
111
  .filter((q) =>
112
112
  args.threadId
113
- ? q.eq(q.field("threadId"), args.threadId)
113
+ ? q.eq(q.field("threadId"), args.threadId!)
114
114
  : q.eq(q.field("threadId"), undefined)
115
115
  )
116
116
  .first();
@@ -146,10 +146,10 @@ export const updateStatus = mutation({
146
146
  handler: async (ctx, args) => {
147
147
  const heartbeat = await ctx.db
148
148
  .query("heartbeats")
149
- .withIndex("byAgentId", (q) => q.eq("agentId", args.agentId))
149
+ .withIndex("byAgentId", (q) => q.eq("agentId", args.agentId!))
150
150
  .filter((q) =>
151
151
  args.threadId
152
- ? q.eq(q.field("threadId"), args.threadId)
152
+ ? q.eq(q.field("threadId"), args.threadId!)
153
153
  : q.eq(q.field("threadId"), undefined)
154
154
  )
155
155
  .first();
@@ -178,10 +178,10 @@ export const addPendingTask = mutation({
178
178
  handler: async (ctx, args) => {
179
179
  const heartbeat = await ctx.db
180
180
  .query("heartbeats")
181
- .withIndex("byAgentId", (q) => q.eq("agentId", args.agentId))
181
+ .withIndex("byAgentId", (q) => q.eq("agentId", args.agentId!))
182
182
  .filter((q) =>
183
183
  args.threadId
184
- ? q.eq(q.field("threadId"), args.threadId)
184
+ ? q.eq(q.field("threadId"), args.threadId!)
185
185
  : q.eq(q.field("threadId"), undefined)
186
186
  )
187
187
  .first();
@@ -210,10 +210,10 @@ export const removePendingTask = mutation({
210
210
  handler: async (ctx, args) => {
211
211
  const heartbeat = await ctx.db
212
212
  .query("heartbeats")
213
- .withIndex("byAgentId", (q) => q.eq("agentId", args.agentId))
213
+ .withIndex("byAgentId", (q) => q.eq("agentId", args.agentId!))
214
214
  .filter((q) =>
215
215
  args.threadId
216
- ? q.eq(q.field("threadId"), args.threadId)
216
+ ? q.eq(q.field("threadId"), args.threadId!)
217
217
  : q.eq(q.field("threadId"), undefined)
218
218
  )
219
219
  .first();
@@ -242,10 +242,10 @@ export const updateContext = mutation({
242
242
  handler: async (ctx, args) => {
243
243
  const heartbeat = await ctx.db
244
244
  .query("heartbeats")
245
- .withIndex("byAgentId", (q) => q.eq("agentId", args.agentId))
245
+ .withIndex("byAgentId", (q) => q.eq("agentId", args.agentId!))
246
246
  .filter((q) =>
247
247
  args.threadId
248
- ? q.eq(q.field("threadId"), args.threadId)
248
+ ? q.eq(q.field("threadId"), args.threadId!)
249
249
  : q.eq(q.field("threadId"), undefined)
250
250
  )
251
251
  .first();
@@ -353,10 +353,10 @@ export const remove = mutation({
353
353
  handler: async (ctx, args) => {
354
354
  const heartbeat = await ctx.db
355
355
  .query("heartbeats")
356
- .withIndex("byAgentId", (q) => q.eq("agentId", args.agentId))
356
+ .withIndex("byAgentId", (q) => q.eq("agentId", args.agentId!))
357
357
  .filter((q) =>
358
358
  args.threadId
359
- ? q.eq(q.field("threadId"), args.threadId)
359
+ ? q.eq(q.field("threadId"), args.threadId!)
360
360
  : q.eq(q.field("threadId"), undefined)
361
361
  )
362
362
  .first();
@@ -54,6 +54,7 @@ export const executeAgent = action({
54
54
 
55
55
  try {
56
56
  // Import Mastra dynamically (Node.js runtime)
57
+ // @ts-expect-error - Mastra is installed at runtime in the user's project
57
58
  const { Agent } = await import("@mastra/core/agent");
58
59
 
59
60
  // Format model string for Mastra
@@ -83,7 +84,7 @@ export const executeAgent = action({
83
84
  .join("\n");
84
85
 
85
86
  // Execute agent
86
- const result = await mastraAgent.generate(args.prompt, {
87
+ const result: any = await mastraAgent.generate(args.prompt, {
87
88
  ...(args.stream && { stream: args.stream }),
88
89
  context: context || undefined,
89
90
  });
@@ -11,8 +11,8 @@ export const list = query({
11
11
  if (args.isEnabled !== undefined) {
12
12
  const connections = await ctx.db
13
13
  .query("mcpConnections")
14
- .withIndex("byIsEnabled", (q) => q.eq("isEnabled", args.isEnabled))
15
- .take(100).collect();
14
+ .withIndex("byIsEnabled", (q) => q.eq("isEnabled", args.isEnabled!))
15
+ .collect();
16
16
 
17
17
  if (args.userId) {
18
18
  return connections.filter((c) => c.userId === args.userId);
@@ -23,11 +23,11 @@ export const list = query({
23
23
  if (args.userId) {
24
24
  return await ctx.db
25
25
  .query("mcpConnections")
26
- .withIndex("byUserId", (q) => q.eq("userId", args.userId))
27
- .take(100).collect();
26
+ .withIndex("byUserId", (q) => q.eq("userId", args.userId!))
27
+ .collect();
28
28
  }
29
29
 
30
- return await ctx.db.query("mcpConnections").take(100).collect();
30
+ return await ctx.db.query("mcpConnections").collect();
31
31
  },
32
32
  });
33
33
 
@@ -57,8 +57,8 @@ export const list = query({
57
57
  handler: async (ctx, args) => {
58
58
  const messages = await ctx.db
59
59
  .query("messages")
60
- .withIndex("by_thread", (q) => q.eq("threadId", args.threadId))
61
- .take(100).collect();
60
+ .withIndex("byThread", (q) => q.eq("threadId", args.threadId!))
61
+ .collect();
62
62
  return messages;
63
63
  },
64
64
  });
@@ -78,8 +78,8 @@ export const clearThread = mutation({
78
78
  handler: async (ctx, args) => {
79
79
  const messages = await ctx.db
80
80
  .query("messages")
81
- .withIndex("by_thread", (q) => q.eq("threadId", args.threadId))
82
- .take(100).collect();
81
+ .withIndex("byThread", (q) => q.eq("threadId", args.threadId!))
82
+ .collect();
83
83
 
84
84
  for (const message of messages) {
85
85
  await ctx.db.delete(message._id);