claude-roi 0.3.4 → 0.4.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
@@ -116,11 +116,11 @@ Parsed session data is cached at `~/.cache/claude-roi/parsed-sessions.json`. On
116
116
 
117
117
  ### Cost Calculation
118
118
 
119
- Token costs are version-aware and calculated per model:
119
+ Token costs are version-aware and calculated per model (see [Anthropic pricing](https://platform.claude.com/docs/en/about-claude/pricing)):
120
120
 
121
121
  | Model | Input | Output | Cache Read | Cache Write |
122
122
  | --- | --- | --- | --- | --- |
123
- | Opus 4.6 | $15/M | $75/M | $1.50/M | $18.75/M |
123
+ | Opus 4.6 | $5/M | $25/M | $0.50/M | $6.25/M |
124
124
  | Opus 4.5 | $5/M | $25/M | $0.50/M | $6.25/M |
125
125
  | Opus 4.0/4.1 (legacy) | $15/M | $75/M | $1.50/M | $18.75/M |
126
126
  | Sonnet 3.7/4.0/4.5/4.6 | $3/M | $15/M | $0.30/M | $3.75/M |
@@ -161,7 +161,7 @@ git push --follow-tags
161
161
 
162
162
  This automatically publishes to npm and creates a GitHub Release with auto-generated notes.
163
163
 
164
- **Setup (one-time):** Add an `NPM_TOKEN` secret in your repo settings (Settings → Secrets → Actions) with a [granular access token](https://www.npmjs.com/settings/~/tokens/granular-access-tokens/new) that has read/write access to the `claude-roi` package.
164
+ **Setup (one-time):** Configure [trusted publishing](https://docs.npmjs.com/trusted-publishers/) on npm for the `claude-roi` package, linking it to the GitHub Actions workflow. No tokens or secrets needed.
165
165
 
166
166
  ## Contributing
167
167
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-roi",
3
- "version": "0.3.4",
3
+ "version": "0.4.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": {
@@ -2187,7 +2187,17 @@ function initCharts() {
2187
2187
  const model = modelLabels[ctx.dataIndex];
2188
2188
  const d = models[model];
2189
2189
  const tpc = d.tokensPerCommit ? formatTokens(d.tokensPerCommit) + ' tok/commit' : 'no commits';
2190
- return ` $${d.cost.toFixed(2)} | ${d.sessions} sessions | ${d.commits} commits | ${tpc}`;
2190
+ const lines = [
2191
+ ` $${d.cost.toFixed(2)} | ${formatTokens(d.tokens)} tokens | ${d.sessions} sessions | ${Math.round(d.commits)} commits | ${tpc}`,
2192
+ ];
2193
+ const subEntries = Object.entries(d.subModels || {});
2194
+ if (subEntries.length >= 1) {
2195
+ for (const [modelId, sub] of subEntries) {
2196
+ const pct = d.cost > 0 ? Math.round((sub.cost / d.cost) * 100) : 0;
2197
+ lines.push(` ${formatModelName(modelId)}: $${sub.cost.toFixed(2)} | ${formatTokens(sub.tokens)} tokens (${pct}%)`);
2198
+ }
2199
+ }
2200
+ return lines;
2191
2201
  },
2192
2202
  },
2193
2203
  },
package/src/metrics.js CHANGED
@@ -420,11 +420,18 @@ export function computeMetrics(correlatedSessions, organicCommits, commitsByRepo
420
420
  for (const [model, data] of Object.entries(session.modelBreakdown)) {
421
421
  const family = getModelFamily(model) || 'unknown';
422
422
  if (!modelBreakdown[family]) {
423
- modelBreakdown[family] = { cost: 0, tokens: 0, sessions: 0, commits: 0, avgCostPerCommit: null };
423
+ modelBreakdown[family] = { cost: 0, tokens: 0, sessions: 0, commits: 0, avgCostPerCommit: null, subModels: {} };
424
424
  }
425
425
  modelBreakdown[family].cost += data.cost;
426
426
  modelBreakdown[family].tokens += data.tokens;
427
427
 
428
+ // Accumulate sub-model cost and tokens within this family
429
+ if (!modelBreakdown[family].subModels[model]) {
430
+ modelBreakdown[family].subModels[model] = { cost: 0, tokens: 0 };
431
+ }
432
+ modelBreakdown[family].subModels[model].cost += data.cost;
433
+ modelBreakdown[family].subModels[model].tokens += data.tokens;
434
+
428
435
  // Distribute sessions and commits proportionally by token share
429
436
  const share = sessionTotalTokens > 0 ? data.tokens / sessionTotalTokens : 0;
430
437
  modelBreakdown[family].sessions += share;
@@ -435,6 +442,9 @@ export function computeMetrics(correlatedSessions, organicCommits, commitsByRepo
435
442
  data.sessions = Math.round(data.sessions);
436
443
  data.avgCostPerCommit = data.commits > 0 ? data.cost / data.commits : null;
437
444
  data.tokensPerCommit = data.commits > 0 ? Math.round(data.tokens / data.commits) : null;
445
+ data.subModels = Object.fromEntries(
446
+ Object.entries(data.subModels).sort(([, a], [, b]) => b.cost - a.cost)
447
+ );
438
448
  }
439
449
 
440
450
  // ---- Tool breakdown ----