agentlytics 0.2.8 → 0.2.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentlytics",
3
- "version": "0.2.8",
3
+ "version": "0.2.10",
4
4
  "description": "Comprehensive analytics dashboard for AI coding agents — Cursor, Windsurf, Claude Code, VS Code Copilot, Zed, Antigravity, OpenCode, Command Code",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -23,7 +23,9 @@
23
23
  "ui/package-lock.json",
24
24
  "ui/vite.config.js",
25
25
  "ui/eslint.config.js",
26
- "README.md"
26
+ "README.md",
27
+ "mod.ts",
28
+ "deno.json"
27
29
  ],
28
30
  "scripts": {
29
31
  "start": "node index.js",
@@ -46,6 +48,9 @@
46
48
  ],
47
49
  "author": "fkadev",
48
50
  "license": "ISC",
51
+ "engines": {
52
+ "node": ">=20.19.0"
53
+ },
49
54
  "repository": {
50
55
  "type": "git",
51
56
  "url": "https://github.com/f/agentlytics"
package/relay-server.js CHANGED
@@ -542,7 +542,7 @@ function createRelayApp() {
542
542
  if (fs.existsSync(index)) {
543
543
  res.sendFile(index);
544
544
  } else {
545
- res.status(404).send('UI not built. Run: cd ui && npm install && npm run build');
545
+ res.status(404).send('UI not built. Run: cd ui && npm install && npm run build (or use your preferred package manager)');
546
546
  }
547
547
  });
548
548
 
package/ui/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "version": "0.0.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
- "dev": "vite",
7
+ "dev": "node ../index.js --ui-dev & vite",
8
8
  "build": "vite build",
9
9
  "lint": "eslint .",
10
10
  "preview": "vite preview"
package/ui/src/App.jsx CHANGED
@@ -3,6 +3,7 @@ import { Routes, Route, NavLink, useLocation } from 'react-router-dom'
3
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
+ import { useLive } from './hooks/useLive'
6
7
  import AnimatedLogo from './components/AnimatedLogo'
7
8
  import AnimatedLoader from './components/AnimatedLoader'
8
9
  import LoginScreen from './components/LoginScreen'
@@ -70,7 +71,7 @@ function NavDropdown({ icon: Icon, label, items }) {
70
71
  export default function App() {
71
72
  const [overview, setOverview] = useState(null)
72
73
  const [refetchState, setRefetchState] = useState(null) // null | { scanned, total }
73
- const [live, setLive] = useState(false)
74
+ const { live, toggle: toggleLive } = useLive()
74
75
  const [mode, setMode] = useState(null) // 'local' | 'relay'
75
76
  const [needsAuth, setNeedsAuth] = useState(false)
76
77
  const [authed, setAuthed] = useState(!!getAuthToken())
@@ -105,25 +106,29 @@ export default function App() {
105
106
  if (mode === 'local') refreshOverview()
106
107
  }, [mode])
107
108
 
108
- // Live mode: refetch overview every 60s
109
+ const rescanAndRefresh = useCallback(async (onProgress) => {
110
+ await refetchAgents(onProgress)
111
+ const data = await fetchOverview()
112
+ setOverview(data)
113
+ }, [])
114
+
115
+ // Live mode: rescan & refresh every 60s
109
116
  useEffect(() => {
110
117
  if (live && mode === 'local') {
111
118
  liveRef.current = setInterval(() => {
112
- refreshOverview()
119
+ rescanAndRefresh().catch(() => {})
113
120
  }, 60000)
114
121
  } else {
115
122
  if (liveRef.current) clearInterval(liveRef.current)
116
123
  liveRef.current = null
117
124
  }
118
125
  return () => { if (liveRef.current) clearInterval(liveRef.current) }
119
- }, [live, refreshOverview])
126
+ }, [live, rescanAndRefresh])
120
127
 
121
128
  const handleRefetch = async () => {
122
129
  setRefetchState({ scanned: 0, total: 0 })
123
130
  try {
124
- await refetchAgents((p) => setRefetchState({ scanned: p.scanned, total: p.total }))
125
- const data = await fetchOverview()
126
- setOverview(data)
131
+ await rescanAndRefresh((p) => setRefetchState({ scanned: p.scanned, total: p.total }))
127
132
  } catch (e) { console.error(e) }
128
133
  setRefetchState(null)
129
134
  }
@@ -187,7 +192,7 @@ export default function App() {
187
192
  {!isRelay && (
188
193
  <>
189
194
  <button
190
- onClick={() => setLive(!live)}
195
+ onClick={toggleLive}
191
196
  className="flex items-center gap-1.5 px-2 py-0.5 text-[11px] transition"
192
197
  style={{
193
198
  color: live ? '#22c55e' : 'var(--c-text3)',
@@ -0,0 +1,15 @@
1
+ import { useState, useEffect, useCallback } from 'react'
2
+
3
+ const KEY = 'agentlytics-live'
4
+
5
+ export function useLive() {
6
+ const [live, setLive] = useState(() => localStorage.getItem(KEY) === 'true')
7
+
8
+ useEffect(() => {
9
+ localStorage.setItem(KEY, live)
10
+ }, [live])
11
+
12
+ const toggle = useCallback(() => setLive(l => !l), [])
13
+
14
+ return { live, toggle }
15
+ }