claude-roi 0.5.0 → 0.7.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/CLAUDE.md +119 -0
- package/README.md +10 -1
- package/package.json +2 -2
- package/skills-lock.json +10 -0
- package/src/cache.js +1 -1
- package/src/claude-parser.js +56 -0
- package/src/dashboard.html +1024 -4
- package/src/index.js +24 -1
- package/src/metrics.js +152 -8
- package/src/server.js +5 -0
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# CLAUDE.md — Codelens-AI
|
|
2
|
+
|
|
3
|
+
## Project Overview
|
|
4
|
+
|
|
5
|
+
**Codelens AI** (`claude-roi` on npm) is a CLI tool that measures ROI from AI coding agents by correlating Claude Code token usage with git commit output. It parses Claude Code session files, analyzes git history, and serves an interactive dashboard at `http://localhost:3457`.
|
|
6
|
+
|
|
7
|
+
**Version:** 0.6.0
|
|
8
|
+
**License:** MIT
|
|
9
|
+
**npm package:** `claude-roi`
|
|
10
|
+
|
|
11
|
+
## Tech Stack
|
|
12
|
+
|
|
13
|
+
- **Runtime:** Node.js >= 18, ES modules (`"type": "module"`)
|
|
14
|
+
- **Backend:** Express.js 5.0.0
|
|
15
|
+
- **CLI:** Commander.js 13.0.0
|
|
16
|
+
- **Frontend:** Single-file HTML (`src/dashboard.html`) with vanilla JS + Chart.js 4.4.7
|
|
17
|
+
- **Testing:** Playwright (E2E)
|
|
18
|
+
- **Styling:** Inline CSS with CSS variables, glassmorphism design, dark/light theme
|
|
19
|
+
|
|
20
|
+
## Project Structure
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
src/
|
|
24
|
+
├── index.js # CLI entry point & orchestration (Commander)
|
|
25
|
+
├── claude-parser.js # Parses JSONL session files from ~/.claude/projects/
|
|
26
|
+
├── git-analyzer.js # Git log analysis, branch detection, diff stats
|
|
27
|
+
├── correlator.js # Matches sessions to commits via file overlap + time window
|
|
28
|
+
├── metrics.js # ROI calculations, grades, insights, heatmap, survival rate
|
|
29
|
+
├── server.js # Express REST API routes
|
|
30
|
+
├── cache.js # Smart caching with stale file detection
|
|
31
|
+
├── dashboard.html # Single-file SPA dashboard (3000+ lines)
|
|
32
|
+
└── agents/ # Agent integration stubs (claude/, cursor/)
|
|
33
|
+
|
|
34
|
+
tests/
|
|
35
|
+
└── dashboard.spec.js # Playwright E2E tests
|
|
36
|
+
|
|
37
|
+
.github/workflows/
|
|
38
|
+
├── ci.yml # CI: syntax check, Node 18/20/22 matrix
|
|
39
|
+
└── release.yml # npm publish on version tag push
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Data Flow
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
Claude Sessions (JSONL) → claude-parser.js → [Cache] → git-analyzer.js
|
|
46
|
+
→ correlator.js → metrics.js → server.js (REST API) → dashboard.html
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Key API Routes (server.js)
|
|
50
|
+
|
|
51
|
+
- `GET /` — dashboard HTML
|
|
52
|
+
- `GET /api/all` — full payload
|
|
53
|
+
- `GET /api/summary` — hero stats + insights
|
|
54
|
+
- `GET /api/timeline` — daily cost/output chart data
|
|
55
|
+
- `GET /api/sessions` — paginated sessions with sorting
|
|
56
|
+
- `GET /api/models` — model breakdown
|
|
57
|
+
- `GET /api/heatmap` — productivity heatmap
|
|
58
|
+
- `GET /api/tools` — tool usage breakdown
|
|
59
|
+
- `GET /api/survival` — line survival stats
|
|
60
|
+
- `GET /api/tokens` — detailed token analytics
|
|
61
|
+
- `POST /api/refresh` — force re-parse
|
|
62
|
+
|
|
63
|
+
## CLI Usage
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npx claude-roi # defaults: 30 days, port 3457
|
|
67
|
+
npx claude-roi --days 90 # custom lookback
|
|
68
|
+
npx claude-roi --port 8080 # custom port
|
|
69
|
+
npx claude-roi --no-open # don't auto-open browser
|
|
70
|
+
npx claude-roi --json # dump raw JSON to stdout
|
|
71
|
+
npx claude-roi --project X # filter by project name
|
|
72
|
+
npx claude-roi --refresh # force full re-parse
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Development Commands
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npm install # install dependencies
|
|
79
|
+
npm test # run Playwright E2E tests (needs fixtures)
|
|
80
|
+
node src/index.js # run locally
|
|
81
|
+
node --check src/*.js # syntax validation
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Key Design Decisions
|
|
85
|
+
|
|
86
|
+
- **Single-file dashboard** — no build step, served directly by Express
|
|
87
|
+
- **Zero-config** — auto-discovers `~/.claude/projects/`
|
|
88
|
+
- **Smart caching** — incremental parsing, only re-processes changed JSONL files (`~/.cache/agent-analytics/`)
|
|
89
|
+
- **File-first correlation** — sessions matched to commits by file overlap, 2-hour temporal buffer
|
|
90
|
+
- **Privacy-first** — all data stays local, no telemetry
|
|
91
|
+
- **Version-aware pricing** — token costs reflect Anthropic's pricing tiers per model
|
|
92
|
+
|
|
93
|
+
## Coding Conventions
|
|
94
|
+
|
|
95
|
+
- ES module imports (`import`/`export`)
|
|
96
|
+
- No build tooling or transpilation
|
|
97
|
+
- Inline styles and scripts in dashboard.html (no external CSS/JS bundles)
|
|
98
|
+
- Express 5 (path params, async error handling)
|
|
99
|
+
- Functions and variables use camelCase
|
|
100
|
+
- Constants defined at module top
|
|
101
|
+
|
|
102
|
+
## Available Skills
|
|
103
|
+
|
|
104
|
+
Use these skills when working on this project:
|
|
105
|
+
|
|
106
|
+
- **`/simplify`** — Review changed code for reuse, quality, and efficiency, then fix issues found. Use after writing or modifying code.
|
|
107
|
+
- **`/frontend-design`** — Create distinctive, production-grade frontend interfaces. Use when modifying `dashboard.html` or building new UI components.
|
|
108
|
+
- **`/claude-developer-platform`** — Build apps with the Claude API or Anthropic SDK. Use when working on agent integrations in `src/agents/`.
|
|
109
|
+
- **`/find-skills`** — Discover and install new agent skills for extended capabilities.
|
|
110
|
+
- **`/keybindings-help`** — Configure keyboard shortcuts for Claude Code.
|
|
111
|
+
|
|
112
|
+
## Important Notes
|
|
113
|
+
|
|
114
|
+
- The dashboard is a single 3000+ line HTML file — changes should maintain the inline architecture
|
|
115
|
+
- Cache is stored at `~/.cache/agent-analytics/parsed-sessions.json`
|
|
116
|
+
- Session JSONL files are at `~/.claude/projects/`
|
|
117
|
+
- Token pricing is hardcoded in `claude-parser.js` — update when Anthropic changes pricing
|
|
118
|
+
- Playwright tests require Claude session fixtures to run (run locally, not in CI)
|
|
119
|
+
- CI runs syntax checks only; E2E tests are local-only
|
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Codelens AI
|
|
2
2
|
|
|
3
|
+
**[codelensai-dev.vercel.app](https://codelensai-dev.vercel.app/)**
|
|
4
|
+
|
|
3
5
|
**Agent Productivity-to-Cost Correlator** — Is your AI coding agent actually shipping code?
|
|
4
6
|
|
|
5
7
|
Codelens AI ties Claude Code token usage to actual git output. It reads your local Claude Code session files, correlates them with git commits by timestamp, and serves a dashboard answering: *"Am I getting ROI from my AI coding agent?"*
|
|
@@ -77,6 +79,11 @@ This parses your `~/.claude/projects/` session data, analyzes your git repos, an
|
|
|
77
79
|
| **Model Comparison** | Efficiency breakdown across Opus, Sonnet, and Haiku |
|
|
78
80
|
| **Branch Awareness** | What % of AI commits landed on production |
|
|
79
81
|
| **Peak Hours** | Hour-of-day x day-of-week productivity heatmap |
|
|
82
|
+
| **Autonomy Score** | Composite A-F grade measuring how independently the agent works |
|
|
83
|
+
| **Autopilot Ratio** | Assistant messages per user prompt (higher = more autonomous) |
|
|
84
|
+
| **Self-Heal Score** | % of bash calls that are test/lint commands (self-verification) |
|
|
85
|
+
| **Toolbelt Coverage** | % of available tools used per session (workflow breadth) |
|
|
86
|
+
| **Commit Velocity** | Tool calls per commit (lower = more efficient) |
|
|
80
87
|
|
|
81
88
|
## CLI Options
|
|
82
89
|
|
|
@@ -88,6 +95,7 @@ claude-roi --no-open # don't auto-open browser
|
|
|
88
95
|
claude-roi --json # dump all metrics as JSON to stdout
|
|
89
96
|
claude-roi --project techops # filter to a specific project
|
|
90
97
|
claude-roi --refresh # force full re-parse (ignore cache)
|
|
98
|
+
claude-roi --autonomy # print autonomy score to terminal and exit
|
|
91
99
|
```
|
|
92
100
|
|
|
93
101
|
## Dashboard
|
|
@@ -100,7 +108,8 @@ The dashboard includes:
|
|
|
100
108
|
- **Model comparison** — cost breakdown by Claude model
|
|
101
109
|
- **Session length analysis** — which session sizes have the best ROI
|
|
102
110
|
- **Productivity heatmap** — GitHub-style grid showing when you're most productive
|
|
103
|
-
- **
|
|
111
|
+
- **Agent Autonomy** — autonomy score badge, autopilot ratio, self-heal score, toolbelt coverage, commit velocity, and top verification commands
|
|
112
|
+
- **Sessions table** — sortable, expandable table with per-session metrics, matched commits, and autopilot ratio
|
|
104
113
|
|
|
105
114
|
## How It Works
|
|
106
115
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-roi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Correlate Claude Code token usage with git output to measure AI coding agent ROI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"bugs": {
|
|
32
32
|
"url": "https://github.com/Akshat2634/Codelens-AI/issues"
|
|
33
33
|
},
|
|
34
|
-
"homepage": "https://
|
|
34
|
+
"homepage": "https://codelensai-dev.vercel.app/",
|
|
35
35
|
"engines": {
|
|
36
36
|
"node": ">=18.0.0"
|
|
37
37
|
},
|
package/skills-lock.json
ADDED
package/src/cache.js
CHANGED
|
@@ -4,7 +4,7 @@ import os from 'node:os';
|
|
|
4
4
|
|
|
5
5
|
const CACHE_DIR = path.join(os.homedir(), '.cache', 'agent-analytics');
|
|
6
6
|
const CACHE_FILE = path.join(CACHE_DIR, 'parsed-sessions.json');
|
|
7
|
-
const CACHE_VERSION =
|
|
7
|
+
const CACHE_VERSION = 2;
|
|
8
8
|
|
|
9
9
|
export function loadCache() {
|
|
10
10
|
if (!existsSync(CACHE_FILE)) {
|
package/src/claude-parser.js
CHANGED
|
@@ -96,6 +96,43 @@ function toRelativePath(absolutePath, repoPath) {
|
|
|
96
96
|
return absolutePath.split('/').pop();
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
// Commands that are clearly NOT verification even if they contain matching keywords
|
|
100
|
+
const NON_VERIFICATION_PATTERNS = [
|
|
101
|
+
/^\s*node\s+-e\b/, // inline JS eval
|
|
102
|
+
/^\s*find\s+/, // file search
|
|
103
|
+
/^\s*cat\s+/, // file display
|
|
104
|
+
/^\s*echo\s+/, // printing
|
|
105
|
+
/^\s*ls\b/, // listing
|
|
106
|
+
/^\s*rm\s+/, // file deletion
|
|
107
|
+
];
|
|
108
|
+
|
|
109
|
+
// Patterns that identify test/lint/typecheck commands (for autonomy self-heal score)
|
|
110
|
+
const VERIFICATION_PATTERNS = [
|
|
111
|
+
/\bnpm\s+(test|run\s+(test|lint|check|typecheck))\b/,
|
|
112
|
+
/\b(pnpm|yarn|bun)\s+(run\s+)?(test|lint|check|typecheck)\b/,
|
|
113
|
+
/\b(jest|vitest|mocha|ava)\b/,
|
|
114
|
+
/\b(pytest|python\s+-m\s+(pytest|unittest))\b/,
|
|
115
|
+
/\b(go\s+test|cargo\s+(test|clippy))\b/,
|
|
116
|
+
/\b(eslint|biome|prettier\b.*--check)/,
|
|
117
|
+
/\btsc(\s+--noEmit|\s+-p)\b/,
|
|
118
|
+
/\b(mypy|ruff|flake8|pylint|rubocop)\b/,
|
|
119
|
+
/\bnode\s+--check\b/,
|
|
120
|
+
/\bmake\s+(test|check|lint)\b/,
|
|
121
|
+
];
|
|
122
|
+
|
|
123
|
+
function isVerificationCommand(command) {
|
|
124
|
+
if (!command || typeof command !== 'string') return false;
|
|
125
|
+
// Strip cd/path and env var prefixes to get the core command
|
|
126
|
+
const core = command
|
|
127
|
+
.replace(/^(?:cd\s+\S+\s*&&\s*)+/g, '')
|
|
128
|
+
.replace(/^(?:cd\s+\S+\s*;\s*)+/g, '')
|
|
129
|
+
.replace(/^(?:\w+=\S+\s+)+/g, '')
|
|
130
|
+
.trim();
|
|
131
|
+
// Exclude commands that are clearly not verification
|
|
132
|
+
if (NON_VERIFICATION_PATTERNS.some(p => p.test(core))) return false;
|
|
133
|
+
return VERIFICATION_PATTERNS.some(p => p.test(core));
|
|
134
|
+
}
|
|
135
|
+
|
|
99
136
|
function extractToolUse(session, msg) {
|
|
100
137
|
const content = msg.content;
|
|
101
138
|
if (!Array.isArray(content)) return;
|
|
@@ -108,6 +145,17 @@ function extractToolUse(session, msg) {
|
|
|
108
145
|
// Count tool calls
|
|
109
146
|
session.toolCalls[toolName] = (session.toolCalls[toolName] || 0) + 1;
|
|
110
147
|
|
|
148
|
+
// Track Bash commands for autonomy self-heal scoring
|
|
149
|
+
if (toolName === 'Bash') {
|
|
150
|
+
const command = block.input?.command || block.input?.content;
|
|
151
|
+
if (command) {
|
|
152
|
+
session.totalBashCalls++;
|
|
153
|
+
const isVerif = isVerificationCommand(command);
|
|
154
|
+
if (isVerif) session.verificationBashCalls++;
|
|
155
|
+
session.bashCommands.push({ command: command.slice(0, 200), isVerification: isVerif });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
111
159
|
// Track files written/read
|
|
112
160
|
const filePath = block.input?.file_path;
|
|
113
161
|
if (!filePath) continue;
|
|
@@ -145,6 +193,9 @@ function createEmptySession(sessionId) {
|
|
|
145
193
|
filesRead: [],
|
|
146
194
|
userMessageCount: 0,
|
|
147
195
|
assistantMessageCount: 0,
|
|
196
|
+
bashCommands: [],
|
|
197
|
+
totalBashCalls: 0,
|
|
198
|
+
verificationBashCalls: 0,
|
|
148
199
|
};
|
|
149
200
|
}
|
|
150
201
|
|
|
@@ -380,6 +431,11 @@ function mergeSubagentIntoSession(parent, sub) {
|
|
|
380
431
|
parent.toolCalls[tool] = (parent.toolCalls[tool] || 0) + count;
|
|
381
432
|
}
|
|
382
433
|
|
|
434
|
+
// Merge bash command tracking
|
|
435
|
+
parent.totalBashCalls += sub.totalBashCalls;
|
|
436
|
+
parent.verificationBashCalls += sub.verificationBashCalls;
|
|
437
|
+
parent.bashCommands.push(...sub.bashCommands);
|
|
438
|
+
|
|
383
439
|
// Merge files
|
|
384
440
|
for (const f of sub.filesWritten) {
|
|
385
441
|
if (!parent.filesWritten.includes(f)) parent.filesWritten.push(f);
|