claude-usage-rzp 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.
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.projectsCommand = projectsCommand;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const cli_table3_1 = __importDefault(require("cli-table3"));
9
+ const loader_1 = require("../loader");
10
+ const pricing_1 = require("../pricing");
11
+ const config_1 = require("../config");
12
+ function projectsCommand() {
13
+ if (!(0, config_1.hasProjects)()) {
14
+ console.log(chalk_1.default.red(`✗ No projects directory found in ${(0, config_1.getDataDir)()}`));
15
+ process.exit(1);
16
+ }
17
+ const projectSummaries = (0, loader_1.buildProjectSummaries)();
18
+ if (Object.keys(projectSummaries).length === 0) {
19
+ console.log(chalk_1.default.yellow('No projects found'));
20
+ return;
21
+ }
22
+ const projectData = [];
23
+ for (const [encodedPath, sessions] of Object.entries(projectSummaries)) {
24
+ const displayPath = decodeURIComponent(encodedPath);
25
+ const sessionCount = sessions.length;
26
+ const totalInput = sessions.reduce((sum, s) => sum + s.totalInputTokens, 0);
27
+ const totalOutput = sessions.reduce((sum, s) => sum + s.totalOutputTokens, 0);
28
+ const totalCost = sessions.reduce((sum, s) => sum + s.totalCostUsd, 0);
29
+ projectData.push({
30
+ path: displayPath,
31
+ encoded: encodedPath,
32
+ sessions: sessionCount,
33
+ input: totalInput,
34
+ output: totalOutput,
35
+ cost: totalCost,
36
+ });
37
+ }
38
+ // Sort by cost descending
39
+ projectData.sort((a, b) => b.cost - a.cost);
40
+ console.log(chalk_1.default.cyan.bold('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
41
+ console.log(chalk_1.default.cyan.bold(` Projects (${projectData.length} total)`));
42
+ console.log(chalk_1.default.cyan.bold('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
43
+ const table = new cli_table3_1.default({
44
+ head: [
45
+ chalk_1.default.cyan('Project Path'),
46
+ chalk_1.default.white('Sessions'),
47
+ chalk_1.default.blue('Input Tokens'),
48
+ chalk_1.default.green('Output Tokens'),
49
+ chalk_1.default.green.bold('Total Cost'),
50
+ ],
51
+ colAligns: ['left', 'right', 'right', 'right', 'right'],
52
+ colWidths: [40, 10, 15, 15, 12],
53
+ wordWrap: true,
54
+ });
55
+ for (const proj of projectData) {
56
+ table.push([
57
+ proj.path,
58
+ proj.sessions.toString(),
59
+ (0, pricing_1.formatTokens)(proj.input),
60
+ (0, pricing_1.formatTokens)(proj.output),
61
+ (0, pricing_1.formatCost)(proj.cost),
62
+ ]);
63
+ }
64
+ console.log(table.toString());
65
+ console.log(chalk_1.default.dim('\n💡 Tip: Use "claude-usage project <path>" to see sessions in a project\n'));
66
+ }
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.sessionCommand = sessionCommand;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const cli_table3_1 = __importDefault(require("cli-table3"));
9
+ const loader_1 = require("../loader");
10
+ const pricing_1 = require("../pricing");
11
+ function sessionCommand(sessionId, options) {
12
+ const projectSummaries = (0, loader_1.buildProjectSummaries)();
13
+ let foundSession = null;
14
+ let foundProject = '';
15
+ if (options.project) {
16
+ // User specified project
17
+ const encoded = encodeURIComponent(options.project);
18
+ if (encoded in projectSummaries) {
19
+ for (const sess of projectSummaries[encoded]) {
20
+ if (sess.sessionId === sessionId || sess.sessionId.startsWith(sessionId)) {
21
+ foundSession = sess;
22
+ foundProject = encoded;
23
+ break;
24
+ }
25
+ }
26
+ }
27
+ }
28
+ else {
29
+ // Search all projects
30
+ for (const [encodedPath, sessions] of Object.entries(projectSummaries)) {
31
+ for (const sess of sessions) {
32
+ if (sess.sessionId === sessionId || sess.sessionId.startsWith(sessionId)) {
33
+ foundSession = sess;
34
+ foundProject = encodedPath;
35
+ break;
36
+ }
37
+ }
38
+ if (foundSession)
39
+ break;
40
+ }
41
+ }
42
+ if (!foundSession) {
43
+ console.log(chalk_1.default.red(`✗ Session not found: ${sessionId}`));
44
+ process.exit(1);
45
+ }
46
+ // Load messages
47
+ const messages = (0, loader_1.loadSessionMessages)(foundProject, foundSession.sessionId);
48
+ if (messages.length === 0) {
49
+ console.log(chalk_1.default.yellow('No messages found in this session'));
50
+ return;
51
+ }
52
+ console.log(chalk_1.default.cyan.bold('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
53
+ console.log(chalk_1.default.cyan.bold(` Session: ${foundSession.slug}`));
54
+ console.log(chalk_1.default.dim(` Project: ${decodeURIComponent(foundProject)}`));
55
+ console.log(chalk_1.default.dim(` ID: ${foundSession.sessionId}`));
56
+ console.log(chalk_1.default.dim(` ${messages.length} messages`));
57
+ console.log(chalk_1.default.cyan.bold('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
58
+ // Summary
59
+ console.log(chalk_1.default.bold('Summary:'));
60
+ console.log(` Total Input Tokens: ${chalk_1.default.blue((0, pricing_1.formatTokens)(foundSession.totalInputTokens))}`);
61
+ console.log(` Total Output Tokens: ${chalk_1.default.green((0, pricing_1.formatTokens)(foundSession.totalOutputTokens))}`);
62
+ console.log(` Total Cost: ${chalk_1.default.green.bold((0, pricing_1.formatCost)(foundSession.totalCostUsd))}`);
63
+ console.log(` Models Used: ${chalk_1.default.yellow(Array.from(foundSession.modelsUsed).join(', '))}`);
64
+ // Message breakdown
65
+ console.log(chalk_1.default.bold('\nMessage Details:'));
66
+ const table = new cli_table3_1.default({
67
+ head: [
68
+ chalk_1.default.dim('#'),
69
+ chalk_1.default.dim('Timestamp'),
70
+ chalk_1.default.cyan('Model'),
71
+ chalk_1.default.blue('Input'),
72
+ chalk_1.default.green('Output'),
73
+ chalk_1.default.yellow('Cache Write'),
74
+ chalk_1.default.magenta('Cache Read'),
75
+ chalk_1.default.green.bold('Cost'),
76
+ ],
77
+ colAligns: ['right', 'left', 'left', 'right', 'right', 'right', 'right', 'right'],
78
+ });
79
+ for (let i = 0; i < messages.length; i++) {
80
+ const msg = messages[i];
81
+ // Simplify model name
82
+ let modelDisplay = msg.model.replace('claude-', '').replace(/-20\d{6}/, (match) => ` (${match.substring(1)})`);
83
+ // Format timestamp
84
+ const timestamp = msg.timestamp ? new Date(msg.timestamp).toLocaleString('en-US') : 'N/A';
85
+ table.push([
86
+ (i + 1).toString(),
87
+ timestamp,
88
+ modelDisplay,
89
+ (0, pricing_1.formatTokens)(msg.inputTokens),
90
+ (0, pricing_1.formatTokens)(msg.outputTokens),
91
+ (0, pricing_1.formatTokens)(msg.cacheCreationInputTokens),
92
+ (0, pricing_1.formatTokens)(msg.cacheReadInputTokens),
93
+ (0, pricing_1.formatCost)(msg.costUsd),
94
+ ]);
95
+ }
96
+ console.log(table.toString());
97
+ console.log();
98
+ }
package/dist/config.js ADDED
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getDataDir = getDataDir;
4
+ exports.setDataDir = setDataDir;
5
+ exports.hasStatsCache = hasStatsCache;
6
+ exports.hasProjects = hasProjects;
7
+ const os_1 = require("os");
8
+ const path_1 = require("path");
9
+ const fs_1 = require("fs");
10
+ let dataDir = null;
11
+ function getDataDir() {
12
+ if (dataDir) {
13
+ return dataDir;
14
+ }
15
+ // Check environment variable
16
+ const envDir = process.env.CLAUDE_DATA_DIR;
17
+ if (envDir) {
18
+ dataDir = envDir;
19
+ return dataDir;
20
+ }
21
+ // Default to ~/.claude
22
+ dataDir = (0, path_1.join)((0, os_1.homedir)(), '.claude');
23
+ return dataDir;
24
+ }
25
+ function setDataDir(path) {
26
+ dataDir = path;
27
+ }
28
+ function hasStatsCache() {
29
+ return (0, fs_1.existsSync)((0, path_1.join)(getDataDir(), 'stats-cache.json'));
30
+ }
31
+ function hasProjects() {
32
+ return (0, fs_1.existsSync)((0, path_1.join)(getDataDir(), 'projects'));
33
+ }
package/dist/index.js ADDED
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const commander_1 = require("commander");
5
+ const config_1 = require("./config");
6
+ const interactive_1 = require("./commands/interactive");
7
+ const overview_1 = require("./commands/overview");
8
+ const projects_1 = require("./commands/projects");
9
+ const project_1 = require("./commands/project");
10
+ const session_1 = require("./commands/session");
11
+ const config_2 = require("./commands/config");
12
+ const program = new commander_1.Command();
13
+ program
14
+ .name('claude-usage')
15
+ .description('View Claude Code API usage directly in your terminal')
16
+ .version('0.1.0')
17
+ .option('--data-dir <path>', 'Path to Claude data directory')
18
+ .hook('preAction', (thisCommand) => {
19
+ const opts = thisCommand.opts();
20
+ if (opts.dataDir) {
21
+ (0, config_1.setDataDir)(opts.dataDir);
22
+ }
23
+ });
24
+ // Default command (interactive)
25
+ program
26
+ .action(async () => {
27
+ await (0, interactive_1.interactiveCommand)();
28
+ });
29
+ // Overview command (non-interactive, one-shot)
30
+ program
31
+ .command('overview')
32
+ .description('Show usage overview and statistics (non-interactive)')
33
+ .action(() => {
34
+ (0, overview_1.overviewCommand)();
35
+ });
36
+ // Projects command
37
+ program
38
+ .command('projects')
39
+ .description('List all projects with session counts and costs')
40
+ .action(() => {
41
+ (0, projects_1.projectsCommand)();
42
+ });
43
+ // Project command
44
+ program
45
+ .command('project <path>')
46
+ .description('Show sessions for a specific project')
47
+ .action((path) => {
48
+ (0, project_1.projectCommand)(path);
49
+ });
50
+ // Session command
51
+ program
52
+ .command('session <session-id>')
53
+ .description('Show detailed message breakdown for a session')
54
+ .option('--project <path>', 'Project path (encoded or decoded)')
55
+ .action((sessionId, options) => {
56
+ (0, session_1.sessionCommand)(sessionId, options);
57
+ });
58
+ // Config command
59
+ program
60
+ .command('config')
61
+ .description('Show current configuration')
62
+ .action(() => {
63
+ (0, config_2.configCommand)();
64
+ });
65
+ program.parse();
package/dist/loader.js ADDED
@@ -0,0 +1,299 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadStatsCache = loadStatsCache;
4
+ exports.loadHistory = loadHistory;
5
+ exports.loadSessionMessages = loadSessionMessages;
6
+ exports.buildSessionSummary = buildSessionSummary;
7
+ exports.buildProjectSummaries = buildProjectSummaries;
8
+ const fs_1 = require("fs");
9
+ const path_1 = require("path");
10
+ const config_1 = require("./config");
11
+ const pricing_1 = require("./pricing");
12
+ function loadStatsCache() {
13
+ const statsPath = (0, path_1.join)((0, config_1.getDataDir)(), 'stats-cache.json');
14
+ if (!(0, fs_1.existsSync)(statsPath)) {
15
+ return null;
16
+ }
17
+ try {
18
+ const raw = JSON.parse((0, fs_1.readFileSync)(statsPath, 'utf-8'));
19
+ // Parse daily activity
20
+ const dailyActivity = (raw.dailyActivity || []).map((d) => ({
21
+ date: d.date,
22
+ messageCount: d.messageCount || 0,
23
+ sessionCount: d.sessionCount || 0,
24
+ toolCallCount: d.toolCallCount || 0,
25
+ }));
26
+ // Parse daily model tokens
27
+ const dailyModelTokens = (raw.dailyModelTokens || []).map((d) => ({
28
+ date: d.date,
29
+ tokensByModel: d.tokensByModel || {},
30
+ }));
31
+ // Parse model stats
32
+ const modelStats = {};
33
+ let totalInputTokens = 0;
34
+ let totalOutputTokens = 0;
35
+ for (const [modelId, usage] of Object.entries(raw.modelUsage || {})) {
36
+ const u = usage;
37
+ const stats = {
38
+ modelId,
39
+ inputTokens: u.inputTokens || 0,
40
+ outputTokens: u.outputTokens || 0,
41
+ cacheCreationInputTokens: u.cacheCreationInputTokens || 0,
42
+ cacheReadInputTokens: u.cacheReadInputTokens || 0,
43
+ };
44
+ modelStats[modelId] = stats;
45
+ totalInputTokens += stats.inputTokens;
46
+ totalOutputTokens += stats.outputTokens;
47
+ }
48
+ return {
49
+ totalSessions: raw.totalSessions || 0,
50
+ totalMessages: raw.totalMessages || 0,
51
+ totalInputTokens,
52
+ totalOutputTokens,
53
+ firstSessionDate: raw.firstSessionDate,
54
+ lastComputedDate: raw.lastComputedDate,
55
+ dailyActivity,
56
+ dailyModelTokens,
57
+ modelStats,
58
+ hourCounts: raw.hourCounts || {},
59
+ };
60
+ }
61
+ catch (error) {
62
+ console.error('Failed to load stats-cache.json:', error);
63
+ return null;
64
+ }
65
+ }
66
+ function loadHistory() {
67
+ const historyPath = (0, path_1.join)((0, config_1.getDataDir)(), 'history.jsonl');
68
+ if (!(0, fs_1.existsSync)(historyPath)) {
69
+ return {};
70
+ }
71
+ const history = {};
72
+ try {
73
+ const lines = (0, fs_1.readFileSync)(historyPath, 'utf-8').split('\n');
74
+ for (const line of lines) {
75
+ if (!line.trim())
76
+ continue;
77
+ try {
78
+ const entry = JSON.parse(line);
79
+ const sessionId = entry.sessionId;
80
+ if (!sessionId)
81
+ continue;
82
+ const display = (entry.display || '').trim();
83
+ // Check for /rename command
84
+ if (display.startsWith('/rename')) {
85
+ const renamed = display.substring(7).trim();
86
+ if (renamed) {
87
+ if (sessionId in history) {
88
+ history[sessionId].display = renamed;
89
+ history[sessionId].renamed = true;
90
+ }
91
+ else {
92
+ history[sessionId] = {
93
+ project: entry.project,
94
+ timestamp: entry.timestamp,
95
+ display: renamed,
96
+ renamed: true,
97
+ };
98
+ }
99
+ }
100
+ }
101
+ else {
102
+ // Regular entry
103
+ if (!(sessionId in history)) {
104
+ history[sessionId] = {
105
+ project: entry.project,
106
+ timestamp: entry.timestamp,
107
+ display,
108
+ renamed: false,
109
+ };
110
+ }
111
+ }
112
+ }
113
+ catch (err) {
114
+ // Skip malformed lines
115
+ continue;
116
+ }
117
+ }
118
+ }
119
+ catch (error) {
120
+ console.error('Failed to read history.jsonl:', error);
121
+ return {};
122
+ }
123
+ return history;
124
+ }
125
+ function parseMessageUsage(usage) {
126
+ return {
127
+ inputTokens: usage.input_tokens || 0,
128
+ outputTokens: usage.output_tokens || 0,
129
+ cacheCreationInputTokens: usage.cache_creation_input_tokens || 0,
130
+ cacheReadInputTokens: usage.cache_read_input_tokens || 0,
131
+ };
132
+ }
133
+ function loadSessionMessages(encodedPath, sessionId) {
134
+ const sessionPath = (0, path_1.join)((0, config_1.getDataDir)(), 'projects', encodedPath, `${sessionId}.jsonl`);
135
+ if (!(0, fs_1.existsSync)(sessionPath)) {
136
+ return [];
137
+ }
138
+ const messages = [];
139
+ try {
140
+ const lines = (0, fs_1.readFileSync)(sessionPath, 'utf-8').split('\n');
141
+ for (const line of lines) {
142
+ if (!line.trim())
143
+ continue;
144
+ try {
145
+ const msg = JSON.parse(line);
146
+ // Skip non-assistant messages
147
+ if (msg.type !== 'assistant')
148
+ continue;
149
+ // Skip synthetic models
150
+ if (msg.message?.model === '<synthetic>')
151
+ continue;
152
+ // Skip sidechain
153
+ if (msg.isSidechain)
154
+ continue;
155
+ const usage = msg.message?.usage;
156
+ if (!usage)
157
+ continue;
158
+ const parsed = parseMessageUsage(usage);
159
+ const model = msg.message?.model || 'unknown';
160
+ const cost = (0, pricing_1.estimateCost)(model, parsed.inputTokens, parsed.outputTokens, parsed.cacheCreationInputTokens, parsed.cacheReadInputTokens);
161
+ messages.push({
162
+ timestamp: msg.timestamp || '',
163
+ model,
164
+ inputTokens: parsed.inputTokens,
165
+ outputTokens: parsed.outputTokens,
166
+ cacheCreationInputTokens: parsed.cacheCreationInputTokens,
167
+ cacheReadInputTokens: parsed.cacheReadInputTokens,
168
+ costUsd: cost,
169
+ });
170
+ }
171
+ catch (err) {
172
+ // Skip malformed lines
173
+ continue;
174
+ }
175
+ }
176
+ }
177
+ catch (error) {
178
+ console.error(`Failed to read session ${sessionId}:`, error);
179
+ return [];
180
+ }
181
+ return messages;
182
+ }
183
+ function buildSessionSummary(encodedPath, sessionId, history) {
184
+ const messages = loadSessionMessages(encodedPath, sessionId);
185
+ if (messages.length === 0) {
186
+ return null;
187
+ }
188
+ // Compute totals
189
+ let totalInput = messages.reduce((sum, m) => sum + m.inputTokens, 0);
190
+ let totalOutput = messages.reduce((sum, m) => sum + m.outputTokens, 0);
191
+ let totalCost = messages.reduce((sum, m) => sum + m.costUsd, 0);
192
+ const modelsUsed = new Set(messages.map(m => m.model));
193
+ const firstMsgTimestamp = messages[0]?.timestamp || '';
194
+ const histEntry = history[sessionId] || {};
195
+ const project = histEntry.project || `/${encodedPath}`;
196
+ let slug = histEntry.display?.trim() || '';
197
+ // Handle renamed sessions
198
+ if (histEntry.renamed && slug) {
199
+ slug = slug.substring(0, 100);
200
+ }
201
+ else if (slug) {
202
+ slug = slug.replace(/\n/g, ' ').trim();
203
+ // Skip meta commands
204
+ if (slug.startsWith('/') || slug.startsWith('!') || ['yes', 'Sure', 'go ahead'].includes(slug)) {
205
+ slug = '';
206
+ }
207
+ else {
208
+ slug = slug.substring(0, 80);
209
+ }
210
+ }
211
+ if (!slug) {
212
+ slug = sessionId.substring(0, 8);
213
+ }
214
+ // Merge subagent tokens
215
+ const subagentDir = (0, path_1.join)((0, config_1.getDataDir)(), 'projects', encodedPath, sessionId, 'subagents');
216
+ if ((0, fs_1.existsSync)(subagentDir)) {
217
+ try {
218
+ const agentFiles = (0, fs_1.readdirSync)(subagentDir).filter(f => f.startsWith('agent-') && f.endsWith('.jsonl'));
219
+ for (const agentFile of agentFiles) {
220
+ const agentPath = (0, path_1.join)(subagentDir, agentFile);
221
+ const lines = (0, fs_1.readFileSync)(agentPath, 'utf-8').split('\n');
222
+ for (const line of lines) {
223
+ if (!line.trim())
224
+ continue;
225
+ try {
226
+ const msg = JSON.parse(line);
227
+ if (msg.type !== 'assistant')
228
+ continue;
229
+ if (msg.message?.model === '<synthetic>')
230
+ continue;
231
+ const usage = msg.message?.usage;
232
+ if (!usage)
233
+ continue;
234
+ const parsed = parseMessageUsage(usage);
235
+ const model = msg.message?.model || 'unknown';
236
+ const cost = (0, pricing_1.estimateCost)(model, parsed.inputTokens, parsed.outputTokens, parsed.cacheCreationInputTokens, parsed.cacheReadInputTokens);
237
+ totalInput += parsed.inputTokens;
238
+ totalOutput += parsed.outputTokens;
239
+ totalCost += cost;
240
+ modelsUsed.add(model);
241
+ }
242
+ catch (err) {
243
+ continue;
244
+ }
245
+ }
246
+ }
247
+ }
248
+ catch (error) {
249
+ // Ignore subagent errors
250
+ }
251
+ }
252
+ return {
253
+ sessionId,
254
+ slug,
255
+ project,
256
+ timestamp: firstMsgTimestamp,
257
+ messageCount: messages.length,
258
+ totalInputTokens: totalInput,
259
+ totalOutputTokens: totalOutput,
260
+ totalCostUsd: totalCost,
261
+ modelsUsed,
262
+ };
263
+ }
264
+ function buildProjectSummaries() {
265
+ const projectsDir = (0, path_1.join)((0, config_1.getDataDir)(), 'projects');
266
+ if (!(0, fs_1.existsSync)(projectsDir)) {
267
+ return {};
268
+ }
269
+ const history = loadHistory();
270
+ const projects = {};
271
+ try {
272
+ const encodedDirs = (0, fs_1.readdirSync)(projectsDir);
273
+ for (const encodedDir of encodedDirs) {
274
+ const dirPath = (0, path_1.join)(projectsDir, encodedDir);
275
+ const stat = require('fs').statSync(dirPath);
276
+ if (!stat.isDirectory())
277
+ continue;
278
+ const sessions = [];
279
+ const files = (0, fs_1.readdirSync)(dirPath);
280
+ for (const file of files) {
281
+ if (!file.endsWith('.jsonl'))
282
+ continue;
283
+ const sessionId = file.replace('.jsonl', '');
284
+ const summary = buildSessionSummary(encodedDir, sessionId, history);
285
+ if (summary) {
286
+ sessions.push(summary);
287
+ }
288
+ }
289
+ if (sessions.length > 0) {
290
+ projects[encodedDir] = sessions;
291
+ }
292
+ }
293
+ }
294
+ catch (error) {
295
+ console.error('Failed to build project summaries:', error);
296
+ return {};
297
+ }
298
+ return projects;
299
+ }
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getModelPricing = getModelPricing;
4
+ exports.estimateCost = estimateCost;
5
+ exports.formatCost = formatCost;
6
+ exports.formatTokens = formatTokens;
7
+ // Pricing in $/MTok (million tokens)
8
+ const FALLBACK_PRICING = {
9
+ 'claude-opus-4-6': {
10
+ input: 15.0,
11
+ output: 75.0,
12
+ cacheWrite: 18.75,
13
+ cacheRead: 1.5,
14
+ },
15
+ 'claude-opus-4-5-20251101': {
16
+ input: 15.0,
17
+ output: 75.0,
18
+ cacheWrite: 18.75,
19
+ cacheRead: 1.5,
20
+ },
21
+ 'claude-sonnet-4-5-20250929': {
22
+ input: 3.0,
23
+ output: 15.0,
24
+ cacheWrite: 3.75,
25
+ cacheRead: 0.3,
26
+ },
27
+ 'claude-haiku-4-5-20251001': {
28
+ input: 0.8,
29
+ output: 4.0,
30
+ cacheWrite: 1.0,
31
+ cacheRead: 0.08,
32
+ },
33
+ };
34
+ const DEFAULT_PRICING = FALLBACK_PRICING['claude-sonnet-4-5-20250929'];
35
+ function getModelPricing(modelId) {
36
+ if (modelId in FALLBACK_PRICING) {
37
+ return FALLBACK_PRICING[modelId];
38
+ }
39
+ return DEFAULT_PRICING;
40
+ }
41
+ function estimateCost(modelId, inputTokens = 0, outputTokens = 0, cacheCreationInputTokens = 0, cacheReadInputTokens = 0) {
42
+ const pricing = getModelPricing(modelId);
43
+ const cost = (inputTokens * pricing.input +
44
+ outputTokens * pricing.output +
45
+ cacheCreationInputTokens * pricing.cacheWrite +
46
+ cacheReadInputTokens * pricing.cacheRead) /
47
+ 1_000_000;
48
+ return cost;
49
+ }
50
+ function formatCost(cost) {
51
+ return `$${cost.toFixed(4)}`;
52
+ }
53
+ function formatTokens(tokens) {
54
+ return tokens.toLocaleString('en-US');
55
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "claude-usage-rzp",
3
+ "version": "0.1.0",
4
+ "description": "View Claude Code API usage directly in your terminal",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "claude-usage": "./dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "dev": "tsx src/index.ts",
12
+ "start": "node dist/index.js",
13
+ "prepublishOnly": "npm run build"
14
+ },
15
+ "keywords": [
16
+ "claude",
17
+ "anthropic",
18
+ "usage",
19
+ "cli",
20
+ "tokens",
21
+ "cost"
22
+ ],
23
+ "author": "Hamid",
24
+ "license": "MIT",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/hamid-miran/claude-usage-cli"
28
+ },
29
+ "homepage": "https://github.com/hamid-miran/claude-usage-cli#readme",
30
+ "bugs": {
31
+ "url": "https://github.com/hamid-miran/claude-usage-cli/issues"
32
+ },
33
+ "dependencies": {
34
+ "chalk": "^5.3.0",
35
+ "cli-table3": "^0.6.5",
36
+ "commander": "^12.1.0",
37
+ "inquirer": "^9.2.12"
38
+ },
39
+ "devDependencies": {
40
+ "@types/inquirer": "^9.0.9",
41
+ "@types/node": "^22.10.2",
42
+ "tsx": "^4.19.2",
43
+ "typescript": "^5.7.2"
44
+ },
45
+ "engines": {
46
+ "node": ">=18.0.0"
47
+ }
48
+ }
@@ -0,0 +1,16 @@
1
+ import chalk from 'chalk';
2
+ import { getDataDir, hasStatsCache, hasProjects } from '../config';
3
+
4
+ export function configCommand() {
5
+ console.log(chalk.cyan.bold('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
6
+ console.log(chalk.cyan.bold(' Configuration'));
7
+ console.log(chalk.cyan.bold('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
8
+
9
+ console.log(` Data Directory: ${chalk.green(getDataDir())}`);
10
+ console.log(` Has stats-cache.json: ${hasStatsCache() ? chalk.green('✓') : chalk.red('✗')}`);
11
+ console.log(` Has projects/: ${hasProjects() ? chalk.green('✓') : chalk.red('✗')}`);
12
+
13
+ console.log(
14
+ chalk.dim('\n💡 Set CLAUDE_DATA_DIR environment variable or use --data-dir option\n')
15
+ );
16
+ }