getaimeter 0.1.1 → 0.1.2

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 (2) hide show
  1. package/package.json +1 -1
  2. package/watcher.js +11 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "getaimeter",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
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
@@ -72,9 +72,11 @@ function extractNewUsage(filePath) {
72
72
  if (lastOffset > 0 && lines.length > 0) lines.shift();
73
73
 
74
74
  const usageEvents = [];
75
+ let lineOffset = lastOffset;
75
76
 
76
77
  for (const line of lines) {
77
78
  const trimmed = line.trim();
79
+ lineOffset += Buffer.byteLength(line + '\n', 'utf8');
78
80
  if (!trimmed) continue;
79
81
 
80
82
  let obj;
@@ -85,9 +87,9 @@ function extractNewUsage(filePath) {
85
87
  const u = obj.message.usage;
86
88
  const model = obj.message.model || 'unknown';
87
89
 
88
- // Build dedup hash
90
+ // Build dedup hash — include line offset for uniqueness
89
91
  const hash = crypto.createHash('md5')
90
- .update(`${filePath}:${model}:${u.input_tokens || 0}:${u.output_tokens || 0}:${currentSize}`)
92
+ .update(`${filePath}:${lineOffset}:${model}:${u.input_tokens || 0}:${u.output_tokens || 0}`)
91
93
  .digest('hex');
92
94
 
93
95
  if (isDuplicate(hash)) continue;
@@ -141,12 +143,15 @@ function handleFileChange(filePath) {
141
143
  // Only care about .jsonl files
142
144
  if (!filePath.endsWith('.jsonl')) return;
143
145
 
144
- // Debounce: wait 500ms after last change before processing
145
- const existing = _debounceTimers.get(filePath);
146
+ // Normalize path for consistent debounce key (Windows fires with mixed separators/casing)
147
+ const normalizedKey = path.resolve(filePath).toLowerCase();
148
+
149
+ // Debounce: wait 1000ms after last change before processing
150
+ const existing = _debounceTimers.get(normalizedKey);
146
151
  if (existing) clearTimeout(existing);
147
152
 
148
- _debounceTimers.set(filePath, setTimeout(async () => {
149
- _debounceTimers.delete(filePath);
153
+ _debounceTimers.set(normalizedKey, setTimeout(async () => {
154
+ _debounceTimers.delete(normalizedKey);
150
155
  try {
151
156
  const events = extractNewUsage(filePath);
152
157
  if (events.length > 0) {