grammata 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 +237 -0
- package/dist/claude.d.ts +36 -0
- package/dist/claude.d.ts.map +1 -0
- package/dist/claude.js +170 -0
- package/dist/claude.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +679 -0
- package/dist/cli.js.map +1 -0
- package/dist/codex.d.ts +32 -0
- package/dist/codex.d.ts.map +1 -0
- package/dist/codex.js +212 -0
- package/dist/codex.js.map +1 -0
- package/dist/format.d.ts +5 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +26 -0
- package/dist/format.js.map +1 -0
- package/dist/index.d.ts +94 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +198 -0
- package/dist/index.js.map +1 -0
- package/dist/pricing.d.ts +20 -0
- package/dist/pricing.d.ts.map +1 -0
- package/dist/pricing.js +46 -0
- package/dist/pricing.js.map +1 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# grammata
|
|
2
|
+
|
|
3
|
+
Read and aggregate coding agent usage data from your local machine. Parses session files from **Claude Code** (`~/.claude/`) and **Codex** (`~/.codex/`) to give you accurate cost, token, and activity breakdowns.
|
|
4
|
+
|
|
5
|
+
Zero external dependencies. Reads session JSONL files directly from disk for accurate cost and token breakdowns.
|
|
6
|
+
|
|
7
|
+
Part of the [Pella Labs](https://github.com/pella-labs) ecosystem. See also [@pella-labs/pinakes](https://www.npmjs.com/package/@pella-labs/pinakes) for building knowledge graphs over your codebase.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install grammata
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { readAll } from 'grammata';
|
|
19
|
+
|
|
20
|
+
const data = await readAll();
|
|
21
|
+
|
|
22
|
+
console.log(`Total cost: $${data.combined.totalCost.toFixed(2)}`);
|
|
23
|
+
console.log(`Sessions: ${data.combined.totalSessions}`);
|
|
24
|
+
console.log(`Claude: $${data.claude.cost.toFixed(2)} (${data.claude.sessions} sessions)`);
|
|
25
|
+
console.log(`Codex: $${data.codex.cost.toFixed(2)} (${data.codex.sessions} sessions)`);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## API
|
|
29
|
+
|
|
30
|
+
### `readAll()`
|
|
31
|
+
|
|
32
|
+
Returns a combined summary across all sources.
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
const data = await readAll();
|
|
36
|
+
|
|
37
|
+
data.claude.sessions // number of Claude Code sessions
|
|
38
|
+
data.claude.cost // total cost in USD
|
|
39
|
+
data.claude.inputTokens // total input tokens
|
|
40
|
+
data.claude.outputTokens // total output tokens
|
|
41
|
+
data.claude.cacheReadTokens // total cache read tokens
|
|
42
|
+
data.claude.cacheSavingsUsd // how much caching saved you
|
|
43
|
+
data.claude.models // { 'claude-opus-4-6': { sessions: 100, cost: 500 } }
|
|
44
|
+
data.claude.topTools // [{ name: 'Bash', count: 14877 }, ...]
|
|
45
|
+
data.claude.hourDistribution // 24-element array, index = hour
|
|
46
|
+
data.claude.activeDays // number of unique days with sessions
|
|
47
|
+
|
|
48
|
+
data.codex.sessions // number of Codex sessions
|
|
49
|
+
data.codex.cost // total cost in USD
|
|
50
|
+
data.codex.inputTokens // total input tokens (includes cached)
|
|
51
|
+
data.codex.cachedInputTokens // cached portion of input
|
|
52
|
+
data.codex.outputTokens // total output tokens
|
|
53
|
+
data.codex.models // { 'gpt-5.3-codex': { sessions: 47, cost: 558 } }
|
|
54
|
+
|
|
55
|
+
data.combined.totalCost // claude + codex
|
|
56
|
+
data.combined.totalSessions // claude + codex
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### `readClaude(dir?)`
|
|
60
|
+
|
|
61
|
+
Read only Claude Code data. Optionally pass a custom directory (defaults to `~/.claude/projects`).
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
import { readClaude } from 'grammata';
|
|
65
|
+
|
|
66
|
+
const claude = await readClaude();
|
|
67
|
+
|
|
68
|
+
for (const session of claude.sessions) {
|
|
69
|
+
console.log(session.sessionName, session.model, `$${session.costUsd.toFixed(2)}`);
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Session fields:** `sessionId`, `sessionName`, `project`, `model`, `inputTokens`, `outputTokens`, `cacheReadTokens`, `cacheCreateTokens`, `costUsd`, `turnCount`, `toolCalls`, `toolBreakdown`, `startHour`, `firstTimestamp`, `lastTimestamp`
|
|
74
|
+
|
|
75
|
+
### `readCodex(dir?)`
|
|
76
|
+
|
|
77
|
+
Read only Codex data. Optionally pass a custom directory (defaults to `~/.codex`).
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { readCodex } from 'grammata';
|
|
81
|
+
|
|
82
|
+
const codex = await readCodex();
|
|
83
|
+
|
|
84
|
+
for (const session of codex.sessions) {
|
|
85
|
+
console.log(session.model, `$${session.costUsd.toFixed(2)}`, session.project);
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Session fields:** `sessionId`, `sessionName`, `project`, `model`, `modelProvider`, `inputTokens`, `cachedInputTokens`, `outputTokens`, `costUsd`, `durationMs`, `createdAt`, `updatedAt`, `source`, `gitBranch`
|
|
90
|
+
|
|
91
|
+
### Formatting Helpers
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import { formatCost, formatTokens, formatDuration } from 'grammata';
|
|
95
|
+
|
|
96
|
+
formatCost(4382.95) // "$4383"
|
|
97
|
+
formatCost(42.5) // "$42.50"
|
|
98
|
+
formatCost(0.003) // "$0.0030"
|
|
99
|
+
|
|
100
|
+
formatTokens(6_771_925_747) // "6.8B"
|
|
101
|
+
formatTokens(2_300_000) // "2.3M"
|
|
102
|
+
formatTokens(45_000) // "45.0K"
|
|
103
|
+
|
|
104
|
+
formatDuration(5_400_000) // "1.5h"
|
|
105
|
+
formatDuration(300_000) // "5m"
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Pricing Tables
|
|
109
|
+
|
|
110
|
+
Access the pricing tables directly if you need custom cost calculations:
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
import { CLAUDE_PRICING, CODEX_PRICING, getClaudePricing, getCodexPricing } from 'grammata';
|
|
114
|
+
|
|
115
|
+
// Per-million-token rates
|
|
116
|
+
const opus = getClaudePricing('claude-opus-4-6');
|
|
117
|
+
// { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }
|
|
118
|
+
|
|
119
|
+
const codex = getCodexPricing('gpt-5.3-codex');
|
|
120
|
+
// { input: 1.75, output: 14, cachedInput: 0.175 }
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## CLI
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
npx grammata # full summary (default)
|
|
127
|
+
npx grammata claude # Claude Code: cost, tokens, models, tools, projects
|
|
128
|
+
npx grammata codex # Codex: cost, tokens, models, projects
|
|
129
|
+
npx grammata sessions # list all sessions (most recent first)
|
|
130
|
+
npx grammata models # model breakdown across both sources
|
|
131
|
+
npx grammata tools # tool usage ranking with bar chart
|
|
132
|
+
npx grammata tokens # token breakdown by source
|
|
133
|
+
npx grammata cost # cost summary + cache savings
|
|
134
|
+
npx grammata daily # day-by-day costs with chart
|
|
135
|
+
npx grammata hours # activity by hour of day
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
All commands support `--json` for machine-readable output:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
npx grammata cost --json
|
|
142
|
+
npx grammata models --json
|
|
143
|
+
npx grammata daily --json
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Example output (`npx grammata`):
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
grammata
|
|
150
|
+
─────────────────────────────────────
|
|
151
|
+
|
|
152
|
+
Claude Code
|
|
153
|
+
Sessions: 3024
|
|
154
|
+
Cost: $6683
|
|
155
|
+
Input tokens: 2.4M
|
|
156
|
+
Output tokens: 23.5M
|
|
157
|
+
Cache read: 9.2B
|
|
158
|
+
Cache savings: $40979
|
|
159
|
+
Active days: 32
|
|
160
|
+
Top tools: Bash(14885), Read(13768), Edit(6998), Grep(3142), Write(2972)
|
|
161
|
+
|
|
162
|
+
Models:
|
|
163
|
+
claude-opus-4-6 $6467 (1525 sessions)
|
|
164
|
+
claude-haiku-4-5-20251001 $62.43 (1253 sessions)
|
|
165
|
+
claude-sonnet-4-6 $24.64 (75 sessions)
|
|
166
|
+
|
|
167
|
+
Codex
|
|
168
|
+
Sessions: 80
|
|
169
|
+
Cost: $698.25
|
|
170
|
+
Input tokens: 2.3B
|
|
171
|
+
Cached input: 2.2B
|
|
172
|
+
Output tokens: 9.1M
|
|
173
|
+
|
|
174
|
+
Models:
|
|
175
|
+
gpt-5.3-codex $558.32 (47 sessions)
|
|
176
|
+
gpt-5.2-codex $66.24 (7 sessions)
|
|
177
|
+
gpt-5.4 $56.41 (12 sessions)
|
|
178
|
+
|
|
179
|
+
─────────────────────────────────────
|
|
180
|
+
Combined: $7381 (3104 sessions)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## How It Works
|
|
184
|
+
|
|
185
|
+
### Claude Code
|
|
186
|
+
|
|
187
|
+
Reads JSONL session files from `~/.claude/projects/<project>/<session-id>.jsonl`. Each file contains per-turn `assistant` messages with token usage breakdowns:
|
|
188
|
+
|
|
189
|
+
- `input_tokens` — direct input tokens
|
|
190
|
+
- `output_tokens` — model output tokens
|
|
191
|
+
- `cache_read_input_tokens` — tokens served from prompt cache
|
|
192
|
+
- `cache_creation_input_tokens` — tokens written to prompt cache
|
|
193
|
+
|
|
194
|
+
Cost is calculated as: `(input * input_price + output * output_price + cache_read * cache_read_price + cache_create * cache_write_price) / 1M`
|
|
195
|
+
|
|
196
|
+
### Codex
|
|
197
|
+
|
|
198
|
+
Reads JSONL rollout files from `~/.codex/sessions/YYYY/MM/DD/<rollout>.jsonl`. Each file contains `token_count` events with per-turn usage:
|
|
199
|
+
|
|
200
|
+
- `input_tokens` — total input (includes cached)
|
|
201
|
+
- `cached_input_tokens` — cached portion
|
|
202
|
+
- `output_tokens` — model output
|
|
203
|
+
- `reasoning_output_tokens` — chain-of-thought tokens
|
|
204
|
+
|
|
205
|
+
Cost is calculated as: `(uncached_input * input_price + cached * cached_price + output * output_price) / 1M`
|
|
206
|
+
|
|
207
|
+
Model names come from `turn_context` events. Session metadata (title, cwd, git branch) comes from the SQLite threads table as a fallback.
|
|
208
|
+
|
|
209
|
+
### Pricing
|
|
210
|
+
|
|
211
|
+
Pricing tables are sourced from [LiteLLM](https://github.com/BerriAI/litellm) and official pricing pages. Supported models:
|
|
212
|
+
|
|
213
|
+
| Model | Input | Output | Cache Read | Cache Write |
|
|
214
|
+
|-------|------:|-------:|-----------:|------------:|
|
|
215
|
+
| claude-opus-4-6 | $5.00 | $25.00 | $0.50 | $6.25 |
|
|
216
|
+
| claude-sonnet-4-6 | $3.00 | $15.00 | $0.30 | $3.75 |
|
|
217
|
+
| claude-haiku-4-5 | $1.00 | $5.00 | $0.10 | $1.25 |
|
|
218
|
+
| gpt-5.3-codex | $1.75 | $14.00 | $0.175 | — |
|
|
219
|
+
| gpt-5.2-codex | $1.75 | $14.00 | $0.175 | — |
|
|
220
|
+
| gpt-5.1-codex | $1.25 | $10.00 | $0.125 | — |
|
|
221
|
+
| gpt-5.1-codex-mini | $0.25 | $2.00 | $0.025 | — |
|
|
222
|
+
| gpt-5.4 | $2.50 | $15.00 | $0.25 | — |
|
|
223
|
+
|
|
224
|
+
Unknown models fall back to Sonnet pricing (Claude) or gpt-5.2-codex pricing (Codex).
|
|
225
|
+
|
|
226
|
+
## Requirements
|
|
227
|
+
|
|
228
|
+
- Node.js 18+
|
|
229
|
+
- `sqlite3` CLI tool in PATH (for Codex session metadata; Codex token data and all Claude data work without it)
|
|
230
|
+
|
|
231
|
+
## Related
|
|
232
|
+
|
|
233
|
+
- [@pella-labs/pinakes](https://www.npmjs.com/package/@pella-labs/pinakes) — Build knowledge graphs over your codebase
|
|
234
|
+
|
|
235
|
+
## License
|
|
236
|
+
|
|
237
|
+
MIT
|
package/dist/claude.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads Claude Code session JSONL files from ~/.claude/projects/
|
|
3
|
+
* and aggregates token usage, cost, and model data.
|
|
4
|
+
*/
|
|
5
|
+
import { CLAUDE_PRICING } from './pricing.js';
|
|
6
|
+
export { CLAUDE_PRICING };
|
|
7
|
+
export interface ClaudeSession {
|
|
8
|
+
sessionId: string;
|
|
9
|
+
sessionName: string;
|
|
10
|
+
project: string;
|
|
11
|
+
firstTimestamp: string;
|
|
12
|
+
lastTimestamp: string;
|
|
13
|
+
model: string;
|
|
14
|
+
inputTokens: number;
|
|
15
|
+
outputTokens: number;
|
|
16
|
+
cacheReadTokens: number;
|
|
17
|
+
cacheCreateTokens: number;
|
|
18
|
+
costUsd: number;
|
|
19
|
+
turnCount: number;
|
|
20
|
+
toolCalls: number;
|
|
21
|
+
toolBreakdown: Record<string, number>;
|
|
22
|
+
startHour: number;
|
|
23
|
+
}
|
|
24
|
+
export interface ClaudeSummary {
|
|
25
|
+
sessions: ClaudeSession[];
|
|
26
|
+
totalCost: number;
|
|
27
|
+
totalInputTokens: number;
|
|
28
|
+
totalOutputTokens: number;
|
|
29
|
+
totalCacheReadTokens: number;
|
|
30
|
+
totalCacheCreateTokens: number;
|
|
31
|
+
cacheSavingsUsd: number;
|
|
32
|
+
toolBreakdown: Record<string, number>;
|
|
33
|
+
hourDistribution: number[];
|
|
34
|
+
}
|
|
35
|
+
export declare function readClaude(dir?: string): Promise<ClaudeSummary>;
|
|
36
|
+
//# sourceMappingURL=claude.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../src/claude.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,cAAc,EAAoB,MAAM,cAAc,CAAC;AAEhE,OAAO,EAAE,cAAc,EAAE,CAAC;AAI1B,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AA0HD,wBAAsB,UAAU,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAuErE"}
|
package/dist/claude.js
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads Claude Code session JSONL files from ~/.claude/projects/
|
|
3
|
+
* and aggregates token usage, cost, and model data.
|
|
4
|
+
*/
|
|
5
|
+
import { lstat, readdir, readFile } from 'fs/promises';
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
import { homedir } from 'os';
|
|
8
|
+
import { CLAUDE_PRICING, getClaudePricing } from './pricing.js';
|
|
9
|
+
export { CLAUDE_PRICING };
|
|
10
|
+
const MAX_FILE_SIZE = 50 * 1024 * 1024; // 50 MB
|
|
11
|
+
function isAssistantWithUsage(d) {
|
|
12
|
+
const obj = d;
|
|
13
|
+
return obj?.type === 'assistant' && typeof obj?.message === 'object' && obj.message !== null;
|
|
14
|
+
}
|
|
15
|
+
async function parseSessionFile(filePath, projectName) {
|
|
16
|
+
try {
|
|
17
|
+
const fileInfo = await lstat(filePath);
|
|
18
|
+
if (fileInfo.isSymbolicLink())
|
|
19
|
+
return null;
|
|
20
|
+
if (fileInfo.size > MAX_FILE_SIZE)
|
|
21
|
+
return null;
|
|
22
|
+
const content = await readFile(filePath, 'utf-8');
|
|
23
|
+
const lines = content.split('\n').filter((l) => l.trim());
|
|
24
|
+
let model = 'unknown';
|
|
25
|
+
let totalInput = 0;
|
|
26
|
+
let totalOutput = 0;
|
|
27
|
+
let cacheRead = 0;
|
|
28
|
+
let cacheCreate = 0;
|
|
29
|
+
let turnCount = 0;
|
|
30
|
+
let toolCalls = 0;
|
|
31
|
+
const toolBreakdown = {};
|
|
32
|
+
let firstTs = '';
|
|
33
|
+
let lastTs = '';
|
|
34
|
+
let sessionName = '';
|
|
35
|
+
for (const line of lines) {
|
|
36
|
+
try {
|
|
37
|
+
const d = JSON.parse(line);
|
|
38
|
+
if (d.timestamp) {
|
|
39
|
+
if (!firstTs)
|
|
40
|
+
firstTs = d.timestamp;
|
|
41
|
+
lastTs = d.timestamp;
|
|
42
|
+
}
|
|
43
|
+
if (!sessionName && d.type === 'queue-operation' && d.content) {
|
|
44
|
+
const text = typeof d.content === 'string' ? d.content : '';
|
|
45
|
+
sessionName = text.replace(/^-\n?/, '').trim().slice(0, 80);
|
|
46
|
+
}
|
|
47
|
+
if (isAssistantWithUsage(d)) {
|
|
48
|
+
const usage = d.message.usage;
|
|
49
|
+
if (usage) {
|
|
50
|
+
totalInput += usage.input_tokens || 0;
|
|
51
|
+
totalOutput += usage.output_tokens || 0;
|
|
52
|
+
cacheRead += usage.cache_read_input_tokens || 0;
|
|
53
|
+
cacheCreate += usage.cache_creation_input_tokens || 0;
|
|
54
|
+
turnCount++;
|
|
55
|
+
}
|
|
56
|
+
if (d.message.model && d.message.model !== '<synthetic>') {
|
|
57
|
+
model = d.message.model;
|
|
58
|
+
}
|
|
59
|
+
if (d.message.content) {
|
|
60
|
+
for (const c of d.message.content) {
|
|
61
|
+
if (c && typeof c === 'object' && c.type === 'tool_use') {
|
|
62
|
+
toolCalls++;
|
|
63
|
+
const toolName = c.name || 'unknown';
|
|
64
|
+
toolBreakdown[toolName] = (toolBreakdown[toolName] || 0) + 1;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// Skip malformed lines
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (turnCount === 0)
|
|
75
|
+
return null;
|
|
76
|
+
const pricing = getClaudePricing(model);
|
|
77
|
+
const costUsd = (totalInput * pricing.input +
|
|
78
|
+
totalOutput * pricing.output +
|
|
79
|
+
cacheRead * pricing.cacheRead +
|
|
80
|
+
cacheCreate * pricing.cacheWrite) /
|
|
81
|
+
1_000_000;
|
|
82
|
+
const sessionId = filePath.split('/').pop()?.replace('.jsonl', '') || '';
|
|
83
|
+
const startHour = firstTs ? new Date(firstTs).getHours() : 0;
|
|
84
|
+
return {
|
|
85
|
+
sessionId,
|
|
86
|
+
sessionName: sessionName || sessionId.slice(0, 8),
|
|
87
|
+
project: projectName,
|
|
88
|
+
firstTimestamp: firstTs,
|
|
89
|
+
lastTimestamp: lastTs,
|
|
90
|
+
model,
|
|
91
|
+
inputTokens: totalInput,
|
|
92
|
+
outputTokens: totalOutput,
|
|
93
|
+
cacheReadTokens: cacheRead,
|
|
94
|
+
cacheCreateTokens: cacheCreate,
|
|
95
|
+
costUsd,
|
|
96
|
+
turnCount,
|
|
97
|
+
toolCalls,
|
|
98
|
+
toolBreakdown,
|
|
99
|
+
startHour,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
export async function readClaude(dir) {
|
|
107
|
+
const claudeDir = dir || join(homedir(), '.claude', 'projects');
|
|
108
|
+
const result = {
|
|
109
|
+
sessions: [],
|
|
110
|
+
totalCost: 0,
|
|
111
|
+
totalInputTokens: 0,
|
|
112
|
+
totalOutputTokens: 0,
|
|
113
|
+
totalCacheReadTokens: 0,
|
|
114
|
+
totalCacheCreateTokens: 0,
|
|
115
|
+
cacheSavingsUsd: 0,
|
|
116
|
+
toolBreakdown: {},
|
|
117
|
+
hourDistribution: new Array(24).fill(0),
|
|
118
|
+
};
|
|
119
|
+
try {
|
|
120
|
+
const projects = await readdir(claudeDir);
|
|
121
|
+
for (const project of projects) {
|
|
122
|
+
const projectDir = join(claudeDir, project);
|
|
123
|
+
try {
|
|
124
|
+
const dirInfo = await lstat(projectDir);
|
|
125
|
+
if (dirInfo.isSymbolicLink())
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
let files;
|
|
132
|
+
try {
|
|
133
|
+
files = (await readdir(projectDir)).filter((f) => f.endsWith('.jsonl'));
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
const BATCH_SIZE = 50;
|
|
139
|
+
for (let i = 0; i < files.length; i += BATCH_SIZE) {
|
|
140
|
+
const batch = files.slice(i, i + BATCH_SIZE);
|
|
141
|
+
const sessions = await Promise.all(batch.map((f) => parseSessionFile(join(projectDir, f), project)));
|
|
142
|
+
for (const session of sessions) {
|
|
143
|
+
if (session) {
|
|
144
|
+
result.sessions.push(session);
|
|
145
|
+
result.totalCost += session.costUsd;
|
|
146
|
+
result.totalInputTokens += session.inputTokens;
|
|
147
|
+
result.totalOutputTokens += session.outputTokens;
|
|
148
|
+
result.totalCacheReadTokens += session.cacheReadTokens;
|
|
149
|
+
result.totalCacheCreateTokens += session.cacheCreateTokens;
|
|
150
|
+
for (const [tool, count] of Object.entries(session.toolBreakdown)) {
|
|
151
|
+
result.toolBreakdown[tool] = (result.toolBreakdown[tool] || 0) + count;
|
|
152
|
+
}
|
|
153
|
+
result.hourDistribution[session.startHour]++;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
for (const session of result.sessions) {
|
|
159
|
+
const pricing = getClaudePricing(session.model);
|
|
160
|
+
const savingsPerToken = (pricing.input - pricing.cacheRead) / 1_000_000;
|
|
161
|
+
result.cacheSavingsUsd += session.cacheReadTokens * savingsPerToken;
|
|
162
|
+
}
|
|
163
|
+
result.sessions.sort((a, b) => new Date(b.firstTimestamp).getTime() - new Date(a.firstTimestamp).getTime());
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
// Directory doesn't exist or is unreadable
|
|
167
|
+
}
|
|
168
|
+
return result;
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=claude.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../src/claude.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|