@thehammer/danx-session-telemetry 0.1.9 → 0.1.10

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.
@@ -292,27 +292,31 @@ export function ledgerLineFromLogEntry(entry) {
292
292
  ? d.content
293
293
  : [];
294
294
  const hasMessageId = typeof d.messageId === "string" && d.messageId.length > 0;
295
+ const hasUsage = Boolean(d.usage && typeof d.usage === "object");
296
+ const toolUseIds = content
297
+ .filter((b) => b.type === "tool_use" && typeof b.id === "string")
298
+ .map((b) => b.id);
295
299
  // DX-3261 — `byteOffset` only matters as the synthetic key for a line with
296
300
  // no `message.id` (`syntheticMessageKey`); a missing/invalid one used to
297
301
  // silently default to `0`, collapsing EVERY no-id reply from this source
298
302
  // onto one key so only the largest single reply was ever credited. Fail
299
- // loud rather than repeat that silent collapse. Harmless when a real
300
- // `messageId` is present (byteOffset is never used to key that line), so
301
- // only fail when the line actually needs it.
302
- if (!hasMessageId && typeof d.byte_offset !== "number") {
303
- throw new LedgerLineDataError(`ledgerLineFromLogEntry: missing/invalid byte_offset on a no-message-id line (source=${typeof d.subagent_id === "string" ? d.subagent_id : MAIN_SOURCE})`);
303
+ // loud rather than repeat that silent collapse — but ONLY when the line
304
+ // will actually reach that keying step: `UsageLedgerCounter.observe()`
305
+ // discards a no-id line with neither usage nor a tool-use id before ever
306
+ // building a key (a tool-call block with no reported `id`, an empty
307
+ // wrapper entry), so requiring a valid `byteOffset` on THOSE too would
308
+ // reject lines the counter was always going to ignore. Harmless when a
309
+ // real `messageId` is present (byteOffset is never used to key that line).
310
+ if (!hasMessageId && (hasUsage || toolUseIds.length > 0) && typeof d.byte_offset !== "number") {
311
+ throw new LedgerLineDataError(`ledgerLineFromLogEntry: missing/invalid byte_offset on a no-message-id line carrying usage or a tool-use id (source=${typeof d.subagent_id === "string" ? d.subagent_id : MAIN_SOURCE})`);
304
312
  }
305
313
  return {
306
314
  messageId: hasMessageId ? d.messageId : undefined,
307
315
  source: typeof d.subagent_id === "string" ? d.subagent_id : MAIN_SOURCE,
308
316
  byteOffset: typeof d.byte_offset === "number" ? d.byte_offset : 0,
309
317
  model: typeof d.model === "string" && d.model.length > 0 ? d.model : undefined,
310
- usage: d.usage && typeof d.usage === "object"
311
- ? d.usage
312
- : undefined,
318
+ usage: hasUsage ? d.usage : undefined,
313
319
  timestamp: entry.timestamp,
314
- toolUseIds: content
315
- .filter((b) => b.type === "tool_use" && typeof b.id === "string")
316
- .map((b) => b.id),
320
+ toolUseIds,
317
321
  };
318
322
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thehammer/danx-session-telemetry",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "Shared Claude Code transcript collector (DX-2962) — incremental JSONL tailing for the danxbot worker and the danx-dashboard-mcp desktop bridge, so both run identical collector code.",
5
5
  "license": "MIT",
6
6
  "type": "module",