claude-roi 0.1.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/README.md +191 -0
- package/package.json +34 -0
- package/src/cache.js +86 -0
- package/src/claude-parser.js +462 -0
- package/src/correlator.js +103 -0
- package/src/dashboard.html +995 -0
- package/src/git-analyzer.js +170 -0
- package/src/index.js +138 -0
- package/src/metrics.js +396 -0
- package/src/server.js +116 -0
package/src/server.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
|
|
8
|
+
export function createServer(payload) {
|
|
9
|
+
const app = express();
|
|
10
|
+
|
|
11
|
+
// Serve dashboard HTML
|
|
12
|
+
const dashboardHtml = readFileSync(path.join(__dirname, 'dashboard.html'), 'utf-8');
|
|
13
|
+
|
|
14
|
+
app.get('/', (req, res) => {
|
|
15
|
+
res.type('html').send(dashboardHtml);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// Full payload (single fetch for dashboard)
|
|
19
|
+
app.get('/api/all', (req, res) => {
|
|
20
|
+
res.json(payload);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Hero stats + insights
|
|
24
|
+
app.get('/api/summary', (req, res) => {
|
|
25
|
+
res.json({
|
|
26
|
+
...payload.meta,
|
|
27
|
+
...payload.summary,
|
|
28
|
+
insights: payload.insights,
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Daily timeline data for charts
|
|
33
|
+
app.get('/api/timeline', (req, res) => {
|
|
34
|
+
res.json(payload.daily);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// All sessions with pagination
|
|
38
|
+
app.get('/api/sessions', (req, res) => {
|
|
39
|
+
const page = parseInt(req.query.page) || 1;
|
|
40
|
+
const limit = parseInt(req.query.limit) || 50;
|
|
41
|
+
const sortBy = req.query.sort || 'startTime';
|
|
42
|
+
const order = req.query.order === 'asc' ? 1 : -1;
|
|
43
|
+
const mainOnly = req.query.mainOnly === 'true';
|
|
44
|
+
|
|
45
|
+
let sessions = payload.sessions;
|
|
46
|
+
|
|
47
|
+
// Filter to main branch commits only if requested
|
|
48
|
+
if (mainOnly) {
|
|
49
|
+
sessions = sessions.map(s => {
|
|
50
|
+
const mainCommits = s.commits.filter(c => c.onMain);
|
|
51
|
+
return {
|
|
52
|
+
...s,
|
|
53
|
+
commits: mainCommits,
|
|
54
|
+
commitCount: mainCommits.length,
|
|
55
|
+
linesAdded: mainCommits.reduce((sum, c) => sum + c.totalAdded, 0),
|
|
56
|
+
linesDeleted: mainCommits.reduce((sum, c) => sum + c.totalDeleted, 0),
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Sort
|
|
62
|
+
sessions = [...sessions].sort((a, b) => {
|
|
63
|
+
const av = a[sortBy] ?? 0;
|
|
64
|
+
const bv = b[sortBy] ?? 0;
|
|
65
|
+
if (typeof av === 'string') return order * av.localeCompare(bv);
|
|
66
|
+
return order * (av - bv);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const start = (page - 1) * limit;
|
|
70
|
+
res.json({
|
|
71
|
+
sessions: sessions.slice(start, start + limit),
|
|
72
|
+
total: sessions.length,
|
|
73
|
+
page,
|
|
74
|
+
limit,
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Model comparison data
|
|
79
|
+
app.get('/api/models', (req, res) => {
|
|
80
|
+
res.json(payload.modelBreakdown);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Hour x day heatmap
|
|
84
|
+
app.get('/api/heatmap', (req, res) => {
|
|
85
|
+
res.json(payload.heatmap);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Single session detail
|
|
89
|
+
app.get('/api/session/:id', (req, res) => {
|
|
90
|
+
const session = payload.sessions.find(s => s.sessionId === req.params.id);
|
|
91
|
+
if (!session) return res.status(404).json({ error: 'Session not found' });
|
|
92
|
+
res.json(session);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Projects breakdown
|
|
96
|
+
app.get('/api/projects', (req, res) => {
|
|
97
|
+
res.json(payload.projects);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// Session buckets
|
|
101
|
+
app.get('/api/buckets', (req, res) => {
|
|
102
|
+
res.json(payload.sessionBuckets);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Tool usage
|
|
106
|
+
app.get('/api/tools', (req, res) => {
|
|
107
|
+
res.json(payload.toolBreakdown);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Line survival
|
|
111
|
+
app.get('/api/survival', (req, res) => {
|
|
112
|
+
res.json(payload.lineSurvival);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
return app;
|
|
116
|
+
}
|