claude-cost-cry 0.3.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.
Files changed (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.ko.md +173 -0
  3. package/README.md +174 -0
  4. package/bin/cli.js +333 -0
  5. package/dist/calculator.d.ts +8 -0
  6. package/dist/calculator.js +74 -0
  7. package/dist/calculator.js.map +1 -0
  8. package/dist/config.d.ts +5 -0
  9. package/dist/config.js +49 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/display.d.ts +11 -0
  12. package/dist/display.js +204 -0
  13. package/dist/display.js.map +1 -0
  14. package/dist/exchange.d.ts +5 -0
  15. package/dist/exchange.js +104 -0
  16. package/dist/exchange.js.map +1 -0
  17. package/dist/history.d.ts +3 -0
  18. package/dist/history.js +176 -0
  19. package/dist/history.js.map +1 -0
  20. package/dist/i18n.d.ts +9 -0
  21. package/dist/i18n.js +34 -0
  22. package/dist/i18n.js.map +1 -0
  23. package/dist/index.d.ts +1 -0
  24. package/dist/index.js +112 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/locales/en.d.ts +191 -0
  27. package/dist/locales/en.js +204 -0
  28. package/dist/locales/en.js.map +1 -0
  29. package/dist/locales/ko.d.ts +191 -0
  30. package/dist/locales/ko.js +204 -0
  31. package/dist/locales/ko.js.map +1 -0
  32. package/dist/messages.d.ts +9 -0
  33. package/dist/messages.js +73 -0
  34. package/dist/messages.js.map +1 -0
  35. package/dist/parser.d.ts +2 -0
  36. package/dist/parser.js +21 -0
  37. package/dist/parser.js.map +1 -0
  38. package/dist/pricing.d.ts +6 -0
  39. package/dist/pricing.js +49 -0
  40. package/dist/pricing.js.map +1 -0
  41. package/dist/providers/claude.d.ts +3 -0
  42. package/dist/providers/claude.js +79 -0
  43. package/dist/providers/claude.js.map +1 -0
  44. package/dist/providers/cursor.d.ts +9 -0
  45. package/dist/providers/cursor.js +217 -0
  46. package/dist/providers/cursor.js.map +1 -0
  47. package/dist/providers/google.d.ts +3 -0
  48. package/dist/providers/google.js +72 -0
  49. package/dist/providers/google.js.map +1 -0
  50. package/dist/providers/index.d.ts +9 -0
  51. package/dist/providers/index.js +41 -0
  52. package/dist/providers/index.js.map +1 -0
  53. package/dist/providers/openai.d.ts +3 -0
  54. package/dist/providers/openai.js +90 -0
  55. package/dist/providers/openai.js.map +1 -0
  56. package/dist/report.d.ts +36 -0
  57. package/dist/report.js +203 -0
  58. package/dist/report.js.map +1 -0
  59. package/dist/types.d.ts +137 -0
  60. package/dist/types.js +2 -0
  61. package/dist/types.js.map +1 -0
  62. package/dist/watcher.d.ts +12 -0
  63. package/dist/watcher.js +222 -0
  64. package/dist/watcher.js.map +1 -0
  65. package/electron/main.js +405 -0
  66. package/electron/overlay.html +1390 -0
  67. package/electron/package.json +1 -0
  68. package/electron/preload.js +15 -0
  69. package/package.json +65 -0
@@ -0,0 +1,8 @@
1
+ import type { Usage, Config, EquivalentResult, SavingsNudge } from './types.js';
2
+ export declare function calculateCost(usage: Usage): number;
3
+ export declare function formatCost(cost: number): string;
4
+ export declare function formatCostShort(cost: number): string;
5
+ export declare function getAllEquivalents(config: Config): import("./types.js").EquivalentItem[];
6
+ export declare function toEquivalent(cost: number, config: Config): EquivalentResult | null;
7
+ export declare function formatTokenCount(n: number): string;
8
+ export declare function getSavingsNudge(usage: Usage, actualCost: number): SavingsNudge | null;
@@ -0,0 +1,74 @@
1
+ import { getPricing, getEquivalents, resolveEquivKey } from './pricing.js';
2
+ import { calculateCost as providerCalculateCost, getProvider } from './providers/index.js';
3
+ export function calculateCost(usage) {
4
+ if (usage.provider) {
5
+ return providerCalculateCost(usage);
6
+ }
7
+ const pricing = getPricing(usage.model);
8
+ return (usage.inputTokens / 1e6) * pricing.input
9
+ + (usage.outputTokens / 1e6) * pricing.output
10
+ + (usage.cacheCreationTokens / 1e6) * (pricing.cacheWrite || 0)
11
+ + (usage.cacheReadTokens / 1e6) * (pricing.cacheRead || 0);
12
+ }
13
+ export function formatCost(cost) {
14
+ return `$${cost.toFixed(4)}`;
15
+ }
16
+ export function formatCostShort(cost) {
17
+ if (cost < 0.01)
18
+ return `$${cost.toFixed(4)}`;
19
+ if (cost < 1)
20
+ return `$${cost.toFixed(3)}`;
21
+ return `$${cost.toFixed(2)}`;
22
+ }
23
+ export function getAllEquivalents(config) {
24
+ const custom = config?.customEquivalents || [];
25
+ return [...custom, ...getEquivalents()];
26
+ }
27
+ export function toEquivalent(cost, config) {
28
+ if (cost < 0.01)
29
+ return null;
30
+ const allItems = getAllEquivalents(config);
31
+ const unit = config?.equivalentUnit || 'auto';
32
+ if (unit !== 'auto') {
33
+ const resolved = resolveEquivKey(unit);
34
+ const fixed = allItems.find(i => i.key === resolved || i.name === resolved);
35
+ if (fixed) {
36
+ return { ...fixed, count: Math.round((cost / fixed.price) * 10) / 10 };
37
+ }
38
+ }
39
+ for (const item of allItems) {
40
+ const count = cost / item.price;
41
+ if (count >= 0.1) {
42
+ return { ...item, count: Math.round(count * 10) / 10 };
43
+ }
44
+ }
45
+ return { ...allItems[0], count: Math.round((cost / allItems[0].price) * 10) / 10 };
46
+ }
47
+ export function formatTokenCount(n) {
48
+ if (n >= 1_000_000)
49
+ return `${(n / 1_000_000).toFixed(1)}M`;
50
+ if (n >= 1_000)
51
+ return `${(n / 1_000).toFixed(1)}K`;
52
+ return String(n);
53
+ }
54
+ export function getSavingsNudge(usage, actualCost) {
55
+ const provider = usage.provider ? getProvider(usage.provider) : null;
56
+ if (!provider)
57
+ return null;
58
+ const models = provider.models;
59
+ const currentLabel = provider.getModelLabel(usage.model).toLowerCase();
60
+ let bestSaving = null;
61
+ for (const [, pricing] of Object.entries(models)) {
62
+ if (pricing.label.toLowerCase() === currentLabel)
63
+ continue;
64
+ const totalInput = usage.inputTokens + usage.cacheCreationTokens + usage.cacheReadTokens;
65
+ const altCost = (totalInput / 1e6) * pricing.input
66
+ + (usage.outputTokens / 1e6) * pricing.output;
67
+ const saving = actualCost - altCost;
68
+ if (saving > 0.001 && (!bestSaving || saving > bestSaving.saving)) {
69
+ bestSaving = { model: pricing.label, cost: altCost, saving };
70
+ }
71
+ }
72
+ return bestSaving;
73
+ }
74
+ //# sourceMappingURL=calculator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calculator.js","sourceRoot":"","sources":["../src/calculator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { Config, BudgetStatus } from './types.js';
2
+ export declare function loadConfig(): Config;
3
+ export declare function saveConfig(config: Config): void;
4
+ export declare function updateConfig(updates: Partial<Config>): Config;
5
+ export declare function getBudgetStatus(cost: number, budget: number | null): BudgetStatus;
package/dist/config.js ADDED
@@ -0,0 +1,49 @@
1
+ import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ const CONFIG_DIR = join(homedir(), '.claude-cost-cry');
5
+ const CONFIG_PATH = join(CONFIG_DIR, 'config.json');
6
+ const DEFAULTS = {
7
+ dailyBudget: null,
8
+ monthlyBudget: null,
9
+ currency: 'USD',
10
+ exchangeRate: null,
11
+ showNudge: true,
12
+ equivalentUnit: 'auto',
13
+ customEquivalents: [],
14
+ logSources: [],
15
+ language: 'en',
16
+ };
17
+ export function loadConfig() {
18
+ try {
19
+ const raw = readFileSync(CONFIG_PATH, 'utf-8');
20
+ return { ...DEFAULTS, ...JSON.parse(raw) };
21
+ }
22
+ catch {
23
+ return { ...DEFAULTS };
24
+ }
25
+ }
26
+ export function saveConfig(config) {
27
+ mkdirSync(CONFIG_DIR, { recursive: true });
28
+ writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2) + '\n', 'utf-8');
29
+ }
30
+ export function updateConfig(updates) {
31
+ const config = loadConfig();
32
+ Object.assign(config, updates);
33
+ saveConfig(config);
34
+ return config;
35
+ }
36
+ export function getBudgetStatus(cost, budget) {
37
+ if (!budget || budget <= 0)
38
+ return { ratio: 0, status: 'ok', budget: null };
39
+ const ratio = cost / budget;
40
+ let status = 'ok';
41
+ if (ratio >= 1)
42
+ status = 'exceeded';
43
+ else if (ratio >= 0.9)
44
+ status = 'danger';
45
+ else if (ratio >= 0.7)
46
+ status = 'warning';
47
+ return { ratio: Math.min(ratio, 1), status, budget, remaining: Math.max(0, budget - cost) };
48
+ }
49
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAGlC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,kBAAkB,CAAC,CAAC;AACvD,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAEpD,MAAM,QAAQ,GAAW;IACvB,WAAW,EAAE,IAAI;IACjB,aAAa,EAAE,IAAI;IACnB,QAAQ,EAAE,KAAK;IACf,YAAY,EAAE,IAAI;IAClB,SAAS,EAAE,IAAI;IACf,cAAc,EAAE,MAAM;IACtB,iBAAiB,EAAE,EAAE;IACrB,UAAU,EAAE,EAAE;IACd,QAAQ,EAAE,IAAI;CACf,CAAC;AAEF,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAC/C,OAAO,EAAE,GAAG,QAAQ,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,GAAG,QAAQ,EAAE,CAAC;IACzB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAc;IACvC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAwB;IACnD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,UAAU,CAAC,MAAM,CAAC,CAAC;IACnB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,MAAqB;IACjE,IAAI,CAAC,MAAM,IAAI,MAAM,IAAI,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAE5E,MAAM,KAAK,GAAG,IAAI,GAAG,MAAM,CAAC;IAE5B,IAAI,MAAM,GAA2B,IAAI,CAAC;IAC1C,IAAI,KAAK,IAAI,CAAC;QAAE,MAAM,GAAG,UAAU,CAAC;SAC/B,IAAI,KAAK,IAAI,GAAG;QAAE,MAAM,GAAG,QAAQ,CAAC;SACpC,IAAI,KAAK,IAAI,GAAG;QAAE,MAAM,GAAG,SAAS,CAAC;IAE1C,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;AAC9F,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { Usage, Config, ExchangeInfo, BudgetStatus, TopRequest } from './types.js';
2
+ export declare function showBanner(): void;
3
+ export declare function showTodaySummary(totalCost: number, callCount: number, budgetStatus: BudgetStatus | null, config: Config, exchange: ExchangeInfo | null, costByProvider?: Record<string, number>): void;
4
+ export declare function showBudgetBar(totalCost: number, budgetStatus: BudgetStatus, exchange: ExchangeInfo | null): void;
5
+ export declare function showCostUpdate(usage: Usage, cost: number, totalCost: number, config: Config, exchange: ExchangeInfo | null): void;
6
+ export declare function showBudgetAlert(budgetStatus: BudgetStatus, exchange: ExchangeInfo | null): void;
7
+ export declare function showTopExpensive(topRequests: TopRequest[], exchange: ExchangeInfo | null): void;
8
+ export declare function showShutdown(sessionCost: number, totalCost: number, savingsTotal: number, topRequests: TopRequest[], config: Config, exchange: ExchangeInfo | null, costByProvider?: Record<string, number>): void;
9
+ export declare function showError(message: string): void;
10
+ export declare function showInfo(message: string): void;
11
+ export declare function showConfigUpdate(key: string, value: string | number): void;
@@ -0,0 +1,204 @@
1
+ import chalk from 'chalk';
2
+ import { formatCostShort, formatTokenCount, toEquivalent, getSavingsNudge } from './calculator.js';
3
+ import { getMessage, getStartupMood } from './messages.js';
4
+ import { formatLocalCost } from './exchange.js';
5
+ import { getModelLabel as getProviderModelLabel, getProviderEmoji, getProviderDisplayName } from './providers/index.js';
6
+ import { t } from './i18n.js';
7
+ const VERSION = '0.3.0';
8
+ const DIVIDER = chalk.gray('─'.repeat(56));
9
+ function fc(cost, ex) {
10
+ return ex ? formatLocalCost(cost, ex) : formatCostShort(cost);
11
+ }
12
+ function resolveModelLabel(usage) {
13
+ if (usage.provider)
14
+ return getProviderModelLabel(usage);
15
+ return usage.model || 'Unknown';
16
+ }
17
+ function providerTag(providerName) {
18
+ if (!providerName)
19
+ return '';
20
+ const emoji = getProviderEmoji(providerName);
21
+ return `${emoji} `;
22
+ }
23
+ export function showBanner() {
24
+ console.log();
25
+ console.log(chalk.bold(` 🪙 claude-cost-cry v${VERSION}`));
26
+ console.log(chalk.gray(` ${t('display.tagline')}`));
27
+ console.log();
28
+ }
29
+ export function showTodaySummary(totalCost, callCount, budgetStatus, config, exchange, costByProvider) {
30
+ const mood = getStartupMood(totalCost);
31
+ const equiv = toEquivalent(totalCost, config);
32
+ const defaultUnit = t('display.defaultUnit');
33
+ const equivText = equiv
34
+ ? chalk.gray(` (${equiv.emoji} ${equiv.name} ${equiv.count}${equiv.unit || defaultUnit})`)
35
+ : '';
36
+ console.log(` ${t('display.todayTotal')} ${chalk.bold.yellow(fc(totalCost, exchange))}${equivText}`);
37
+ if (callCount > 0) {
38
+ console.log(chalk.gray(` ${t('display.apiCalls', { count: callCount })}`));
39
+ }
40
+ if (costByProvider && Object.keys(costByProvider).length > 1) {
41
+ const breakdown = Object.entries(costByProvider)
42
+ .sort((a, b) => b[1] - a[1])
43
+ .map(([p, c]) => `${getProviderEmoji(p)} ${getProviderDisplayName(p)} ${fc(c, exchange)}`)
44
+ .join(' ');
45
+ console.log(chalk.gray(` ${breakdown}`));
46
+ }
47
+ console.log(chalk.gray(` ${mood}`));
48
+ if (exchange && exchange.currency !== 'USD') {
49
+ const src = exchange.source === 'manual' ? t('display.exchangeManual') : exchange.updatedAt || '';
50
+ console.log(chalk.gray(` 💱 1 USD = ${exchange.rate.toLocaleString()} ${exchange.currency} (${src})`));
51
+ }
52
+ if (budgetStatus?.budget) {
53
+ console.log();
54
+ showBudgetBar(totalCost, budgetStatus, exchange);
55
+ }
56
+ console.log();
57
+ console.log(DIVIDER);
58
+ console.log(chalk.gray(` ${t('display.watching')}`));
59
+ console.log(DIVIDER);
60
+ console.log();
61
+ }
62
+ export function showBudgetBar(totalCost, budgetStatus, exchange) {
63
+ const { ratio, status, budget, remaining } = budgetStatus;
64
+ const barWidth = 30;
65
+ const filled = Math.round(ratio * barWidth);
66
+ const empty = barWidth - filled;
67
+ let barColor;
68
+ let statusIcon;
69
+ if (status === 'exceeded') {
70
+ barColor = chalk.bgRed.white;
71
+ statusIcon = '🚫';
72
+ }
73
+ else if (status === 'danger') {
74
+ barColor = chalk.bgRedBright.black;
75
+ statusIcon = '🔴';
76
+ }
77
+ else if (status === 'warning') {
78
+ barColor = chalk.bgYellow.black;
79
+ statusIcon = '🟡';
80
+ }
81
+ else {
82
+ barColor = chalk.bgGreen.black;
83
+ statusIcon = '🟢';
84
+ }
85
+ const bar = barColor('█'.repeat(filled)) + chalk.gray('░'.repeat(empty));
86
+ const pct = Math.round(ratio * 100);
87
+ console.log(` ${statusIcon} ${t('display.budget')} ${bar} ${pct}%`);
88
+ console.log(chalk.gray(` ${fc(totalCost, exchange)} / ${fc(budget, exchange)} (${t('display.budgetRemaining')} ${fc(remaining, exchange)})`));
89
+ if (status === 'exceeded') {
90
+ console.log(chalk.red.bold(` ${t('display.budgetExceeded')}`));
91
+ }
92
+ else if (status === 'danger') {
93
+ console.log(chalk.red(` ${t('display.budget90')}`));
94
+ }
95
+ else if (status === 'warning') {
96
+ console.log(chalk.yellow(` ${t('display.budget70')}`));
97
+ }
98
+ }
99
+ export function showCostUpdate(usage, cost, totalCost, config, exchange) {
100
+ const now = new Date();
101
+ const timeStr = chalk.gray(`[${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}]`);
102
+ const modelLabel = resolveModelLabel(usage);
103
+ const pEmoji = providerTag(usage.provider);
104
+ const isCursor = usage.provider === 'cursor';
105
+ const modelColor = isCursor ? chalk.hex('#06b6d4')
106
+ : /opus/i.test(modelLabel) ? chalk.magenta
107
+ : /haiku/i.test(modelLabel) ? chalk.green
108
+ : /gpt/i.test(modelLabel) ? chalk.hex('#74aa9c')
109
+ : /gemini/i.test(modelLabel) ? chalk.hex('#4285f4')
110
+ : chalk.blue;
111
+ const modelStr = modelColor(`${pEmoji}${modelLabel}`);
112
+ const totalInputTokens = usage.inputTokens + usage.cacheCreationTokens + usage.cacheReadTokens;
113
+ const tokenInfo = chalk.gray(`📥 ${formatTokenCount(totalInputTokens)} 📤 ${formatTokenCount(usage.outputTokens)}`);
114
+ const { emoji, message } = getMessage(totalCost);
115
+ const costDelta = cost >= 0.01
116
+ ? chalk.red(`+${fc(cost, exchange)}`)
117
+ : chalk.yellow(`+${fc(cost, exchange)}`);
118
+ const totalStr = chalk.bold.yellow(fc(totalCost, exchange));
119
+ const equiv = toEquivalent(totalCost, config);
120
+ const defaultUnit = t('display.defaultUnit');
121
+ const equivStr = equiv
122
+ ? chalk.gray(` ${equiv.emoji} ${equiv.count}${equiv.unit || defaultUnit}`)
123
+ : '';
124
+ console.log(` ${timeStr} ${modelStr} ${tokenInfo}`);
125
+ console.log(` ${emoji} ${costDelta} → ${t('display.cumulative')} ${totalStr}${equivStr}`);
126
+ console.log(chalk.italic.gray(` "${message}"`));
127
+ if (config?.showNudge && cost > 0.01) {
128
+ const nudge = getSavingsNudge(usage, cost);
129
+ if (nudge && nudge.saving > 0.005) {
130
+ console.log(chalk.cyan(` ${t('display.nudge', { model: nudge.model, cost: fc(nudge.cost, exchange), saving: fc(nudge.saving, exchange) })}`));
131
+ }
132
+ }
133
+ console.log();
134
+ }
135
+ export function showBudgetAlert(budgetStatus, exchange) {
136
+ const { status } = budgetStatus;
137
+ if (status === 'exceeded') {
138
+ console.log(chalk.bgRed.white.bold(` ${t('display.budgetExceededBanner')} `));
139
+ console.log();
140
+ }
141
+ else if (status === 'danger') {
142
+ console.log(chalk.red(` ${t('display.budget90Alert', { remaining: fc(budgetStatus.remaining, exchange) })}`));
143
+ console.log();
144
+ }
145
+ }
146
+ export function showTopExpensive(topRequests, exchange) {
147
+ if (!topRequests || topRequests.length === 0)
148
+ return;
149
+ console.log();
150
+ console.log(` 🏆 ${chalk.bold(t('display.topExpensive'))}`);
151
+ console.log();
152
+ topRequests.forEach((req, i) => {
153
+ const medal = ['🥇', '🥈', '🥉'][i];
154
+ const pEmoji = req.providerEmoji ? `${req.providerEmoji} ` : '';
155
+ const modelColor = req.provider === 'cursor' ? chalk.hex('#06b6d4')
156
+ : /opus/i.test(req.model) ? chalk.magenta
157
+ : /haiku/i.test(req.model) ? chalk.green
158
+ : /gpt/i.test(req.model) ? chalk.hex('#74aa9c')
159
+ : /gemini/i.test(req.model) ? chalk.hex('#4285f4')
160
+ : chalk.blue;
161
+ const timeStr = req.time || '';
162
+ console.log(` ${medal} ${chalk.bold.yellow(fc(req.cost, exchange))} ${pEmoji}${modelColor(req.model)} ${chalk.gray(timeStr)}`);
163
+ if (req.prompt) {
164
+ console.log(chalk.white(` 💬 "${req.prompt}"`));
165
+ }
166
+ console.log(chalk.gray(` 📥 ${formatTokenCount(req.inputTokens)} 📤 ${formatTokenCount(req.outputTokens)}`));
167
+ });
168
+ }
169
+ export function showShutdown(sessionCost, totalCost, savingsTotal, topRequests, config, exchange, costByProvider) {
170
+ console.log();
171
+ console.log(DIVIDER);
172
+ const equiv = toEquivalent(sessionCost, config);
173
+ const defaultUnit = t('display.defaultUnit');
174
+ const equivText = equiv
175
+ ? ` (${equiv.emoji} ${equiv.name} ${equiv.count}${equiv.unit || defaultUnit})`
176
+ : '';
177
+ console.log(` ${t('display.sessionCost')} ${chalk.bold.yellow(fc(sessionCost, exchange))}${equivText}`);
178
+ console.log(` ${t('display.todayCost')} ${chalk.bold.yellow(fc(totalCost, exchange))}`);
179
+ if (costByProvider && Object.keys(costByProvider).length > 1) {
180
+ const breakdown = Object.entries(costByProvider)
181
+ .sort((a, b) => b[1] - a[1])
182
+ .map(([p, c]) => `${getProviderEmoji(p)} ${getProviderDisplayName(p)} ${fc(c, exchange)}`)
183
+ .join(' ');
184
+ console.log(chalk.gray(` ${breakdown}`));
185
+ }
186
+ if (savingsTotal > 0.01) {
187
+ console.log(chalk.cyan(` ${t('display.potentialSavings', { amount: fc(savingsTotal, exchange) })}`));
188
+ }
189
+ showTopExpensive(topRequests, exchange);
190
+ console.log();
191
+ console.log(chalk.gray(` ${t('display.goodbye')}`));
192
+ console.log(DIVIDER);
193
+ console.log();
194
+ }
195
+ export function showError(message) {
196
+ console.error(chalk.red(` ❌ ${message}`));
197
+ }
198
+ export function showInfo(message) {
199
+ console.log(chalk.gray(` ℹ️ ${message}`));
200
+ }
201
+ export function showConfigUpdate(key, value) {
202
+ console.log(chalk.green(` ✅ ${key} = ${value}`));
203
+ }
204
+ //# sourceMappingURL=display.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display.js","sourceRoot":"","sources":["../src/display.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { Config, ExchangeInfo } from './types.js';
2
+ export declare function getExchangeRate(config: Config): Promise<ExchangeInfo>;
3
+ export declare function formatLocalCost(usdCost: number, exchangeInfo: ExchangeInfo): string;
4
+ export declare function getCurrencySymbol(currency: string): string;
5
+ export declare const SUPPORTED_CURRENCIES: string[];
@@ -0,0 +1,104 @@
1
+ import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ import { t, getLocale } from './i18n.js';
5
+ const CACHE_DIR = join(homedir(), '.claude-cost-cry');
6
+ const CACHE_PATH = join(CACHE_DIR, 'exchange-cache.json');
7
+ const API_URL = 'https://api.frankfurter.app/latest?from=USD';
8
+ const CACHE_TTL_MS = 24 * 60 * 60 * 1000;
9
+ const CURRENCY_SYMBOLS = {
10
+ USD: '$', KRW: '₩', JPY: '¥', EUR: '€', GBP: '£', CNY: '¥',
11
+ };
12
+ function loadCache() {
13
+ try {
14
+ return JSON.parse(readFileSync(CACHE_PATH, 'utf-8'));
15
+ }
16
+ catch {
17
+ return null;
18
+ }
19
+ }
20
+ function saveCache(data) {
21
+ mkdirSync(CACHE_DIR, { recursive: true });
22
+ writeFileSync(CACHE_PATH, JSON.stringify(data, null, 2) + '\n', 'utf-8');
23
+ }
24
+ async function fetchRates() {
25
+ try {
26
+ const res = await fetch(API_URL);
27
+ if (!res.ok)
28
+ return null;
29
+ const data = await res.json();
30
+ return data.rates || null;
31
+ }
32
+ catch {
33
+ return null;
34
+ }
35
+ }
36
+ function dateLocale() {
37
+ return getLocale() === 'ko' ? 'ko-KR' : 'en-US';
38
+ }
39
+ export async function getExchangeRate(config) {
40
+ const currency = config?.currency || 'USD';
41
+ if (currency === 'USD')
42
+ return { rate: 1, symbol: '$', currency: 'USD', source: 'base' };
43
+ if (config?.exchangeRate) {
44
+ return {
45
+ rate: config.exchangeRate,
46
+ symbol: CURRENCY_SYMBOLS[currency] || currency,
47
+ currency,
48
+ source: 'manual',
49
+ };
50
+ }
51
+ const cache = loadCache();
52
+ const now = Date.now();
53
+ if (cache?.rates?.[currency] && cache.timestamp && (now - cache.timestamp < CACHE_TTL_MS)) {
54
+ return {
55
+ rate: cache.rates[currency],
56
+ symbol: CURRENCY_SYMBOLS[currency] || currency,
57
+ currency,
58
+ source: 'cache',
59
+ updatedAt: new Date(cache.timestamp).toLocaleDateString(dateLocale()),
60
+ };
61
+ }
62
+ const rates = await fetchRates();
63
+ if (rates && rates[currency]) {
64
+ const cacheData = { rates, timestamp: now };
65
+ saveCache(cacheData);
66
+ return {
67
+ rate: rates[currency],
68
+ symbol: CURRENCY_SYMBOLS[currency] || currency,
69
+ currency,
70
+ source: 'api',
71
+ updatedAt: new Date(now).toLocaleDateString(dateLocale()),
72
+ };
73
+ }
74
+ if (cache?.rates?.[currency]) {
75
+ return {
76
+ rate: cache.rates[currency],
77
+ symbol: CURRENCY_SYMBOLS[currency] || currency,
78
+ currency,
79
+ source: 'stale-cache',
80
+ updatedAt: cache.timestamp ? new Date(cache.timestamp).toLocaleDateString(dateLocale()) : t('exchange.unknown'),
81
+ };
82
+ }
83
+ return { rate: 1, symbol: '$', currency: 'USD', source: 'fallback' };
84
+ }
85
+ export function formatLocalCost(usdCost, exchangeInfo) {
86
+ if (!exchangeInfo || exchangeInfo.currency === 'USD') {
87
+ if (usdCost < 0.01)
88
+ return `$${usdCost.toFixed(4)}`;
89
+ if (usdCost < 1)
90
+ return `$${usdCost.toFixed(3)}`;
91
+ return `$${usdCost.toFixed(2)}`;
92
+ }
93
+ const local = usdCost * exchangeInfo.rate;
94
+ const sym = exchangeInfo.symbol;
95
+ if (exchangeInfo.currency === 'KRW' || exchangeInfo.currency === 'JPY') {
96
+ return `${sym}${Math.round(local).toLocaleString()}`;
97
+ }
98
+ return `${sym}${local.toFixed(2)}`;
99
+ }
100
+ export function getCurrencySymbol(currency) {
101
+ return CURRENCY_SYMBOLS[currency] || currency;
102
+ }
103
+ export const SUPPORTED_CURRENCIES = Object.keys(CURRENCY_SYMBOLS);
104
+ //# sourceMappingURL=exchange.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exchange.js","sourceRoot":"","sources":["../src/exchange.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { DailyData, DailyStats } from './types.js';
2
+ export declare function aggregateByDate(daysBack?: number): Promise<DailyData[]>;
3
+ export declare function computeStats(dailyData: DailyData[]): DailyStats;