getaimeter 0.1.5 → 0.1.7

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 (3) hide show
  1. package/cli.js +35 -2
  2. package/package.json +1 -1
  3. package/watcher.js +4 -0
package/cli.js CHANGED
@@ -161,10 +161,43 @@ async function runSetup() {
161
161
  // ---------------------------------------------------------------------------
162
162
 
163
163
  function runWatch() {
164
+ const fs = require('fs');
165
+ const path = require('path');
166
+ const lockFile = path.join(AIMETER_DIR, 'watcher.lock');
167
+
168
+ // Check if another instance is already running
169
+ try {
170
+ if (fs.existsSync(lockFile)) {
171
+ const lockData = JSON.parse(fs.readFileSync(lockFile, 'utf8'));
172
+ // Check if the PID is still alive
173
+ try {
174
+ process.kill(lockData.pid, 0); // signal 0 = just check if alive
175
+ console.log(`Another watcher is already running (PID ${lockData.pid}). Use 'aimeter stop' first.`);
176
+ process.exitCode = 1;
177
+ return;
178
+ } catch {
179
+ // PID is dead — stale lock, remove it
180
+ }
181
+ }
182
+ } catch {}
183
+
184
+ // Write lock file
185
+ fs.mkdirSync(AIMETER_DIR, { recursive: true });
186
+ fs.writeFileSync(lockFile, JSON.stringify({ pid: process.pid, startedAt: new Date().toISOString() }));
187
+
164
188
  const cleanup = startWatching();
165
189
 
166
- process.on('SIGINT', () => { cleanup(); process.exit(0); });
167
- process.on('SIGTERM', () => { cleanup(); process.exit(0); });
190
+ const cleanupAll = () => {
191
+ cleanup();
192
+ try { fs.unlinkSync(lockFile); } catch {}
193
+ process.exit(0);
194
+ };
195
+
196
+ process.on('SIGINT', cleanupAll);
197
+ process.on('SIGTERM', cleanupAll);
198
+ process.on('exit', () => {
199
+ try { fs.unlinkSync(lockFile); } catch {}
200
+ });
168
201
 
169
202
  process.on('uncaughtException', (err) => {
170
203
  console.error('[aimeter] Uncaught:', err.message);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "getaimeter",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Track your Claude AI usage across CLI, VS Code, and Desktop App. One command to start.",
5
5
  "bin": {
6
6
  "aimeter": "cli.js"
package/watcher.js CHANGED
@@ -84,6 +84,10 @@ function extractNewUsage(filePath) {
84
84
 
85
85
  if (obj.type !== 'assistant' || !obj.message || !obj.message.usage) continue;
86
86
 
87
+ // Skip streaming progress messages (stop_reason: null = not yet complete)
88
+ // Only count final responses with a real stop_reason
89
+ if (obj.message.stop_reason === null || obj.message.stop_reason === undefined) continue;
90
+
87
91
  const u = obj.message.usage;
88
92
  const model = obj.message.model || 'unknown';
89
93