@agentforge-ai/cli 0.4.3 → 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 (67) 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 +185 -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/schema.ts +150 -83
  13. package/dist/default/convex/sessions.ts +174 -0
  14. package/dist/default/convex/settings.ts +79 -0
  15. package/dist/default/convex/skills.ts +178 -0
  16. package/dist/default/convex/threads.ts +100 -0
  17. package/dist/default/convex/usage.ts +195 -0
  18. package/dist/default/convex/vault.ts +397 -0
  19. package/dist/default/dashboard/app/main.tsx +7 -3
  20. package/dist/default/dashboard/app/routes/agents.tsx +103 -161
  21. package/dist/default/dashboard/app/routes/chat.tsx +163 -317
  22. package/dist/default/dashboard/app/routes/connections.tsx +247 -386
  23. package/dist/default/dashboard/app/routes/cron.tsx +127 -286
  24. package/dist/default/dashboard/app/routes/files.tsx +184 -167
  25. package/dist/default/dashboard/app/routes/index.tsx +63 -96
  26. package/dist/default/dashboard/app/routes/projects.tsx +106 -225
  27. package/dist/default/dashboard/app/routes/sessions.tsx +87 -253
  28. package/dist/default/dashboard/app/routes/settings.tsx +316 -532
  29. package/dist/default/dashboard/app/routes/skills.tsx +329 -216
  30. package/dist/default/dashboard/app/routes/usage.tsx +107 -150
  31. package/dist/default/dashboard/tsconfig.json +3 -2
  32. package/dist/default/dashboard/vite.config.ts +6 -0
  33. package/dist/index.js +256 -49
  34. package/dist/index.js.map +1 -1
  35. package/package.json +1 -1
  36. package/templates/default/convex/agents.ts +204 -0
  37. package/templates/default/convex/apiKeys.ts +133 -0
  38. package/templates/default/convex/cronJobs.ts +224 -0
  39. package/templates/default/convex/files.ts +103 -0
  40. package/templates/default/convex/folders.ts +110 -0
  41. package/templates/default/convex/heartbeat.ts +371 -0
  42. package/templates/default/convex/logs.ts +66 -0
  43. package/templates/default/convex/mastraIntegration.ts +185 -0
  44. package/templates/default/convex/mcpConnections.ts +127 -0
  45. package/templates/default/convex/messages.ts +90 -0
  46. package/templates/default/convex/projects.ts +114 -0
  47. package/templates/default/convex/schema.ts +150 -83
  48. package/templates/default/convex/sessions.ts +174 -0
  49. package/templates/default/convex/settings.ts +79 -0
  50. package/templates/default/convex/skills.ts +178 -0
  51. package/templates/default/convex/threads.ts +100 -0
  52. package/templates/default/convex/usage.ts +195 -0
  53. package/templates/default/convex/vault.ts +397 -0
  54. package/templates/default/dashboard/app/main.tsx +7 -3
  55. package/templates/default/dashboard/app/routes/agents.tsx +103 -161
  56. package/templates/default/dashboard/app/routes/chat.tsx +163 -317
  57. package/templates/default/dashboard/app/routes/connections.tsx +247 -386
  58. package/templates/default/dashboard/app/routes/cron.tsx +127 -286
  59. package/templates/default/dashboard/app/routes/files.tsx +184 -167
  60. package/templates/default/dashboard/app/routes/index.tsx +63 -96
  61. package/templates/default/dashboard/app/routes/projects.tsx +106 -225
  62. package/templates/default/dashboard/app/routes/sessions.tsx +87 -253
  63. package/templates/default/dashboard/app/routes/settings.tsx +316 -532
  64. package/templates/default/dashboard/app/routes/skills.tsx +329 -216
  65. package/templates/default/dashboard/app/routes/usage.tsx +107 -150
  66. package/templates/default/dashboard/tsconfig.json +3 -2
  67. package/templates/default/dashboard/vite.config.ts +6 -0
@@ -1,272 +1,106 @@
1
1
  import { createFileRoute } from '@tanstack/react-router';
2
2
  import { DashboardLayout } from '../components/DashboardLayout';
3
- import { useState, useMemo, useEffect } from 'react';
4
- // import { useQuery, useMutation } from 'convex/react';
5
- // import { api } from '../../convex/_generated/api';
6
- import { Button } from '../components/ui/button';
7
- import { Card, CardContent, CardHeader, CardTitle } from '../components/ui/card';
8
- import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '../components/ui/table';
9
- import { Tabs, TabsContent, TabsList, TabsTrigger } from '../components/ui/tabs';
10
- import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription, SheetFooter, SheetClose } from '../components/ui/sheet';
11
- import { Badge } from '../components/ui/badge';
12
- import { Activity, Clock, MessageSquare, XCircle, Loader2 } from 'lucide-react';
3
+ import { useState, useMemo } from 'react';
4
+ import { useQuery, useMutation } from 'convex/react';
5
+ import { api } from '@convex/_generated/api';
6
+ import { Activity, Clock, Trash2, Search, Filter, X, MessageSquare } from 'lucide-react';
13
7
 
14
- // Mock data structure, aligned with the requirements
15
- const mockSessions = [
16
- {
17
- _id: 's1',
18
- agentId: 'agent-001',
19
- status: 'active',
20
- _creationTime: new Date().getTime() - 1000 * 60 * 5,
21
- messageCount: 42,
22
- },
23
- {
24
- _id: 's2',
25
- agentId: 'agent-007',
26
- status: 'idle',
27
- _creationTime: new Date().getTime() - 1000 * 60 * 30,
28
- messageCount: 12,
29
- },
30
- {
31
- _id: 's3',
32
- agentId: 'agent-002',
33
- status: 'ended',
34
- _creationTime: new Date().getTime() - 1000 * 60 * 120,
35
- endTime: new Date().getTime() - 1000 * 60 * 60,
36
- messageCount: 150,
37
- },
38
- {
39
- _id: 's4',
40
- agentId: 'agent-001',
41
- status: 'active',
42
- _creationTime: new Date().getTime() - 1000 * 60 * 2,
43
- messageCount: 5,
44
- },
45
- ];
46
-
47
- type Session = typeof mockSessions[0] & { endTime?: number };
48
-
49
- export const Route = createFileRoute('/sessions')({
50
- component: SessionsPage,
51
- });
52
-
53
- function formatDuration(startTime: number, endTime?: number) {
54
- const end = endTime ? endTime : new Date().getTime();
55
- const seconds = Math.floor((end - startTime) / 1000);
56
- if (seconds < 60) return `${seconds}s`;
57
- const minutes = Math.floor(seconds / 60);
58
- if (minutes < 60) return `${minutes}m ${seconds % 60}s`;
59
- const hours = Math.floor(minutes / 60);
60
- return `${hours}h ${minutes % 60}m`;
61
- }
8
+ export const Route = createFileRoute('/sessions')({ component: SessionsPage });
62
9
 
63
10
  function SessionsPage() {
64
- const [sessions, setSessions] = useState<Session[]>([]);
65
- const [isLoading, setIsLoading] = useState(true);
66
- const [error, setError] = useState<string | null>(null);
67
- const [statusFilter, setStatusFilter] = useState('all');
68
- const [selectedSession, setSelectedSession] = useState<Session | null>(null);
11
+ const sessions = useQuery(api.sessions.list, {}) ?? [];
12
+ const removeSession = useMutation(api.sessions.remove);
13
+ const [searchQuery, setSearchQuery] = useState('');
14
+ const [statusFilter, setStatusFilter] = useState<string>('all');
69
15
 
70
- // --- Commented-out Convex Hooks ---
71
- /*
72
- const sessionsData = useQuery(
73
- api.sessions.listByStatus,
74
- statusFilter === 'all' ? {} : { status: statusFilter }
75
- );
76
- const endSessionMutation = useMutation(api.sessions.endSession);
77
-
78
- useEffect(() => {
79
- if (sessionsData === undefined) {
80
- setIsLoading(true);
81
- setError(null);
82
- } else if (sessionsData) {
83
- setSessions(sessionsData);
84
- setIsLoading(false);
85
- } else {
86
- // Handle potential query error from Convex
87
- setIsLoading(false);
88
- setError("Failed to fetch sessions.");
16
+ const filtered = useMemo(() => {
17
+ let result = sessions;
18
+ if (statusFilter !== 'all') {
19
+ result = result.filter((s: any) => s.status === statusFilter);
89
20
  }
90
- }, [sessionsData]);
91
- */
92
-
93
- // Local state simulation of fetching data
94
- useEffect(() => {
95
- setIsLoading(true);
96
- setError(null);
97
- const timer = setTimeout(() => {
98
- try {
99
- // Simulate API call
100
- setSessions(mockSessions.map(s => ({...s, endTime: s.status === 'ended' ? (s as any).endTime : undefined })));
101
- setIsLoading(false);
102
- } catch (e) {
103
- setError("Failed to load sessions.");
104
- setIsLoading(false);
105
- }
106
- }, 1000);
107
- return () => clearTimeout(timer);
108
- }, []);
109
-
110
- const handleEndSession = async (sessionId: string) => {
111
- // Optimistic update for local state
112
- setSessions(prev =>
113
- prev.map(s =>
114
- s._id === sessionId ? { ...s, status: 'ended', endTime: new Date().getTime() } : s
115
- )
116
- );
117
-
118
- // --- Commented-out Convex Mutation Call ---
119
- /*
120
- try {
121
- await endSessionMutation({ sessionId });
122
- // Optionally, you can show a toast notification for success
123
- } catch (err) {
124
- console.error("Failed to end session:", err);
125
- // Revert optimistic update on failure
126
- setSessions(sessionsData || []); // Revert to original data from query
127
- // Optionally, show an error toast
21
+ if (searchQuery) {
22
+ const q = searchQuery.toLowerCase();
23
+ result = result.filter((s: any) => s.sessionId.toLowerCase().includes(q) || s.agentId.toLowerCase().includes(q));
128
24
  }
129
- */
130
- };
25
+ return result;
26
+ }, [sessions, searchQuery, statusFilter]);
131
27
 
132
- const filteredSessions = useMemo(() => {
133
- if (statusFilter === 'all') {
134
- return sessions;
28
+ const handleDelete = async (id: any) => {
29
+ if (confirm('Delete this session?')) {
30
+ await removeSession({ id });
135
31
  }
136
- return sessions.filter(s => s.status === statusFilter);
137
- }, [sessions, statusFilter]);
32
+ };
138
33
 
139
- const statusBadge = (status: string) => {
140
- switch (status) {
141
- case 'active':
142
- return <Badge variant="default" className="bg-green-500 text-white">Active</Badge>;
143
- case 'idle':
144
- return <Badge variant="secondary" className="bg-yellow-500 text-white">Idle</Badge>;
145
- case 'ended':
146
- return <Badge variant="destructive" className="bg-gray-500 text-white">Ended</Badge>;
147
- default:
148
- return <Badge>{status}</Badge>;
149
- }
34
+ const statusColors: Record<string, string> = {
35
+ active: 'bg-green-500/10 text-green-500',
36
+ paused: 'bg-yellow-500/10 text-yellow-500',
37
+ completed: 'bg-blue-500/10 text-blue-500',
38
+ error: 'bg-red-500/10 text-red-500',
150
39
  };
151
40
 
152
41
  return (
153
42
  <DashboardLayout>
154
- <div className="p-4 md:p-6 lg:p-8">
155
- <h1 className="text-2xl font-bold mb-4">Sessions</h1>
156
- <Card>
157
- <CardHeader>
158
- <CardTitle>Manage and monitor all user sessions.</CardTitle>
159
- <Tabs value={statusFilter} onValueChange={setStatusFilter} className="w-full pt-4">
160
- <TabsList>
161
- <TabsTrigger value="all">All</TabsTrigger>
162
- <TabsTrigger value="active">Active</TabsTrigger>
163
- <TabsTrigger value="idle">Idle</TabsTrigger>
164
- <TabsTrigger value="ended">Ended</TabsTrigger>
165
- </TabsList>
166
- </Tabs>
167
- </CardHeader>
168
- <CardContent>
169
- {isLoading ? (
170
- <div className="flex justify-center items-center h-64">
171
- <Loader2 className="h-8 w-8 animate-spin text-primary" />
172
- </div>
173
- ) : error ? (
174
- <div className="text-center text-destructive py-10">{error}</div>
175
- ) : filteredSessions.length === 0 ? (
176
- <div className="text-center text-muted-foreground py-10">
177
- <p className="text-lg">No sessions found.</p>
178
- <p>Start a new chat to create a session.</p>
179
- </div>
180
- ) : (
181
- <div className="overflow-x-auto">
182
- <Table>
183
- <TableHeader>
184
- <TableRow>
185
- <TableHead>Session ID</TableHead>
186
- <TableHead>Agent</TableHead>
187
- <TableHead>Status</TableHead>
188
- <TableHead>Started</TableHead>
189
- <TableHead>Duration</TableHead>
190
- <TableHead className="text-right">Messages</TableHead>
191
- <TableHead className="text-right">Actions</TableHead>
192
- </TableRow>
193
- </TableHeader>
194
- <TableBody>
195
- {filteredSessions.map(session => (
196
- <TableRow key={session._id} onClick={() => setSelectedSession(session)} className="cursor-pointer hover:bg-muted/50">
197
- <TableCell className="font-mono text-xs">{session._id}</TableCell>
198
- <TableCell>{session.agentId}</TableCell>
199
- <TableCell>{statusBadge(session.status)}</TableCell>
200
- <TableCell>{new Date(session._creationTime).toLocaleString()}</TableCell>
201
- <TableCell>{formatDuration(session._creationTime, session.endTime)}</TableCell>
202
- <TableCell className="text-right">{session.messageCount}</TableCell>
203
- <TableCell className="text-right">
204
- {session.status !== 'ended' && (
205
- <Button
206
- variant="destructive"
207
- size="sm"
208
- onClick={(e) => { e.stopPropagation(); handleEndSession(session._id); }}
209
- >
210
- <XCircle className="h-4 w-4 mr-2" />
211
- End Session
212
- </Button>
213
- )}
214
- </TableCell>
215
- </TableRow>
216
- ))}
217
- </TableBody>
218
- </Table>
219
- </div>
220
- )}
221
- </CardContent>
222
- </Card>
223
- </div>
43
+ <div className="space-y-6">
44
+ <div>
45
+ <h1 className="text-3xl font-bold">Sessions</h1>
46
+ <p className="text-muted-foreground">Monitor active and past agent sessions.</p>
47
+ </div>
48
+
49
+ <div className="flex flex-col sm:flex-row gap-3">
50
+ <div className="relative flex-1 max-w-sm">
51
+ <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
52
+ <input type="text" placeholder="Search by session or agent ID..." value={searchQuery} onChange={(e) => setSearchQuery(e.target.value)} className="pl-9 pr-3 py-2 bg-card border border-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary w-full" />
53
+ </div>
54
+ <select value={statusFilter} onChange={(e) => setStatusFilter(e.target.value)} className="bg-card border border-border rounded-lg px-3 py-2 text-sm">
55
+ <option value="all">All Statuses</option>
56
+ <option value="active">Active</option>
57
+ <option value="paused">Paused</option>
58
+ <option value="completed">Completed</option>
59
+ <option value="error">Error</option>
60
+ </select>
61
+ </div>
224
62
 
225
- <Sheet open={!!selectedSession} onOpenChange={(open) => !open && setSelectedSession(null)}>
226
- <SheetContent className="w-full sm:max-w-lg bg-background border-l">
227
- {selectedSession && (
228
- <>
229
- <SheetHeader>
230
- <SheetTitle>Session Details</SheetTitle>
231
- <SheetDescription className="font-mono text-xs pt-2">{selectedSession._id}</SheetDescription>
232
- </SheetHeader>
233
- <div className="py-6 space-y-4">
234
- <div className="flex items-center justify-between">
235
- <span className="text-muted-foreground">Status</span>
236
- {statusBadge(selectedSession.status)}
237
- </div>
238
- <div className="flex items-center justify-between">
239
- <span className="text-muted-foreground flex items-center"><Activity className="h-4 w-4 mr-2" />Agent</span>
240
- <span>{selectedSession.agentId}</span>
241
- </div>
242
- <div className="flex items-center justify-between">
243
- <span className="text-muted-foreground flex items-center"><Clock className="h-4 w-4 mr-2" />Started</span>
244
- <span>{new Date(selectedSession._creationTime).toLocaleString()}</span>
245
- </div>
246
- <div className="flex items-center justify-between">
247
- <span className="text-muted-foreground flex items-center"><Clock className="h-4 w-4 mr-2" />Duration</span>
248
- <span>{formatDuration(selectedSession._creationTime, selectedSession.endTime)}</span>
249
- </div>
250
- <div className="flex items-center justify-between">
251
- <span className="text-muted-foreground flex items-center"><MessageSquare className="h-4 w-4 mr-2" />Messages</span>
252
- <span>{selectedSession.messageCount}</span>
253
- </div>
254
- {selectedSession.status === 'ended' && selectedSession.endTime && (
255
- <div className="flex items-center justify-between">
256
- <span className="text-muted-foreground flex items-center"><XCircle className="h-4 w-4 mr-2" />Ended</span>
257
- <span>{new Date(selectedSession.endTime).toLocaleString()}</span>
258
- </div>
259
- )}
260
- </div>
261
- <SheetFooter>
262
- <SheetClose asChild>
263
- <Button variant="outline">Close</Button>
264
- </SheetClose>
265
- </SheetFooter>
266
- </>
267
- )}
268
- </SheetContent>
269
- </Sheet>
63
+ {filtered.length === 0 ? (
64
+ <div className="text-center py-16 bg-card border border-border rounded-lg">
65
+ <Activity className="w-16 h-16 text-muted-foreground/30 mx-auto mb-4" />
66
+ <h3 className="text-lg font-semibold mb-2">{sessions.length === 0 ? 'No sessions yet' : 'No matching sessions'}</h3>
67
+ <p className="text-muted-foreground">Sessions are created when agents start conversations.</p>
68
+ </div>
69
+ ) : (
70
+ <div className="bg-card border border-border rounded-lg overflow-hidden">
71
+ <table className="w-full text-sm">
72
+ <thead className="bg-muted/50">
73
+ <tr>
74
+ <th className="text-left px-4 py-3 font-medium text-muted-foreground">Session ID</th>
75
+ <th className="text-left px-4 py-3 font-medium text-muted-foreground">Agent</th>
76
+ <th className="text-left px-4 py-3 font-medium text-muted-foreground">Status</th>
77
+ <th className="text-left px-4 py-3 font-medium text-muted-foreground">Channel</th>
78
+ <th className="text-left px-4 py-3 font-medium text-muted-foreground">Started</th>
79
+ <th className="text-left px-4 py-3 font-medium text-muted-foreground">Last Activity</th>
80
+ <th className="text-right px-4 py-3 font-medium text-muted-foreground">Actions</th>
81
+ </tr>
82
+ </thead>
83
+ <tbody>
84
+ {filtered.map((session: any) => (
85
+ <tr key={session._id} className="border-t border-border hover:bg-muted/30">
86
+ <td className="px-4 py-3 font-mono text-xs">{session.sessionId}</td>
87
+ <td className="px-4 py-3">{session.agentId}</td>
88
+ <td className="px-4 py-3">
89
+ <span className={`text-xs px-2 py-0.5 rounded-full ${statusColors[session.status] || 'bg-muted text-muted-foreground'}`}>{session.status}</span>
90
+ </td>
91
+ <td className="px-4 py-3 text-muted-foreground">{session.channel || 'dashboard'}</td>
92
+ <td className="px-4 py-3 text-muted-foreground text-xs">{new Date(session.startedAt).toLocaleString()}</td>
93
+ <td className="px-4 py-3 text-muted-foreground text-xs">{new Date(session.lastActivityAt).toLocaleString()}</td>
94
+ <td className="px-4 py-3 text-right">
95
+ <button onClick={() => handleDelete(session._id)} className="p-1.5 rounded hover:bg-destructive/10"><Trash2 className="w-4 h-4 text-destructive" /></button>
96
+ </td>
97
+ </tr>
98
+ ))}
99
+ </tbody>
100
+ </table>
101
+ </div>
102
+ )}
103
+ </div>
270
104
  </DashboardLayout>
271
105
  );
272
106
  }