@winston.wan/burn-your-money 2.1.1 → 2.2.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/README.md CHANGED
@@ -11,9 +11,7 @@
11
11
 
12
12
  ## 📸 效果预览
13
13
 
14
- ```
15
- [Claude 3.5 Sonnet] 今日:78.2K $0.47 🔥1.2K tok/s | 总计:285.1M $20.12
16
- ```
14
+ ![预览](docs/images/where_is_my_money.png)
17
15
 
18
16
  ---
19
17
 
@@ -147,7 +145,24 @@ burn-your-money total # 总计统计
147
145
  如果现实太过沉重:
148
146
 
149
147
  ```bash
150
- npm uninstall -g @winston.wan/burn-your-money
148
+ npm uninstall -g "@winston.wan/burn-your-money"
149
+ ```
150
+
151
+ 如果卸载后状态栏仍然显示,手动运行清理脚本:
152
+
153
+ ```bash
154
+ node ~/.claude/node_modules/@winston.wan/burn-your-money/uninstall.js
155
+ ```
156
+
157
+ 或直接删除文件和配置:
158
+
159
+ ```bash
160
+ # 删除插件文件
161
+ rm -f ~/.claude/statusline.sh ~/.claude/statusline-wrapper.sh
162
+ rm -f ~/.claude/scripts/token-history.sh
163
+ rm -f ~/.claude/commands/burn-your-money-*.md
164
+
165
+ # 清理配置(需要删除 statusLine 配置项)
151
166
  ```
152
167
 
153
168
  然后重启 Claude Code。
@@ -1,11 +1,11 @@
1
1
  Stack trace:
2
2
  Frame Function Args
3
- 0007FFFFBA30 00021005FE8E (000210285F68, 00021026AB6E, 000000000000, 0007FFFFA930) msys-2.0.dll+0x1FE8E
4
- 0007FFFFBA30 0002100467F9 (000000000000, 000000000000, 000000000000, 0007FFFFBD08) msys-2.0.dll+0x67F9
5
- 0007FFFFBA30 000210046832 (000210286019, 0007FFFFB8E8, 000000000000, 000000000000) msys-2.0.dll+0x6832
6
- 0007FFFFBA30 000210068CF6 (000000000000, 000000000000, 000000000000, 000000000000) msys-2.0.dll+0x28CF6
7
- 0007FFFFBA30 000210068E24 (0007FFFFBA40, 000000000000, 000000000000, 000000000000) msys-2.0.dll+0x28E24
8
- 0007FFFFBD10 00021006A225 (0007FFFFBA40, 000000000000, 000000000000, 000000000000) msys-2.0.dll+0x2A225
3
+ 0007FFFFB550 00021005FE8E (000210285F68, 00021026AB6E, 000000000000, 0007FFFFA450) msys-2.0.dll+0x1FE8E
4
+ 0007FFFFB550 0002100467F9 (000000000000, 000000000000, 000000000000, 0007FFFFB828) msys-2.0.dll+0x67F9
5
+ 0007FFFFB550 000210046832 (000210286019, 0007FFFFB408, 000000000000, 000000000000) msys-2.0.dll+0x6832
6
+ 0007FFFFB550 000210068CF6 (000000000000, 000000000000, 000000000000, 000000000000) msys-2.0.dll+0x28CF6
7
+ 0007FFFFB550 000210068E24 (0007FFFFB560, 000000000000, 000000000000, 000000000000) msys-2.0.dll+0x28E24
8
+ 0007FFFFB830 00021006A225 (0007FFFFB560, 000000000000, 000000000000, 000000000000) msys-2.0.dll+0x2A225
9
9
  End of stack trace
10
10
  Loaded modules:
11
11
  000100400000 bash.exe
@@ -13,8 +13,8 @@ Loaded modules:
13
13
  7FFAC7620000 KERNEL32.DLL
14
14
  7FFAC57F0000 KERNELBASE.dll
15
15
  7FFAC7C30000 USER32.dll
16
- 000210040000 msys-2.0.dll
17
16
  7FFAC54F0000 win32u.dll
17
+ 000210040000 msys-2.0.dll
18
18
  7FFAC74C0000 GDI32.dll
19
19
  7FFAC5EA0000 gdi32full.dll
20
20
  7FFAC5CA0000 msvcp_win.dll
package/install.js CHANGED
@@ -2,17 +2,14 @@ const fs = require('fs');
2
2
  const path = require('path');
3
3
  const os = require('os');
4
4
  const { execSync } = require('child_process');
5
- const https = require('https');
6
- const { createWriteStream, existsSync, mkdirSync } = fs;
7
5
 
8
- // ANSI colors for console output
6
+ // ANSI colors
9
7
  const colors = {
10
8
  reset: "\x1b[0m",
11
9
  red: "\x1b[31m",
12
10
  green: "\x1b[32m",
13
11
  yellow: "\x1b[33m",
14
12
  blue: "\x1b[34m",
15
- purple: "\x1b[35m",
16
13
  cyan: "\x1b[36m"
17
14
  };
18
15
 
@@ -36,141 +33,19 @@ function getHomeDir() {
36
33
  return os.homedir();
37
34
  }
38
35
 
39
- // Download file following redirects
40
- function downloadFile(url, destPath) {
41
- return new Promise((resolve, reject) => {
42
- const download = (url) => {
43
- https.get(url, (response) => {
44
- // Handle redirects (301, 302, 307, 308)
45
- if ([301, 302, 307, 308].includes(response.statusCode)) {
46
- const redirectUrl = response.headers.location;
47
- if (redirectUrl) {
48
- download(redirectUrl);
49
- return;
50
- }
51
- }
52
-
53
- // Handle errors
54
- if (response.statusCode !== 200) {
55
- reject(new Error(`Failed to download: HTTP ${response.statusCode}`));
56
- return;
57
- }
58
-
59
- const file = createWriteStream(destPath);
60
- response.pipe(file);
61
-
62
- file.on('finish', () => {
63
- file.close();
64
- resolve();
65
- });
66
-
67
- file.on('error', (err) => {
68
- fs.unlink(destPath, () => {});
69
- reject(err);
70
- });
71
- }).on('error', (err) => {
72
- reject(err);
73
- });
74
- };
75
-
76
- download(url);
77
- });
78
- }
79
-
80
- // Install jq for Windows by downloading binary
81
- async function installJqWindows() {
82
- const home = getHomeDir();
83
- const binDir = path.join(home, '.claude', 'bin');
84
-
85
- // Create bin directory
86
- if (!existsSync(binDir)) {
87
- mkdirSync(binDir, { recursive: true });
88
- }
89
-
90
- const jqPath = path.join(binDir, 'jq.exe');
91
- const jqUrl = 'https://github.com/jqlang/jq/releases/latest/download/jq-windows-amd64.exe';
92
-
93
- log(`Downloading jq to ${jqPath}...`, colors.cyan);
94
-
95
- try {
96
- await downloadFile(jqUrl, jqPath);
97
- success("jq downloaded successfully!");
98
- return jqPath;
99
- } catch (err) {
100
- error(`Failed to download jq: ${err.message}`);
101
- throw err;
102
- }
103
- }
104
-
105
- // Install jq for macOS/Linux
106
- function installJqUnix() {
107
- try {
108
- log("Attempting to install jq via brew...", colors.cyan);
109
- execSync('brew install jq', { stdio: 'inherit' });
110
- success("jq installed successfully!");
111
- return 'jq';
112
- } catch (brewError) {
113
- try {
114
- log("Attempting to install jq via apt...", colors.cyan);
115
- execSync('sudo apt-get install -y jq', { stdio: 'inherit' });
116
- success("jq installed successfully!");
117
- return 'jq';
118
- } catch (aptError) {
119
- throw new Error("Could not auto-install jq. Please install manually: brew install jq or sudo apt-get install jq");
120
- }
121
- }
122
- }
123
-
124
- async function checkDependencies() {
125
- log("Checking dependencies...", colors.cyan);
126
-
127
- let jqPath = 'jq'; // Default to system jq
128
-
129
- // Check for jq
130
- try {
131
- execSync('jq --version', { stdio: 'ignore' });
132
- success("jq is installed");
133
- } catch (e) {
134
- warning("jq not found! Attempting auto-installation...");
135
-
136
- try {
137
- if (os.platform() === 'win32') {
138
- jqPath = await installJqWindows();
139
- } else if (os.platform() === 'darwin') {
140
- installJqUnix();
141
- } else {
142
- // Linux
143
- installJqUnix();
144
- }
145
- } catch (installError) {
146
- error("Auto-installation failed.");
147
- log(" Please install jq manually:", colors.yellow);
148
- log(" Windows: Run installer again (will download automatically)", colors.yellow);
149
- log(" macOS: brew install jq", colors.yellow);
150
- log(" Linux: sudo apt-get install jq", colors.yellow);
151
- throw installError;
152
- }
153
- }
154
-
155
- // Check for Claude Code (informational only)
156
- try {
157
- const version = execSync('claude --version', { encoding: 'utf8' }).trim();
158
- success(`Claude Code found: ${version}`);
159
- } catch (e) {
160
- warning("Claude Code not found in PATH.");
161
- }
162
-
163
- return jqPath;
164
- }
165
-
36
+ /**
37
+ * Create necessary directories
38
+ */
166
39
  function createDirectories() {
167
40
  log("Creating directories...", colors.cyan);
168
41
  const home = getHomeDir();
169
- const claudeDir = path.join(home, '.claude');
170
- const scriptsDir = path.join(claudeDir, 'scripts');
171
- const cacheDir = path.join(claudeDir, 'cache');
42
+ const dirs = [
43
+ path.join(home, '.claude', 'scripts'),
44
+ path.join(home, '.claude', 'cache'),
45
+ path.join(home, '.claude', 'commands')
46
+ ];
172
47
 
173
- [claudeDir, scriptsDir, cacheDir].forEach(dir => {
48
+ dirs.forEach(dir => {
174
49
  if (!fs.existsSync(dir)) {
175
50
  fs.mkdirSync(dir, { recursive: true });
176
51
  }
@@ -179,35 +54,38 @@ function createDirectories() {
179
54
  success("Directories created");
180
55
  }
181
56
 
57
+ /**
58
+ * Install scripts
59
+ */
182
60
  function installScripts() {
183
61
  log("Installing scripts...", colors.cyan);
184
62
  const home = getHomeDir();
185
- const srcDir = path.join(__dirname, 'src');
63
+ const projectRoot = __dirname;
186
64
 
187
- const files = [
188
- { src: 'statusline.sh', dest: path.join(home, '.claude', 'statusline.sh') },
189
- { src: 'token-history.sh', dest: path.join(home, '.claude', 'scripts', 'token-history.sh') }
65
+ // Copy scripts
66
+ const scripts = [
67
+ { src: 'src/statusline.js', dest: '.claude/statusline.js' },
68
+ { src: 'src/token-history.js', dest: '.claude/scripts/token-history.js' }
190
69
  ];
191
70
 
192
- files.forEach(file => {
193
- const srcPath = path.join(srcDir, file.src);
194
- const destPath = file.dest;
71
+ scripts.forEach(script => {
72
+ const srcPath = path.join(projectRoot, script.src);
73
+ const destPath = path.join(home, script.dest);
74
+ fs.copyFileSync(srcPath, destPath);
195
75
 
196
- try {
197
- fs.copyFileSync(srcPath, destPath);
198
- // Make executable
199
- if (os.platform() !== 'win32') {
200
- fs.chmodSync(destPath, '755');
201
- }
202
- success(`Installed ${file.src}`);
203
- } catch (e) {
204
- error(`Failed to install ${file.src}: ${e.message}`);
205
- process.exit(1);
76
+ // Make executable on Unix
77
+ if (process.platform !== 'win32') {
78
+ fs.chmodSync(destPath, '755');
206
79
  }
80
+
81
+ success(`Installed ${script.dest}`);
207
82
  });
208
83
  }
209
84
 
210
- function configureSettings(jqPath) {
85
+ /**
86
+ * Configure settings.json
87
+ */
88
+ function configureSettings() {
211
89
  log("Configuring Claude Code...", colors.cyan);
212
90
  const home = getHomeDir();
213
91
  const settingsFile = path.join(home, '.claude', 'settings.json');
@@ -221,82 +99,13 @@ function configureSettings(jqPath) {
221
99
  }
222
100
  }
223
101
 
224
- // Configure command based on platform
225
- let commandEnv = "~/.claude/statusline.sh";
226
-
227
- if (os.platform() === 'win32') {
228
- // Get the raw Windows path first
229
- const scriptPathWindows = path.join(home, '.claude', 'statusline.sh');
230
-
231
- // Convert Windows jq path to Git Bash path format
232
- // C:\Users\... -> /c/Users/... (lowercase drive letter)
233
- let jqPathForBash = 'jq';
234
- if (jqPath && jqPath !== 'jq' && /^[A-Z]:/.test(jqPath)) {
235
- jqPathForBash = jqPath.replace(/^([A-Z]):\\/, (match, drive) => `/${drive.toLowerCase()}/`).replace(/\\/g, '/');
236
- }
237
-
238
- // Also convert scriptPath to Git Bash format for sourcing
239
- const scriptPathGitBash = scriptPathWindows.replace(/^([A-Z]):\\/, (match, drive) => `/${drive.toLowerCase()}/`).replace(/\\/g, '/');
240
-
241
- // Create environment variable for jq path in the script
242
- const wrapperScriptPath = path.join(home, '.claude', 'statusline-wrapper.sh');
243
- const wrapperContent = `#!/bin/bash
244
- # Export JQ_PATH for the scripts to use
245
- export JQ_PATH="${jqPathForBash}"
246
- # Source the statusline script to preserve environment
247
- . "${scriptPathGitBash}"
248
- `;
249
- fs.writeFileSync(wrapperScriptPath, wrapperContent);
250
- if (os.platform() !== 'win32') {
251
- fs.chmodSync(wrapperScriptPath, '755');
252
- }
253
-
254
- // Robust bash detection: try Git Bash first, then fallback to 'bash'
255
- let bashPath = 'bash';
256
- // Common Git Bash locations
257
- const gitBashPaths = [
258
- 'C:/Program Files/Git/bin/bash.exe',
259
- 'C:/Program Files/Git/cmd/bash.exe',
260
- 'C:/Program Files (x86)/Git/bin/bash.exe',
261
- 'C:/Program Files (x86)/Git/cmd/bash.exe'
262
- ];
263
-
264
- let foundBash = false;
265
- for (const p of gitBashPaths) {
266
- if (fs.existsSync(p)) {
267
- bashPath = `"${p}"`;
268
- foundBash = true;
269
- break;
270
- }
271
- }
272
-
273
- if (!foundBash) {
274
- // Warn if we are falling back to potentially broken 'bash' (WSL default)
275
- try {
276
- execSync('bash --version', { stdio: 'ignore' });
277
- } catch (e) {
278
- warning("Warning: 'bash' command seems broken on this system.");
279
- log(" Recommend installing Git Bash: https://git-scm.com/download/win", colors.yellow);
280
- }
281
- }
282
-
283
- const wrapperPathGitBash = wrapperScriptPath.replace(/^([A-Z]):\\/, (match, drive) => `/${drive.toLowerCase()}/`).replace(/\\/g, '/');
284
- commandEnv = `${bashPath} "${wrapperPathGitBash}"`;
285
- } else {
286
- // On Unix, just set the JQ_PATH in the wrapper script
287
- const wrapperScriptPath = path.join(home, '.claude', 'statusline-wrapper.sh');
288
- const wrapperContent = `#!/bin/bash
289
- export JQ_PATH="${jqPath}"
290
- exec ~/.claude/statusline.sh
291
- `;
292
- fs.writeFileSync(wrapperScriptPath, wrapperContent);
293
- fs.chmodSync(wrapperScriptPath, '755');
294
- commandEnv = "bash ~/.claude/statusline-wrapper.sh";
295
- }
102
+ // Use Node.js to run the statusline script
103
+ const scriptPath = path.join(home, '.claude', 'statusline.js');
104
+ const nodeCmd = process.execPath; // Get the Node.js executable path
296
105
 
297
106
  settings.statusLine = {
298
107
  type: "command",
299
- command: commandEnv
108
+ command: `"${nodeCmd}" "${scriptPath}"`
300
109
  };
301
110
 
302
111
  try {
@@ -306,11 +115,10 @@ exec ~/.claude/statusline.sh
306
115
  error(`Failed to update settings.json: ${e.message}`);
307
116
  }
308
117
 
309
- // 安装自定义命令文件到 ~/.claude/commands/
118
+ // Install custom commands
310
119
  log("Installing custom commands...", colors.cyan);
311
120
  const commandsDir = path.join(home, '.claude', 'commands');
312
121
 
313
- // 确保 commands 目录存在
314
122
  if (!fs.existsSync(commandsDir)) {
315
123
  fs.mkdirSync(commandsDir, { recursive: true });
316
124
  }
@@ -325,10 +133,10 @@ description: 📊 查看 token 使用趋势图
325
133
 
326
134
  # Token 使用趋势图
327
135
 
328
- 请执行以下 bash 命令查看过去 7 天的 token 使用趋势图:
136
+ 请执行以下命令查看过去 7 天的 token 使用趋势图:
329
137
 
330
138
  \\\`\\\`\\\`bash
331
- bash ~/.claude/scripts/token-history.sh chart
139
+ node ~/.claude/scripts/token-history.js chart
332
140
  \\\`\\\`\\\`
333
141
  `
334
142
  },
@@ -341,10 +149,10 @@ description: 📅 查看今日 token 使用情况
341
149
 
342
150
  # 今日 Token 使用情况
343
151
 
344
- 请执行以下 bash 命令查看今日的 token 使用量:
152
+ 请执行以下命令查看今日的 token 使用量:
345
153
 
346
154
  \\\`\\\`\\\`bash
347
- bash ~/.claude/scripts/token-history.sh today_tokens
155
+ node ~/.claude/scripts/token-history.js today_tokens
348
156
  \\\`\\\`\\\`
349
157
  `
350
158
  },
@@ -357,10 +165,10 @@ description: 📆 查看本周 token 使用情况
357
165
 
358
166
  # 本周 Token 使用情况
359
167
 
360
- 请执行以下 bash 命令查看本周的 token 使用量:
168
+ 请执行以下命令查看本周的 token 使用量:
361
169
 
362
170
  \\\`\\\`\\\`bash
363
- bash ~/.claude/scripts/token-history.sh week_tokens
171
+ node ~/.claude/scripts/token-history.js week_tokens
364
172
  \\\`\\\`\\\`
365
173
  `
366
174
  },
@@ -373,10 +181,10 @@ description: 🗓️ 查看本月 token 使用情况
373
181
 
374
182
  # 本月 Token 使用情况
375
183
 
376
- 请执行以下 bash 命令查看本月的 token 使用量:
184
+ 请执行以下命令查看本月的 token 使用量:
377
185
 
378
186
  \\\`\\\`\\\`bash
379
- bash ~/.claude/scripts/token-history.sh month_tokens
187
+ node ~/.claude/scripts/token-history.js month_tokens
380
188
  \\\`\\\`\\\`
381
189
  `
382
190
  },
@@ -389,10 +197,10 @@ description: 💾 导出 token 数据(JSON)
389
197
 
390
198
  # 导出 Token 数据
391
199
 
392
- 请执行以下 bash 命令导出 token 数据为 JSON 格式:
200
+ 请执行以下命令导出 token 数据为 JSON 格式:
393
201
 
394
202
  \\\`\\\`\\\`bash
395
- bash ~/.claude/scripts/token-history.sh export json
203
+ node ~/.claude/scripts/token-history.js export json
396
204
  \\\`\\\`\\\`
397
205
  `
398
206
  },
@@ -405,10 +213,10 @@ description: 📄 导出 token 数据(CSV)
405
213
 
406
214
  # 导出 Token 数据 (CSV)
407
215
 
408
- 请执行以下 bash 命令导出 token 数据为 CSV 格式:
216
+ 请执行以下命令导出 token 数据为 CSV 格式:
409
217
 
410
218
  \\\`\\\`\\\`bash
411
- bash ~/.claude/scripts/token-history.sh export csv
219
+ node ~/.claude/scripts/token-history.js export csv
412
220
  \\\`\\\`\\\`
413
221
  `
414
222
  }
@@ -421,14 +229,16 @@ bash ~/.claude/scripts/token-history.sh export csv
421
229
  });
422
230
  }
423
231
 
232
+ /**
233
+ * Main function
234
+ */
424
235
  async function main() {
425
- log("\n💸 Burn Your Money - Installer\n", colors.purple);
236
+ log("\n💸 Burn Your Money - Installer\n", colors.cyan);
426
237
 
427
238
  try {
428
- const jqPath = await checkDependencies();
429
239
  createDirectories();
430
240
  installScripts();
431
- configureSettings(jqPath);
241
+ configureSettings();
432
242
 
433
243
  log("\n✅ Installation complete!", colors.green);
434
244
  log("Please restart Claude Code to see the status bar.\n", colors.cyan);
package/package.json CHANGED
@@ -1,33 +1,29 @@
1
- {
2
- "name": "@winston.wan/burn-your-money",
3
- "version": "2.1.1",
4
- "description": "💸 Burn Your Money - 实时显示 Claude Code 的 token 消耗,看着你的钱包燃烧!",
5
- "main": "src/statusline.sh",
6
- "bin": {
7
- "burn-your-money": "./bin/burn-your-money"
8
- },
9
- "scripts": {
10
- "postinstall": "node install.js",
11
- "uninstall": "node uninstall.js",
12
- "test": "bash ./test.sh"
13
- },
14
- "repository": {
15
- "type": "git",
16
- "url": "git+https://github.com/winston-wwzhen/burn-your-money.git"
17
- },
18
- "keywords": [
19
- "claude-code",
20
- "token-monitor",
21
- "statusline",
22
- "claude",
23
- "ai",
24
- "cost-tracker",
25
- "burn-money"
26
- ],
27
- "author": "winston-wwzhen",
28
- "license": "MIT",
29
- "bugs": {
30
- "url": "https://github.com/winston-wwzhen/burn-your-money/issues"
31
- },
32
- "homepage": "https://github.com/winston-wwzhen/burn-your-money#readme"
33
- }
1
+ {
2
+ "name": "@winston.wan/burn-your-money",
3
+ "version": "2.2.0",
4
+ "description": "💸 Burn Your Money - 实时显示 Claude Code 的 token 消耗,看着你的钱包燃烧!",
5
+ "main": "src/statusline.js",
6
+ "scripts": {
7
+ "postinstall": "node install.js",
8
+ "preuninstall": "node uninstall.js"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/winston-wwzhen/burn-your-money.git"
13
+ },
14
+ "keywords": [
15
+ "claude-code",
16
+ "token-monitor",
17
+ "statusline",
18
+ "claude",
19
+ "ai",
20
+ "cost-tracker",
21
+ "burn-money"
22
+ ],
23
+ "author": "winston-wwzhen",
24
+ "license": "MIT",
25
+ "bugs": {
26
+ "url": "https://github.com/winston-wwzhen/burn-your-money/issues"
27
+ },
28
+ "homepage": "https://github.com/winston-wwzhen/burn-your-money#readme"
29
+ }