@oh-my-pi/omp-stats 17.0.9 → 17.1.1

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/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [17.1.0] - 2026-07-24
6
+
7
+ ### Fixed
8
+
9
+ - Fixed an issue where malformed persisted content blocks could abort stats ingestion for subsequent projects, and ensured pending full-session migrations are properly settled after successful backfills.
10
+
5
11
  ## [17.0.6] - 2026-07-20
6
12
 
7
13
  ### Changed
@@ -79,9 +79,10 @@ export declare function getMessageById(id: number): MessageStats | null;
79
79
  * Get daily cost time series data for the last N days, broken down by model.
80
80
  */
81
81
  export declare function getCostTimeSeries(days?: number, cutoff?: number | null): CostTimeSeriesPoint[];
82
- export declare function markPriorityPremiumRequestsBackfillComplete(): void;
83
- export declare function markUserMessagesBackfillComplete(): void;
84
- export declare function markUserMessageLinksRepairComplete(): void;
82
+ /**
83
+ * Settle every full-session backfill after a successful sync pass.
84
+ */
85
+ export declare function markSessionBackfillsComplete(): void;
85
86
  /**
86
87
  * Insert user-message stats. Idempotent via UNIQUE(session_file, entry_id).
87
88
  * The `WHERE NOT EXISTS` clause matches {@link insertMessageStats}: forks
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/omp-stats",
4
- "version": "17.0.9",
4
+ "version": "17.1.1",
5
5
  "description": "Local observability dashboard for pi AI usage statistics",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Can Boluk",
@@ -39,9 +39,9 @@
39
39
  "fmt": "biome format --write ."
40
40
  },
41
41
  "dependencies": {
42
- "@oh-my-pi/pi-ai": "17.0.9",
43
- "@oh-my-pi/pi-catalog": "17.0.9",
44
- "@oh-my-pi/pi-utils": "17.0.9",
42
+ "@oh-my-pi/pi-ai": "17.1.1",
43
+ "@oh-my-pi/pi-catalog": "17.1.1",
44
+ "@oh-my-pi/pi-utils": "17.1.1",
45
45
  "@tailwindcss/node": "^4.3.2",
46
46
  "chart.js": "^4.5.1",
47
47
  "date-fns": "^4.4.0",
package/src/aggregator.ts CHANGED
@@ -24,6 +24,7 @@ import {
24
24
  insertMessageStats,
25
25
  insertToolCalls,
26
26
  insertUserMessageStats,
27
+ markSessionBackfillsComplete,
27
28
  setFileOffset,
28
29
  updateToolResults,
29
30
  updateUserMessageLinks,
@@ -209,12 +210,15 @@ export async function syncAllSessions(opts?: SyncOptions): Promise<{ processed:
209
210
  await initDb();
210
211
 
211
212
  const files = await listAllSessionFiles();
212
- if (files.length === 0) return { processed: 0, files: 0 };
213
-
214
213
  let totalProcessed = 0;
215
214
  let filesProcessed = 0;
216
215
  let completed = 0;
217
216
  let cursor = 0;
217
+ const finish = () => {
218
+ markSessionBackfillsComplete();
219
+ return { processed: totalProcessed, files: filesProcessed };
220
+ };
221
+ if (files.length === 0) return finish();
218
222
 
219
223
  const report = (sessionFile: string) => {
220
224
  completed++;
@@ -259,7 +263,7 @@ export async function syncAllSessions(opts?: SyncOptions): Promise<{ processed:
259
263
  for (const sessionFile of files) {
260
264
  await processFile(sessionFile, parseSessionFile);
261
265
  }
262
- return { processed: totalProcessed, files: filesProcessed };
266
+ return finish();
263
267
  }
264
268
 
265
269
  const poolSize = Math.min(files.length, requestedWorkers);
@@ -282,7 +286,7 @@ export async function syncAllSessions(opts?: SyncOptions): Promise<{ processed:
282
286
  for (const handle of handles) handle.worker.terminate();
283
287
  }
284
288
 
285
- return { processed: totalProcessed, files: filesProcessed };
289
+ return finish();
286
290
  }
287
291
 
288
292
  const HOUR_MS = 60 * 60 * 1000;
package/src/db.ts CHANGED
@@ -1079,28 +1079,23 @@ function backfillPriorityPremiumRequests(database: Database): void {
1079
1079
  .run(PRIORITY_PREMIUM_REQUESTS_BACKFILL_KEY, BACKFILL_PENDING);
1080
1080
  }
1081
1081
 
1082
- export function markPriorityPremiumRequestsBackfillComplete(): void {
1083
- if (!db) return;
1084
- db.prepare("INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)").run(
1085
- PRIORITY_PREMIUM_REQUESTS_BACKFILL_KEY,
1086
- BACKFILL_COMPLETE,
1087
- );
1088
- }
1089
-
1090
- export function markUserMessagesBackfillComplete(): void {
1091
- if (!db) return;
1092
- db.prepare("INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)").run(
1093
- USER_MESSAGES_BACKFILL_KEY,
1094
- BACKFILL_COMPLETE,
1095
- );
1096
- }
1097
-
1098
- export function markUserMessageLinksRepairComplete(): void {
1082
+ /**
1083
+ * Settle every full-session backfill after a successful sync pass.
1084
+ */
1085
+ export function markSessionBackfillsComplete(): void {
1099
1086
  if (!db) return;
1100
- db.prepare("INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)").run(
1101
- USER_MESSAGE_LINKS_REPAIR_KEY,
1102
- BACKFILL_COMPLETE,
1103
- );
1087
+ const markComplete = db.prepare("INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)");
1088
+ const apply = db.transaction(() => {
1089
+ for (const key of [
1090
+ USER_MESSAGES_BACKFILL_KEY,
1091
+ TOOL_CALLS_BACKFILL_KEY,
1092
+ USER_MESSAGE_LINKS_REPAIR_KEY,
1093
+ PRIORITY_PREMIUM_REQUESTS_BACKFILL_KEY,
1094
+ ]) {
1095
+ markComplete.run(key, BACKFILL_COMPLETE);
1096
+ }
1097
+ });
1098
+ apply();
1104
1099
  }
1105
1100
 
1106
1101
  /**
package/src/parser.ts CHANGED
@@ -240,7 +240,11 @@ function extractToolCalls(
240
240
 
241
241
  const blocks = msg.content.filter(
242
242
  (block): block is ToolCall =>
243
- block.type === "toolCall" && typeof block.id === "string" && typeof block.name === "string",
243
+ block !== null &&
244
+ typeof block === "object" &&
245
+ block.type === "toolCall" &&
246
+ typeof block.id === "string" &&
247
+ typeof block.name === "string",
244
248
  );
245
249
  if (blocks.length === 0) return [];
246
250
 
@@ -277,7 +281,9 @@ function extractToolResultLink(sessionFile: string, entry: SessionMessageEntry):
277
281
  let resultChars = 0;
278
282
  if (Array.isArray(msg.content)) {
279
283
  for (const block of msg.content) {
280
- if (block.type === "text" && typeof block.text === "string") resultChars += block.text.length;
284
+ if (block && typeof block === "object" && block.type === "text" && typeof block.text === "string") {
285
+ resultChars += block.text.length;
286
+ }
281
287
  }
282
288
  }
283
289
  return {