agentlytics 0.1.19 → 0.2.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/cache.js +3 -2
- package/editors/antigravity.js +532 -31
- package/editors/base.js +87 -0
- package/editors/claude.js +11 -1
- package/editors/codex.js +11 -0
- package/editors/copilot.js +11 -1
- package/editors/cursor.js +11 -1
- package/editors/gemini.js +11 -1
- package/editors/goose.js +30 -8
- package/editors/index.js +40 -1
- package/editors/kiro.js +11 -1
- package/editors/opencode.js +4 -22
- package/editors/vscode.js +11 -1
- package/editors/windsurf.js +21 -10
- package/editors/zed.js +23 -3
- package/index.js +40 -38
- package/package.json +1 -1
- package/server.js +74 -1
- package/ui/src/App.jsx +75 -16
- package/ui/src/components/AiAuditCard.jsx +4 -5
- package/ui/src/components/AnimatedLoader.jsx +14 -0
- package/ui/src/lib/api.js +13 -0
- package/ui/src/pages/Artifacts.jsx +600 -0
- package/ui/src/pages/CostAnalysis.jsx +2 -1
- package/ui/src/pages/Dashboard.jsx +2 -1
- package/ui/src/pages/ProjectDetail.jsx +3 -1
- package/ui/src/pages/Projects.jsx +2 -1
- package/ui/src/pages/RelayDashboard.jsx +2 -1
- package/ui/src/pages/Settings.jsx +2 -1
- package/ui/src/pages/Subscriptions.jsx +2 -1
package/ui/src/App.jsx
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { useState, useEffect, useRef, useCallback } from 'react'
|
|
2
|
-
import { Routes, Route, NavLink } from 'react-router-dom'
|
|
3
|
-
import { Activity, BarChart3, GitCompare, MessageSquare, FolderOpen, DollarSign, CreditCard, Sun, Moon, RefreshCw, AlertTriangle, Github, Terminal, Database, Users, Plug, Copy, Check, Settings as SettingsIcon } from 'lucide-react'
|
|
2
|
+
import { Routes, Route, NavLink, useLocation } from 'react-router-dom'
|
|
3
|
+
import { Activity, BarChart3, GitCompare, MessageSquare, FolderOpen, DollarSign, CreditCard, Sun, Moon, RefreshCw, AlertTriangle, Github, Terminal, Database, Users, Plug, Copy, Check, Settings as SettingsIcon, Package, ChevronDown } from 'lucide-react'
|
|
4
4
|
import { fetchOverview, refetchAgents, fetchMode, fetchRelayConfig, getAuthToken, setOnAuthFailure } from './lib/api'
|
|
5
5
|
import { useTheme } from './lib/theme'
|
|
6
6
|
import AnimatedLogo from './components/AnimatedLogo'
|
|
7
|
+
import AnimatedLoader from './components/AnimatedLoader'
|
|
7
8
|
import LoginScreen from './components/LoginScreen'
|
|
8
9
|
import Dashboard from './pages/Dashboard'
|
|
9
10
|
import Sessions from './pages/Sessions'
|
|
@@ -13,11 +14,58 @@ import Projects from './pages/Projects'
|
|
|
13
14
|
import ProjectDetail from './pages/ProjectDetail'
|
|
14
15
|
import CostAnalysis from './pages/CostAnalysis'
|
|
15
16
|
import SqlViewer from './pages/SqlViewer'
|
|
17
|
+
import Artifacts from './pages/Artifacts'
|
|
16
18
|
import Settings from './pages/Settings'
|
|
17
19
|
import Subscriptions from './pages/Subscriptions'
|
|
18
20
|
import RelayDashboard from './pages/RelayDashboard'
|
|
19
21
|
import RelayUserDetail from './pages/RelayUserDetail'
|
|
20
22
|
|
|
23
|
+
function NavDropdown({ icon: Icon, label, items }) {
|
|
24
|
+
const [open, setOpen] = useState(false)
|
|
25
|
+
const location = useLocation()
|
|
26
|
+
const isActive = items.some(i => i.to === location.pathname)
|
|
27
|
+
const timeout = useRef(null)
|
|
28
|
+
|
|
29
|
+
const enter = () => { clearTimeout(timeout.current); setOpen(true) }
|
|
30
|
+
const leave = () => { timeout.current = setTimeout(() => setOpen(false), 150) }
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<div className="relative" onMouseEnter={enter} onMouseLeave={leave}>
|
|
34
|
+
<button
|
|
35
|
+
className={`flex items-center gap-1.5 px-2.5 py-1 text-[12px] rounded transition ${
|
|
36
|
+
isActive ? 'bg-[var(--c-card)] text-[var(--c-white)]' : 'text-[var(--c-text2)] hover:text-[var(--c-white)]'
|
|
37
|
+
}`}
|
|
38
|
+
>
|
|
39
|
+
<Icon size={12} />
|
|
40
|
+
{label}
|
|
41
|
+
<ChevronDown size={10} style={{ opacity: 0.5 }} />
|
|
42
|
+
</button>
|
|
43
|
+
{open && (
|
|
44
|
+
<div
|
|
45
|
+
className="absolute top-full left-0 mt-1 py-1 rounded shadow-lg min-w-[160px] z-[100]"
|
|
46
|
+
style={{ background: 'var(--c-bg)', border: '1px solid var(--c-border)' }}
|
|
47
|
+
>
|
|
48
|
+
{items.map(({ to, icon: SubIcon, label: subLabel }) => (
|
|
49
|
+
<NavLink
|
|
50
|
+
key={to}
|
|
51
|
+
to={to}
|
|
52
|
+
onClick={() => setOpen(false)}
|
|
53
|
+
className={({ isActive: a }) =>
|
|
54
|
+
`flex items-center gap-2 px-3 py-1.5 text-[12px] transition ${
|
|
55
|
+
a ? 'bg-[var(--c-bg3)] text-[var(--c-white)]' : 'text-[var(--c-text2)] hover:text-[var(--c-white)] hover:bg-[var(--c-bg3)]'
|
|
56
|
+
}`
|
|
57
|
+
}
|
|
58
|
+
>
|
|
59
|
+
<SubIcon size={12} />
|
|
60
|
+
{subLabel}
|
|
61
|
+
</NavLink>
|
|
62
|
+
))}
|
|
63
|
+
</div>
|
|
64
|
+
)}
|
|
65
|
+
</div>
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
|
|
21
69
|
export default function App() {
|
|
22
70
|
const [overview, setOverview] = useState(null)
|
|
23
71
|
const [refetchState, setRefetchState] = useState(null) // null | { scanned, total }
|
|
@@ -82,16 +130,24 @@ export default function App() {
|
|
|
82
130
|
const isRelay = mode === 'relay'
|
|
83
131
|
const showLogin = isRelay && needsAuth && !authed
|
|
84
132
|
|
|
133
|
+
const location = useLocation()
|
|
134
|
+
const isFullWidth = location.pathname === '/artifacts'
|
|
135
|
+
|
|
85
136
|
const nav = isRelay ? [
|
|
86
137
|
{ to: '/', icon: Users, label: 'Team' },
|
|
87
138
|
] : [
|
|
88
139
|
{ to: '/', icon: Activity, label: 'Dashboard' },
|
|
89
|
-
{ to: '/projects', icon: FolderOpen, label: 'Projects' },
|
|
90
140
|
{ to: '/sessions', icon: MessageSquare, label: 'Sessions' },
|
|
91
|
-
{ to: '/
|
|
92
|
-
{
|
|
93
|
-
|
|
94
|
-
|
|
141
|
+
{ to: '/projects', icon: FolderOpen, label: 'Projects' },
|
|
142
|
+
{ icon: DollarSign, label: 'Costs', children: [
|
|
143
|
+
{ to: '/costs', icon: DollarSign, label: 'Cost Analysis' },
|
|
144
|
+
{ to: '/subscriptions', icon: CreditCard, label: 'Subscriptions' },
|
|
145
|
+
]},
|
|
146
|
+
{ icon: BarChart3, label: 'Insights', children: [
|
|
147
|
+
{ to: '/analysis', icon: BarChart3, label: 'Deep Analysis' },
|
|
148
|
+
{ to: '/compare', icon: GitCompare, label: 'Compare' },
|
|
149
|
+
]},
|
|
150
|
+
{ to: '/artifacts', icon: Package, label: 'Artifacts' },
|
|
95
151
|
{ to: '/sql', icon: Database, label: 'SQL' },
|
|
96
152
|
]
|
|
97
153
|
|
|
@@ -107,19 +163,21 @@ export default function App() {
|
|
|
107
163
|
Agentlytics{isRelay && <span className="ml-1.5 text-[10px] font-medium px-1.5 py-0.5" style={{ background: 'rgba(99,102,241,0.15)', color: '#818cf8' }}>relay</span>}
|
|
108
164
|
</span>
|
|
109
165
|
<nav className="flex gap-0.5 ml-2">
|
|
110
|
-
{nav.map((
|
|
166
|
+
{nav.map((item) => item.children ? (
|
|
167
|
+
<NavDropdown key={item.label} icon={item.icon} label={item.label} items={item.children} />
|
|
168
|
+
) : (
|
|
111
169
|
<NavLink
|
|
112
|
-
key={to}
|
|
113
|
-
to={to}
|
|
114
|
-
end={to === '/'}
|
|
170
|
+
key={item.to}
|
|
171
|
+
to={item.to}
|
|
172
|
+
end={item.to === '/'}
|
|
115
173
|
className={({ isActive }) =>
|
|
116
174
|
`flex items-center gap-1.5 px-2.5 py-1 text-[12px] rounded transition ${
|
|
117
175
|
isActive ? 'bg-[var(--c-card)] text-[var(--c-white)]' : 'text-[var(--c-text2)] hover:text-[var(--c-white)]'
|
|
118
176
|
}`
|
|
119
177
|
}
|
|
120
178
|
>
|
|
121
|
-
<
|
|
122
|
-
{label}
|
|
179
|
+
<item.icon size={12} />
|
|
180
|
+
{item.label}
|
|
123
181
|
</NavLink>
|
|
124
182
|
))}
|
|
125
183
|
</nav>
|
|
@@ -196,9 +254,9 @@ export default function App() {
|
|
|
196
254
|
</div>
|
|
197
255
|
)}
|
|
198
256
|
|
|
199
|
-
<main className={isRelay ? 'px-0' : 'p-4 max-w-[1400px] mx-auto'}>
|
|
257
|
+
<main className={isRelay ? 'px-0' : isFullWidth ? 'p-0 overflow-hidden' : 'p-4 max-w-[1400px] mx-auto'}>
|
|
200
258
|
{mode === null ? (
|
|
201
|
-
<
|
|
259
|
+
<AnimatedLoader label="Loading..." />
|
|
202
260
|
) : isRelay ? (
|
|
203
261
|
<Routes>
|
|
204
262
|
<Route path="/" element={<RelayDashboard />} />
|
|
@@ -216,13 +274,14 @@ export default function App() {
|
|
|
216
274
|
<Route path="/analysis" element={<DeepAnalysis overview={overview} />} />
|
|
217
275
|
<Route path="/compare" element={<Compare overview={overview} />} />
|
|
218
276
|
<Route path="/subscriptions" element={<Subscriptions />} />
|
|
277
|
+
<Route path="/artifacts" element={<Artifacts />} />
|
|
219
278
|
<Route path="/sql" element={<SqlViewer />} />
|
|
220
279
|
<Route path="/settings" element={<Settings />} />
|
|
221
280
|
</Routes>
|
|
222
281
|
)}
|
|
223
282
|
</main>
|
|
224
283
|
|
|
225
|
-
<footer className=
|
|
284
|
+
<footer className={`border-t mt-8 px-4 py-3 flex items-center justify-between text-[11px]${isFullWidth ? ' hidden' : ''}`} style={{ borderColor: 'var(--c-border)', color: 'var(--c-text3)' }}>
|
|
226
285
|
<div className="flex items-center gap-3">
|
|
227
286
|
<a href="https://github.com/f/agentlytics" target="_blank" rel="noopener noreferrer" className="flex items-center gap-1 hover:text-[var(--c-text)] transition">
|
|
228
287
|
<Github size={11} />
|
|
@@ -68,13 +68,14 @@ function Tip({ missing }) {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
export default function AiAuditCard({ folder }) {
|
|
71
|
+
console.log('AiAuditCard rendering, folder:', folder)
|
|
71
72
|
const [audit, setAudit] = useState(null)
|
|
72
73
|
const [loading, setLoading] = useState(false)
|
|
73
74
|
const [error, setError] = useState(null)
|
|
74
75
|
const [expanded, setExpanded] = useState(new Set())
|
|
75
|
-
const ran = useRef(false)
|
|
76
76
|
|
|
77
77
|
const runAudit = async () => {
|
|
78
|
+
if (!folder) return
|
|
78
79
|
setLoading(true)
|
|
79
80
|
setError(null)
|
|
80
81
|
try {
|
|
@@ -88,10 +89,8 @@ export default function AiAuditCard({ folder }) {
|
|
|
88
89
|
}
|
|
89
90
|
|
|
90
91
|
useEffect(() => {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
runAudit()
|
|
94
|
-
}
|
|
92
|
+
console.log('AiAuditCard useEffect triggered, folder:', folder)
|
|
93
|
+
runAudit()
|
|
95
94
|
}, [folder])
|
|
96
95
|
|
|
97
96
|
if (loading) {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import AnimatedLogo from './AnimatedLogo'
|
|
2
|
+
|
|
3
|
+
export default function AnimatedLoader({ label = 'Loading...' }) {
|
|
4
|
+
return (
|
|
5
|
+
<div className="flex flex-col items-center justify-center py-16 gap-3">
|
|
6
|
+
<div style={{ opacity: 0.7 }}>
|
|
7
|
+
<AnimatedLogo size={32} />
|
|
8
|
+
</div>
|
|
9
|
+
{label && (
|
|
10
|
+
<span className="text-[12px]" style={{ color: 'var(--c-text3)' }}>{label}</span>
|
|
11
|
+
)}
|
|
12
|
+
</div>
|
|
13
|
+
)
|
|
14
|
+
}
|
package/ui/src/lib/api.js
CHANGED
|
@@ -214,6 +214,19 @@ export async function fetchUsage() {
|
|
|
214
214
|
return res.json();
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
+
// ── Artifacts API ──
|
|
218
|
+
|
|
219
|
+
export async function fetchArtifacts() {
|
|
220
|
+
const res = await fetch(`${BASE}/api/artifacts`);
|
|
221
|
+
return res.json();
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export async function fetchArtifactContent(filePath) {
|
|
225
|
+
const q = new URLSearchParams({ path: filePath });
|
|
226
|
+
const res = await fetch(`${BASE}/api/artifact-content?${q}`);
|
|
227
|
+
return res.json();
|
|
228
|
+
}
|
|
229
|
+
|
|
217
230
|
// ── Relay API ──
|
|
218
231
|
|
|
219
232
|
export async function fetchMode() {
|