opencode-usage 0.1.1 → 0.2.1
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 +20 -4
- package/dist/aggregator.d.ts +2 -0
- package/dist/cli.d.ts +4 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +215 -26
- package/dist/index.js.map +7 -7
- package/dist/renderer.d.ts +30 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,9 +4,10 @@ CLI tool for tracking [OpenCode](https://github.com/sst/opencode) AI coding assi
|
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- Daily usage breakdown with token counts and estimated costs
|
|
7
|
+
- Daily or monthly usage breakdown with token counts and estimated costs
|
|
8
8
|
- Provider breakdown (Anthropic, OpenAI, Google, etc.)
|
|
9
|
-
- Filter by provider or time
|
|
9
|
+
- Filter by provider, date range, or relative time
|
|
10
|
+
- JSON output for scripting and automation
|
|
10
11
|
- Model pricing for accurate cost estimation
|
|
11
12
|
- Terminal table output
|
|
12
13
|
|
|
@@ -27,7 +28,7 @@ npm install -g opencode-usage
|
|
|
27
28
|
## Usage
|
|
28
29
|
|
|
29
30
|
```bash
|
|
30
|
-
# Show all usage data
|
|
31
|
+
# Show all usage data (daily breakdown)
|
|
31
32
|
opencode-usage
|
|
32
33
|
|
|
33
34
|
# Filter by provider
|
|
@@ -38,8 +39,23 @@ opencode-usage -p openai
|
|
|
38
39
|
opencode-usage --days 30
|
|
39
40
|
opencode-usage -d 7
|
|
40
41
|
|
|
42
|
+
# Date range filtering
|
|
43
|
+
opencode-usage --since 20251201 --until 20251231
|
|
44
|
+
opencode-usage --since 2025-12-01
|
|
45
|
+
opencode-usage --since 7d # last 7 days
|
|
46
|
+
opencode-usage --since 1w # last week
|
|
47
|
+
opencode-usage --since 1m # last month
|
|
48
|
+
|
|
49
|
+
# Monthly aggregation
|
|
50
|
+
opencode-usage --monthly
|
|
51
|
+
opencode-usage -m --since 2025-01-01
|
|
52
|
+
|
|
53
|
+
# JSON output (for scripting)
|
|
54
|
+
opencode-usage --json
|
|
55
|
+
opencode-usage --monthly --json > usage.json
|
|
56
|
+
|
|
41
57
|
# Combine filters
|
|
42
|
-
opencode-usage --provider anthropic --
|
|
58
|
+
opencode-usage --provider anthropic --since 7d --json
|
|
43
59
|
```
|
|
44
60
|
|
|
45
61
|
## Output
|
package/dist/aggregator.d.ts
CHANGED
|
@@ -4,3 +4,5 @@
|
|
|
4
4
|
import type { DailyStats, MessageJson } from "./types.js";
|
|
5
5
|
export declare function aggregateByDate(messages: MessageJson[]): Map<string, DailyStats>;
|
|
6
6
|
export declare function filterByDays(dailyStats: Map<string, DailyStats>, days: number): Map<string, DailyStats>;
|
|
7
|
+
export declare function filterByDateRange(dailyStats: Map<string, DailyStats>, since?: string, until?: string): Map<string, DailyStats>;
|
|
8
|
+
export declare function aggregateByMonth(dailyStats: Map<string, DailyStats>): Map<string, DailyStats>;
|
package/dist/cli.d.ts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -8,6 +8,31 @@ function getArgs() {
|
|
|
8
8
|
}
|
|
9
9
|
return process.argv.slice(2);
|
|
10
10
|
}
|
|
11
|
+
function parseDate(value) {
|
|
12
|
+
if (!value)
|
|
13
|
+
return;
|
|
14
|
+
const relativeMatch = value.match(/^(\d+)([dwm])$/);
|
|
15
|
+
if (relativeMatch) {
|
|
16
|
+
const num = parseInt(relativeMatch[1], 10);
|
|
17
|
+
const unit = relativeMatch[2];
|
|
18
|
+
const date = new Date;
|
|
19
|
+
if (unit === "d")
|
|
20
|
+
date.setDate(date.getDate() - num);
|
|
21
|
+
else if (unit === "w")
|
|
22
|
+
date.setDate(date.getDate() - num * 7);
|
|
23
|
+
else if (unit === "m")
|
|
24
|
+
date.setMonth(date.getMonth() - num);
|
|
25
|
+
return date.toISOString().split("T")[0];
|
|
26
|
+
}
|
|
27
|
+
if (/^\d{8}$/.test(value)) {
|
|
28
|
+
return `${value.slice(0, 4)}-${value.slice(4, 6)}-${value.slice(6, 8)}`;
|
|
29
|
+
}
|
|
30
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(value)) {
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
console.error(`Invalid date format: ${value}. Use YYYYMMDD, YYYY-MM-DD, or relative (7d, 1w, 1m)`);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
11
36
|
function parseArgs() {
|
|
12
37
|
try {
|
|
13
38
|
const { values } = nodeParseArgs({
|
|
@@ -15,6 +40,10 @@ function parseArgs() {
|
|
|
15
40
|
options: {
|
|
16
41
|
provider: { type: "string", short: "p" },
|
|
17
42
|
days: { type: "string", short: "d" },
|
|
43
|
+
since: { type: "string", short: "s" },
|
|
44
|
+
until: { type: "string", short: "u" },
|
|
45
|
+
json: { type: "boolean", short: "j" },
|
|
46
|
+
monthly: { type: "boolean", short: "m" },
|
|
18
47
|
help: { type: "boolean", short: "h" }
|
|
19
48
|
},
|
|
20
49
|
strict: true
|
|
@@ -25,7 +54,11 @@ function parseArgs() {
|
|
|
25
54
|
}
|
|
26
55
|
return {
|
|
27
56
|
provider: values.provider?.toLowerCase(),
|
|
28
|
-
days: values.days ? parseInt(values.days, 10) : undefined
|
|
57
|
+
days: values.days ? parseInt(values.days, 10) : undefined,
|
|
58
|
+
since: parseDate(values.since ?? ""),
|
|
59
|
+
until: parseDate(values.until ?? ""),
|
|
60
|
+
json: values.json,
|
|
61
|
+
monthly: values.monthly
|
|
29
62
|
};
|
|
30
63
|
} catch (error) {
|
|
31
64
|
if (error instanceof Error && error.message.includes("Unknown option")) {
|
|
@@ -46,12 +79,19 @@ Usage:
|
|
|
46
79
|
Options:
|
|
47
80
|
-p, --provider <name> Filter by provider (anthropic, openai, google, opencode)
|
|
48
81
|
-d, --days <n> Show only last N days
|
|
82
|
+
-s, --since <date> Start date (YYYYMMDD, YYYY-MM-DD, or 7d/1w/1m)
|
|
83
|
+
-u, --until <date> End date (YYYYMMDD, YYYY-MM-DD, or 7d/1w/1m)
|
|
84
|
+
-j, --json Output as JSON
|
|
85
|
+
-m, --monthly Aggregate by month instead of day
|
|
49
86
|
-h, --help Show this help message
|
|
50
87
|
|
|
51
88
|
Examples:
|
|
52
89
|
bunx opencode-usage
|
|
53
90
|
bunx opencode-usage --provider anthropic
|
|
54
91
|
bunx opencode-usage -p openai -d 30
|
|
92
|
+
bunx opencode-usage --since 20251201 --until 20251231
|
|
93
|
+
bunx opencode-usage --since 7d
|
|
94
|
+
bunx opencode-usage --monthly --json
|
|
55
95
|
`);
|
|
56
96
|
}
|
|
57
97
|
|
|
@@ -73,9 +113,9 @@ async function readJsonFile(filePath) {
|
|
|
73
113
|
}
|
|
74
114
|
async function loadMessages(storagePath, providerFilter) {
|
|
75
115
|
const messagesDir = join(storagePath, "message");
|
|
76
|
-
const messages = [];
|
|
77
116
|
try {
|
|
78
117
|
const sessionDirs = readdirSync(messagesDir);
|
|
118
|
+
const filePaths = [];
|
|
79
119
|
for (const sessionDir of sessionDirs) {
|
|
80
120
|
const sessionPath = join(messagesDir, sessionDir);
|
|
81
121
|
const stat = statSync(sessionPath);
|
|
@@ -83,25 +123,34 @@ async function loadMessages(storagePath, providerFilter) {
|
|
|
83
123
|
continue;
|
|
84
124
|
const messageFiles = readdirSync(sessionPath).filter((f) => f.endsWith(".json"));
|
|
85
125
|
for (const messageFile of messageFiles) {
|
|
86
|
-
|
|
87
|
-
const messagePath = join(sessionPath, messageFile);
|
|
88
|
-
const msg = await readJsonFile(messagePath);
|
|
89
|
-
if (msg.role === "user")
|
|
90
|
-
continue;
|
|
91
|
-
if (!msg.tokens)
|
|
92
|
-
continue;
|
|
93
|
-
const providerId = msg.model?.providerID ?? msg.providerID ?? "unknown";
|
|
94
|
-
if (providerFilter && providerId.toLowerCase() !== providerFilter) {
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
|
-
messages.push(msg);
|
|
98
|
-
} catch {}
|
|
126
|
+
filePaths.push(join(sessionPath, messageFile));
|
|
99
127
|
}
|
|
100
128
|
}
|
|
129
|
+
const results = await Promise.all(filePaths.map(async (filePath) => {
|
|
130
|
+
try {
|
|
131
|
+
return await readJsonFile(filePath);
|
|
132
|
+
} catch {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
}));
|
|
136
|
+
return results.filter((msg) => {
|
|
137
|
+
if (!msg)
|
|
138
|
+
return false;
|
|
139
|
+
if (msg.role === "user")
|
|
140
|
+
return false;
|
|
141
|
+
if (!msg.tokens)
|
|
142
|
+
return false;
|
|
143
|
+
if (providerFilter) {
|
|
144
|
+
const providerId = msg.model?.providerID ?? msg.providerID ?? "unknown";
|
|
145
|
+
if (providerId.toLowerCase() !== providerFilter)
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
return true;
|
|
149
|
+
});
|
|
101
150
|
} catch (err) {
|
|
102
151
|
console.error(`Error reading messages directory: ${err}`);
|
|
152
|
+
return [];
|
|
103
153
|
}
|
|
104
|
-
return messages;
|
|
105
154
|
}
|
|
106
155
|
|
|
107
156
|
// src/pricing.ts
|
|
@@ -359,6 +408,76 @@ function filterByDays(dailyStats, days) {
|
|
|
359
408
|
}
|
|
360
409
|
return filtered;
|
|
361
410
|
}
|
|
411
|
+
function filterByDateRange(dailyStats, since, until) {
|
|
412
|
+
const filtered = new Map;
|
|
413
|
+
for (const [date, stats] of dailyStats) {
|
|
414
|
+
if (since && date < since)
|
|
415
|
+
continue;
|
|
416
|
+
if (until && date > until)
|
|
417
|
+
continue;
|
|
418
|
+
filtered.set(date, stats);
|
|
419
|
+
}
|
|
420
|
+
return filtered;
|
|
421
|
+
}
|
|
422
|
+
function dateToMonth(date) {
|
|
423
|
+
return date.slice(0, 7);
|
|
424
|
+
}
|
|
425
|
+
function aggregateByMonth(dailyStats) {
|
|
426
|
+
const monthlyStats = new Map;
|
|
427
|
+
for (const [date, stats] of dailyStats) {
|
|
428
|
+
const month = dateToMonth(date);
|
|
429
|
+
let monthStats = monthlyStats.get(month);
|
|
430
|
+
if (!monthStats) {
|
|
431
|
+
monthStats = {
|
|
432
|
+
date: month,
|
|
433
|
+
models: new Set,
|
|
434
|
+
providers: new Set,
|
|
435
|
+
providerStats: new Map,
|
|
436
|
+
input: 0,
|
|
437
|
+
output: 0,
|
|
438
|
+
cacheWrite: 0,
|
|
439
|
+
cacheRead: 0,
|
|
440
|
+
reasoning: 0,
|
|
441
|
+
cost: 0
|
|
442
|
+
};
|
|
443
|
+
monthlyStats.set(month, monthStats);
|
|
444
|
+
}
|
|
445
|
+
for (const model of stats.models)
|
|
446
|
+
monthStats.models.add(model);
|
|
447
|
+
for (const provider of stats.providers)
|
|
448
|
+
monthStats.providers.add(provider);
|
|
449
|
+
monthStats.input += stats.input;
|
|
450
|
+
monthStats.output += stats.output;
|
|
451
|
+
monthStats.cacheWrite += stats.cacheWrite;
|
|
452
|
+
monthStats.cacheRead += stats.cacheRead;
|
|
453
|
+
monthStats.reasoning += stats.reasoning;
|
|
454
|
+
monthStats.cost += stats.cost;
|
|
455
|
+
for (const [providerId, providerStat] of stats.providerStats) {
|
|
456
|
+
let monthProviderStat = monthStats.providerStats.get(providerId);
|
|
457
|
+
if (!monthProviderStat) {
|
|
458
|
+
monthProviderStat = {
|
|
459
|
+
input: 0,
|
|
460
|
+
output: 0,
|
|
461
|
+
cacheWrite: 0,
|
|
462
|
+
cacheRead: 0,
|
|
463
|
+
reasoning: 0,
|
|
464
|
+
cost: 0,
|
|
465
|
+
models: new Set
|
|
466
|
+
};
|
|
467
|
+
monthStats.providerStats.set(providerId, monthProviderStat);
|
|
468
|
+
}
|
|
469
|
+
for (const model of providerStat.models)
|
|
470
|
+
monthProviderStat.models.add(model);
|
|
471
|
+
monthProviderStat.input += providerStat.input;
|
|
472
|
+
monthProviderStat.output += providerStat.output;
|
|
473
|
+
monthProviderStat.cacheWrite += providerStat.cacheWrite;
|
|
474
|
+
monthProviderStat.cacheRead += providerStat.cacheRead;
|
|
475
|
+
monthProviderStat.reasoning += providerStat.reasoning;
|
|
476
|
+
monthProviderStat.cost += providerStat.cost;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
return monthlyStats;
|
|
480
|
+
}
|
|
362
481
|
|
|
363
482
|
// src/renderer.ts
|
|
364
483
|
function formatNumber(num) {
|
|
@@ -373,6 +492,51 @@ function padRight(str, len) {
|
|
|
373
492
|
function padLeft(str, len) {
|
|
374
493
|
return str.padStart(len);
|
|
375
494
|
}
|
|
495
|
+
function renderJson(dailyStats) {
|
|
496
|
+
const sortedDates = Array.from(dailyStats.keys()).sort((a, b) => a.localeCompare(b));
|
|
497
|
+
let totalInput = 0;
|
|
498
|
+
let totalOutput = 0;
|
|
499
|
+
let totalCost = 0;
|
|
500
|
+
const periods = sortedDates.map((date) => {
|
|
501
|
+
const stats = dailyStats.get(date);
|
|
502
|
+
const combinedInput = stats.input + stats.cacheRead + stats.cacheWrite;
|
|
503
|
+
totalInput += combinedInput;
|
|
504
|
+
totalOutput += stats.output;
|
|
505
|
+
totalCost += stats.cost;
|
|
506
|
+
const providers = Array.from(stats.providerStats.entries()).sort((a, b) => b[1].cost - a[1].cost).map(([id, ps]) => ({
|
|
507
|
+
id,
|
|
508
|
+
models: Array.from(ps.models).sort(),
|
|
509
|
+
input: ps.input,
|
|
510
|
+
output: ps.output,
|
|
511
|
+
cacheRead: ps.cacheRead,
|
|
512
|
+
cacheWrite: ps.cacheWrite,
|
|
513
|
+
reasoning: ps.reasoning,
|
|
514
|
+
cost: Math.round(ps.cost * 100) / 100
|
|
515
|
+
}));
|
|
516
|
+
return {
|
|
517
|
+
date,
|
|
518
|
+
models: Array.from(stats.models).sort(),
|
|
519
|
+
providers,
|
|
520
|
+
totals: {
|
|
521
|
+
input: stats.input,
|
|
522
|
+
output: stats.output,
|
|
523
|
+
cacheRead: stats.cacheRead,
|
|
524
|
+
cacheWrite: stats.cacheWrite,
|
|
525
|
+
reasoning: stats.reasoning,
|
|
526
|
+
cost: Math.round(stats.cost * 100) / 100
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
});
|
|
530
|
+
const output = {
|
|
531
|
+
periods,
|
|
532
|
+
totals: {
|
|
533
|
+
input: totalInput,
|
|
534
|
+
output: totalOutput,
|
|
535
|
+
cost: Math.round(totalCost * 100) / 100
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
console.log(JSON.stringify(output, null, 2));
|
|
539
|
+
}
|
|
376
540
|
function renderTable(dailyStats) {
|
|
377
541
|
const sortedDates = Array.from(dailyStats.keys()).sort((a, b) => a.localeCompare(b));
|
|
378
542
|
if (sortedDates.length === 0) {
|
|
@@ -438,23 +602,48 @@ No usage data found.
|
|
|
438
602
|
|
|
439
603
|
// src/index.ts
|
|
440
604
|
async function main() {
|
|
441
|
-
const { provider, days } = parseArgs();
|
|
605
|
+
const { provider, days, since, until, json, monthly } = parseArgs();
|
|
442
606
|
const storagePath = getOpenCodeStoragePath();
|
|
443
|
-
|
|
607
|
+
if (!json) {
|
|
608
|
+
console.log(`
|
|
444
609
|
Loading OpenCode usage data from: ${storagePath}`);
|
|
445
|
-
|
|
446
|
-
|
|
610
|
+
if (provider) {
|
|
611
|
+
console.log(`Filtering: ${provider} provider only`);
|
|
612
|
+
}
|
|
447
613
|
}
|
|
448
614
|
const messages = await loadMessages(storagePath, provider);
|
|
449
|
-
|
|
450
|
-
|
|
615
|
+
if (!json) {
|
|
616
|
+
console.log(`Found ${messages.length} assistant messages with token data`);
|
|
617
|
+
}
|
|
618
|
+
let stats = aggregateByDate(messages);
|
|
451
619
|
if (days) {
|
|
452
|
-
|
|
453
|
-
|
|
620
|
+
stats = filterByDays(stats, days);
|
|
621
|
+
if (!json)
|
|
622
|
+
console.log(`Showing last ${days} days`);
|
|
623
|
+
}
|
|
624
|
+
if (since || until) {
|
|
625
|
+
stats = filterByDateRange(stats, since, until);
|
|
626
|
+
if (!json) {
|
|
627
|
+
if (since && until)
|
|
628
|
+
console.log(`Date range: ${since} to ${until}`);
|
|
629
|
+
else if (since)
|
|
630
|
+
console.log(`From: ${since}`);
|
|
631
|
+
else if (until)
|
|
632
|
+
console.log(`Until: ${until}`);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
if (monthly) {
|
|
636
|
+
stats = aggregateByMonth(stats);
|
|
637
|
+
if (!json)
|
|
638
|
+
console.log(`Aggregated by month`);
|
|
639
|
+
}
|
|
640
|
+
if (json) {
|
|
641
|
+
renderJson(stats);
|
|
642
|
+
} else {
|
|
643
|
+
renderTable(stats);
|
|
454
644
|
}
|
|
455
|
-
renderTable(dailyStats);
|
|
456
645
|
}
|
|
457
646
|
main().catch(console.error);
|
|
458
647
|
|
|
459
|
-
//# debugId=
|
|
648
|
+
//# debugId=CFEB06924236C7EF64756E2164756E21
|
|
460
649
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/cli.ts", "../src/loader.ts", "../src/pricing.ts", "../src/aggregator.ts", "../src/renderer.ts", "../src/index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * CLI argument parser using Node.js parseArgs (works with both Bun and Node.js)\n */\n\nimport { parseArgs as nodeParseArgs } from \"node:util\";\n\nexport type CliArgs = {\n provider?: string;\n days?: number;\n};\n\n// Get CLI args - works with both Bun and Node.js\nfunction getArgs(): string[] {\n if (typeof globalThis.Bun !== \"undefined\") {\n return Bun.argv.slice(2);\n }\n return process.argv.slice(2);\n}\n\nexport function parseArgs(): CliArgs {\n try {\n const { values } = nodeParseArgs({\n args: getArgs(),\n options: {\n provider: { type: \"string\", short: \"p\" },\n days: { type: \"string\", short: \"d\" },\n help: { type: \"boolean\", short: \"h\" },\n },\n strict: true,\n });\n\n if (values.help) {\n printHelp();\n process.exit(0);\n }\n\n return {\n provider: values.provider?.toLowerCase(),\n days: values.days ? parseInt(values.days, 10) : undefined,\n };\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"Unknown option\")) {\n console.error(`Error: ${error.message}`);\n printHelp();\n process.exit(1);\n }\n throw error;\n }\n}\n\nfunction printHelp(): void {\n console.log(`\nopencode-usage - Track OpenCode AI coding assistant usage and costs\n\nUsage:\n bunx opencode-usage [options]\n\nOptions:\n -p, --provider <name> Filter by provider (anthropic, openai, google, opencode)\n -d, --days <n> Show only last N days\n -h, --help Show this help message\n\nExamples:\n bunx opencode-usage\n bunx opencode-usage --provider anthropic\n bunx opencode-usage -p openai -d 30\n`);\n}\n",
|
|
6
|
-
"/**\n * OpenCode storage data loader - works with both Bun and Node.js\n */\n\nimport { readFileSync, readdirSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { MessageJson } from \"./types.js\";\n\n// Runtime detection\nconst isBun = typeof globalThis.Bun !== \"undefined\";\n\nexport function getOpenCodeStoragePath(): string {\n const xdgDataHome =\n process.env.XDG_DATA_HOME ?? join(homedir(), \".local\", \"share\");\n return join(xdgDataHome, \"opencode\", \"storage\");\n}\n\nasync function readJsonFile(filePath: string): Promise<MessageJson> {\n if (isBun) {\n return Bun.file(filePath).json() as Promise<MessageJson>;\n }\n const content = readFileSync(filePath, \"utf-8\");\n return JSON.parse(content) as MessageJson;\n}\n\nexport async function loadMessages(\n storagePath: string,\n providerFilter?: string\n): Promise<MessageJson[]> {\n const messagesDir = join(storagePath, \"message\");\n
|
|
5
|
+
"/**\n * CLI argument parser using Node.js parseArgs (works with both Bun and Node.js)\n */\n\nimport { parseArgs as nodeParseArgs } from \"node:util\";\n\nexport type CliArgs = {\n provider?: string;\n days?: number;\n since?: string;\n until?: string;\n json?: boolean;\n monthly?: boolean;\n};\n\n// Get CLI args - works with both Bun and Node.js\nfunction getArgs(): string[] {\n if (typeof globalThis.Bun !== \"undefined\") {\n return Bun.argv.slice(2);\n }\n return process.argv.slice(2);\n}\n\n/**\n * Parse date string in formats: YYYYMMDD, YYYY-MM-DD, or relative like \"7d\", \"1w\", \"1m\"\n */\nfunction parseDate(value: string): string | undefined {\n if (!value) return undefined;\n\n // Relative date: 7d, 1w, 1m\n const relativeMatch = value.match(/^(\\d+)([dwm])$/);\n if (relativeMatch) {\n const num = parseInt(relativeMatch[1], 10);\n const unit = relativeMatch[2];\n const date = new Date();\n if (unit === \"d\") date.setDate(date.getDate() - num);\n else if (unit === \"w\") date.setDate(date.getDate() - num * 7);\n else if (unit === \"m\") date.setMonth(date.getMonth() - num);\n return date.toISOString().split(\"T\")[0];\n }\n\n // YYYYMMDD format\n if (/^\\d{8}$/.test(value)) {\n return `${value.slice(0, 4)}-${value.slice(4, 6)}-${value.slice(6, 8)}`;\n }\n\n // YYYY-MM-DD format\n if (/^\\d{4}-\\d{2}-\\d{2}$/.test(value)) {\n return value;\n }\n\n console.error(\n `Invalid date format: ${value}. Use YYYYMMDD, YYYY-MM-DD, or relative (7d, 1w, 1m)`\n );\n process.exit(1);\n}\n\nexport function parseArgs(): CliArgs {\n try {\n const { values } = nodeParseArgs({\n args: getArgs(),\n options: {\n provider: { type: \"string\", short: \"p\" },\n days: { type: \"string\", short: \"d\" },\n since: { type: \"string\", short: \"s\" },\n until: { type: \"string\", short: \"u\" },\n json: { type: \"boolean\", short: \"j\" },\n monthly: { type: \"boolean\", short: \"m\" },\n help: { type: \"boolean\", short: \"h\" },\n },\n strict: true,\n });\n\n if (values.help) {\n printHelp();\n process.exit(0);\n }\n\n return {\n provider: values.provider?.toLowerCase(),\n days: values.days ? parseInt(values.days, 10) : undefined,\n since: parseDate(values.since ?? \"\"),\n until: parseDate(values.until ?? \"\"),\n json: values.json,\n monthly: values.monthly,\n };\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"Unknown option\")) {\n console.error(`Error: ${error.message}`);\n printHelp();\n process.exit(1);\n }\n throw error;\n }\n}\n\nfunction printHelp(): void {\n console.log(`\nopencode-usage - Track OpenCode AI coding assistant usage and costs\n\nUsage:\n bunx opencode-usage [options]\n\nOptions:\n -p, --provider <name> Filter by provider (anthropic, openai, google, opencode)\n -d, --days <n> Show only last N days\n -s, --since <date> Start date (YYYYMMDD, YYYY-MM-DD, or 7d/1w/1m)\n -u, --until <date> End date (YYYYMMDD, YYYY-MM-DD, or 7d/1w/1m)\n -j, --json Output as JSON\n -m, --monthly Aggregate by month instead of day\n -h, --help Show this help message\n\nExamples:\n bunx opencode-usage\n bunx opencode-usage --provider anthropic\n bunx opencode-usage -p openai -d 30\n bunx opencode-usage --since 20251201 --until 20251231\n bunx opencode-usage --since 7d\n bunx opencode-usage --monthly --json\n`);\n}\n",
|
|
6
|
+
"/**\n * OpenCode storage data loader - works with both Bun and Node.js\n */\n\nimport { readFileSync, readdirSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { MessageJson } from \"./types.js\";\n\n// Runtime detection\nconst isBun = typeof globalThis.Bun !== \"undefined\";\n\nexport function getOpenCodeStoragePath(): string {\n const xdgDataHome =\n process.env.XDG_DATA_HOME ?? join(homedir(), \".local\", \"share\");\n return join(xdgDataHome, \"opencode\", \"storage\");\n}\n\nasync function readJsonFile(filePath: string): Promise<MessageJson> {\n if (isBun) {\n return Bun.file(filePath).json() as Promise<MessageJson>;\n }\n const content = readFileSync(filePath, \"utf-8\");\n return JSON.parse(content) as MessageJson;\n}\n\nexport async function loadMessages(\n storagePath: string,\n providerFilter?: string\n): Promise<MessageJson[]> {\n const messagesDir = join(storagePath, \"message\");\n\n try {\n const sessionDirs = readdirSync(messagesDir);\n\n const filePaths: string[] = [];\n for (const sessionDir of sessionDirs) {\n const sessionPath = join(messagesDir, sessionDir);\n const stat = statSync(sessionPath);\n\n if (!stat.isDirectory()) continue;\n\n const messageFiles = readdirSync(sessionPath).filter((f) =>\n f.endsWith(\".json\")\n );\n\n for (const messageFile of messageFiles) {\n filePaths.push(join(sessionPath, messageFile));\n }\n }\n\n const results = await Promise.all(\n filePaths.map(async (filePath) => {\n try {\n return await readJsonFile(filePath);\n } catch {\n return null; // Skip invalid JSON files\n }\n })\n );\n\n return results.filter((msg): msg is MessageJson => {\n if (!msg) return false;\n if (msg.role === \"user\") return false;\n if (!msg.tokens) return false;\n\n if (providerFilter) {\n const providerId = msg.model?.providerID ?? msg.providerID ?? \"unknown\";\n if (providerId.toLowerCase() !== providerFilter) return false;\n }\n\n return true;\n });\n } catch (err) {\n console.error(`Error reading messages directory: ${err}`);\n return [];\n }\n}\n",
|
|
7
7
|
"/**\n * Model pricing configuration (per million tokens)\n */\n\nimport type { ModelPricing, TokenUsage } from \"./types\";\n\nexport const MODEL_PRICING: Record<string, ModelPricing> = {\n // Anthropic - Current Models\n \"claude-opus-4-5\": {\n input: 5,\n output: 25,\n cacheWrite: 6.25,\n cacheRead: 0.5,\n },\n \"claude-sonnet-4-5\": {\n input: 3,\n output: 15,\n cacheWrite: 3.75,\n cacheRead: 0.3,\n },\n \"claude-haiku-4-5\": {\n input: 1,\n output: 5,\n cacheWrite: 1.25,\n cacheRead: 0.1,\n },\n \"claude-opus-4\": {\n input: 15,\n output: 75,\n cacheWrite: 18.75,\n cacheRead: 1.5,\n },\n \"claude-sonnet-4\": {\n input: 3,\n output: 15,\n cacheWrite: 3.75,\n cacheRead: 0.3,\n },\n \"claude-opus-4-1\": {\n input: 15,\n output: 75,\n cacheWrite: 18.75,\n cacheRead: 1.5,\n },\n \"claude-opus-3\": {\n input: 15,\n output: 75,\n cacheWrite: 18.75,\n cacheRead: 1.5,\n },\n \"claude-haiku-3\": {\n input: 0.25,\n output: 1.25,\n cacheWrite: 0.3,\n cacheRead: 0.03,\n },\n\n // OpenAI Models\n \"gpt-4o\": {\n input: 2.5,\n output: 10,\n cacheWrite: 0,\n cacheRead: 0,\n },\n \"gpt-4o-mini\": {\n input: 0.15,\n output: 0.6,\n cacheWrite: 0,\n cacheRead: 0,\n },\n \"gpt-4-turbo\": {\n input: 10,\n output: 30,\n cacheWrite: 0,\n cacheRead: 0,\n },\n \"gpt-5\": {\n input: 5,\n output: 15,\n cacheWrite: 0,\n cacheRead: 0,\n },\n \"gpt-5.2\": {\n input: 5,\n output: 15,\n cacheWrite: 0,\n cacheRead: 0,\n },\n o1: {\n input: 15,\n output: 60,\n cacheWrite: 0,\n cacheRead: 0,\n },\n \"o1-mini\": {\n input: 3,\n output: 12,\n cacheWrite: 0,\n cacheRead: 0,\n },\n \"o1-pro\": {\n input: 150,\n output: 600,\n cacheWrite: 0,\n cacheRead: 0,\n },\n o3: {\n input: 10,\n output: 40,\n cacheWrite: 0,\n cacheRead: 0,\n },\n \"o3-mini\": {\n input: 1.1,\n output: 4.4,\n cacheWrite: 0,\n cacheRead: 0,\n },\n\n // Google Models\n \"gemini-2.0-flash\": {\n input: 0.1,\n output: 0.4,\n cacheWrite: 0,\n cacheRead: 0,\n },\n \"gemini-2.5-pro\": {\n input: 1.25,\n output: 10,\n cacheWrite: 0,\n cacheRead: 0,\n },\n \"gemini-2.5-flash\": {\n input: 0.15,\n output: 0.6,\n cacheWrite: 0,\n cacheRead: 0,\n },\n \"gemini-3-flash-preview\": {\n input: 0.15,\n output: 0.6,\n cacheWrite: 0,\n cacheRead: 0,\n },\n\n // Free/OpenCode hosted models\n \"qwen3-coder\": {\n input: 0,\n output: 0,\n cacheWrite: 0,\n cacheRead: 0,\n },\n \"glm-4.7-free\": {\n input: 0,\n output: 0,\n cacheWrite: 0,\n cacheRead: 0,\n },\n \"minimax-m2.1-free\": {\n input: 0,\n output: 0,\n cacheWrite: 0,\n cacheRead: 0,\n },\n};\n\nconst DEFAULT_PRICING: ModelPricing = {\n input: 3,\n output: 15,\n cacheWrite: 3.75,\n cacheRead: 0.3,\n};\n\nexport function getModelPricing(modelId: string): ModelPricing {\n const normalized = modelId.toLowerCase().replace(/_/g, \"-\");\n\n if (MODEL_PRICING[normalized]) {\n return MODEL_PRICING[normalized];\n }\n\n for (const [key, pricing] of Object.entries(MODEL_PRICING)) {\n if (normalized.includes(key) || key.includes(normalized)) {\n return pricing;\n }\n }\n\n return DEFAULT_PRICING;\n}\n\nexport function calculateCost(tokens: TokenUsage, modelId: string): number {\n const pricing = getModelPricing(modelId);\n\n const inputCost = (tokens.input / 1_000_000) * pricing.input;\n const outputCost = (tokens.output / 1_000_000) * pricing.output;\n const cacheWriteCost = (tokens.cache.write / 1_000_000) * pricing.cacheWrite;\n const cacheReadCost = (tokens.cache.read / 1_000_000) * pricing.cacheRead;\n const reasoningCost = (tokens.reasoning / 1_000_000) * pricing.output;\n\n return (\n inputCost + outputCost + cacheWriteCost + cacheReadCost + reasoningCost\n );\n}\n",
|
|
8
|
-
"/**\n * Data aggregation functions\n */\n\nimport type { DailyStats, MessageJson } from \"./types.js\";\nimport { calculateCost } from \"./pricing\";\n\nfunction timestampToDate(timestamp: number): string {\n return new Date(timestamp).toISOString().split(\"T\")[0];\n}\n\nexport function aggregateByDate(\n messages: MessageJson[]\n): Map<string, DailyStats> {\n const dailyStats = new Map<string, DailyStats>();\n\n for (const msg of messages) {\n const timestamp = msg.time?.created ?? msg.time?.completed;\n if (!timestamp) continue;\n\n const date = timestampToDate(timestamp);\n const modelId = msg.model?.modelID ?? msg.modelID ?? \"unknown\";\n const providerId = msg.model?.providerID ?? msg.providerID ?? \"unknown\";\n const tokens = msg.tokens!;\n const msgCost = calculateCost(tokens, modelId);\n\n let stats = dailyStats.get(date);\n if (!stats) {\n stats = {\n date,\n models: new Set(),\n providers: new Set(),\n providerStats: new Map(),\n input: 0,\n output: 0,\n cacheWrite: 0,\n cacheRead: 0,\n reasoning: 0,\n cost: 0,\n };\n dailyStats.set(date, stats);\n }\n\n // Update daily totals\n stats.models.add(modelId);\n stats.providers.add(providerId);\n stats.input += tokens.input ?? 0;\n stats.output += tokens.output ?? 0;\n stats.cacheWrite += tokens.cache?.write ?? 0;\n stats.cacheRead += tokens.cache?.read ?? 0;\n stats.reasoning += tokens.reasoning ?? 0;\n stats.cost += msgCost;\n\n // Update provider-specific stats\n let providerStat = stats.providerStats.get(providerId);\n if (!providerStat) {\n providerStat = {\n input: 0,\n output: 0,\n cacheWrite: 0,\n cacheRead: 0,\n reasoning: 0,\n cost: 0,\n models: new Set(),\n };\n stats.providerStats.set(providerId, providerStat);\n }\n providerStat.models.add(modelId);\n providerStat.input += tokens.input ?? 0;\n providerStat.output += tokens.output ?? 0;\n providerStat.cacheWrite += tokens.cache?.write ?? 0;\n providerStat.cacheRead += tokens.cache?.read ?? 0;\n providerStat.reasoning += tokens.reasoning ?? 0;\n providerStat.cost += msgCost;\n }\n\n return dailyStats;\n}\n\nexport function filterByDays(\n dailyStats: Map<string, DailyStats>,\n days: number\n): Map<string, DailyStats> {\n const cutoffDate = new Date();\n cutoffDate.setDate(cutoffDate.getDate() - days);\n const cutoffStr = cutoffDate.toISOString().split(\"T\")[0];\n\n const filtered = new Map<string, DailyStats>();\n for (const [date, stats] of dailyStats) {\n if (date >= cutoffStr) {\n filtered.set(date, stats);\n }\n }\n return filtered;\n}\n",
|
|
9
|
-
"/**\n * Terminal table renderer\n */\n\nimport type { DailyStats } from \"./types\";\n\nfunction formatNumber(num: number): string {\n return num.toLocaleString(\"en-US\");\n}\n\nfunction formatCost(cost: number): string {\n return `$${cost.toFixed(2)}`;\n}\n\nfunction padRight(str: string, len: number): string {\n return str.padEnd(len);\n}\n\nfunction padLeft(str: string, len: number): string {\n return str.padStart(len);\n}\n\nexport function renderTable(dailyStats: Map<string, DailyStats>): void {\n const sortedDates = Array.from(dailyStats.keys()).sort((a, b) =>\n a.localeCompare(b)\n );\n\n if (sortedDates.length === 0) {\n console.log(\"\\nNo usage data found.\\n\");\n return;\n }\n\n // Column widths\n const colDate = 12;\n const colModels = 35;\n const colInput = 16;\n const colOutput = 14;\n const colTotal = 16;\n const colCost = 12;\n\n // Border characters\n const h = \"\\u2500\";\n const v = \"\\u2502\";\n const tl = \"\\u250C\";\n const tr = \"\\u2510\";\n const bl = \"\\u2514\";\n const br = \"\\u2518\";\n const ml = \"\\u251C\";\n const mr = \"\\u2524\";\n const mt = \"\\u252C\";\n const mb = \"\\u2534\";\n const mm = \"\\u253C\";\n\n const topLine =\n tl +\n h.repeat(colDate) +\n mt +\n h.repeat(colModels) +\n mt +\n h.repeat(colInput) +\n mt +\n h.repeat(colOutput) +\n mt +\n h.repeat(colTotal) +\n mt +\n h.repeat(colCost) +\n tr;\n\n const midLine =\n ml +\n h.repeat(colDate) +\n mm +\n h.repeat(colModels) +\n mm +\n h.repeat(colInput) +\n mm +\n h.repeat(colOutput) +\n mm +\n h.repeat(colTotal) +\n mm +\n h.repeat(colCost) +\n mr;\n\n const bottomLine =\n bl +\n h.repeat(colDate) +\n mb +\n h.repeat(colModels) +\n mb +\n h.repeat(colInput) +\n mb +\n h.repeat(colOutput) +\n mb +\n h.repeat(colTotal) +\n mb +\n h.repeat(colCost) +\n br;\n\n const header =\n v +\n padRight(\" Date\", colDate) +\n v +\n padRight(\" Models\", colModels) +\n v +\n padLeft(\"Input \", colInput) +\n v +\n padLeft(\"Output \", colOutput) +\n v +\n padLeft(\"Total Tokens \", colTotal) +\n v +\n padLeft(\"Cost \", colCost) +\n v;\n\n console.log(\"\\n\" + topLine);\n console.log(header);\n console.log(midLine);\n\n let totalInput = 0;\n let totalOutput = 0;\n let totalCost = 0;\n\n for (const date of sortedDates) {\n const stats = dailyStats.get(date)!;\n const models = Array.from(stats.models).sort();\n\n const combinedInput = stats.input + stats.cacheRead + stats.cacheWrite;\n const totalTokens = combinedInput + stats.output;\n\n totalInput += combinedInput;\n totalOutput += stats.output;\n totalCost += stats.cost;\n\n const firstModel = models[0] ? `- ${models[0]}` : \"\";\n console.log(\n v +\n padRight(` ${date}`, colDate) +\n v +\n padRight(` ${firstModel}`, colModels) +\n v +\n padLeft(`${formatNumber(combinedInput)} `, colInput) +\n v +\n padLeft(`${formatNumber(stats.output)} `, colOutput) +\n v +\n padLeft(`${formatNumber(totalTokens)} `, colTotal) +\n v +\n padLeft(`${formatCost(stats.cost)} `, colCost) +\n v\n );\n\n for (let i = 1; i < models.length; i++) {\n console.log(\n v +\n \" \".repeat(colDate) +\n v +\n padRight(` - ${models[i]}`, colModels) +\n v +\n \" \".repeat(colInput) +\n v +\n \" \".repeat(colOutput) +\n v +\n \" \".repeat(colTotal) +\n v +\n \" \".repeat(colCost) +\n v\n );\n }\n\n const providers = Array.from(stats.providerStats.entries()).sort(\n (a, b) => b[1].cost - a[1].cost\n );\n\n for (const [providerId, providerStat] of providers) {\n const providerInput =\n providerStat.input + providerStat.cacheRead + providerStat.cacheWrite;\n const providerTokens = providerInput + providerStat.output;\n console.log(\n v +\n \" \".repeat(colDate) +\n v +\n padRight(` [${providerId}]`, colModels) +\n v +\n padLeft(`${formatNumber(providerInput)} `, colInput) +\n v +\n padLeft(`${formatNumber(providerStat.output)} `, colOutput) +\n v +\n padLeft(`${formatNumber(providerTokens)} `, colTotal) +\n v +\n padLeft(`${formatCost(providerStat.cost)} `, colCost) +\n v\n );\n }\n\n console.log(midLine);\n }\n\n const grandTotal = totalInput + totalOutput;\n console.log(\n v +\n padRight(\" Total\", colDate) +\n v +\n \" \".repeat(colModels) +\n v +\n padLeft(`${formatNumber(totalInput)} `, colInput) +\n v +\n padLeft(`${formatNumber(totalOutput)} `, colOutput) +\n v +\n padLeft(`${formatNumber(grandTotal)} `, colTotal) +\n v +\n padLeft(`${formatCost(totalCost)} `, colCost) +\n v\n );\n console.log(bottomLine);\n console.log();\n}\n",
|
|
10
|
-
"#!/usr/bin/env node\n/**\n * OpenCode Usage - CLI tool for tracking OpenCode AI usage and costs\n *\n * Usage:\n * bunx opencode-usage\n * bunx opencode-usage --provider anthropic\n * bunx opencode-usage --days 30\n */\n\nimport { parseArgs } from \"./cli.js\";\nimport { getOpenCodeStoragePath, loadMessages } from \"./loader.js\";\nimport {
|
|
8
|
+
"/**\n * Data aggregation functions\n */\n\nimport type { DailyStats, MessageJson } from \"./types.js\";\nimport { calculateCost } from \"./pricing\";\n\nfunction timestampToDate(timestamp: number): string {\n return new Date(timestamp).toISOString().split(\"T\")[0];\n}\n\nexport function aggregateByDate(\n messages: MessageJson[]\n): Map<string, DailyStats> {\n const dailyStats = new Map<string, DailyStats>();\n\n for (const msg of messages) {\n const timestamp = msg.time?.created ?? msg.time?.completed;\n if (!timestamp) continue;\n\n const date = timestampToDate(timestamp);\n const modelId = msg.model?.modelID ?? msg.modelID ?? \"unknown\";\n const providerId = msg.model?.providerID ?? msg.providerID ?? \"unknown\";\n const tokens = msg.tokens!;\n const msgCost = calculateCost(tokens, modelId);\n\n let stats = dailyStats.get(date);\n if (!stats) {\n stats = {\n date,\n models: new Set(),\n providers: new Set(),\n providerStats: new Map(),\n input: 0,\n output: 0,\n cacheWrite: 0,\n cacheRead: 0,\n reasoning: 0,\n cost: 0,\n };\n dailyStats.set(date, stats);\n }\n\n // Update daily totals\n stats.models.add(modelId);\n stats.providers.add(providerId);\n stats.input += tokens.input ?? 0;\n stats.output += tokens.output ?? 0;\n stats.cacheWrite += tokens.cache?.write ?? 0;\n stats.cacheRead += tokens.cache?.read ?? 0;\n stats.reasoning += tokens.reasoning ?? 0;\n stats.cost += msgCost;\n\n // Update provider-specific stats\n let providerStat = stats.providerStats.get(providerId);\n if (!providerStat) {\n providerStat = {\n input: 0,\n output: 0,\n cacheWrite: 0,\n cacheRead: 0,\n reasoning: 0,\n cost: 0,\n models: new Set(),\n };\n stats.providerStats.set(providerId, providerStat);\n }\n providerStat.models.add(modelId);\n providerStat.input += tokens.input ?? 0;\n providerStat.output += tokens.output ?? 0;\n providerStat.cacheWrite += tokens.cache?.write ?? 0;\n providerStat.cacheRead += tokens.cache?.read ?? 0;\n providerStat.reasoning += tokens.reasoning ?? 0;\n providerStat.cost += msgCost;\n }\n\n return dailyStats;\n}\n\nexport function filterByDays(\n dailyStats: Map<string, DailyStats>,\n days: number\n): Map<string, DailyStats> {\n const cutoffDate = new Date();\n cutoffDate.setDate(cutoffDate.getDate() - days);\n const cutoffStr = cutoffDate.toISOString().split(\"T\")[0];\n\n const filtered = new Map<string, DailyStats>();\n for (const [date, stats] of dailyStats) {\n if (date >= cutoffStr) {\n filtered.set(date, stats);\n }\n }\n return filtered;\n}\n\nexport function filterByDateRange(\n dailyStats: Map<string, DailyStats>,\n since?: string,\n until?: string\n): Map<string, DailyStats> {\n const filtered = new Map<string, DailyStats>();\n for (const [date, stats] of dailyStats) {\n if (since && date < since) continue;\n if (until && date > until) continue;\n filtered.set(date, stats);\n }\n return filtered;\n}\n\nfunction dateToMonth(date: string): string {\n return date.slice(0, 7); // YYYY-MM\n}\n\nexport function aggregateByMonth(\n dailyStats: Map<string, DailyStats>\n): Map<string, DailyStats> {\n const monthlyStats = new Map<string, DailyStats>();\n\n for (const [date, stats] of dailyStats) {\n const month = dateToMonth(date);\n\n let monthStats = monthlyStats.get(month);\n if (!monthStats) {\n monthStats = {\n date: month,\n models: new Set(),\n providers: new Set(),\n providerStats: new Map(),\n input: 0,\n output: 0,\n cacheWrite: 0,\n cacheRead: 0,\n reasoning: 0,\n cost: 0,\n };\n monthlyStats.set(month, monthStats);\n }\n\n // Merge models and providers\n for (const model of stats.models) monthStats.models.add(model);\n for (const provider of stats.providers) monthStats.providers.add(provider);\n\n // Sum totals\n monthStats.input += stats.input;\n monthStats.output += stats.output;\n monthStats.cacheWrite += stats.cacheWrite;\n monthStats.cacheRead += stats.cacheRead;\n monthStats.reasoning += stats.reasoning;\n monthStats.cost += stats.cost;\n\n // Merge provider stats\n for (const [providerId, providerStat] of stats.providerStats) {\n let monthProviderStat = monthStats.providerStats.get(providerId);\n if (!monthProviderStat) {\n monthProviderStat = {\n input: 0,\n output: 0,\n cacheWrite: 0,\n cacheRead: 0,\n reasoning: 0,\n cost: 0,\n models: new Set(),\n };\n monthStats.providerStats.set(providerId, monthProviderStat);\n }\n for (const model of providerStat.models)\n monthProviderStat.models.add(model);\n monthProviderStat.input += providerStat.input;\n monthProviderStat.output += providerStat.output;\n monthProviderStat.cacheWrite += providerStat.cacheWrite;\n monthProviderStat.cacheRead += providerStat.cacheRead;\n monthProviderStat.reasoning += providerStat.reasoning;\n monthProviderStat.cost += providerStat.cost;\n }\n }\n\n return monthlyStats;\n}\n",
|
|
9
|
+
"/**\n * Terminal table renderer\n */\n\nimport type { DailyStats } from \"./types\";\n\nfunction formatNumber(num: number): string {\n return num.toLocaleString(\"en-US\");\n}\n\nfunction formatCost(cost: number): string {\n return `$${cost.toFixed(2)}`;\n}\n\nfunction padRight(str: string, len: number): string {\n return str.padEnd(len);\n}\n\nfunction padLeft(str: string, len: number): string {\n return str.padStart(len);\n}\n\nexport type JsonOutput = {\n periods: Array<{\n date: string;\n models: string[];\n providers: Array<{\n id: string;\n models: string[];\n input: number;\n output: number;\n cacheRead: number;\n cacheWrite: number;\n reasoning: number;\n cost: number;\n }>;\n totals: {\n input: number;\n output: number;\n cacheRead: number;\n cacheWrite: number;\n reasoning: number;\n cost: number;\n };\n }>;\n totals: {\n input: number;\n output: number;\n cost: number;\n };\n};\n\nexport function renderJson(dailyStats: Map<string, DailyStats>): void {\n const sortedDates = Array.from(dailyStats.keys()).sort((a, b) =>\n a.localeCompare(b)\n );\n\n let totalInput = 0;\n let totalOutput = 0;\n let totalCost = 0;\n\n const periods = sortedDates.map((date) => {\n const stats = dailyStats.get(date)!;\n const combinedInput = stats.input + stats.cacheRead + stats.cacheWrite;\n\n totalInput += combinedInput;\n totalOutput += stats.output;\n totalCost += stats.cost;\n\n const providers = Array.from(stats.providerStats.entries())\n .sort((a, b) => b[1].cost - a[1].cost)\n .map(([id, ps]) => ({\n id,\n models: Array.from(ps.models).sort(),\n input: ps.input,\n output: ps.output,\n cacheRead: ps.cacheRead,\n cacheWrite: ps.cacheWrite,\n reasoning: ps.reasoning,\n cost: Math.round(ps.cost * 100) / 100,\n }));\n\n return {\n date,\n models: Array.from(stats.models).sort(),\n providers,\n totals: {\n input: stats.input,\n output: stats.output,\n cacheRead: stats.cacheRead,\n cacheWrite: stats.cacheWrite,\n reasoning: stats.reasoning,\n cost: Math.round(stats.cost * 100) / 100,\n },\n };\n });\n\n const output: JsonOutput = {\n periods,\n totals: {\n input: totalInput,\n output: totalOutput,\n cost: Math.round(totalCost * 100) / 100,\n },\n };\n\n console.log(JSON.stringify(output, null, 2));\n}\n\nexport function renderTable(dailyStats: Map<string, DailyStats>): void {\n const sortedDates = Array.from(dailyStats.keys()).sort((a, b) =>\n a.localeCompare(b)\n );\n\n if (sortedDates.length === 0) {\n console.log(\"\\nNo usage data found.\\n\");\n return;\n }\n\n // Column widths\n const colDate = 12;\n const colModels = 35;\n const colInput = 16;\n const colOutput = 14;\n const colTotal = 16;\n const colCost = 12;\n\n // Border characters\n const h = \"\\u2500\";\n const v = \"\\u2502\";\n const tl = \"\\u250C\";\n const tr = \"\\u2510\";\n const bl = \"\\u2514\";\n const br = \"\\u2518\";\n const ml = \"\\u251C\";\n const mr = \"\\u2524\";\n const mt = \"\\u252C\";\n const mb = \"\\u2534\";\n const mm = \"\\u253C\";\n\n const topLine =\n tl +\n h.repeat(colDate) +\n mt +\n h.repeat(colModels) +\n mt +\n h.repeat(colInput) +\n mt +\n h.repeat(colOutput) +\n mt +\n h.repeat(colTotal) +\n mt +\n h.repeat(colCost) +\n tr;\n\n const midLine =\n ml +\n h.repeat(colDate) +\n mm +\n h.repeat(colModels) +\n mm +\n h.repeat(colInput) +\n mm +\n h.repeat(colOutput) +\n mm +\n h.repeat(colTotal) +\n mm +\n h.repeat(colCost) +\n mr;\n\n const bottomLine =\n bl +\n h.repeat(colDate) +\n mb +\n h.repeat(colModels) +\n mb +\n h.repeat(colInput) +\n mb +\n h.repeat(colOutput) +\n mb +\n h.repeat(colTotal) +\n mb +\n h.repeat(colCost) +\n br;\n\n const header =\n v +\n padRight(\" Date\", colDate) +\n v +\n padRight(\" Models\", colModels) +\n v +\n padLeft(\"Input \", colInput) +\n v +\n padLeft(\"Output \", colOutput) +\n v +\n padLeft(\"Total Tokens \", colTotal) +\n v +\n padLeft(\"Cost \", colCost) +\n v;\n\n console.log(\"\\n\" + topLine);\n console.log(header);\n console.log(midLine);\n\n let totalInput = 0;\n let totalOutput = 0;\n let totalCost = 0;\n\n for (const date of sortedDates) {\n const stats = dailyStats.get(date)!;\n const models = Array.from(stats.models).sort();\n\n const combinedInput = stats.input + stats.cacheRead + stats.cacheWrite;\n const totalTokens = combinedInput + stats.output;\n\n totalInput += combinedInput;\n totalOutput += stats.output;\n totalCost += stats.cost;\n\n const firstModel = models[0] ? `- ${models[0]}` : \"\";\n console.log(\n v +\n padRight(` ${date}`, colDate) +\n v +\n padRight(` ${firstModel}`, colModels) +\n v +\n padLeft(`${formatNumber(combinedInput)} `, colInput) +\n v +\n padLeft(`${formatNumber(stats.output)} `, colOutput) +\n v +\n padLeft(`${formatNumber(totalTokens)} `, colTotal) +\n v +\n padLeft(`${formatCost(stats.cost)} `, colCost) +\n v\n );\n\n for (let i = 1; i < models.length; i++) {\n console.log(\n v +\n \" \".repeat(colDate) +\n v +\n padRight(` - ${models[i]}`, colModels) +\n v +\n \" \".repeat(colInput) +\n v +\n \" \".repeat(colOutput) +\n v +\n \" \".repeat(colTotal) +\n v +\n \" \".repeat(colCost) +\n v\n );\n }\n\n const providers = Array.from(stats.providerStats.entries()).sort(\n (a, b) => b[1].cost - a[1].cost\n );\n\n for (const [providerId, providerStat] of providers) {\n const providerInput =\n providerStat.input + providerStat.cacheRead + providerStat.cacheWrite;\n const providerTokens = providerInput + providerStat.output;\n console.log(\n v +\n \" \".repeat(colDate) +\n v +\n padRight(` [${providerId}]`, colModels) +\n v +\n padLeft(`${formatNumber(providerInput)} `, colInput) +\n v +\n padLeft(`${formatNumber(providerStat.output)} `, colOutput) +\n v +\n padLeft(`${formatNumber(providerTokens)} `, colTotal) +\n v +\n padLeft(`${formatCost(providerStat.cost)} `, colCost) +\n v\n );\n }\n\n console.log(midLine);\n }\n\n const grandTotal = totalInput + totalOutput;\n console.log(\n v +\n padRight(\" Total\", colDate) +\n v +\n \" \".repeat(colModels) +\n v +\n padLeft(`${formatNumber(totalInput)} `, colInput) +\n v +\n padLeft(`${formatNumber(totalOutput)} `, colOutput) +\n v +\n padLeft(`${formatNumber(grandTotal)} `, colTotal) +\n v +\n padLeft(`${formatCost(totalCost)} `, colCost) +\n v\n );\n console.log(bottomLine);\n console.log();\n}\n",
|
|
10
|
+
"#!/usr/bin/env node\n/**\n * OpenCode Usage - CLI tool for tracking OpenCode AI usage and costs\n *\n * Usage:\n * bunx opencode-usage\n * bunx opencode-usage --provider anthropic\n * bunx opencode-usage --days 30\n * bunx opencode-usage --since 20251201 --until 20251231\n * bunx opencode-usage --monthly --json\n */\n\nimport { parseArgs } from \"./cli.js\";\nimport { getOpenCodeStoragePath, loadMessages } from \"./loader.js\";\nimport {\n aggregateByDate,\n aggregateByMonth,\n filterByDays,\n filterByDateRange,\n} from \"./aggregator.js\";\nimport { renderTable, renderJson } from \"./renderer.js\";\n\nasync function main(): Promise<void> {\n const { provider, days, since, until, json, monthly } = parseArgs();\n const storagePath = getOpenCodeStoragePath();\n\n if (!json) {\n console.log(`\\nLoading OpenCode usage data from: ${storagePath}`);\n if (provider) {\n console.log(`Filtering: ${provider} provider only`);\n }\n }\n\n const messages = await loadMessages(storagePath, provider);\n\n if (!json) {\n console.log(`Found ${messages.length} assistant messages with token data`);\n }\n\n let stats = aggregateByDate(messages);\n\n // Apply date filters\n if (days) {\n stats = filterByDays(stats, days);\n if (!json) console.log(`Showing last ${days} days`);\n }\n\n if (since || until) {\n stats = filterByDateRange(stats, since, until);\n if (!json) {\n if (since && until) console.log(`Date range: ${since} to ${until}`);\n else if (since) console.log(`From: ${since}`);\n else if (until) console.log(`Until: ${until}`);\n }\n }\n\n // Aggregate by month if requested\n if (monthly) {\n stats = aggregateByMonth(stats);\n if (!json) console.log(`Aggregated by month`);\n }\n\n // Render output\n if (json) {\n renderJson(stats);\n } else {\n renderTable(stats);\n }\n}\n\nmain().catch(console.error);\n"
|
|
11
11
|
],
|
|
12
|
-
"mappings": "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",
|
|
13
|
-
"debugId": "
|
|
12
|
+
"mappings": "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",
|
|
13
|
+
"debugId": "CFEB06924236C7EF64756E2164756E21",
|
|
14
14
|
"names": []
|
|
15
15
|
}
|
package/dist/renderer.d.ts
CHANGED
|
@@ -2,4 +2,34 @@
|
|
|
2
2
|
* Terminal table renderer
|
|
3
3
|
*/
|
|
4
4
|
import type { DailyStats } from "./types";
|
|
5
|
+
export type JsonOutput = {
|
|
6
|
+
periods: Array<{
|
|
7
|
+
date: string;
|
|
8
|
+
models: string[];
|
|
9
|
+
providers: Array<{
|
|
10
|
+
id: string;
|
|
11
|
+
models: string[];
|
|
12
|
+
input: number;
|
|
13
|
+
output: number;
|
|
14
|
+
cacheRead: number;
|
|
15
|
+
cacheWrite: number;
|
|
16
|
+
reasoning: number;
|
|
17
|
+
cost: number;
|
|
18
|
+
}>;
|
|
19
|
+
totals: {
|
|
20
|
+
input: number;
|
|
21
|
+
output: number;
|
|
22
|
+
cacheRead: number;
|
|
23
|
+
cacheWrite: number;
|
|
24
|
+
reasoning: number;
|
|
25
|
+
cost: number;
|
|
26
|
+
};
|
|
27
|
+
}>;
|
|
28
|
+
totals: {
|
|
29
|
+
input: number;
|
|
30
|
+
output: number;
|
|
31
|
+
cost: number;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
export declare function renderJson(dailyStats: Map<string, DailyStats>): void;
|
|
5
35
|
export declare function renderTable(dailyStats: Map<string, DailyStats>): void;
|