@agentforge-ai/cli 0.4.3 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/default/convex/agents.ts +204 -0
  2. package/dist/default/convex/apiKeys.ts +133 -0
  3. package/dist/default/convex/cronJobs.ts +224 -0
  4. package/dist/default/convex/files.ts +103 -0
  5. package/dist/default/convex/folders.ts +110 -0
  6. package/dist/default/convex/heartbeat.ts +371 -0
  7. package/dist/default/convex/logs.ts +66 -0
  8. package/dist/default/convex/mastraIntegration.ts +184 -0
  9. package/dist/default/convex/mcpConnections.ts +127 -0
  10. package/dist/default/convex/messages.ts +90 -0
  11. package/dist/default/convex/projects.ts +114 -0
  12. package/dist/default/convex/sessions.ts +174 -0
  13. package/dist/default/convex/settings.ts +79 -0
  14. package/dist/default/convex/skills.ts +178 -0
  15. package/dist/default/convex/threads.ts +100 -0
  16. package/dist/default/convex/usage.ts +195 -0
  17. package/dist/default/convex/vault.ts +383 -0
  18. package/dist/default/dashboard/app/main.tsx +7 -3
  19. package/dist/default/dashboard/app/routes/agents.tsx +103 -161
  20. package/dist/default/dashboard/app/routes/chat.tsx +163 -317
  21. package/dist/default/dashboard/app/routes/connections.tsx +247 -386
  22. package/dist/default/dashboard/app/routes/cron.tsx +127 -286
  23. package/dist/default/dashboard/app/routes/files.tsx +184 -167
  24. package/dist/default/dashboard/app/routes/index.tsx +63 -96
  25. package/dist/default/dashboard/app/routes/projects.tsx +106 -225
  26. package/dist/default/dashboard/app/routes/sessions.tsx +87 -253
  27. package/dist/default/dashboard/app/routes/settings.tsx +316 -532
  28. package/dist/default/dashboard/app/routes/skills.tsx +329 -216
  29. package/dist/default/dashboard/app/routes/usage.tsx +107 -150
  30. package/dist/default/dashboard/tsconfig.json +3 -2
  31. package/dist/default/dashboard/vite.config.ts +6 -0
  32. package/dist/index.js +256 -49
  33. package/dist/index.js.map +1 -1
  34. package/package.json +1 -1
  35. package/templates/default/convex/agents.ts +204 -0
  36. package/templates/default/convex/apiKeys.ts +133 -0
  37. package/templates/default/convex/cronJobs.ts +224 -0
  38. package/templates/default/convex/files.ts +103 -0
  39. package/templates/default/convex/folders.ts +110 -0
  40. package/templates/default/convex/heartbeat.ts +371 -0
  41. package/templates/default/convex/logs.ts +66 -0
  42. package/templates/default/convex/mastraIntegration.ts +184 -0
  43. package/templates/default/convex/mcpConnections.ts +127 -0
  44. package/templates/default/convex/messages.ts +90 -0
  45. package/templates/default/convex/projects.ts +114 -0
  46. package/templates/default/convex/sessions.ts +174 -0
  47. package/templates/default/convex/settings.ts +79 -0
  48. package/templates/default/convex/skills.ts +178 -0
  49. package/templates/default/convex/threads.ts +100 -0
  50. package/templates/default/convex/usage.ts +195 -0
  51. package/templates/default/convex/vault.ts +383 -0
  52. package/templates/default/dashboard/app/main.tsx +7 -3
  53. package/templates/default/dashboard/app/routes/agents.tsx +103 -161
  54. package/templates/default/dashboard/app/routes/chat.tsx +163 -317
  55. package/templates/default/dashboard/app/routes/connections.tsx +247 -386
  56. package/templates/default/dashboard/app/routes/cron.tsx +127 -286
  57. package/templates/default/dashboard/app/routes/files.tsx +184 -167
  58. package/templates/default/dashboard/app/routes/index.tsx +63 -96
  59. package/templates/default/dashboard/app/routes/projects.tsx +106 -225
  60. package/templates/default/dashboard/app/routes/sessions.tsx +87 -253
  61. package/templates/default/dashboard/app/routes/settings.tsx +316 -532
  62. package/templates/default/dashboard/app/routes/skills.tsx +329 -216
  63. package/templates/default/dashboard/app/routes/usage.tsx +107 -150
  64. package/templates/default/dashboard/tsconfig.json +3 -2
  65. package/templates/default/dashboard/vite.config.ts +6 -0
@@ -0,0 +1,79 @@
1
+ import { v } from "convex/values";
2
+ import { mutation, query } from "./_generated/server";
3
+
4
+ // Query: Get a setting by key
5
+ export const get = query({
6
+ args: { userId: v.string(), key: v.string() },
7
+ handler: async (ctx, args) => {
8
+ const setting = await ctx.db
9
+ .query("settings")
10
+ .withIndex("byUserIdAndKey", (q) =>
11
+ q.eq("userId", args.userId).eq("key", args.key)
12
+ )
13
+ .first();
14
+ return setting;
15
+ },
16
+ });
17
+
18
+ // Query: List all settings for a user
19
+ export const list = query({
20
+ args: { userId: v.optional(v.string()) },
21
+ handler: async (ctx, args) => {
22
+ if (args.userId) {
23
+ return await ctx.db
24
+ .query("settings")
25
+ .withIndex("byUserId", (q) => q.eq("userId", args.userId!))
26
+ .collect();
27
+ }
28
+ return await ctx.db.query("settings").collect();
29
+ },
30
+ });
31
+
32
+ // Mutation: Set a setting (upsert)
33
+ export const set = mutation({
34
+ args: {
35
+ userId: v.string(),
36
+ key: v.string(),
37
+ value: v.any(),
38
+ },
39
+ handler: async (ctx, args) => {
40
+ const existing = await ctx.db
41
+ .query("settings")
42
+ .withIndex("byUserIdAndKey", (q) =>
43
+ q.eq("userId", args.userId).eq("key", args.key)
44
+ )
45
+ .first();
46
+
47
+ if (existing) {
48
+ await ctx.db.patch(existing._id, {
49
+ value: args.value,
50
+ updatedAt: Date.now(),
51
+ });
52
+ return existing._id;
53
+ }
54
+
55
+ return await ctx.db.insert("settings", {
56
+ userId: args.userId,
57
+ key: args.key,
58
+ value: args.value,
59
+ updatedAt: Date.now(),
60
+ });
61
+ },
62
+ });
63
+
64
+ // Mutation: Delete a setting
65
+ export const remove = mutation({
66
+ args: { userId: v.string(), key: v.string() },
67
+ handler: async (ctx, args) => {
68
+ const existing = await ctx.db
69
+ .query("settings")
70
+ .withIndex("byUserIdAndKey", (q) =>
71
+ q.eq("userId", args.userId).eq("key", args.key)
72
+ )
73
+ .first();
74
+
75
+ if (existing) {
76
+ await ctx.db.delete(existing._id);
77
+ }
78
+ },
79
+ });
@@ -0,0 +1,178 @@
1
+ import { v } from "convex/values";
2
+ import { mutation, query } from "./_generated/server";
3
+
4
+ // Query: List skills
5
+ export const list = query({
6
+ args: {
7
+ userId: v.optional(v.string()),
8
+ category: v.optional(v.string()),
9
+ isInstalled: v.optional(v.boolean()),
10
+ },
11
+ handler: async (ctx, args) => {
12
+ if (args.category) {
13
+ const skills = await ctx.db
14
+ .query("skills")
15
+ .withIndex("byCategory", (q) => q.eq("category", args.category))
16
+ .take(100).collect();
17
+
18
+ if (args.userId) {
19
+ return skills.filter((s) => s.userId === args.userId);
20
+ }
21
+ if (args.isInstalled !== undefined) {
22
+ return skills.filter((s) => s.isInstalled === args.isInstalled);
23
+ }
24
+ return skills;
25
+ }
26
+
27
+ if (args.isInstalled !== undefined) {
28
+ const skills = await ctx.db
29
+ .query("skills")
30
+ .withIndex("byIsInstalled", (q) => q.eq("isInstalled", args.isInstalled))
31
+ .take(100).collect();
32
+
33
+ if (args.userId) {
34
+ return skills.filter((s) => s.userId === args.userId);
35
+ }
36
+ return skills;
37
+ }
38
+
39
+ if (args.userId) {
40
+ return await ctx.db
41
+ .query("skills")
42
+ .withIndex("byUserId", (q) => q.eq("userId", args.userId))
43
+ .take(100).collect();
44
+ }
45
+
46
+ return await ctx.db.query("skills").take(100).collect();
47
+ },
48
+ });
49
+
50
+ // Query: Get skill by ID
51
+ export const get = query({
52
+ args: { id: v.id("skills") },
53
+ handler: async (ctx, args) => {
54
+ return await ctx.db.get(args.id);
55
+ },
56
+ });
57
+
58
+ // Query: Get installed skills
59
+ export const listInstalled = query({
60
+ args: {
61
+ userId: v.optional(v.string()),
62
+ },
63
+ handler: async (ctx, args) => {
64
+ const skills = await ctx.db
65
+ .query("skills")
66
+ .withIndex("byIsInstalled", (q) => q.eq("isInstalled", true))
67
+ .take(100).collect();
68
+
69
+ if (args.userId) {
70
+ return skills.filter((s) => s.userId === args.userId);
71
+ }
72
+
73
+ return skills;
74
+ },
75
+ });
76
+
77
+ // Mutation: Create skill
78
+ export const create = mutation({
79
+ args: {
80
+ name: v.string(),
81
+ displayName: v.string(),
82
+ description: v.string(),
83
+ category: v.string(),
84
+ version: v.string(),
85
+ author: v.optional(v.string()),
86
+ repository: v.optional(v.string()),
87
+ documentation: v.optional(v.string()),
88
+ code: v.string(),
89
+ schema: v.optional(v.any()),
90
+ userId: v.optional(v.string()),
91
+ },
92
+ handler: async (ctx, args) => {
93
+ const now = Date.now();
94
+ const skillId = await ctx.db.insert("skills", {
95
+ ...args,
96
+ isInstalled: false,
97
+ isEnabled: false,
98
+ createdAt: now,
99
+ updatedAt: now,
100
+ });
101
+ return skillId;
102
+ },
103
+ });
104
+
105
+ // Mutation: Install skill
106
+ export const install = mutation({
107
+ args: { id: v.id("skills") },
108
+ handler: async (ctx, args) => {
109
+ await ctx.db.patch(args.id, {
110
+ isInstalled: true,
111
+ isEnabled: true,
112
+ installedAt: Date.now(),
113
+ updatedAt: Date.now(),
114
+ });
115
+ return args.id;
116
+ },
117
+ });
118
+
119
+ // Mutation: Uninstall skill
120
+ export const uninstall = mutation({
121
+ args: { id: v.id("skills") },
122
+ handler: async (ctx, args) => {
123
+ await ctx.db.patch(args.id, {
124
+ isInstalled: false,
125
+ isEnabled: false,
126
+ updatedAt: Date.now(),
127
+ });
128
+ return args.id;
129
+ },
130
+ });
131
+
132
+ // Mutation: Toggle skill enabled status
133
+ export const toggleEnabled = mutation({
134
+ args: { id: v.id("skills") },
135
+ handler: async (ctx, args) => {
136
+ const skill = await ctx.db.get(args.id);
137
+
138
+ if (!skill) {
139
+ throw new Error(`Skill not found`);
140
+ }
141
+
142
+ await ctx.db.patch(args.id, {
143
+ isEnabled: !skill.isEnabled,
144
+ updatedAt: Date.now(),
145
+ });
146
+
147
+ return { success: true, isEnabled: !skill.isEnabled };
148
+ },
149
+ });
150
+
151
+ // Mutation: Update skill
152
+ export const update = mutation({
153
+ args: {
154
+ id: v.id("skills"),
155
+ displayName: v.optional(v.string()),
156
+ description: v.optional(v.string()),
157
+ version: v.optional(v.string()),
158
+ code: v.optional(v.string()),
159
+ schema: v.optional(v.any()),
160
+ },
161
+ handler: async (ctx, args) => {
162
+ const { id, ...updates } = args;
163
+ await ctx.db.patch(id, {
164
+ ...updates,
165
+ updatedAt: Date.now(),
166
+ });
167
+ return id;
168
+ },
169
+ });
170
+
171
+ // Mutation: Delete skill
172
+ export const remove = mutation({
173
+ args: { id: v.id("skills") },
174
+ handler: async (ctx, args) => {
175
+ await ctx.db.delete(args.id);
176
+ return { success: true };
177
+ },
178
+ });
@@ -0,0 +1,100 @@
1
+ import { v } from "convex/values";
2
+ import { mutation, query } from "./_generated/server";
3
+
4
+ // Query: Get all threads
5
+ export const list = query({
6
+ args: {
7
+ userId: v.optional(v.string()),
8
+ agentId: v.optional(v.string()),
9
+ projectId: v.optional(v.id("projects")),
10
+ },
11
+ handler: async (ctx, args) => {
12
+ if (args.projectId) {
13
+ return await ctx.db
14
+ .query("threads")
15
+ .withIndex("byProjectId", (q) => q.eq("projectId", args.projectId))
16
+ .take(100).collect();
17
+ }
18
+
19
+ if (args.agentId) {
20
+ return await ctx.db
21
+ .query("threads")
22
+ .withIndex("byAgentId", (q) => q.eq("agentId", args.agentId))
23
+ .take(100).collect();
24
+ }
25
+
26
+ if (args.userId) {
27
+ return await ctx.db
28
+ .query("threads")
29
+ .withIndex("byUserId", (q) => q.eq("userId", args.userId))
30
+ .take(100).collect();
31
+ }
32
+
33
+ return await ctx.db.query("threads").take(100).collect();
34
+ },
35
+ });
36
+
37
+ // Query: Get thread by ID
38
+ export const get = query({
39
+ args: { id: v.id("threads") },
40
+ handler: async (ctx, args) => {
41
+ return await ctx.db.get(args.id);
42
+ },
43
+ });
44
+
45
+ // Mutation: Create a new thread
46
+ export const create = mutation({
47
+ args: {
48
+ name: v.optional(v.string()),
49
+ agentId: v.string(),
50
+ userId: v.optional(v.string()),
51
+ projectId: v.optional(v.id("projects")),
52
+ metadata: v.optional(v.any()),
53
+ },
54
+ handler: async (ctx, args) => {
55
+ const now = Date.now();
56
+ const threadId = await ctx.db.insert("threads", {
57
+ ...args,
58
+ createdAt: now,
59
+ updatedAt: now,
60
+ });
61
+ return threadId;
62
+ },
63
+ });
64
+
65
+ // Mutation: Update thread
66
+ export const update = mutation({
67
+ args: {
68
+ id: v.id("threads"),
69
+ name: v.optional(v.string()),
70
+ metadata: v.optional(v.any()),
71
+ },
72
+ handler: async (ctx, args) => {
73
+ const { id, ...updates } = args;
74
+ await ctx.db.patch(id, {
75
+ ...updates,
76
+ updatedAt: Date.now(),
77
+ });
78
+ return id;
79
+ },
80
+ });
81
+
82
+ // Mutation: Delete thread
83
+ export const remove = mutation({
84
+ args: { id: v.id("threads") },
85
+ handler: async (ctx, args) => {
86
+ // Delete all messages in the thread
87
+ const messages = await ctx.db
88
+ .query("messages")
89
+ .withIndex("byThread", (q) => q.eq("threadId", args.id))
90
+ .take(100).collect();
91
+
92
+ for (const message of messages) {
93
+ await ctx.db.delete(message._id);
94
+ }
95
+
96
+ // Delete the thread
97
+ await ctx.db.delete(args.id);
98
+ return { success: true };
99
+ },
100
+ });
@@ -0,0 +1,195 @@
1
+ import { v } from "convex/values";
2
+ import { mutation, query } from "./_generated/server";
3
+
4
+ // Query: Get usage records
5
+ export const list = query({
6
+ args: {
7
+ userId: v.optional(v.string()),
8
+ agentId: v.optional(v.string()),
9
+ provider: v.optional(v.string()),
10
+ startTime: v.optional(v.number()),
11
+ endTime: v.optional(v.number()),
12
+ },
13
+ handler: async (ctx, args) => {
14
+ let records;
15
+
16
+ if (args.provider) {
17
+ records = await ctx.db
18
+ .query("usage")
19
+ .withIndex("byProvider", (q) => q.eq("provider", args.provider))
20
+ .take(100).collect();
21
+ } else if (args.agentId) {
22
+ records = await ctx.db
23
+ .query("usage")
24
+ .withIndex("byAgentId", (q) => q.eq("agentId", args.agentId))
25
+ .take(100).collect();
26
+ } else if (args.userId) {
27
+ records = await ctx.db
28
+ .query("usage")
29
+ .withIndex("byUserId", (q) => q.eq("userId", args.userId))
30
+ .take(100).collect();
31
+ } else {
32
+ records = await ctx.db.query("usage").take(100).collect();
33
+ }
34
+
35
+ // Filter by time range if provided
36
+ if (args.startTime) {
37
+ records = records.filter((r) => r.timestamp >= args.startTime!);
38
+ }
39
+ if (args.endTime) {
40
+ records = records.filter((r) => r.timestamp <= args.endTime!);
41
+ }
42
+
43
+ return records;
44
+ },
45
+ });
46
+
47
+ // Query: Get usage statistics
48
+ export const getStats = query({
49
+ args: {
50
+ userId: v.optional(v.string()),
51
+ agentId: v.optional(v.string()),
52
+ startTime: v.optional(v.number()),
53
+ endTime: v.optional(v.number()),
54
+ },
55
+ handler: async (ctx, args) => {
56
+ let records;
57
+
58
+ if (args.agentId) {
59
+ records = await ctx.db
60
+ .query("usage")
61
+ .withIndex("byAgentId", (q) => q.eq("agentId", args.agentId))
62
+ .take(100).collect();
63
+ } else if (args.userId) {
64
+ records = await ctx.db
65
+ .query("usage")
66
+ .withIndex("byUserId", (q) => q.eq("userId", args.userId))
67
+ .take(100).collect();
68
+ } else {
69
+ records = await ctx.db.query("usage").take(100).collect();
70
+ }
71
+
72
+ // Filter by time range
73
+ if (args.startTime) {
74
+ records = records.filter((r) => r.timestamp >= args.startTime!);
75
+ }
76
+ if (args.endTime) {
77
+ records = records.filter((r) => r.timestamp <= args.endTime!);
78
+ }
79
+
80
+ // Calculate statistics
81
+ const totalTokens = records.reduce((sum, r) => sum + r.totalTokens, 0);
82
+ const totalCost = records.reduce((sum, r) => sum + (r.cost || 0), 0);
83
+ const totalRequests = records.length;
84
+
85
+ const byProvider: Record<string, { tokens: number; cost: number; requests: number }> = {};
86
+ const byModel: Record<string, { tokens: number; cost: number; requests: number }> = {};
87
+
88
+ for (const record of records) {
89
+ // By provider
90
+ if (!byProvider[record.provider]) {
91
+ byProvider[record.provider] = { tokens: 0, cost: 0, requests: 0 };
92
+ }
93
+ byProvider[record.provider].tokens += record.totalTokens;
94
+ byProvider[record.provider].cost += record.cost || 0;
95
+ byProvider[record.provider].requests += 1;
96
+
97
+ // By model
98
+ if (!byModel[record.model]) {
99
+ byModel[record.model] = { tokens: 0, cost: 0, requests: 0 };
100
+ }
101
+ byModel[record.model].tokens += record.totalTokens;
102
+ byModel[record.model].cost += record.cost || 0;
103
+ byModel[record.model].requests += 1;
104
+ }
105
+
106
+ return {
107
+ totalTokens,
108
+ totalCost,
109
+ totalRequests,
110
+ byProvider,
111
+ byModel,
112
+ };
113
+ },
114
+ });
115
+
116
+ // Query: Get usage by time period
117
+ export const getByTimePeriod = query({
118
+ args: {
119
+ userId: v.optional(v.string()),
120
+ period: v.union(v.literal("day"), v.literal("week"), v.literal("month")),
121
+ },
122
+ handler: async (ctx, args) => {
123
+ const now = Date.now();
124
+ let startTime: number;
125
+
126
+ switch (args.period) {
127
+ case "day":
128
+ startTime = now - 24 * 60 * 60 * 1000;
129
+ break;
130
+ case "week":
131
+ startTime = now - 7 * 24 * 60 * 60 * 1000;
132
+ break;
133
+ case "month":
134
+ startTime = now - 30 * 24 * 60 * 60 * 1000;
135
+ break;
136
+ }
137
+
138
+ let records;
139
+ if (args.userId) {
140
+ records = await ctx.db
141
+ .query("usage")
142
+ .withIndex("byUserId", (q) => q.eq("userId", args.userId))
143
+ .take(100).collect();
144
+ } else {
145
+ records = await ctx.db.query("usage").take(100).collect();
146
+ }
147
+
148
+ records = records.filter((r) => r.timestamp >= startTime);
149
+
150
+ return records;
151
+ },
152
+ });
153
+
154
+ // Mutation: Record usage
155
+ export const record = mutation({
156
+ args: {
157
+ agentId: v.string(),
158
+ sessionId: v.optional(v.string()),
159
+ provider: v.string(),
160
+ model: v.string(),
161
+ promptTokens: v.number(),
162
+ completionTokens: v.number(),
163
+ totalTokens: v.number(),
164
+ cost: v.optional(v.number()),
165
+ userId: v.optional(v.string()),
166
+ },
167
+ handler: async (ctx, args) => {
168
+ const usageId = await ctx.db.insert("usage", {
169
+ ...args,
170
+ timestamp: Date.now(),
171
+ });
172
+ return usageId;
173
+ },
174
+ });
175
+
176
+ // Mutation: Delete old usage records
177
+ export const cleanup = mutation({
178
+ args: {
179
+ olderThan: v.number(), // Timestamp
180
+ },
181
+ handler: async (ctx, args) => {
182
+ const records = await ctx.db
183
+ .query("usage")
184
+ .withIndex("byTimestamp")
185
+ .take(100).collect();
186
+
187
+ const toDelete = records.filter((r) => r.timestamp < args.olderThan);
188
+
189
+ for (const record of toDelete) {
190
+ await ctx.db.delete(record._id);
191
+ }
192
+
193
+ return { deleted: toDelete.length };
194
+ },
195
+ });