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.
- package/LICENSE +21 -0
- package/README.ko.md +173 -0
- package/README.md +174 -0
- package/bin/cli.js +333 -0
- package/dist/calculator.d.ts +8 -0
- package/dist/calculator.js +74 -0
- package/dist/calculator.js.map +1 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.js +49 -0
- package/dist/config.js.map +1 -0
- package/dist/display.d.ts +11 -0
- package/dist/display.js +204 -0
- package/dist/display.js.map +1 -0
- package/dist/exchange.d.ts +5 -0
- package/dist/exchange.js +104 -0
- package/dist/exchange.js.map +1 -0
- package/dist/history.d.ts +3 -0
- package/dist/history.js +176 -0
- package/dist/history.js.map +1 -0
- package/dist/i18n.d.ts +9 -0
- package/dist/i18n.js +34 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +112 -0
- package/dist/index.js.map +1 -0
- package/dist/locales/en.d.ts +191 -0
- package/dist/locales/en.js +204 -0
- package/dist/locales/en.js.map +1 -0
- package/dist/locales/ko.d.ts +191 -0
- package/dist/locales/ko.js +204 -0
- package/dist/locales/ko.js.map +1 -0
- package/dist/messages.d.ts +9 -0
- package/dist/messages.js +73 -0
- package/dist/messages.js.map +1 -0
- package/dist/parser.d.ts +2 -0
- package/dist/parser.js +21 -0
- package/dist/parser.js.map +1 -0
- package/dist/pricing.d.ts +6 -0
- package/dist/pricing.js +49 -0
- package/dist/pricing.js.map +1 -0
- package/dist/providers/claude.d.ts +3 -0
- package/dist/providers/claude.js +79 -0
- package/dist/providers/claude.js.map +1 -0
- package/dist/providers/cursor.d.ts +9 -0
- package/dist/providers/cursor.js +217 -0
- package/dist/providers/cursor.js.map +1 -0
- package/dist/providers/google.d.ts +3 -0
- package/dist/providers/google.js +72 -0
- package/dist/providers/google.js.map +1 -0
- package/dist/providers/index.d.ts +9 -0
- package/dist/providers/index.js +41 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/openai.d.ts +3 -0
- package/dist/providers/openai.js +90 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/report.d.ts +36 -0
- package/dist/report.js +203 -0
- package/dist/report.js.map +1 -0
- package/dist/types.d.ts +137 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/watcher.d.ts +12 -0
- package/dist/watcher.js +222 -0
- package/dist/watcher.js.map +1 -0
- package/electron/main.js +405 -0
- package/electron/overlay.html +1390 -0
- package/electron/package.json +1 -0
- package/electron/preload.js +15 -0
- package/package.json +65 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Shimsuyeon
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.ko.md
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# ๐ช claude-cost-cry
|
|
2
|
+
|
|
3
|
+
> ๋น์ ์ API ๋น์ฉ์ ๊ฐ์ ์ ์ผ๋ก ์ฒด๊ฐ์์ผ์ฃผ๋ ๋๊ตฌ
|
|
4
|
+
|
|
5
|
+
์ซ์๋ก ๋ณด๋ฉด ๋ฌด๊ฐ๊ฐํ API ๋น์ฉ์, **์์ด์ค ์๋ฉ๋ฆฌ์นด๋
ธ์ ์นํจ์ผ๋ก ํ์ฐํ๋ฉด ์ํ๋ค.**
|
|
6
|
+
|
|
7
|
+
[English](README.md)
|
|
8
|
+
|
|
9
|
+
## ๋ญํ๋ ๋๊ตฌ์ธ๊ฐ์?
|
|
10
|
+
|
|
11
|
+
Claude Code(๋ฐ ๊ธฐํ LLM ํ๋ก๋ฐ์ด๋) ์ฌ์ฉ ์ ์ค์๊ฐ์ผ๋ก ๋น์ฉ์ ์ถ์ ํ๋ฉด์, ๋์ด ๋ ์๊ฐ๋ ์๊ฐ์ ๊ฐ์ ๋ฉ์์ง, ์ผ์ ํ์ฐ, ํ๋กํ
์์ ฏ์ผ๋ก ์ฒด๊ฐ์์ผ์ค๋๋ค.
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
$ cost-cry
|
|
15
|
+
|
|
16
|
+
๐ช claude-cost-cry v0.3.0
|
|
17
|
+
๋น์ ์ API ๋น์ฉ์ ๊ฐ์ ์ ์ผ๋ก ์ฒด๊ฐ์์ผ๋๋ฆฝ๋๋ค
|
|
18
|
+
|
|
19
|
+
๐ ์ค๋ ๋์ : $2.41 (โ ์์ด์ค ์๋ฉ๋ฆฌ์นด๋
ธ 0.5์)
|
|
20
|
+
API ํธ์ถ 12๊ฑด
|
|
21
|
+
๐ค๏ธ ์กฐ๊ธ์ฉ ์ฐ๊ณ ์๋ค์...
|
|
22
|
+
|
|
23
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
24
|
+
๊ฐ์ ์ค... (Ctrl+C๋ก ์ข
๋ฃ)
|
|
25
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
26
|
+
|
|
27
|
+
[14:32:15] Opus ๐ฅ 15.2K ๐ค 1.2K
|
|
28
|
+
๐ฅ +$0.38 โ ๋์ : $8.73 ๐ 0.5๋ง๋ฆฌ
|
|
29
|
+
"์ด ๋์ด๋ฉด ๊ณ ๊ธ ๋ทํ๋ฅผ ๊ฐ ์ ์์๋๋ฐ..."
|
|
30
|
+
|
|
31
|
+
[14:35:22] Sonnet ๐ฅ 8.3K ๐ค 2.1K
|
|
32
|
+
๐ธ +$0.06 โ ๋์ : $8.79 ๐ 0.5๋ง๋ฆฌ
|
|
33
|
+
"์ง๊ฐ์ด ์ธ๊ณ ์์ด์ ์ง์ง๋ก"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## ๋น์ฉ ๊ตฌ๊ฐ๋ณ ๊ฐ์ ์ดํํธ
|
|
37
|
+
|
|
38
|
+
| ๋น์ฉ ๊ตฌ๊ฐ | ์ด๋ชจ์ง | ๊ธฐ๋ถ | ๋ฉ์์ง ์์ |
|
|
39
|
+
|-----------|-------|------|------------|
|
|
40
|
+
| $0 ~ $1 | ๐ช | ํํ | "์์ง ๊ด์ฐฎ์์, ์ด ์ ๋๋ ๊ณต๊ธฐ๊ฐ์ด์ฃ " |
|
|
41
|
+
| $1 ~ $5 | ๐ธ | ๋ถ์ | "์ฌ์ฌ ์ํ๊ธฐ ์ปคํผ๊ฐ์ด ๋์ด๊ฐ๋ค์..." |
|
|
42
|
+
| $5 ~ $10 | ๐ฅ | ๊ฑฑ์ | "์ด๊ฑฐ ์ง์ง ๊ด์ฐฎ์ ๊ฑด๊ฐ์...?" |
|
|
43
|
+
| $10 ~ $30 | ๐จ | ๊ฒฝ๊ณ | "ํด๋ก๋ํํ
์๊ธ์ ์ฃผ๋ ๊ฑด๊ฐ..." |
|
|
44
|
+
| $30 ~ $100 | ๐ | ๊ณตํฌ | "์ํ ์๊ณ ๊ฐ ๋น๋ช
์ ์ง๋ฅด๊ณ ์์ต๋๋ค" |
|
|
45
|
+
| $100+ | โฐ๏ธ | ์ฅ๋ก์ | "๐จ ๊ฒฝ๊ณ : ์ด API ํค๋ ๋ถ์ ํ๊ณ ์์ต๋๋ค ๐จ" |
|
|
46
|
+
|
|
47
|
+
## ์ค์น
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm install -g claude-cost-cry
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## ์ฌ์ฉ๋ฒ
|
|
54
|
+
|
|
55
|
+
### ์ค๋ฒ๋ ์ด ๋ชจ๋ (ํ๋กํ
์์ ฏ) โ ๊ธฐ๋ณธ
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
cost-cry
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
ํ๋ฉด ์ค๋ฅธ์ชฝ ์์ ๋ ์๋ ์์ ฏ์ผ๋ก ์ค์๊ฐ ๋น์ฉ์ ํ์ธํฉ๋๋ค:
|
|
62
|
+
- ๋น์ฉ ๊ตฌ๊ฐ์ ๋ฐ๋ผ ์ด๋ชจ์ง์ ๊ธ์ ์์์ด ๋ณํฉ๋๋ค
|
|
63
|
+
- ์ API ํธ์ถ ์ ๋ฐ์ด์ค ์ ๋๋ฉ์ด์
+ ๋น์ฉ ํ๋์
|
|
64
|
+
- $30 ์ด์์ด๋ฉด ์์ ฏ์ด ํ๋ค๋ฆฝ๋๋ค
|
|
65
|
+
- ์์คํ
ํธ๋ ์ด์์ ์์ ฏ ์ด๊ธฐ/๋ซ๊ธฐ ๊ฐ๋ฅ
|
|
66
|
+
- ๋๋๊ทธ๋ก ์์น ์ด๋ ๊ฐ๋ฅ
|
|
67
|
+
- ํ์ฅ ํจ๋: ์ผ๋ณ ์ฐจํธ, ๋ชจ๋ธ๋ณ ๋น์ฉ, TOP 3 ๋น์ผ ์์ฒญ, ์ค์
|
|
68
|
+
|
|
69
|
+
> macOS์์ ์ฒ์ ์คํ ์ `xattr -cr node_modules/electron/dist/Electron.app` ์คํ์ด ํ์ํ ์ ์์ต๋๋ค.
|
|
70
|
+
|
|
71
|
+
### CLI ๋ชจ๋ (ํฐ๋ฏธ๋)
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
cost-cry cli
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
ํฐ๋ฏธ๋์์ ์ค์๊ฐ ์ถ์ :
|
|
78
|
+
1. ์ค๋์ ๋์ ๋น์ฉ์ ์ค์บํ์ฌ ๋ณด์ฌ์ค๋๋ค
|
|
79
|
+
2. Claude Code ์ฌ์ฉ์ ์ค์๊ฐ์ผ๋ก ๊ฐ์ํฉ๋๋ค
|
|
80
|
+
3. API ํธ์ถ์ด ๊ฐ์ง๋ ๋๋ง๋ค ๋น์ฉ๊ณผ ๊ฐ์ ๋ฉ์์ง๋ฅผ ํ์ํฉ๋๋ค
|
|
81
|
+
4. `Ctrl+C`๋ก ์ข
๋ฃํ๋ฉด ์ธ์
์์ฝ์ ๋ณด์ฌ์ค๋๋ค
|
|
82
|
+
|
|
83
|
+
### ๋ฆฌํฌํธ
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
cost-cry report # ์ฃผ๊ฐ ๋ฆฌํฌํธ
|
|
87
|
+
cost-cry report --monthly # ์๊ฐ ๋ฆฌํฌํธ
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
์ผ๋ณ ๋น์ฉ ASCII ์ฐจํธ, ๋ชจ๋ธ๋ณ ๋น์ฉ ๋ถ์, ์ ์ฝ ์๋ฎฌ๋ ์ด์
์ ์ ๊ณตํฉ๋๋ค.
|
|
91
|
+
|
|
92
|
+
### ์ค์
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
cost-cry config # ํ์ฌ ์ค์ ๋ณด๊ธฐ
|
|
96
|
+
cost-cry config --daily-budget 10 # ์ผ์ผ ์์ฐ $10 ์ค์
|
|
97
|
+
cost-cry config --daily-budget off # ์์ฐ ํด์
|
|
98
|
+
cost-cry config --currency KRW # ํ์ ํตํ ๋ณ๊ฒฝ
|
|
99
|
+
cost-cry config --nudge off # ์ ์ฝ ๋์ง ๋๊ธฐ
|
|
100
|
+
cost-cry config --language en # ์์ด๋ก ์ ํ
|
|
101
|
+
cost-cry config --add-source cursor # Cursor IDE ์ถ์
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
#### ์์ฐ ์๋ฆผ
|
|
105
|
+
|
|
106
|
+
์์ฐ์ ์ค์ ํ๋ฉด:
|
|
107
|
+
- 70% ๋๋ฌ ์ ๐ก ๊ฒฝ๊ณ , 90% ์ โ ๏ธ ๊ฒฝ๊ณ , 100% ์ด๊ณผ ์ ๐ซ ๊ฒฝ๊ณ
|
|
108
|
+
- CLI์ ์ค๋ฒ๋ ์ด ์์ ฏ ๋ชจ๋์์ ํ์๋ฉ๋๋ค
|
|
109
|
+
|
|
110
|
+
#### ์ ์ฝ ๋์ง
|
|
111
|
+
|
|
112
|
+
API ํธ์ถ ์ ๋ ์ ๋ ดํ ๋ชจ๋ธ์ ์ผ์ผ๋ฉด ์ผ๋ง๋ฅผ ์๋ ์ ์์๋์ง ์ค์๊ฐ์ผ๋ก ๋ณด์ฌ์ค๋๋ค:
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
[14:32:15] Opus ๐ฅ 15.2K ๐ค 1.2K
|
|
116
|
+
๐ฅ +$0.38 โ ๋์ : $8.73
|
|
117
|
+
๐ก Haiku๋ก ํ์ผ๋ฉด $0.02 ($0.36 ์ ์ฝ)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
#### ๋ฉํฐ ํ๋ก๋ฐ์ด๋ ์ง์
|
|
121
|
+
|
|
122
|
+
์ฌ๋ฌ LLM ํ๋ก๋ฐ์ด๋์ ๋น์ฉ์ ํจ๊ป ์ถ์ ํฉ๋๋ค:
|
|
123
|
+
- ๐ฃ **Claude Code** โ ์๋ (๋ก์ปฌ JSONL ๋ก๊ทธ)
|
|
124
|
+
- โก **Cursor IDE** โ API ํด๋ง (`cost-cry config --add-source cursor`)
|
|
125
|
+
- ๐ข **OpenAI** โ ๋ก์ปฌ ๋ก๊ทธ (`cost-cry config --add-source openai:/path/to/logs`)
|
|
126
|
+
- ๐ต **Google Gemini** โ ๋ก์ปฌ ๋ก๊ทธ (`cost-cry config --add-source google:/path/to/logs`)
|
|
127
|
+
|
|
128
|
+
#### ์ธ์ด
|
|
129
|
+
|
|
130
|
+
๊ธฐ๋ณธ ์ธ์ด๋ **์์ด**์
๋๋ค. ํ๊ตญ์ด๋ก ์ ํ:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
cost-cry config --language ko
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
์ค๋ฒ๋ ์ด ์ค์ ํจ๋์์๋ ๋ณ๊ฒฝ ๊ฐ๋ฅํฉ๋๋ค.
|
|
137
|
+
|
|
138
|
+
## ์๋ ์๋ฆฌ
|
|
139
|
+
|
|
140
|
+
Claude Code๋ ๋ชจ๋ API ํธ์ถ ๋ก๊ทธ๋ฅผ `~/.claude/projects/` ์๋์ JSONL ํ์ผ๋ก ์ ์ฅํฉ๋๋ค. cost-cry๋ ์ด ๋ก๊ทธ ํ์ผ์ ์ค์๊ฐ์ผ๋ก ๊ฐ์ํ๋ฉฐ:
|
|
141
|
+
|
|
142
|
+
1. ์๋ก์ด assistant ์๋ต์ `usage` ํ๋์์ ํ ํฐ ์ฌ์ฉ๋์ ์ถ์ถ
|
|
143
|
+
2. ๋ชจ๋ธ๋ณ ๊ณต์ ๊ฐ๊ฒฉํ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋น์ฉ์ ๊ณ์ฐ
|
|
144
|
+
3. ๋น์ฉ ๊ตฌ๊ฐ์ ๋ง๋ ๊ฐ์ ๋ฉ์์ง๋ฅผ ํ์
|
|
145
|
+
|
|
146
|
+
**ํ๋ก์๋ API ํค๊ฐ ํ์ ์์ต๋๋ค.** ๋ก์ปฌ ๋ก๊ทธ ํ์ผ๋ง ์ฝ์ต๋๋ค (๋๋ Cursor ๋ด๋ถ API ํด๋ง).
|
|
147
|
+
|
|
148
|
+
## ์ง์ ๋ชจ๋ธ & ๊ฐ๊ฒฉ
|
|
149
|
+
|
|
150
|
+
| ๋ชจ๋ธ | ์
๋ ฅ ($/1M) | ์ถ๋ ฅ ($/1M) |
|
|
151
|
+
|------|-----------|-----------|
|
|
152
|
+
| Claude Opus | $15.00 | $75.00 |
|
|
153
|
+
| Claude Sonnet | $3.00 | $15.00 |
|
|
154
|
+
| Claude Haiku | $0.80 | $4.00 |
|
|
155
|
+
| GPT-4o | $2.50 | $10.00 |
|
|
156
|
+
| GPT-4o mini | $0.15 | $0.60 |
|
|
157
|
+
| Gemini 2.5 Pro | $1.25 | $10.00 |
|
|
158
|
+
| Gemini Flash | $0.075 | $0.30 |
|
|
159
|
+
|
|
160
|
+
์บ์ ํ ํฐ๋ ์๋ ๋ฐ์๋ฉ๋๋ค (์ฐ๊ธฐ: 1.25x, ์ฝ๊ธฐ: 0.1x).
|
|
161
|
+
|
|
162
|
+
## ์๊ตฌ ์ฌํญ
|
|
163
|
+
|
|
164
|
+
- Node.js >= 18
|
|
165
|
+
- Claude Code ์ค์น (`~/.claude/` ๋๋ ํ ๋ฆฌ) ๋๋ ๊ธฐํ ์ง์ ํ๋ก๋ฐ์ด๋
|
|
166
|
+
|
|
167
|
+
## ๋ฉด์ฑ
์กฐํญ
|
|
168
|
+
|
|
169
|
+
์ด ๋๊ตฌ์ ๋น์ฉ ๊ณ์ฐ์ **์ฐธ๊ณ ์ฉ**์
๋๋ค. ์ ํํ ๊ณผ๊ธ ๊ธ์ก์ [Anthropic ๋์๋ณด๋](https://console.anthropic.com/)์์ ํ์ธํ์ธ์.
|
|
170
|
+
|
|
171
|
+
## ๋ผ์ด์ ์ค
|
|
172
|
+
|
|
173
|
+
MIT
|
package/README.md
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# ๐ช claude-cost-cry
|
|
2
|
+
|
|
3
|
+
> Emotionally experience your API costs
|
|
4
|
+
|
|
5
|
+
Numbers feel numb. But **when your API bill becomes iced americanos and fried chicken, it hurts.**
|
|
6
|
+
|
|
7
|
+
[ํ๊ตญ์ด](README.ko.md)
|
|
8
|
+
|
|
9
|
+
## What is this?
|
|
10
|
+
|
|
11
|
+
A real-time cost tracker for Claude Code (and other LLM providers) that makes you *feel* every dollar leaving your wallet โ with emotional messages, everyday equivalents, and a floating desktop widget.
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
$ cost-cry
|
|
15
|
+
|
|
16
|
+
๐ช claude-cost-cry v0.3.0
|
|
17
|
+
Emotionally experience your API costs
|
|
18
|
+
|
|
19
|
+
๐ Today's total: $2.41 (โ Iced Americano 0.5)
|
|
20
|
+
12 API calls
|
|
21
|
+
๐ค๏ธ Starting to spend a bit...
|
|
22
|
+
|
|
23
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
24
|
+
Watching... (Ctrl+C to exit)
|
|
25
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
26
|
+
|
|
27
|
+
[14:32:15] Opus ๐ฅ 15.2K ๐ค 1.2K
|
|
28
|
+
๐ฅ +$0.38 โ Total: $8.73 ๐ 0.5
|
|
29
|
+
"Could've gone to a fancy buffet with this money..."
|
|
30
|
+
|
|
31
|
+
[14:35:22] Sonnet ๐ฅ 8.3K ๐ค 2.1K
|
|
32
|
+
๐ธ +$0.06 โ Total: $8.79 ๐ 0.5
|
|
33
|
+
"Your wallet is literally crying"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Emotional Cost Tiers
|
|
37
|
+
|
|
38
|
+
| Cost Range | Emoji | Mood | Example Message |
|
|
39
|
+
|-----------|-------|------|-----------------|
|
|
40
|
+
| $0 โ $1 | ๐ช | Peace | "No worries, this is practically free" |
|
|
41
|
+
| $1 โ $5 | ๐ธ | Uneasy | "Starting to cost as much as vending machine coffee..." |
|
|
42
|
+
| $5 โ $10 | ๐ฅ | Worry | "Is this really okay...?" |
|
|
43
|
+
| $10 โ $30 | ๐จ | Alert | "Am I paying Claude a salary...?" |
|
|
44
|
+
| $30 โ $100 | ๐ | Danger | "The bank account is screaming" |
|
|
45
|
+
| $100+ | โฐ๏ธ | Funeral | "๐จ WARNING: This API key is on fire ๐จ" |
|
|
46
|
+
|
|
47
|
+
## Installation
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm install -g claude-cost-cry
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Usage
|
|
54
|
+
|
|
55
|
+
### Overlay Mode (Floating Widget) โ Default
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
cost-cry
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Launches a floating desktop widget (top-right corner) that tracks costs in real time:
|
|
62
|
+
- Emoji and color change based on cost tier
|
|
63
|
+
- Bounce animation + cost flash on new API calls
|
|
64
|
+
- Widget shakes when cost exceeds $30
|
|
65
|
+
- Toggle from system tray
|
|
66
|
+
- Drag to reposition
|
|
67
|
+
- Expandable panels: daily chart, model breakdown, top 3 expensive requests, settings
|
|
68
|
+
|
|
69
|
+
> On macOS, you may need to run `xattr -cr node_modules/electron/dist/Electron.app` on first launch.
|
|
70
|
+
|
|
71
|
+
### CLI Mode (Terminal)
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
cost-cry cli
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Real-time tracking in your terminal:
|
|
78
|
+
1. Scans today's accumulated cost
|
|
79
|
+
2. Watches for new Claude Code API calls in real time
|
|
80
|
+
3. Displays cost + emotional message on each call
|
|
81
|
+
4. Shows session summary on `Ctrl+C` exit
|
|
82
|
+
|
|
83
|
+
### Reports
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
cost-cry report # Weekly report
|
|
87
|
+
cost-cry report --monthly # Monthly report
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
ASCII bar charts with per-day costs, model breakdown, and savings simulation.
|
|
91
|
+
|
|
92
|
+
### Configuration
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
cost-cry config # View current settings
|
|
96
|
+
cost-cry config --daily-budget 10 # Set daily budget ($10)
|
|
97
|
+
cost-cry config --daily-budget off # Remove budget
|
|
98
|
+
cost-cry config --currency KRW # Switch display currency
|
|
99
|
+
cost-cry config --nudge off # Disable savings nudge
|
|
100
|
+
cost-cry config --language ko # Switch to Korean
|
|
101
|
+
cost-cry config --add-source cursor # Track Cursor IDE usage
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
#### Budget Alerts
|
|
105
|
+
|
|
106
|
+
When a budget is set:
|
|
107
|
+
- 70% โ ๐ก warning, 90% โ โ ๏ธ warning, 100% โ ๐ซ exceeded
|
|
108
|
+
- Displayed in both CLI and overlay widget
|
|
109
|
+
|
|
110
|
+
#### Savings Nudge
|
|
111
|
+
|
|
112
|
+
Shows how much you could save using a cheaper model โ in real time:
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
[14:32:15] Opus ๐ฅ 15.2K ๐ค 1.2K
|
|
116
|
+
๐ฅ +$0.38 โ Total: $8.73
|
|
117
|
+
๐ก Would be $0.02 with Haiku (save $0.36)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
#### Multi-Provider Support
|
|
121
|
+
|
|
122
|
+
Track costs across multiple LLM providers:
|
|
123
|
+
- ๐ฃ **Claude Code** โ automatic (local JSONL logs)
|
|
124
|
+
- โก **Cursor IDE** โ API polling (`cost-cry config --add-source cursor`)
|
|
125
|
+
- ๐ข **OpenAI** โ local logs (`cost-cry config --add-source openai:/path/to/logs`)
|
|
126
|
+
- ๐ต **Google Gemini** โ local logs (`cost-cry config --add-source google:/path/to/logs`)
|
|
127
|
+
|
|
128
|
+
#### Language
|
|
129
|
+
|
|
130
|
+
Default language is **English**. Switch to Korean:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
cost-cry config --language ko
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Also available in the overlay settings panel.
|
|
137
|
+
|
|
138
|
+
## How It Works
|
|
139
|
+
|
|
140
|
+
Claude Code saves all API call logs as JSONL files under `~/.claude/projects/`. cost-cry watches these files in real time:
|
|
141
|
+
|
|
142
|
+
1. Extracts token usage from the `usage` field of assistant responses
|
|
143
|
+
2. Calculates cost based on official model pricing
|
|
144
|
+
3. Displays emotional messages based on cost tier
|
|
145
|
+
|
|
146
|
+
**No proxy or API key required.** Only reads local log files (or polls Cursor's internal API).
|
|
147
|
+
|
|
148
|
+
## Supported Models & Pricing
|
|
149
|
+
|
|
150
|
+
| Model | Input ($/1M) | Output ($/1M) |
|
|
151
|
+
|-------|-------------|---------------|
|
|
152
|
+
| Claude Opus | $15.00 | $75.00 |
|
|
153
|
+
| Claude Sonnet | $3.00 | $15.00 |
|
|
154
|
+
| Claude Haiku | $0.80 | $4.00 |
|
|
155
|
+
| GPT-4o | $2.50 | $10.00 |
|
|
156
|
+
| GPT-4o mini | $0.15 | $0.60 |
|
|
157
|
+
| Gemini 2.5 Pro | $1.25 | $10.00 |
|
|
158
|
+
| Gemini Flash | $0.075 | $0.30 |
|
|
159
|
+
|
|
160
|
+
Cache tokens are automatically reflected (write: 1.25x, read: 0.1x).
|
|
161
|
+
|
|
162
|
+
## Requirements
|
|
163
|
+
|
|
164
|
+
- Node.js >= 18
|
|
165
|
+
- Claude Code installed (`~/.claude/` directory) or another supported provider
|
|
166
|
+
|
|
167
|
+
## Disclaimer
|
|
168
|
+
|
|
169
|
+
Cost calculations are **estimates for reference**. For exact billing, check the [Anthropic Dashboard](https://console.anthropic.com/).
|
|
170
|
+
|
|
171
|
+
## License
|
|
172
|
+
|
|
173
|
+
MIT
|
|
174
|
+
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const args = process.argv.slice(2);
|
|
4
|
+
const command = args[0];
|
|
5
|
+
|
|
6
|
+
const { t, setLocale } = await import('../dist/i18n.js');
|
|
7
|
+
const { loadConfig: _lc } = await import('../dist/config.js');
|
|
8
|
+
const _initCfg = _lc();
|
|
9
|
+
if (_initCfg.language) setLocale(_initCfg.language);
|
|
10
|
+
|
|
11
|
+
if (command === 'config') {
|
|
12
|
+
const { updateConfig, loadConfig } = await import('../dist/config.js');
|
|
13
|
+
const { showConfigUpdate, showInfo } = await import('../dist/display.js');
|
|
14
|
+
|
|
15
|
+
const flags = args.slice(1);
|
|
16
|
+
|
|
17
|
+
const { getAllEquivalents } = await import('../dist/calculator.js');
|
|
18
|
+
|
|
19
|
+
if (flags.length === 0) {
|
|
20
|
+
const config = loadConfig();
|
|
21
|
+
const { getExchangeRate, SUPPORTED_CURRENCIES } = await import('../dist/exchange.js');
|
|
22
|
+
const allItems = getAllEquivalents(config);
|
|
23
|
+
const unitKey = config.equivalentUnit || 'auto';
|
|
24
|
+
const matchedUnit = unitKey === 'auto' ? null : allItems.find(i => i.key === unitKey || i.name === unitKey);
|
|
25
|
+
const unitDisplay = unitKey === 'auto'
|
|
26
|
+
? t('cli.autoUnit')
|
|
27
|
+
: matchedUnit ? `${matchedUnit.emoji} ${matchedUnit.name}` : unitKey;
|
|
28
|
+
const exchange = await getExchangeRate(config);
|
|
29
|
+
console.log();
|
|
30
|
+
showInfo(t('cli.currentConfig'));
|
|
31
|
+
console.log(` ${t('cli.dailyBudget')} ${config.dailyBudget ? `$${config.dailyBudget}` : t('cli.noLimit')}`);
|
|
32
|
+
console.log(` ${t('cli.monthlyBudget')} ${config.monthlyBudget ? `$${config.monthlyBudget}` : t('cli.noLimit')}`);
|
|
33
|
+
console.log(` ${t('cli.currency')} ${config.currency || 'USD'}`);
|
|
34
|
+
if (exchange && exchange.currency !== 'USD') {
|
|
35
|
+
const srcLabel = {
|
|
36
|
+
api: t('exchange.src.api'), cache: t('exchange.src.cache'),
|
|
37
|
+
'stale-cache': t('exchange.src.staleCache'), manual: t('exchange.src.manual'), base: ''
|
|
38
|
+
};
|
|
39
|
+
console.log(` ${t('cli.exchangeRate')} 1 USD = ${exchange.rate.toLocaleString()} ${exchange.currency} (${srcLabel[exchange.source] || ''} ${exchange.updatedAt || ''})`);
|
|
40
|
+
}
|
|
41
|
+
if (config.exchangeRate) {
|
|
42
|
+
console.log(` ${t('cli.exchangeFixed')} ${config.exchangeRate}`);
|
|
43
|
+
}
|
|
44
|
+
console.log(` ${t('cli.nudge')} ${config.showNudge ? t('cli.nudgeOn') : t('cli.nudgeOff')}`);
|
|
45
|
+
console.log(` ${t('cli.equivUnit')} ${unitDisplay}`);
|
|
46
|
+
if (config.customEquivalents?.length > 0) {
|
|
47
|
+
console.log(` ${t('cli.customUnits')} ${config.customEquivalents.map(e => `${e.emoji} ${e.name}`).join(', ')}`);
|
|
48
|
+
}
|
|
49
|
+
console.log(` ${t('cli.language')} ${config.language || 'en'}`);
|
|
50
|
+
console.log();
|
|
51
|
+
if (config.logSources?.length > 0) {
|
|
52
|
+
console.log(` ${t('cli.logSources')}`);
|
|
53
|
+
console.log(` ๐ฃ ${t('cli.claudeAuto')}`);
|
|
54
|
+
for (const src of config.logSources) {
|
|
55
|
+
const providerEmoji = { claude: '๐ฃ', openai: '๐ข', google: '๐ต', cursor: 'โก' }[src.provider] || 'โช';
|
|
56
|
+
if (src.path) {
|
|
57
|
+
console.log(` ${providerEmoji} ${src.provider}: ${src.path}`);
|
|
58
|
+
} else {
|
|
59
|
+
console.log(` ${providerEmoji} ${src.provider} ${t('cli.apiPolling')}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
console.log(` ${t('cli.logSources')} ๐ฃ ${t('cli.claudeAuto')}`);
|
|
64
|
+
}
|
|
65
|
+
console.log();
|
|
66
|
+
console.log(` ${t('cli.availableUnits')} ${allItems.map(e => e.name).join(', ')}`);
|
|
67
|
+
console.log(` ${t('cli.supportedCurrencies')} ${SUPPORTED_CURRENCIES.join(', ')}`);
|
|
68
|
+
console.log();
|
|
69
|
+
showInfo(t('cli.configHint'));
|
|
70
|
+
console.log();
|
|
71
|
+
process.exit(0);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
for (let i = 0; i < flags.length; ) {
|
|
75
|
+
const key = flags[i];
|
|
76
|
+
const value = flags[i + 1];
|
|
77
|
+
|
|
78
|
+
switch (key) {
|
|
79
|
+
case '--daily-budget':
|
|
80
|
+
case '-d':
|
|
81
|
+
updateConfig({ dailyBudget: value === 'off' ? null : parseFloat(value) });
|
|
82
|
+
showConfigUpdate(t('cli.dailyBudget'), value === 'off' ? t('cli.noLimit') : `$${value}`);
|
|
83
|
+
i += 2;
|
|
84
|
+
break;
|
|
85
|
+
case '--monthly-budget':
|
|
86
|
+
updateConfig({ monthlyBudget: value === 'off' ? null : parseFloat(value) });
|
|
87
|
+
showConfigUpdate(t('cli.monthlyBudget'), value === 'off' ? t('cli.noLimit') : `$${value}`);
|
|
88
|
+
i += 2;
|
|
89
|
+
break;
|
|
90
|
+
case '--nudge':
|
|
91
|
+
updateConfig({ showNudge: value !== 'off' });
|
|
92
|
+
showConfigUpdate(t('cli.nudge'), value === 'off' ? t('cli.nudgeOff') : t('cli.nudgeOn'));
|
|
93
|
+
i += 2;
|
|
94
|
+
break;
|
|
95
|
+
case '--unit': {
|
|
96
|
+
let unitVal = value;
|
|
97
|
+
if (value !== 'auto') {
|
|
98
|
+
const items = getAllEquivalents(loadConfig());
|
|
99
|
+
const match = items.find(i => i.key === value || i.name === value);
|
|
100
|
+
unitVal = match?.key || value;
|
|
101
|
+
}
|
|
102
|
+
updateConfig({ equivalentUnit: unitVal });
|
|
103
|
+
showConfigUpdate(t('cli.equivUnit'), value === 'auto' ? t('cli.autoUnit') : value);
|
|
104
|
+
i += 2;
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
case '--add-unit': {
|
|
108
|
+
const parts = value.split(':');
|
|
109
|
+
if ((parts.length !== 3 && parts.length !== 4) || isNaN(parseFloat(parts[1]))) {
|
|
110
|
+
console.error(` ${t('cli.unitFormatError')}`);
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
const defaultUnit = t('display.defaultUnit') || '';
|
|
114
|
+
const newItem = { name: parts[0], price: parseFloat(parts[1]), emoji: parts[2], unit: parts[3] || defaultUnit };
|
|
115
|
+
const cfg = loadConfig();
|
|
116
|
+
const customs = (cfg.customEquivalents || []).filter(e => e.name !== newItem.name);
|
|
117
|
+
customs.push(newItem);
|
|
118
|
+
updateConfig({ customEquivalents: customs });
|
|
119
|
+
showConfigUpdate(t('cli.customUnits'), `${newItem.emoji} ${newItem.name} ($${newItem.price})`);
|
|
120
|
+
i += 2;
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
case '--remove-unit': {
|
|
124
|
+
const cfg2 = loadConfig();
|
|
125
|
+
const filtered = (cfg2.customEquivalents || []).filter(e => e.name !== value);
|
|
126
|
+
updateConfig({ customEquivalents: filtered });
|
|
127
|
+
showConfigUpdate(t('cli.customUnits'), value);
|
|
128
|
+
i += 2;
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
case '--currency': {
|
|
132
|
+
const { SUPPORTED_CURRENCIES } = await import('../dist/exchange.js');
|
|
133
|
+
const cur = value.toUpperCase();
|
|
134
|
+
if (!SUPPORTED_CURRENCIES.includes(cur)) {
|
|
135
|
+
console.error(` ${t('cli.unknownCurrency', { currency: cur, supported: SUPPORTED_CURRENCIES.join(', ') })}`);
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
updateConfig({ currency: cur });
|
|
139
|
+
showConfigUpdate(t('cli.currency'), cur);
|
|
140
|
+
i += 2;
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
case '--exchange-rate': {
|
|
144
|
+
if (value === 'auto') {
|
|
145
|
+
updateConfig({ exchangeRate: null });
|
|
146
|
+
showConfigUpdate(t('cli.exchangeRate'), 'Auto (API)');
|
|
147
|
+
} else {
|
|
148
|
+
const rate = parseFloat(value);
|
|
149
|
+
if (isNaN(rate) || rate <= 0) {
|
|
150
|
+
console.error(` ${t('cli.invalidRate')}`);
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
updateConfig({ exchangeRate: rate });
|
|
154
|
+
showConfigUpdate(t('cli.exchangeFixed'), `${rate}`);
|
|
155
|
+
}
|
|
156
|
+
i += 2;
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
case '--add-source': {
|
|
160
|
+
const { getProviderNames, getProvider: gp } = await import('../dist/providers/index.js');
|
|
161
|
+
const colonIdx = value.indexOf(':');
|
|
162
|
+
|
|
163
|
+
if (colonIdx === -1) {
|
|
164
|
+
const provider = gp(value);
|
|
165
|
+
if (!provider) {
|
|
166
|
+
console.error(` ${t('cli.unknownProvider', { provider: value, supported: getProviderNames().join(', ') })}`);
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
169
|
+
if (provider.isApiProvider) {
|
|
170
|
+
if (!provider.isAvailable?.()) {
|
|
171
|
+
console.error(` ${t('cli.notInstalled', { provider: provider.displayName })}`);
|
|
172
|
+
process.exit(1);
|
|
173
|
+
}
|
|
174
|
+
if (!provider.getSessionToken?.()) {
|
|
175
|
+
console.error(` ${t('cli.noToken', { provider: provider.displayName })}`);
|
|
176
|
+
process.exit(1);
|
|
177
|
+
}
|
|
178
|
+
const cfg3 = loadConfig();
|
|
179
|
+
const sources = (cfg3.logSources || []).filter(s => s.provider !== value);
|
|
180
|
+
sources.push({ provider: value });
|
|
181
|
+
updateConfig({ logSources: sources });
|
|
182
|
+
showConfigUpdate(t('cli.logSources'), `${provider.emoji} ${provider.displayName} ${t('cli.apiPolling')}`);
|
|
183
|
+
} else {
|
|
184
|
+
console.error(` ${t('cli.sourceFormatError')}`);
|
|
185
|
+
console.error(` ${t('cli.apiSourceHint')}`);
|
|
186
|
+
console.error(` ${t('cli.providerHint', { providers: getProviderNames().join(', ') })}`);
|
|
187
|
+
process.exit(1);
|
|
188
|
+
}
|
|
189
|
+
i += 2;
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const srcProvider = value.slice(0, colonIdx);
|
|
194
|
+
const srcPath = value.slice(colonIdx + 1);
|
|
195
|
+
if (!getProviderNames().includes(srcProvider)) {
|
|
196
|
+
console.error(` ${t('cli.unknownProvider', { provider: srcProvider, supported: getProviderNames().join(', ') })}`);
|
|
197
|
+
process.exit(1);
|
|
198
|
+
}
|
|
199
|
+
const cfg3 = loadConfig();
|
|
200
|
+
const sources = (cfg3.logSources || []).filter(s => !(s.provider === srcProvider && s.path === srcPath));
|
|
201
|
+
sources.push({ provider: srcProvider, path: srcPath });
|
|
202
|
+
updateConfig({ logSources: sources });
|
|
203
|
+
showConfigUpdate(t('cli.logSources'), `${srcProvider}:${srcPath}`);
|
|
204
|
+
i += 2;
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
case '--remove-source': {
|
|
208
|
+
const cfg4 = loadConfig();
|
|
209
|
+
const colonIdx2 = value.indexOf(':');
|
|
210
|
+
let filtered2;
|
|
211
|
+
if (colonIdx2 !== -1) {
|
|
212
|
+
const rp = value.slice(0, colonIdx2);
|
|
213
|
+
const rpath = value.slice(colonIdx2 + 1);
|
|
214
|
+
filtered2 = (cfg4.logSources || []).filter(s => !(s.provider === rp && s.path === rpath));
|
|
215
|
+
} else {
|
|
216
|
+
filtered2 = (cfg4.logSources || []).filter(s => s.provider !== value);
|
|
217
|
+
}
|
|
218
|
+
updateConfig({ logSources: filtered2 });
|
|
219
|
+
showConfigUpdate(t('cli.logSources'), value);
|
|
220
|
+
i += 2;
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
case '--language': {
|
|
224
|
+
const lang = value?.toLowerCase();
|
|
225
|
+
if (lang !== 'en' && lang !== 'ko') {
|
|
226
|
+
console.error(` ${t('cli.unknownLang', { lang: value })}`);
|
|
227
|
+
process.exit(1);
|
|
228
|
+
}
|
|
229
|
+
updateConfig({ language: lang });
|
|
230
|
+
setLocale(lang);
|
|
231
|
+
showConfigUpdate(t('cli.language'), lang);
|
|
232
|
+
i += 2;
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
default:
|
|
236
|
+
console.error(` ${t('cli.unknownOption', { option: key })}`);
|
|
237
|
+
process.exit(1);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
} else if (command === 'report') {
|
|
241
|
+
const { showWeeklyReport, showMonthlyReport } = await import('../dist/report.js');
|
|
242
|
+
const { showBanner } = await import('../dist/display.js');
|
|
243
|
+
|
|
244
|
+
showBanner();
|
|
245
|
+
|
|
246
|
+
const isMonthly = args.includes('--monthly') || args.includes('-m');
|
|
247
|
+
|
|
248
|
+
if (isMonthly) {
|
|
249
|
+
await showMonthlyReport();
|
|
250
|
+
} else {
|
|
251
|
+
await showWeeklyReport();
|
|
252
|
+
}
|
|
253
|
+
} else if (command === 'cli') {
|
|
254
|
+
const { main } = await import('../dist/index.js');
|
|
255
|
+
main().catch((err) => {
|
|
256
|
+
console.error(`${t('cli.fatalError')} ${err.message}`);
|
|
257
|
+
process.exit(1);
|
|
258
|
+
});
|
|
259
|
+
} else if (args.includes('--help') || args.includes('-h')) {
|
|
260
|
+
showHelp();
|
|
261
|
+
} else {
|
|
262
|
+
launchOverlay();
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function showHelp() {
|
|
266
|
+
console.log(`
|
|
267
|
+
${t('cli.title')}
|
|
268
|
+
|
|
269
|
+
${t('cli.usage')}
|
|
270
|
+
cost-cry ${t('cli.cmdOverlay')}
|
|
271
|
+
cost-cry cli ${t('cli.cmdCli')}
|
|
272
|
+
cost-cry config ${t('cli.cmdConfig')}
|
|
273
|
+
cost-cry config [options] ${t('cli.cmdConfigEdit')}
|
|
274
|
+
cost-cry report ${t('cli.cmdReport')}
|
|
275
|
+
cost-cry report --monthly ${t('cli.cmdReportMonthly')}
|
|
276
|
+
|
|
277
|
+
${t('cli.settingsTitle')}
|
|
278
|
+
--daily-budget <amount> Daily budget (USD). Off: --daily-budget off
|
|
279
|
+
--monthly-budget <amount> Monthly budget (USD). Off: --monthly-budget off
|
|
280
|
+
--nudge <on|off> Savings nudge
|
|
281
|
+
--unit <name|auto> Fixed equivalent unit. Auto: --unit auto
|
|
282
|
+
--add-unit "name:price:emoji:unit" Add custom equivalent unit
|
|
283
|
+
--remove-unit <name> Remove custom equivalent unit
|
|
284
|
+
--currency <code> Display currency (USD, KRW, JPY, EUR, GBP, CNY)
|
|
285
|
+
--exchange-rate <num|auto> Fix exchange rate manually. Auto: --exchange-rate auto
|
|
286
|
+
--add-source "provider:path" Add log source (openai, google)
|
|
287
|
+
--add-source cursor Track Cursor IDE usage (API polling)
|
|
288
|
+
--remove-source <provider> Remove log source
|
|
289
|
+
--language <en|ko> Set language
|
|
290
|
+
|
|
291
|
+
${t('cli.examplesTitle')}
|
|
292
|
+
cost-cry config --daily-budget 10
|
|
293
|
+
cost-cry config --currency KRW
|
|
294
|
+
cost-cry config --add-source cursor
|
|
295
|
+
cost-cry config --language ko
|
|
296
|
+
`);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
async function launchOverlay() {
|
|
300
|
+
const { spawn } = await import('node:child_process');
|
|
301
|
+
const { createRequire } = await import('node:module');
|
|
302
|
+
const { fileURLToPath } = await import('node:url');
|
|
303
|
+
const path = await import('node:path');
|
|
304
|
+
|
|
305
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
306
|
+
const require = createRequire(import.meta.url);
|
|
307
|
+
|
|
308
|
+
let electronPath;
|
|
309
|
+
try {
|
|
310
|
+
electronPath = require('electron');
|
|
311
|
+
} catch {
|
|
312
|
+
console.error(t('cli.noElectron'));
|
|
313
|
+
console.error(t('cli.installElectron'));
|
|
314
|
+
process.exit(1);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const appPath = path.join(__dirname, '..', 'electron');
|
|
318
|
+
|
|
319
|
+
try {
|
|
320
|
+
const child = spawn(electronPath, [appPath], {
|
|
321
|
+
detached: true,
|
|
322
|
+
stdio: 'ignore',
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
child.unref();
|
|
326
|
+
|
|
327
|
+
console.log(t('cli.widgetLaunched'));
|
|
328
|
+
process.exit(0);
|
|
329
|
+
} catch (err) {
|
|
330
|
+
console.error(`${t('cli.electronFail')} ${err.message}`);
|
|
331
|
+
process.exit(1);
|
|
332
|
+
}
|
|
333
|
+
}
|