@agentforge-ai/cli 0.4.2 → 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.
- package/dist/default/README.md +81 -81
- package/dist/default/convex/agents.ts +204 -0
- package/dist/default/convex/apiKeys.ts +133 -0
- package/dist/default/convex/cronJobs.ts +224 -0
- package/dist/default/convex/files.ts +103 -0
- package/dist/default/convex/folders.ts +110 -0
- package/dist/default/convex/heartbeat.ts +371 -0
- package/dist/default/convex/logs.ts +66 -0
- package/dist/default/convex/mastraIntegration.ts +184 -0
- package/dist/default/convex/mcpConnections.ts +127 -0
- package/dist/default/convex/messages.ts +90 -0
- package/dist/default/convex/projects.ts +114 -0
- package/dist/default/convex/sessions.ts +174 -0
- package/dist/default/convex/settings.ts +79 -0
- package/dist/default/convex/skills.ts +178 -0
- package/dist/default/convex/threads.ts +100 -0
- package/dist/default/convex/usage.ts +195 -0
- package/dist/default/convex/vault.ts +383 -0
- package/dist/default/dashboard/app/main.tsx +7 -3
- package/dist/default/dashboard/app/routes/agents.tsx +103 -161
- package/dist/default/dashboard/app/routes/chat.tsx +163 -317
- package/dist/default/dashboard/app/routes/connections.tsx +247 -386
- package/dist/default/dashboard/app/routes/cron.tsx +127 -286
- package/dist/default/dashboard/app/routes/files.tsx +184 -167
- package/dist/default/dashboard/app/routes/index.tsx +63 -96
- package/dist/default/dashboard/app/routes/projects.tsx +106 -225
- package/dist/default/dashboard/app/routes/sessions.tsx +87 -253
- package/dist/default/dashboard/app/routes/settings.tsx +316 -532
- package/dist/default/dashboard/app/routes/skills.tsx +329 -216
- package/dist/default/dashboard/app/routes/usage.tsx +107 -150
- package/dist/default/dashboard/tsconfig.json +3 -2
- package/dist/default/dashboard/vite.config.ts +6 -0
- package/dist/index.js +279 -50
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/default/README.md +81 -81
- package/templates/default/convex/agents.ts +204 -0
- package/templates/default/convex/apiKeys.ts +133 -0
- package/templates/default/convex/cronJobs.ts +224 -0
- package/templates/default/convex/files.ts +103 -0
- package/templates/default/convex/folders.ts +110 -0
- package/templates/default/convex/heartbeat.ts +371 -0
- package/templates/default/convex/logs.ts +66 -0
- package/templates/default/convex/mastraIntegration.ts +184 -0
- package/templates/default/convex/mcpConnections.ts +127 -0
- package/templates/default/convex/messages.ts +90 -0
- package/templates/default/convex/projects.ts +114 -0
- package/templates/default/convex/sessions.ts +174 -0
- package/templates/default/convex/settings.ts +79 -0
- package/templates/default/convex/skills.ts +178 -0
- package/templates/default/convex/threads.ts +100 -0
- package/templates/default/convex/usage.ts +195 -0
- package/templates/default/convex/vault.ts +383 -0
- package/templates/default/dashboard/app/main.tsx +7 -3
- package/templates/default/dashboard/app/routes/agents.tsx +103 -161
- package/templates/default/dashboard/app/routes/chat.tsx +163 -317
- package/templates/default/dashboard/app/routes/connections.tsx +247 -386
- package/templates/default/dashboard/app/routes/cron.tsx +127 -286
- package/templates/default/dashboard/app/routes/files.tsx +184 -167
- package/templates/default/dashboard/app/routes/index.tsx +63 -96
- package/templates/default/dashboard/app/routes/projects.tsx +106 -225
- package/templates/default/dashboard/app/routes/sessions.tsx +87 -253
- package/templates/default/dashboard/app/routes/settings.tsx +316 -532
- package/templates/default/dashboard/app/routes/skills.tsx +329 -216
- package/templates/default/dashboard/app/routes/usage.tsx +107 -150
- package/templates/default/dashboard/tsconfig.json +3 -2
- 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
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import {
|
|
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
|
-
|
|
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
|
|
65
|
-
const
|
|
66
|
-
const [
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
|
|
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
|
|
133
|
-
if (
|
|
134
|
-
|
|
28
|
+
const handleDelete = async (id: any) => {
|
|
29
|
+
if (confirm('Delete this session?')) {
|
|
30
|
+
await removeSession({ id });
|
|
135
31
|
}
|
|
136
|
-
|
|
137
|
-
}, [sessions, statusFilter]);
|
|
32
|
+
};
|
|
138
33
|
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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="
|
|
155
|
-
<
|
|
156
|
-
|
|
157
|
-
<
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
</
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
<
|
|
240
|
-
<
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
<
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
<
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
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
|
}
|