crg-dev-kit 1.0.0 → 2.0.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 CHANGED
@@ -1,111 +1,72 @@
1
- # CRG Dev Kit
1
+ # code-review-graph Dev Kit
2
2
 
3
- One command to set up [code-review-graph](https://github.com/tirth8205/code-review-graph) across any project, any stack. Track token savings and prove ROI to your team.
3
+ AI knowledge graph for your codebase. Gives your AI assistant (Claude Code, Cursor, etc.) structural understanding — callers, dependencies, test coverage, blast radius without reading every file.
4
4
 
5
5
  ## Quick Start
6
6
 
7
- ```bash
8
- # Open the dashboard
9
- npx crg-dev-kit
10
-
11
- # Copy setup scripts to your project
12
- npx crg-dev-kit install
13
-
14
- # Check installation status
15
- npx crg-dev-kit status
7
+ ### Windows (PowerShell)
8
+ ```powershell
9
+ cd your-project
10
+ .\setup-crg.ps1 # basic install
11
+ .\setup-crg.ps1 -WithCommunities # + architecture view
12
+ .\setup-crg.ps1 -WithAll # + semantic search (2GB download)
16
13
  ```
17
14
 
18
- ## Commands
19
-
20
- | Command | What it does |
21
- |---------|-------------|
22
- | `npx crg-dev-kit` | Opens the dashboard (default) |
23
- | `npx crg-dev-kit install` | Copies setup scripts to current directory |
24
- | `npx crg-dev-kit start --port 9000` | Dashboard on custom port |
25
- | `npx crg-dev-kit start --no-open` | Dashboard without auto-opening browser |
26
- | `npx crg-dev-kit status` | Check if CRG is installed in current project |
27
- | `npx crg-dev-kit uninstall` | Remove CRG files from current project |
28
- | `npx crg-dev-kit help` | Show all commands |
29
-
30
- ## What You Get
31
-
32
- ### Setup Scripts
33
- - **Linux/macOS/WSL**: `bash setup-crg.sh --with-communities`
34
- - **Windows**: `.\setup-crg.ps1 -WithCommunities`
35
- - **Health check**: `bash check-crg.sh`
36
- - **AI config**: `CLAUDE.md` (drop in project root)
37
- - **Reference**: `crg-cheatsheet.pdf`
38
-
39
- ### Token Analytics Dashboard
40
-
41
- The dashboard at `http://localhost:8742` shows:
42
- - **Token savings %** — average reduction vs reading full source files
43
- - **Cost estimates** — approximate $ savings at current LLM pricing
44
- - **Per-project breakdown** — sessions, files reviewed, savings by project
45
- - **Tool usage** — which CRG tools your team uses most
46
-
47
- Data stored locally in `~/.crg-analytics/` — zero telemetry.
48
-
49
- ### REST API
50
-
51
- The dashboard exposes endpoints for programmatic access:
15
+ ### Linux / macOS / WSL
16
+ ```bash
17
+ cd your-project
18
+ bash setup-crg.sh # basic install
19
+ bash setup-crg.sh --with-communities # + architecture view
20
+ bash setup-crg.sh --with-all # + semantic search (2GB download)
21
+ ```
52
22
 
23
+ ### Health Check
53
24
  ```bash
54
- # Get all analytics
55
- curl http://localhost:8742/api/analytics
56
-
57
- # Download analytics report (Markdown)
58
- curl http://localhost:8742/api/report
59
-
60
- # Start a new session
61
- curl -X POST http://localhost:8742/api/session \
62
- -H 'Content-Type: application/json' \
63
- -d '{"project": "/path/to/repo", "operation": "code_review"}'
64
-
65
- # Log tool usage
66
- curl -X POST http://localhost:8742/api/session/{sessionId} \
67
- -H 'Content-Type: application/json' \
68
- -d '{"tool": "detect_changes", "count": 1}'
69
-
70
- # End session
71
- curl -X POST http://localhost:8742/api/session/{sessionId} \
72
- -H 'Content-Type: application/json' \
73
- -d '{"filesReviewed": 12, "avgLinesPerFile": 150}'
25
+ bash check-crg.sh # run anytime to verify
74
26
  ```
75
27
 
76
- ## For Team Leads
28
+ ## What's in this kit
77
29
 
78
- Share this with your team:
30
+ | File | Purpose |
31
+ |------|---------|
32
+ | `setup-crg.sh` | Setup script for Linux/macOS/WSL |
33
+ | `setup-crg.ps1` | Setup script for Windows |
34
+ | `check-crg.sh` | Health check (run anytime) |
35
+ | `CLAUDE.md` | Drop into project root — tells AI which tools to use |
36
+ | `crg-cheatsheet.pdf` | One-page visual reference |
37
+ | `.github/workflows/test-crg.yml` | CI workflow to validate on Windows + Ubuntu |
79
38
 
80
- ```bash
81
- # Everyone runs this in their project
82
- npx crg-dev-kit install
83
- bash setup-crg.sh --with-communities
84
- ```
39
+ ## What the setup script does
85
40
 
86
- Then open the dashboard to see team-wide analytics:
87
- ```bash
88
- npx crg-dev-kit
89
- ```
41
+ 1. Detects OS and Python version
42
+ 2. Installs `code-review-graph` (pip on Windows, pipx on Linux)
43
+ 3. Configures MCP server for your AI tool
44
+ 4. Builds the knowledge graph
45
+ 5. Optionally installs extras (communities, embeddings)
46
+ 6. Runs community detection workaround (v2.1.0 bug)
47
+ 7. Adds `.code-review-graph/` to `.gitignore`
48
+ 8. Runs health check
90
49
 
91
- ## Token Savings
50
+ ## What works after setup
92
51
 
93
- Based on benchmarks across 6 real repos, CRG tools reduce token usage by **8.2x on average**:
52
+ **13 tools work immediately** code review, search, impact analysis, refactoring.
94
53
 
95
- | Scenario | Without CRG | With CRG | Reduction |
96
- |----------|:---:|:---:|:---:|
97
- | 200-file project review | ~150k tokens | ~25k tokens | 6x |
98
- | Incremental review | ~150k tokens | ~8k tokens | 19x |
99
- | PR review | ~100k tokens | ~15k tokens | 6.7x |
54
+ **5 tools need `--with-communities`** architecture overview, module clusters.
100
55
 
101
- The dashboard tracks your actual savings in real time.
56
+ **3 tools are broken in v2.1.0** flow analysis (trace_flows TypeError). Skip these.
102
57
 
103
- ## Requirements
58
+ ## Known Issues (v2.1.0)
104
59
 
105
- - Node.js >= 16
106
- - Python 3.10+ (for code-review-graph installation)
107
- - pipx (recommended) or pip
60
+ | Issue | Impact | Workaround |
61
+ |-------|--------|------------|
62
+ | `architecture_overview` returns empty | Misleading — no error | Install communities extra |
63
+ | `build` doesn't trigger Leiden | Communities stay 0 | Setup script handles this automatically |
64
+ | `trace_flows` TypeError | Flows completely broken | No fix — wait for v2.2+ |
65
+ | Over-clustering (400+ for 500 files) | Token overflow | Use `min_size=20` param |
66
+ | `crg` is wrong package name | Installs different package | Always use `code-review-graph` |
67
+ | PEP 668 on Linux | pip blocked | Setup script auto-detects, uses pipx |
68
+ | MCP server caches old env | Extras don't activate | Restart AI tool after installing extras |
108
69
 
109
- ## License
70
+ ## For CI
110
71
 
111
- MIT
72
+ Copy `.github/workflows/test-crg.yml` into your repo. Tests install + build + communities on both Windows and Ubuntu. Trigger manually from Actions tab.
package/bin/cli.js CHANGED
@@ -1,168 +1,35 @@
1
1
  #!/usr/bin/env node
2
- const { spawn, execFile } = require('child_process');
3
2
  const path = require('path');
4
- const fs = require('fs');
5
- const os = require('os');
6
-
7
3
  const pkg = require('../package.json');
8
- const ASSETS = path.join(__dirname, '..', 'assets');
4
+
9
5
  const args = process.argv.slice(2);
10
6
  const cmd = args[0];
11
- const roi = require('../lib/roi');
12
-
13
- const NO_ROI = args.includes('--no-roi');
14
7
 
15
8
  function printHelp() {
16
9
  console.log(`
17
- \x1b[36mCRG Dev Kit\x1b[0m — One-click code-review-graph setup
10
+ \x1b[36mCRG Dev Kit\x1b[0m v${pkg.version} AI-powered code review setup
18
11
 
19
12
  \x1b[1mUsage:\x1b[0m
20
- npx crg-dev-kit [command] [options]
21
-
22
- \x1b[1mCommands:\x1b[0m
23
- install, setup Copy setup scripts to current project
24
- start, serve Launch the dashboard (default)
25
- uninstall Remove CRG files from current project
26
- status Check if CRG is installed in current project
27
- roi Show ROI report (token savings)
28
- tutorial Launch interactive tutorial
29
- help Show this help message
30
- version Show version
13
+ npx crg-dev-kit [options]
31
14
 
32
15
  \x1b[1mOptions:\x1b[0m
33
16
  --port <number> Dashboard port (default: 8742)
34
17
  --no-open Don't auto-open browser
35
- --communities Include community detection flag
36
- --no-roi Skip ROI tracking (installs without analytics)
18
+ help Show this help message
19
+ version Show version
37
20
 
38
- \x1b[1mExamples:\x1b[0m
39
- npx crg-dev-kit # Open dashboard
40
- npx crg-dev-kit install # Copy scripts to project
41
- npx crg-dev-kit start --port 9000 # Custom port
42
- npx crg-dev-kit status # Check installation
21
+ \x1b[1mHow it works:\x1b[0m
22
+ Run \x1b[36mnpx crg-dev-kit\x1b[0m to open the dashboard.
23
+ Everything happens in the browser install, status,
24
+ analytics, downloads, and documentation.
43
25
  `);
44
26
  }
45
27
 
46
- function printVersion() {
28
+ if (cmd === 'help' || cmd === '--help' || cmd === '-h') {
29
+ printHelp();
30
+ } else if (cmd === 'version' || cmd === '--version' || cmd === '-v') {
47
31
  console.log(`crg-dev-kit v${pkg.version}`);
48
- }
49
-
50
- function copyFiles() {
51
- const cwd = process.cwd();
52
- const files = [
53
- { name: 'setup-crg.sh', executable: true },
54
- { name: 'setup-crg.ps1', executable: false },
55
- { name: 'check-crg.sh', executable: true },
56
- { name: 'CLAUDE.md', executable: false },
57
- { name: 'crg-cheatsheet.pdf', executable: false },
58
- { name: 'README.md', executable: false },
59
- ];
60
-
61
- let copied = 0;
62
- files.forEach(f => {
63
- const src = path.join(ASSETS, f.name);
64
- const dst = path.join(cwd, f.name);
65
- if (fs.existsSync(src)) {
66
- if (fs.existsSync(dst)) {
67
- console.log(` \x1b[33m~\x1b[0m ${f.name} \x1b[2m(already exists, skipping)\x1b[0m`);
68
- return;
69
- }
70
- fs.copyFileSync(src, dst);
71
- if (f.executable) {
72
- try { fs.chmodSync(dst, '755'); } catch {}
73
- }
74
- console.log(` \x1b[32m✓\x1b[0m ${f.name}`);
75
- copied++;
76
- }
77
- });
78
-
79
- // Track install date (only if --no-roi not set)
80
- if (!NO_ROI) {
81
- roi.setInstallDate(cwd);
82
- console.log('\n \x1b[36m✓ Install date recorded for ROI tracking\x1b[0m');
83
- }
84
-
85
- if (copied === 0) {
86
- console.log('\n \x1b[33mFiles already exist, install date updated.\x1b[0m');
87
- return;
88
- }
89
-
90
- const isWin = process.platform === 'win32';
91
- console.log(`\n \x1b[32m${copied} file(s) copied to ${cwd}\x1b[0m\n`);
92
- console.log(' \x1b[1mNext steps:\x1b[0m');
93
- if (isWin) {
94
- console.log(' .\\setup-crg.ps1 -WithCommunities');
95
- console.log(' code-review-graph status');
96
- } else {
97
- console.log(' bash setup-crg.sh --with-communities');
98
- console.log(' bash check-crg.sh');
99
- }
100
- console.log('');
101
- }
102
-
103
- function checkStatus() {
104
- const cwd = process.cwd();
105
- const checks = [
106
- { file: 'setup-crg.sh', label: 'Linux/macOS setup script' },
107
- { file: 'setup-crg.ps1', label: 'Windows setup script' },
108
- { file: 'check-crg.sh', label: 'Health check script' },
109
- { file: 'CLAUDE.md', label: 'AI configuration' },
110
- ];
111
-
112
- console.log('\n \x1b[36mCRG Installation Status\x1b[0m\n');
113
- let found = 0;
114
- checks.forEach(c => {
115
- const exists = fs.existsSync(path.join(cwd, c.file));
116
- if (exists) found++;
117
- console.log(` ${exists ? '\x1b[32m✓\x1b[0m' : '\x1b[31m✗\x1b[0m'} ${c.label}`);
118
- });
119
-
120
- // Check if code-review-graph is installed
121
- const checkCRG = () => {
122
- return new Promise(resolve => {
123
- execFile('code-review-graph', ['--version'], (err) => {
124
- resolve(!err);
125
- });
126
- });
127
- };
128
-
129
- checkCRG().then(installed => {
130
- console.log(` ${installed ? '\x1b[32m✓\x1b[0m' : '\x1b[31m✗\x1b[0m'} code-review-graph CLI`);
131
- const total = checks.length + 1;
132
- const score = found + (installed ? 1 : 0);
133
- console.log(`\n ${score}/${total} components present`);
134
- if (score === total) {
135
- console.log(' \x1b[32m✓ Fully set up!\x1b[0m\n');
136
- } else if (score >= 3) {
137
- console.log(' \x1b[33m~ Partially set up. Run install command.\x1b[0m\n');
138
- } else {
139
- console.log(' \x1b[31m✗ Not set up. Run: npx crg-dev-kit install\x1b[0m\n');
140
- }
141
- });
142
- }
143
-
144
- function uninstallFiles() {
145
- const cwd = process.cwd();
146
- const files = ['setup-crg.sh', 'setup-crg.ps1', 'check-crg.sh', 'CLAUDE.md', 'crg-cheatsheet.pdf', 'README.md'];
147
- let removed = 0;
148
-
149
- files.forEach(f => {
150
- const dst = path.join(cwd, f);
151
- if (fs.existsSync(dst)) {
152
- fs.unlinkSync(dst);
153
- console.log(` \x1b[31m✗\x1b[0m ${f}`);
154
- removed++;
155
- }
156
- });
157
-
158
- if (removed === 0) {
159
- console.log('\n \x1b[33mNo CRG files found to remove.\x1b[0m\n');
160
- } else {
161
- console.log(`\n \x1b[31m${removed} file(s) removed from ${cwd}\x1b[0m\n`);
162
- }
163
- }
164
-
165
- function startServer() {
32
+ } else {
166
33
  let port = 8742;
167
34
  let noOpen = false;
168
35
 
@@ -178,73 +45,6 @@ function startServer() {
178
45
  if (args[i] === '--no-open') noOpen = true;
179
46
  }
180
47
 
181
- const serverPath = path.join(__dirname, '..', 'server.js');
182
- const server = require(serverPath);
48
+ const server = require('../server');
183
49
  server.start(port, noOpen);
184
50
  }
185
-
186
- function showROI() {
187
- const cwd = process.cwd();
188
- const report = roi.generateROIReport(cwd);
189
- console.log('\n' + report);
190
- }
191
-
192
- function runTutorial() {
193
- const tutorialPath = path.join(__dirname, 'tutorial.js');
194
- const tutorial = require(tutorialPath);
195
- }
196
-
197
- // Command routing
198
- switch (cmd) {
199
- case 'install':
200
- case 'setup':
201
- copyFiles();
202
- break;
203
-
204
- case 'uninstall':
205
- case 'remove':
206
- uninstallFiles();
207
- break;
208
-
209
- case 'status':
210
- case 'check':
211
- checkStatus();
212
- break;
213
-
214
- case 'start':
215
- case 'serve':
216
- case 'dashboard':
217
- startServer();
218
- break;
219
-
220
- case 'help':
221
- case '--help':
222
- case '-h':
223
- printHelp();
224
- break;
225
-
226
- case 'version':
227
- case '--version':
228
- case '-v':
229
- printVersion();
230
- break;
231
-
232
- case 'roi':
233
- showROI();
234
- break;
235
-
236
- case 'tutorial':
237
- runTutorial();
238
- break;
239
-
240
- default:
241
- // No command or unknown command = start server
242
- if (!cmd || cmd.startsWith('-')) {
243
- startServer();
244
- } else {
245
- console.log(`\x1b[31mUnknown command: ${cmd}\x1b[0m`);
246
- console.log('Run \x1b[1mnpx crg-dev-kit help\x1b[0m for usage.\n');
247
- process.exit(1);
248
- }
249
- break;
250
- }
package/lib/actions.js ADDED
@@ -0,0 +1,127 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { execFile } = require('child_process');
4
+ const { ANALYTICS_DIR } = require('./paths');
5
+ const roi = require('./roi');
6
+
7
+ const ASSETS = path.join(__dirname, '..', 'assets');
8
+
9
+ const INSTALL_FILES = [
10
+ { name: 'setup-crg.sh', executable: true, label: 'Linux/macOS setup script' },
11
+ { name: 'setup-crg.ps1', executable: false, label: 'Windows setup script' },
12
+ { name: 'check-crg.sh', executable: true, label: 'Health check script' },
13
+ { name: 'CLAUDE.md', executable: false, label: 'AI configuration' },
14
+ { name: 'crg-cheatsheet.pdf', executable: false, label: 'Cheatsheet PDF' },
15
+ { name: 'README.md', executable: false, label: 'Documentation' },
16
+ ];
17
+
18
+ function install(targetDir, trackROI = true) {
19
+ const results = [];
20
+ let copied = 0;
21
+
22
+ INSTALL_FILES.forEach(f => {
23
+ const src = path.join(ASSETS, f.name);
24
+ const dst = path.join(targetDir, f.name);
25
+ if (!fs.existsSync(src)) {
26
+ results.push({ file: f.name, status: 'missing_source' });
27
+ return;
28
+ }
29
+ if (fs.existsSync(dst)) {
30
+ results.push({ file: f.name, status: 'skipped', reason: 'already exists' });
31
+ return;
32
+ }
33
+ fs.copyFileSync(src, dst);
34
+ if (f.executable) {
35
+ try { fs.chmodSync(dst, '755'); } catch {}
36
+ }
37
+ results.push({ file: f.name, status: 'copied' });
38
+ copied++;
39
+ });
40
+
41
+ if (trackROI) {
42
+ roi.setInstallDate(targetDir);
43
+ }
44
+
45
+ return { copied, total: INSTALL_FILES.length, results, targetDir };
46
+ }
47
+
48
+ function status(targetDir) {
49
+ const checks = INSTALL_FILES.slice(0, 4).map(f => ({
50
+ file: f.name,
51
+ label: f.label,
52
+ exists: fs.existsSync(path.join(targetDir, f.name))
53
+ }));
54
+
55
+ return new Promise(resolve => {
56
+ execFile('code-review-graph', ['--version'], (err, stdout) => {
57
+ const crgInstalled = !err;
58
+ const crgVersion = crgInstalled ? (stdout || '').trim() : null;
59
+ const found = checks.filter(c => c.exists).length + (crgInstalled ? 1 : 0);
60
+ const total = checks.length + 1;
61
+
62
+ let verdict = 'not_setup';
63
+ if (found === total) verdict = 'ready';
64
+ else if (found >= 3) verdict = 'partial';
65
+
66
+ resolve({ checks, crgInstalled, crgVersion, found, total, verdict, targetDir });
67
+ });
68
+ });
69
+ }
70
+
71
+ function uninstall(targetDir) {
72
+ const files = INSTALL_FILES.map(f => f.name);
73
+ const existing = files.filter(f => fs.existsSync(path.join(targetDir, f)));
74
+ const removed = [];
75
+
76
+ existing.forEach(f => {
77
+ fs.unlinkSync(path.join(targetDir, f));
78
+ removed.push(f);
79
+ });
80
+
81
+ return { removed, targetDir };
82
+ }
83
+
84
+ function healthCheck(targetDir) {
85
+ const results = [];
86
+
87
+ // Check graph DB
88
+ const dbPath = path.join(targetDir, '.code-review-graph', 'graph.db');
89
+ results.push({ check: 'Graph DB exists', pass: fs.existsSync(dbPath) });
90
+
91
+ // Check setup files
92
+ results.push({ check: 'setup-crg.sh present', pass: fs.existsSync(path.join(targetDir, 'setup-crg.sh')) });
93
+ results.push({ check: 'CLAUDE.md present', pass: fs.existsSync(path.join(targetDir, 'CLAUDE.md')) });
94
+
95
+ return new Promise(resolve => {
96
+ execFile('code-review-graph', ['--version'], (err, stdout) => {
97
+ results.push({ check: 'code-review-graph CLI', pass: !err, version: err ? null : (stdout || '').trim() });
98
+
99
+ // Try getting graph stats
100
+ if (fs.existsSync(dbPath)) {
101
+ try {
102
+ const sqlite3 = require('child_process');
103
+ // Use python to read SQLite since we can't require sqlite3
104
+ const cmd = `python3 -c "import sqlite3,json;db=sqlite3.connect('${dbPath}');r=dict(nodes=db.execute('SELECT COUNT(*) FROM nodes').fetchone()[0],edges=db.execute('SELECT COUNT(*) FROM edges').fetchone()[0]);print(json.dumps(r))"`;
105
+ execFile('bash', ['-c', cmd], (err2, stdout2) => {
106
+ if (!err2 && stdout2) {
107
+ try {
108
+ const stats = JSON.parse(stdout2.trim());
109
+ results.push({ check: `Graph: ${stats.nodes} nodes, ${stats.edges} edges`, pass: stats.nodes > 0 });
110
+ } catch {}
111
+ }
112
+ const pass = results.filter(r => r.pass).length;
113
+ resolve({ results, pass, total: results.length, targetDir });
114
+ });
115
+ } catch {
116
+ const pass = results.filter(r => r.pass).length;
117
+ resolve({ results, pass, total: results.length, targetDir });
118
+ }
119
+ } else {
120
+ const pass = results.filter(r => r.pass).length;
121
+ resolve({ results, pass, total: results.length, targetDir });
122
+ }
123
+ });
124
+ });
125
+ }
126
+
127
+ module.exports = { install, status, uninstall, healthCheck, INSTALL_FILES, ASSETS };
package/lib/analytics.js CHANGED
@@ -1,10 +1,7 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
  const crypto = require('crypto');
4
-
5
- const ANALYTICS_DIR = path.join(process.env.HOME || process.env.USERPROFILE, '.crg-analytics');
6
- const SESSIONS_FILE = path.join(ANALYTICS_DIR, 'sessions.json');
7
- const TOKEN_BASELINES = path.join(ANALYTICS_DIR, 'baselines.json');
4
+ const { ANALYTICS_DIR, SESSIONS_FILE, ensureDir } = require('./paths');
8
5
 
9
6
  const TOKEN_ESTIMATES = {
10
7
  read_file_per_100_lines: 75,
@@ -23,12 +20,6 @@ const TOKEN_ESTIMATES = {
23
20
  get_review_context_tool: 400,
24
21
  };
25
22
 
26
- function ensureDir() {
27
- if (!fs.existsSync(ANALYTICS_DIR)) {
28
- fs.mkdirSync(ANALYTICS_DIR, { recursive: true });
29
- }
30
- }
31
-
32
23
  function readJSON(file, fallback) {
33
24
  try {
34
25
  return JSON.parse(fs.readFileSync(file, 'utf8'));
@@ -60,10 +51,14 @@ function estimateTokensWithCRG(toolsUsed) {
60
51
  }
61
52
 
62
53
  function createSession(projectPath, operation) {
54
+ if (typeof projectPath !== 'string' || projectPath.length === 0 || projectPath.length > 500) {
55
+ throw new Error('Invalid project path');
56
+ }
57
+ projectPath = path.resolve(projectPath);
63
58
  ensureDir();
64
59
  const sessions = readJSON(SESSIONS_FILE, []);
65
60
  const session = {
66
- id: crypto.randomUUID(),
61
+ id: crypto.randomUUID ? crypto.randomUUID() : require('crypto').randomBytes(16).toString('hex'),
67
62
  project: projectPath,
68
63
  operation: operation || 'code_review',
69
64
  startTime: new Date().toISOString(),
@@ -174,6 +169,13 @@ function getAllStats() {
174
169
  const totalTokensWithCRG = projectStats.reduce((sum, p) => sum + p.totalTokensWithCRG, 0);
175
170
  const avgSavings = projectStats.reduce((sum, p) => sum + p.avgSavingsPercent, 0) / projectStats.length;
176
171
 
172
+ const toolUsage = {};
173
+ projectStats.forEach(p => {
174
+ Object.entries(p.toolUsage).forEach(([tool, count]) => {
175
+ toolUsage[tool] = (toolUsage[tool] || 0) + count;
176
+ });
177
+ });
178
+
177
179
  return {
178
180
  totalProjects: projectPaths.length,
179
181
  totalSessions: completedSessions.length,
@@ -182,6 +184,7 @@ function getAllStats() {
182
184
  totalTokensSaved: totalTokensWithoutCRG - totalTokensWithCRG,
183
185
  avgSavingsPercent: Math.round(avgSavings),
184
186
  estimatedCostSavings: Math.round((totalTokensWithoutCRG - totalTokensWithCRG) / 1000 * 0.01 * 100) / 100,
187
+ toolUsage,
185
188
  projects: projectStats
186
189
  };
187
190
  }
package/lib/paths.js ADDED
@@ -0,0 +1,13 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const os = require('os');
4
+
5
+ const ANALYTICS_DIR = path.join(os.homedir(), '.crg-analytics');
6
+ const SESSIONS_FILE = path.join(ANALYTICS_DIR, 'sessions.json');
7
+ const HISTORY_FILE = path.join(os.homedir(), '.claude', 'history.jsonl');
8
+
9
+ function ensureDir() {
10
+ fs.mkdirSync(ANALYTICS_DIR, { recursive: true });
11
+ }
12
+
13
+ module.exports = { ANALYTICS_DIR, SESSIONS_FILE, HISTORY_FILE, ensureDir };
package/lib/roi.js CHANGED
@@ -1,14 +1,6 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
-
4
- const ANALYTICS_DIR = path.join(process.env.HOME || process.env.USERPROFILE, '.crg-analytics');
5
- const HISTORY_FILE = path.join(process.env.HOME || process.env.USERPROFILE, '.claude', 'history.jsonl');
6
-
7
- function ensureDir() {
8
- if (!fs.existsSync(ANALYTICS_DIR)) {
9
- fs.mkdirSync(ANALYTICS_DIR, { recursive: true });
10
- }
11
- }
3
+ const { ANALYTICS_DIR, HISTORY_FILE, ensureDir } = require('./paths');
12
4
 
13
5
  function getInstallDate(projectPath) {
14
6
  const installFile = path.join(ANALYTICS_DIR, 'install.json');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "crg-dev-kit",
3
- "version": "1.0.0",
3
+ "version": "2.0.0",
4
4
  "description": "One-click setup for code-review-graph — AI-powered codebase knowledge graph with token analytics",
5
5
  "main": "server.js",
6
6
  "bin": {