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
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
+ }