getaimeter 0.1.1 → 0.1.3
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/package.json +1 -1
- package/watcher.js +33 -8
package/package.json
CHANGED
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}
|
|
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
|
-
//
|
|
145
|
-
const
|
|
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(
|
|
149
|
-
_debounceTimers.delete(
|
|
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) {
|
|
@@ -235,7 +240,7 @@ function startWatching() {
|
|
|
235
240
|
}
|
|
236
241
|
saveState();
|
|
237
242
|
|
|
238
|
-
// Set up fs.watch on each path
|
|
243
|
+
// Set up fs.watch on each path (works well on macOS/Linux)
|
|
239
244
|
const watchers = [];
|
|
240
245
|
for (const watchPath of watchPaths) {
|
|
241
246
|
try {
|
|
@@ -250,18 +255,38 @@ function startWatching() {
|
|
|
250
255
|
});
|
|
251
256
|
|
|
252
257
|
watchers.push(w);
|
|
253
|
-
log('Watching:', watchPath);
|
|
258
|
+
log('Watching (fs.watch):', watchPath);
|
|
254
259
|
} catch (err) {
|
|
255
260
|
logError(`Could not watch ${watchPath}:`, err.message);
|
|
256
261
|
}
|
|
257
262
|
}
|
|
258
263
|
|
|
264
|
+
// Polling fallback — fs.watch is unreliable on Windows for deeply nested dirs.
|
|
265
|
+
// Every 5 seconds, scan all known JSONL files for size changes.
|
|
266
|
+
const POLL_INTERVAL = 5_000;
|
|
267
|
+
const pollInterval = setInterval(() => {
|
|
268
|
+
for (const watchPath of watchPaths) {
|
|
269
|
+
const files = findJsonlFiles(watchPath);
|
|
270
|
+
for (const file of files) {
|
|
271
|
+
try {
|
|
272
|
+
const currentSize = fs.statSync(file).size;
|
|
273
|
+
const lastOffset = getOffset(file);
|
|
274
|
+
if (currentSize > lastOffset) {
|
|
275
|
+
handleFileChange(file);
|
|
276
|
+
}
|
|
277
|
+
} catch {}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}, POLL_INTERVAL);
|
|
281
|
+
log(`Polling every ${POLL_INTERVAL / 1000}s as fallback`);
|
|
282
|
+
|
|
259
283
|
// Periodic state save
|
|
260
284
|
const saveInterval = setInterval(() => saveState(), 30_000);
|
|
261
285
|
|
|
262
286
|
// Return cleanup
|
|
263
287
|
return () => {
|
|
264
288
|
clearInterval(saveInterval);
|
|
289
|
+
clearInterval(pollInterval);
|
|
265
290
|
for (const w of watchers) w.close();
|
|
266
291
|
for (const t of _debounceTimers.values()) clearTimeout(t);
|
|
267
292
|
saveState();
|