agentlytics 0.1.3 → 0.1.6

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 (37) hide show
  1. package/README.md +1 -1
  2. package/cache.js +420 -10
  3. package/editors/cursor.js +28 -6
  4. package/editors/vscode.js +6 -0
  5. package/index.js +78 -11
  6. package/package.json +2 -1
  7. package/server.js +27 -0
  8. package/ui/package-lock.json +60 -375
  9. package/ui/package.json +1 -1
  10. package/ui/src/App.jsx +22 -17
  11. package/ui/src/components/ActivityHeatmap.jsx +3 -3
  12. package/ui/src/components/AnimatedLogo.jsx +96 -0
  13. package/ui/src/components/ChatSidebar.jsx +7 -7
  14. package/ui/src/components/DateRangePicker.jsx +5 -5
  15. package/ui/src/components/EditorBreakdown.jsx +2 -2
  16. package/ui/src/components/EditorDot.jsx +1 -1
  17. package/ui/src/components/KpiCard.jsx +2 -2
  18. package/ui/src/components/LiveFeed.jsx +8 -8
  19. package/ui/src/components/LoginScreen.jsx +8 -6
  20. package/ui/src/components/MessageRenderer.jsx +5 -5
  21. package/ui/src/components/ModelBreakdown.jsx +3 -3
  22. package/ui/src/components/SectionTitle.jsx +1 -1
  23. package/ui/src/index.css +1 -1
  24. package/ui/src/lib/api.js +20 -0
  25. package/ui/src/lib/constants.js +8 -0
  26. package/ui/src/pages/ChatDetail.jsx +5 -2
  27. package/ui/src/pages/Compare.jsx +18 -18
  28. package/ui/src/pages/CostAnalysis.jsx +356 -0
  29. package/ui/src/pages/Dashboard.jsx +39 -21
  30. package/ui/src/pages/DeepAnalysis.jsx +38 -31
  31. package/ui/src/pages/ProjectDetail.jsx +23 -15
  32. package/ui/src/pages/Projects.jsx +14 -8
  33. package/ui/src/pages/RelayDashboard.jsx +29 -29
  34. package/ui/src/pages/RelaySessionDetail.jsx +1 -1
  35. package/ui/src/pages/RelayUserDetail.jsx +18 -18
  36. package/ui/src/pages/Sessions.jsx +24 -20
  37. package/ui/src/pages/SqlViewer.jsx +14 -14
package/index.js CHANGED
@@ -123,9 +123,11 @@ function getLocalIp() {
123
123
  return 'localhost';
124
124
  }
125
125
 
126
+ // ── ASCII banner ─────────────────────────────────────────
127
+ const c1 = chalk.hex('#818cf8'), c2 = chalk.hex('#f472b6'), c3 = chalk.hex('#34d399'), c4 = chalk.hex('#fbbf24');
126
128
  console.log('');
127
- console.log(chalk.bold('Agentlytics'));
128
- console.log(chalk.dim(' Comprehensive analytics for your AI coding agents'));
129
+ console.log(` ${c1('(● ●)')} ${c2('[● ●]')} ${chalk.bold('Agentlytics')}`);
130
+ console.log(` ${c3('{● ●}')} ${c4('<● ●>')} ${chalk.dim('Unified analytics for your AI coding agents')}`);
129
131
  if (collectOnly) console.log(chalk.cyan(' ⟳ Collect-only mode (no server)'));
130
132
  console.log('');
131
133
 
@@ -164,6 +166,10 @@ if (noCache) {
164
166
  const cacheDb = path.join(os.homedir(), '.agentlytics', 'cache.db');
165
167
  if (fs.existsSync(cacheDb)) {
166
168
  fs.unlinkSync(cacheDb);
169
+ // Remove WAL/SHM journal files to avoid SQLITE_IOERR_SHORT_READ
170
+ for (const suffix of ['-wal', '-shm']) {
171
+ if (fs.existsSync(cacheDb + suffix)) fs.unlinkSync(cacheDb + suffix);
172
+ }
167
173
  console.log(chalk.yellow(' ⟳ Cache cleared (--no-cache)'));
168
174
  }
169
175
  }
@@ -204,18 +210,74 @@ const WINDSURF_VARIANTS = [
204
210
  })();
205
211
 
206
212
  // Initialize cache DB
207
- console.log(chalk.dim(' Initializing cache database...'));
208
213
  cache.initDb();
209
214
 
210
- // Scan all editors and populate cache
211
- console.log(chalk.dim(' Scanning editors: Cursor, Windsurf, Claude Code, VS Code, Zed, Antigravity, OpenCode, Codex, Gemini CLI, Copilot CLI, Cursor Agent, Command Code'));
215
+ // ── Detect editors & collect sessions ───────────────────────
216
+ const { editors: editorModules } = require('./editors');
217
+ const EDITOR_DISPLAY = [
218
+ ['cursor', 'Cursor'],
219
+ ['windsurf', 'Windsurf'],
220
+ ['windsurf-next', 'Windsurf Next'],
221
+ ['antigravity', 'Antigravity'],
222
+ ['claude-code', 'Claude Code'],
223
+ ['vscode', 'VS Code'],
224
+ ['vscode-insiders', 'VS Code Insiders'],
225
+ ['zed', 'Zed'],
226
+ ['opencode', 'OpenCode'],
227
+ ['codex', 'Codex'],
228
+ ['gemini-cli', 'Gemini CLI'],
229
+ ['copilot-cli', 'Copilot CLI'],
230
+ ['cursor-agent', 'Cursor Agent'],
231
+ ['commandcode', 'Command Code'],
232
+ ];
233
+
234
+ console.log(chalk.dim(' Looking for AI coding agents...'));
235
+ const allChats = [];
236
+ for (const editor of editorModules) {
237
+ try {
238
+ const chats = editor.getChats();
239
+ allChats.push(...chats);
240
+ } catch { /* skip broken adapters */ }
241
+ }
242
+ allChats.sort((a, b) => (b.lastUpdatedAt || b.createdAt || 0) - (a.lastUpdatedAt || a.createdAt || 0));
243
+
244
+ // Count per source
245
+ const bySource = {};
246
+ for (const chat of allChats) bySource[chat.source] = (bySource[chat.source] || 0) + 1;
247
+
248
+ for (const [src, label] of EDITOR_DISPLAY) {
249
+ const count = bySource[src] || 0;
250
+ if (count > 0) {
251
+ console.log(` ${chalk.green('✓')} ${chalk.bold(label.padEnd(18))} ${chalk.dim(`${count} session${count === 1 ? '' : 's'}`)}`);
252
+ } else {
253
+ console.log(` ${chalk.dim('–')} ${chalk.dim(label.padEnd(18) + '–')}`);
254
+ }
255
+ }
256
+ console.log('');
257
+
258
+ // ── Analyze sessions with robot animation ──────────────────
259
+ const logUpdate = require('log-update');
260
+ const BOT_STYLES = [
261
+ { l: '(', r: ')', color: '#818cf8' },
262
+ { l: '[', r: ']', color: '#f472b6' },
263
+ { l: '{', r: '}', color: '#34d399' },
264
+ { l: '<', r: '>', color: '#fbbf24' },
265
+ ];
266
+ let tick = 0;
267
+
212
268
  const startTime = Date.now();
213
- const result = cache.scanAll((progress) => {
214
- process.stdout.write(chalk.dim(`\r Scanning: ${progress.scanned}/${progress.total} chats (${progress.analyzed} analyzed, ${progress.skipped} cached)`));
215
- });
269
+ const result = cache.scanAll((p) => {
270
+ tick++;
271
+ if (tick % 5 !== 0) return;
272
+ const frame = Math.floor(tick / 40);
273
+ const b = BOT_STYLES[frame % 4];
274
+ const dots = '.'.repeat((Math.floor(tick / 10) % 3) + 1).padEnd(3);
275
+ logUpdate(` ${chalk.hex(b.color)(`${b.l}● ●${b.r}`)} ${chalk.dim(`Analyzing${dots} ${p.scanned}/${p.total}`)}`);
276
+ }, { chats: allChats });
216
277
  const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
217
- console.log('');
218
- console.log(chalk.green(` ✓ Cache ready: ${result.total} chats, ${result.analyzed} analyzed, ${result.skipped} cached (${elapsed}s)`));
278
+ const allFaces = BOT_STYLES.map(b => chalk.hex(b.color)(`${b.l}● ●${b.r}`)).join(' ');
279
+ logUpdate(` ${allFaces} ${chalk.green(`✓ ${result.analyzed} analyzed, ${result.skipped} cached (${elapsed}s)`)}`);
280
+ logUpdate.done();
219
281
  console.log('');
220
282
 
221
283
  // In collect-only mode, exit after cache is built
@@ -231,7 +293,12 @@ const app = require('./server');
231
293
  app.listen(PORT, () => {
232
294
  const url = `http://localhost:${PORT}`;
233
295
  console.log(chalk.green(` ✓ Dashboard ready at ${chalk.bold.white(url)}`));
234
- console.log(chalk.dim(` Press Ctrl+C to stop\n`));
296
+ console.log('');
297
+ console.log(chalk.dim(' 💡 Share sessions with your team:'));
298
+ console.log(chalk.dim(` npx agentlytics --relay Start a relay server`));
299
+ console.log(chalk.dim(` npx agentlytics --join <host:port> --username Join a relay server`));
300
+ console.log('');
301
+ console.log(chalk.dim(' Press Ctrl+C to stop\n'));
235
302
 
236
303
  // Auto-open browser
237
304
  const open = require('open');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentlytics",
3
- "version": "0.1.3",
3
+ "version": "0.1.6",
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": {
@@ -55,6 +55,7 @@
55
55
  "commander": "^14.0.3",
56
56
  "express": "^4.22.1",
57
57
  "inquirer": "^13.3.0",
58
+ "log-update": "^4.0.0",
58
59
  "open": "^8.4.2"
59
60
  }
60
61
  }
package/server.js CHANGED
@@ -66,6 +66,7 @@ app.get('/api/chats', (req, res) => {
66
66
  encrypted: !!c.encrypted,
67
67
  bubbleCount: c.bubble_count,
68
68
  topModel: c.top_model || null,
69
+ cost: c.cost || 0,
69
70
  })),
70
71
  });
71
72
  } catch (err) {
@@ -159,6 +160,32 @@ app.get('/api/dashboard-stats', (req, res) => {
159
160
  }
160
161
  });
161
162
 
163
+ app.get('/api/cost-analytics', (req, res) => {
164
+ try {
165
+ const opts = {
166
+ editor: req.query.editor || null,
167
+ ...parseDateOpts(req.query),
168
+ };
169
+ res.json(cache.getCostAnalytics(opts));
170
+ } catch (err) {
171
+ res.status(500).json({ error: err.message });
172
+ }
173
+ });
174
+
175
+ app.get('/api/costs', (req, res) => {
176
+ try {
177
+ const opts = {
178
+ editor: req.query.editor || null,
179
+ folder: req.query.folder || null,
180
+ chatId: req.query.chatId || null,
181
+ ...parseDateOpts(req.query),
182
+ };
183
+ res.json(cache.getCostBreakdown(opts));
184
+ } catch (err) {
185
+ res.status(500).json({ error: err.message });
186
+ }
187
+ });
188
+
162
189
  app.get('/api/tool-calls', (req, res) => {
163
190
  try {
164
191
  const name = req.query.name;