crg-dev-kit 2.0.1 → 2.0.3
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/assets/setup-crg.sh +2 -2
- package/lib/analytics.js +7 -2
- package/lib/roi.js +31 -10
- package/package.json +1 -1
- package/server.js +7 -7
package/assets/setup-crg.sh
CHANGED
|
@@ -93,8 +93,8 @@ if [ -d "$HOME/.cursor" ] || [ -d "$HOME/Library/Application Support/Cursor" ];
|
|
|
93
93
|
PLATFORM="all"
|
|
94
94
|
fi
|
|
95
95
|
code-review-graph install --platform "$PLATFORM" --no-hooks 2>/dev/null || \
|
|
96
|
-
code-review-graph install --platform claude-code 2>/dev/null || \
|
|
97
|
-
warn "Could not auto-configure MCP. Run manually: code-review-graph install"
|
|
96
|
+
code-review-graph install --platform claude-code --no-hooks 2>/dev/null || \
|
|
97
|
+
warn "Could not auto-configure MCP. Run manually: code-review-graph install --no-hooks"
|
|
98
98
|
ok "MCP server configured for $PLATFORM"
|
|
99
99
|
|
|
100
100
|
# ── Step 4: Build graph ──
|
package/lib/analytics.js
CHANGED
|
@@ -156,9 +156,14 @@ function getProjectStats(projectPath) {
|
|
|
156
156
|
};
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
function getAllStats() {
|
|
159
|
+
function getAllStats(scopeProject) {
|
|
160
160
|
const sessions = readJSON(SESSIONS_FILE, []);
|
|
161
|
-
|
|
161
|
+
let completedSessions = sessions.filter(s => s.status === 'completed');
|
|
162
|
+
|
|
163
|
+
if (scopeProject) {
|
|
164
|
+
const resolved = path.resolve(scopeProject);
|
|
165
|
+
completedSessions = completedSessions.filter(s => s.project === resolved);
|
|
166
|
+
}
|
|
162
167
|
|
|
163
168
|
if (completedSessions.length === 0) return null;
|
|
164
169
|
|
package/lib/roi.js
CHANGED
|
@@ -6,10 +6,20 @@ function getInstallDate(projectPath) {
|
|
|
6
6
|
const installFile = path.join(ANALYTICS_DIR, 'install.json');
|
|
7
7
|
try {
|
|
8
8
|
const data = JSON.parse(fs.readFileSync(installFile, 'utf8'));
|
|
9
|
+
// Support both old format (single object) and new format (keyed by path)
|
|
10
|
+
if (data.projectPath) {
|
|
11
|
+
// Old format: { projectPath, installedAt }
|
|
12
|
+
if (projectPath) return data.projectPath === projectPath ? data.installedAt : null;
|
|
13
|
+
return data.installedAt;
|
|
14
|
+
}
|
|
15
|
+
// New format: { "/path": { installedAt } }
|
|
9
16
|
if (projectPath) {
|
|
10
|
-
|
|
17
|
+
const resolved = path.resolve(projectPath);
|
|
18
|
+
return data[resolved] ? data[resolved].installedAt : null;
|
|
11
19
|
}
|
|
12
|
-
|
|
20
|
+
// Return first entry
|
|
21
|
+
const first = Object.values(data)[0];
|
|
22
|
+
return first ? first.installedAt : null;
|
|
13
23
|
} catch {
|
|
14
24
|
return null;
|
|
15
25
|
}
|
|
@@ -18,12 +28,16 @@ function getInstallDate(projectPath) {
|
|
|
18
28
|
function setInstallDate(projectPath) {
|
|
19
29
|
ensureDir();
|
|
20
30
|
const installFile = path.join(ANALYTICS_DIR, 'install.json');
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
31
|
+
const resolved = path.resolve(projectPath);
|
|
32
|
+
let data = {};
|
|
33
|
+
try { data = JSON.parse(fs.readFileSync(installFile, 'utf8')); } catch {}
|
|
34
|
+
// Migrate old format
|
|
35
|
+
if (data.projectPath) {
|
|
36
|
+
data = { [data.projectPath]: { installedAt: data.installedAt } };
|
|
37
|
+
}
|
|
38
|
+
data[resolved] = { installedAt: new Date().toISOString() };
|
|
39
|
+
fs.writeFileSync(installFile, JSON.stringify(data, null, 2));
|
|
40
|
+
return data[resolved];
|
|
27
41
|
}
|
|
28
42
|
|
|
29
43
|
function parseHistory(fromDate, toDate) {
|
|
@@ -161,11 +175,18 @@ function calculateROI(projectPath) {
|
|
|
161
175
|
};
|
|
162
176
|
}
|
|
163
177
|
|
|
164
|
-
function getAllProjectsROI() {
|
|
178
|
+
function getAllProjectsROI(scopeProject) {
|
|
179
|
+
if (scopeProject) {
|
|
180
|
+
return calculateROI(scopeProject);
|
|
181
|
+
}
|
|
165
182
|
const installFile = path.join(ANALYTICS_DIR, 'install.json');
|
|
166
183
|
try {
|
|
167
184
|
const installData = JSON.parse(fs.readFileSync(installFile, 'utf8'));
|
|
168
|
-
|
|
185
|
+
// Old format
|
|
186
|
+
if (installData.projectPath) return calculateROI(installData.projectPath);
|
|
187
|
+
// New format — return first
|
|
188
|
+
const first = Object.keys(installData)[0];
|
|
189
|
+
return first ? calculateROI(first) : { error: 'No installation found', installed: false };
|
|
169
190
|
} catch {
|
|
170
191
|
return { error: 'No installation found', installed: false };
|
|
171
192
|
}
|
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -359,10 +359,10 @@ function tabStatusFragment(statusData) {
|
|
|
359
359
|
</section>`;
|
|
360
360
|
}
|
|
361
361
|
|
|
362
|
-
function tabAnalytics() {
|
|
362
|
+
function tabAnalytics(cwd) {
|
|
363
363
|
let roiHtml = '';
|
|
364
364
|
try {
|
|
365
|
-
const roiData = roi.getAllProjectsROI();
|
|
365
|
+
const roiData = roi.getAllProjectsROI(cwd);
|
|
366
366
|
if (roiData.installed) {
|
|
367
367
|
const verdictColor = roiData.roi.verdict === 'positive' ? '#16a34a' : roiData.roi.verdict === 'neutral' ? '#ea580c' : '#dc2626';
|
|
368
368
|
const verdictIcon = roiData.roi.verdict === 'positive' ? '✓' : roiData.roi.verdict === 'neutral' ? '−' : '⚠';
|
|
@@ -428,7 +428,7 @@ function tabAnalytics() {
|
|
|
428
428
|
}
|
|
429
429
|
|
|
430
430
|
let tokenHtml = '';
|
|
431
|
-
const analyticsData = analytics.getAllStats();
|
|
431
|
+
const analyticsData = analytics.getAllStats(cwd);
|
|
432
432
|
if (analyticsData) {
|
|
433
433
|
const savingsColor = analyticsData.avgSavingsPercent >= 70 ? '#16a34a' : analyticsData.avgSavingsPercent >= 50 ? '#ea580c' : '#dc2626';
|
|
434
434
|
tokenHtml = `
|
|
@@ -615,7 +615,7 @@ function start(port, noOpen) {
|
|
|
615
615
|
|
|
616
616
|
} else if (url.pathname === '/tab/analytics') {
|
|
617
617
|
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
618
|
-
res.end(tabAnalytics());
|
|
618
|
+
res.end(tabAnalytics(cwd));
|
|
619
619
|
|
|
620
620
|
} else if (url.pathname === '/tab/tools') {
|
|
621
621
|
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
@@ -667,12 +667,12 @@ function start(port, noOpen) {
|
|
|
667
667
|
|
|
668
668
|
/* ── Existing JSON API endpoints ────────────────────────────── */
|
|
669
669
|
} else if (url.pathname === '/api/analytics') {
|
|
670
|
-
const data = analytics.getAllStats();
|
|
670
|
+
const data = analytics.getAllStats(cwd);
|
|
671
671
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
672
672
|
res.end(JSON.stringify(data || { message: 'No analytics data yet' }));
|
|
673
673
|
|
|
674
674
|
} else if (url.pathname === '/api/roi') {
|
|
675
|
-
const data = roi.getAllProjectsROI();
|
|
675
|
+
const data = roi.getAllProjectsROI(cwd);
|
|
676
676
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
677
677
|
res.end(JSON.stringify(data));
|
|
678
678
|
|
|
@@ -776,7 +776,7 @@ function start(port, noOpen) {
|
|
|
776
776
|
const url = `http://localhost:${availablePort}`;
|
|
777
777
|
const portMsg = availablePort !== port ? ` (port ${port} was busy, using ${availablePort})` : '';
|
|
778
778
|
console.log(`\n \x1b[36mCRG Dev Kit\x1b[0m running at \x1b[1m${url}\x1b[0m${portMsg}\n`);
|
|
779
|
-
const analyticsData = analytics.getAllStats();
|
|
779
|
+
const analyticsData = analytics.getAllStats(cwd);
|
|
780
780
|
if (analyticsData) {
|
|
781
781
|
console.log(` \x1b[32m${analyticsData.avgSavingsPercent}% avg token savings\x1b[0m across \x1b[1m${analyticsData.totalSessions}\x1b[0m sessions\n`);
|
|
782
782
|
}
|