sidekick-shared 0.25.0 → 0.26.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.
Files changed (119) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/README.md +50 -3
  3. package/dist/accountChanges.js +22 -3
  4. package/dist/accountRegistry.d.ts +22 -1
  5. package/dist/accountRegistry.js +37 -14
  6. package/dist/accountStatus.d.ts +9 -1
  7. package/dist/accountStatus.js +3 -3
  8. package/dist/accounts.d.ts +3 -1
  9. package/dist/accounts.js +84 -64
  10. package/dist/aggregation/EventAggregator.d.ts +15 -2
  11. package/dist/aggregation/EventAggregator.js +54 -9
  12. package/dist/aggregation/costProvenance.d.ts +14 -0
  13. package/dist/aggregation/costProvenance.js +35 -0
  14. package/dist/aggregation/snapshot.d.ts +13 -2
  15. package/dist/aggregation/snapshot.js +57 -6
  16. package/dist/aggregation/types.d.ts +30 -1
  17. package/dist/analytics/compactionLedger.js +15 -5
  18. package/dist/analytics/qualityScore.js +2 -1
  19. package/dist/browser.d.ts +11 -1
  20. package/dist/browser.js +29 -1
  21. package/dist/codexProfiles.d.ts +3 -1
  22. package/dist/codexProfiles.js +4 -2
  23. package/dist/codexQuota.d.ts +2 -0
  24. package/dist/codexQuota.js +11 -66
  25. package/dist/failingTools.d.ts +37 -0
  26. package/dist/failingTools.js +70 -0
  27. package/dist/formatters/sessionDump.js +13 -7
  28. package/dist/formatting.d.ts +13 -0
  29. package/dist/formatting.js +35 -0
  30. package/dist/historicalStore.d.ts +47 -0
  31. package/dist/historicalStore.js +312 -0
  32. package/dist/index.d.ts +46 -12
  33. package/dist/index.js +112 -24
  34. package/dist/modelContext.js +8 -3
  35. package/dist/modelInfo.js +45 -27
  36. package/dist/node.d.ts +19 -0
  37. package/dist/node.js +47 -1
  38. package/dist/observedContextWindows.d.ts +7 -0
  39. package/dist/observedContextWindows.js +17 -2
  40. package/dist/observedSessionCollector.d.ts +3 -8
  41. package/dist/observedSessionCollector.js +10 -27
  42. package/dist/parsers/sessionActivityDetector.d.ts +24 -2
  43. package/dist/parsers/sessionActivityDetector.js +95 -17
  44. package/dist/parsers/sessionPathResolver.d.ts +11 -0
  45. package/dist/parsers/sessionPathResolver.js +13 -10
  46. package/dist/peakHours.d.ts +34 -3
  47. package/dist/peakHours.js +92 -7
  48. package/dist/pricingCatalog.d.ts +7 -0
  49. package/dist/pricingCatalog.js +8 -5
  50. package/dist/providers/claudeCode.js +11 -96
  51. package/dist/providers/codex.d.ts +2 -0
  52. package/dist/providers/codex.js +94 -259
  53. package/dist/providers/detect.d.ts +2 -0
  54. package/dist/providers/detect.js +29 -24
  55. package/dist/providers/factory.d.ts +6 -0
  56. package/dist/providers/openCode.d.ts +2 -0
  57. package/dist/providers/openCode.js +105 -121
  58. package/dist/providers/rolloutWalker.d.ts +53 -0
  59. package/dist/providers/rolloutWalker.js +209 -0
  60. package/dist/providers/types.d.ts +30 -0
  61. package/dist/quota.d.ts +30 -3
  62. package/dist/quota.js +35 -3
  63. package/dist/quotaHistory.d.ts +1 -1
  64. package/dist/quotaHistory.js +36 -35
  65. package/dist/quotaPresentation.js +17 -5
  66. package/dist/quotaResolver.d.ts +83 -0
  67. package/dist/quotaResolver.js +234 -0
  68. package/dist/quotaSnapshots.d.ts +15 -2
  69. package/dist/quotaSnapshots.js +25 -3
  70. package/dist/quotaThresholds.d.ts +60 -0
  71. package/dist/quotaThresholds.js +90 -0
  72. package/dist/report/htmlReportGenerator.js +10 -4
  73. package/dist/report/sessionReportInputs.d.ts +23 -0
  74. package/dist/report/sessionReportInputs.js +34 -0
  75. package/dist/schemas/index.d.ts +2 -0
  76. package/dist/schemas/index.js +10 -1
  77. package/dist/schemas/quota.d.ts +139 -0
  78. package/dist/schemas/quota.js +17 -2
  79. package/dist/schemas/quotaHistory.d.ts +1 -0
  80. package/dist/schemas/quotaHistory.js +1 -1
  81. package/dist/schemas/sessionEvent.d.ts +6 -0
  82. package/dist/schemas/sessionEvent.js +1 -0
  83. package/dist/schemas/stateFile.d.ts +198 -0
  84. package/dist/schemas/stateFile.js +77 -0
  85. package/dist/schemas/transcript.js +2 -0
  86. package/dist/sessionFingerprint.d.ts +25 -0
  87. package/dist/sessionFingerprint.js +46 -0
  88. package/dist/sessionPreviews.d.ts +7 -1
  89. package/dist/sessionPreviews.js +15 -3
  90. package/dist/sessionStats.d.ts +51 -0
  91. package/dist/sessionStats.js +166 -0
  92. package/dist/stateFile.d.ts +113 -0
  93. package/dist/stateFile.js +160 -0
  94. package/dist/statusline/claudeStatuslinePayload.d.ts +89 -0
  95. package/dist/statusline/claudeStatuslinePayload.js +152 -0
  96. package/dist/statusline/formatter.d.ts +13 -0
  97. package/dist/statusline/formatter.js +48 -6
  98. package/dist/statusline/index.d.ts +10 -2
  99. package/dist/statusline/index.js +19 -1
  100. package/dist/tokenSummary.d.ts +62 -0
  101. package/dist/tokenSummary.js +72 -0
  102. package/dist/transcript.d.ts +5 -0
  103. package/dist/transcript.js +2 -0
  104. package/dist/types/observedSessionV1.d.ts +2 -0
  105. package/dist/types/observedSessionV1.js +75 -18
  106. package/dist/types/sessionEvent.d.ts +2 -0
  107. package/dist/usage/billingBlocks.d.ts +85 -0
  108. package/dist/usage/billingBlocks.js +153 -0
  109. package/dist/usage/importSessionHistory.d.ts +53 -0
  110. package/dist/usage/importSessionHistory.js +88 -0
  111. package/dist/usage/usageEvents.d.ts +92 -0
  112. package/dist/usage/usageEvents.js +322 -0
  113. package/dist/usage/usageReports.d.ts +76 -0
  114. package/dist/usage/usageReports.js +208 -0
  115. package/dist/watchers/factory.d.ts +6 -0
  116. package/dist/watchers/factory.js +30 -25
  117. package/dist/zaiQuotaApi.d.ts +2 -0
  118. package/dist/zaiQuotaApi.js +2 -0
  119. package/package.json +1 -1
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+ /**
3
+ * Five-hour billing blocks computed from usage events.
4
+ *
5
+ * Mirrors the ccusage convention: a block opens at the first usage event
6
+ * (aligned down to the UTC hour), lasts five hours, and an event that lands
7
+ * after the block's end or more than five hours after the previous event opens
8
+ * a new block. The active block also reports a burn rate and an end-of-block
9
+ * projection. Browser-safe: no Node imports.
10
+ *
11
+ * @module usage/billingBlocks
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.BILLING_BLOCK_DURATION_MS = void 0;
15
+ exports.computeBillingBlocks = computeBillingBlocks;
16
+ exports.findActiveBillingBlock = findActiveBillingBlock;
17
+ const costProvenance_1 = require("../aggregation/costProvenance");
18
+ const BurnRateCalculator_1 = require("../statusline/BurnRateCalculator");
19
+ const tokenSummary_1 = require("../tokenSummary");
20
+ /** Length of one billing block. */
21
+ exports.BILLING_BLOCK_DURATION_MS = 5 * 3_600_000;
22
+ function toMs(value) {
23
+ if (value instanceof Date)
24
+ return value.getTime();
25
+ if (typeof value === 'number')
26
+ return value;
27
+ return Date.parse(value);
28
+ }
29
+ function normalizeInput(event) {
30
+ const timestamp = toMs(event.timestamp);
31
+ if (!Number.isFinite(timestamp))
32
+ return null;
33
+ const costUsd = typeof event.costUsd === 'number' && Number.isFinite(event.costUsd) ? event.costUsd : null;
34
+ return {
35
+ timestamp,
36
+ tokens: event.tokens,
37
+ costUsd,
38
+ costProvenance: costUsd === null ? 'unpriced' : (event.costProvenance ?? 'model-catalog'),
39
+ model: event.model ?? 'unknown',
40
+ };
41
+ }
42
+ function floorToUtcHour(ms) {
43
+ return ms - (ms % 3_600_000);
44
+ }
45
+ function buildBlock(events, start, durationMs, nowMs) {
46
+ const end = start + durationMs;
47
+ const first = events[0].timestamp;
48
+ const last = events[events.length - 1].timestamp;
49
+ const isActive = nowMs >= start && nowMs < end && nowMs - last < durationMs;
50
+ const tokens = { inputTokens: 0, outputTokens: 0, cacheWriteTokens: 0, cacheReadTokens: 0 };
51
+ let total = 0;
52
+ let costUsd = 0;
53
+ let reportedCalls = 0;
54
+ let estimatedCalls = 0;
55
+ let unpricedCalls = 0;
56
+ const models = {};
57
+ const burn = new BurnRateCalculator_1.BurnRateCalculator(durationMs / 60_000);
58
+ for (const event of events) {
59
+ const summary = (0, tokenSummary_1.summarizeTokens)(event.tokens);
60
+ tokens.inputTokens += summary.input;
61
+ tokens.outputTokens += summary.output;
62
+ tokens.cacheWriteTokens += summary.cacheWrite;
63
+ tokens.cacheReadTokens += summary.cacheRead;
64
+ total += summary.total;
65
+ burn.addEvent(summary.total, new Date(event.timestamp));
66
+ const model = models[event.model] ?? { calls: 0, tokens: 0, costUsd: 0 };
67
+ model.calls += 1;
68
+ model.tokens += summary.total;
69
+ if (event.costUsd !== null) {
70
+ costUsd += event.costUsd;
71
+ model.costUsd += event.costUsd;
72
+ if (event.costProvenance === 'provider-reported')
73
+ reportedCalls += 1;
74
+ else
75
+ estimatedCalls += 1;
76
+ }
77
+ else {
78
+ unpricedCalls += 1;
79
+ }
80
+ models[event.model] = model;
81
+ }
82
+ const rateAt = isActive ? nowMs : last;
83
+ const elapsedMs = Math.max(0, rateAt - first);
84
+ const burnRatePerMinute = burn.calculateBurnRate(new Date(rateAt));
85
+ const remainingMs = isActive ? Math.max(0, end - nowMs) : 0;
86
+ const projectedTokens = isActive
87
+ ? Math.round(total + burnRatePerMinute * (remainingMs / 60_000))
88
+ : total;
89
+ const costPerToken = total > 0 ? costUsd / total : 0;
90
+ const projectedCostUsd = isActive ? costUsd + costPerToken * (projectedTokens - total) : costUsd;
91
+ const startIso = new Date(start).toISOString();
92
+ return {
93
+ id: startIso,
94
+ start: startIso,
95
+ end: new Date(end).toISOString(),
96
+ firstEvent: new Date(first).toISOString(),
97
+ lastEvent: new Date(last).toISOString(),
98
+ isActive,
99
+ calls: events.length,
100
+ tokens: { ...tokens, total },
101
+ costUsd,
102
+ costProvenance: (0, costProvenance_1.classifyCostProvenance)({ reportedCalls, estimatedCalls, unpricedCalls }),
103
+ unpricedCalls,
104
+ models,
105
+ elapsedMs,
106
+ remainingMs,
107
+ burnRatePerMinute,
108
+ projectedTokens,
109
+ projectedCostUsd,
110
+ };
111
+ }
112
+ /**
113
+ * Group usage events into billing blocks, oldest first.
114
+ *
115
+ * Events with an unparseable timestamp are ignored. Events are sorted before
116
+ * grouping, so callers may pass them in any order.
117
+ */
118
+ function computeBillingBlocks(events, options = {}) {
119
+ const durationMs = options.blockDurationMs ?? exports.BILLING_BLOCK_DURATION_MS;
120
+ const alignToHour = options.alignToHour ?? true;
121
+ const nowMs = options.now === undefined ? Date.now() : toMs(options.now);
122
+ const sorted = events
123
+ .map(normalizeInput)
124
+ .filter((event) => event !== null)
125
+ .sort((a, b) => a.timestamp - b.timestamp);
126
+ const blocks = [];
127
+ let current = [];
128
+ let currentStart = 0;
129
+ for (const event of sorted) {
130
+ const previous = current[current.length - 1];
131
+ const opensNewBlock = !previous ||
132
+ event.timestamp >= currentStart + durationMs ||
133
+ event.timestamp - previous.timestamp > durationMs;
134
+ if (opensNewBlock) {
135
+ if (current.length > 0)
136
+ blocks.push(buildBlock(current, currentStart, durationMs, nowMs));
137
+ current = [];
138
+ currentStart = alignToHour ? floorToUtcHour(event.timestamp) : event.timestamp;
139
+ }
140
+ current.push(event);
141
+ }
142
+ if (current.length > 0)
143
+ blocks.push(buildBlock(current, currentStart, durationMs, nowMs));
144
+ return blocks;
145
+ }
146
+ /** The block that is still open at the calculator's `now`, if any. */
147
+ function findActiveBillingBlock(blocks) {
148
+ for (let index = blocks.length - 1; index >= 0; index -= 1) {
149
+ if (blocks[index].isActive)
150
+ return blocks[index];
151
+ }
152
+ return null;
153
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Import finished sessions from every provider into the history store.
3
+ *
4
+ * The VS Code extension used to import Claude Code only, by hand-parsing
5
+ * JSONL files; the CLI could not import at all. This walks the sessions
6
+ * every provider knows about, reads each once through the unified stats
7
+ * path, and hands a `SessionSummary` to the caller, which applies it to the
8
+ * store it owns (the extension's debounced persistence service or the CLI's
9
+ * locked atomic writer). Dedupe is the caller's `isImported` answer
10
+ * (imported file paths plus persisted session ids); the capped per-session
11
+ * list is deliberately not used as the dedupe key.
12
+ *
13
+ * Node-only: reads session files.
14
+ *
15
+ * @module usage/importSessionHistory
16
+ */
17
+ import type { SessionProviderBase, SessionProviderDiagnostic } from '../providers/types';
18
+ import type { SessionSummary } from '../types/historicalData';
19
+ /** Files modified more recently than this are skipped: they may still be live. */
20
+ export declare const ACTIVE_SESSION_MTIME_THRESHOLD_MS = 60000;
21
+ export interface ImportSessionHistoryOptions {
22
+ providers: SessionProviderBase[];
23
+ /** Only sessions modified after this instant. */
24
+ since?: Date | string;
25
+ /** Restrict to one workspace's sessions. */
26
+ workspacePath?: string;
27
+ /** Clock used for the active-file check (default `new Date()`). */
28
+ now?: Date;
29
+ /** Override of {@link ACTIVE_SESSION_MTIME_THRESHOLD_MS}. */
30
+ activeFileThresholdMs?: number;
31
+ /** Already imported? Checked before the session is read. */
32
+ isImported: (sessionId: string, filePath: string) => boolean;
33
+ /** Apply one credited session to the store. */
34
+ applySummary: (summary: SessionSummary, filePath: string) => void;
35
+ /** Record a file as imported (called after `applySummary`, and alone for usage-free files). */
36
+ markImported: (filePath: string) => void;
37
+ onProgress?: (loaded: number, total: number) => void;
38
+ }
39
+ export interface ImportSessionHistoryResult {
40
+ /** Session files the providers listed in the window. */
41
+ filesFound: number;
42
+ /** Files read and applied. */
43
+ filesProcessed: number;
44
+ /** Files skipped because they were already imported or still live. */
45
+ filesSkipped: number;
46
+ /** Files that could not be read (`availability: 'unavailable'`) or held no usage. */
47
+ filesUnavailable: number;
48
+ sessionsImported: number;
49
+ /** Messages across the imported sessions. */
50
+ messagesImported: number;
51
+ diagnostics: SessionProviderDiagnostic[];
52
+ }
53
+ export declare function importSessionHistory(options: ImportSessionHistoryOptions): Promise<ImportSessionHistoryResult>;
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ /**
3
+ * Import finished sessions from every provider into the history store.
4
+ *
5
+ * The VS Code extension used to import Claude Code only, by hand-parsing
6
+ * JSONL files; the CLI could not import at all. This walks the sessions
7
+ * every provider knows about, reads each once through the unified stats
8
+ * path, and hands a `SessionSummary` to the caller, which applies it to the
9
+ * store it owns (the extension's debounced persistence service or the CLI's
10
+ * locked atomic writer). Dedupe is the caller's `isImported` answer
11
+ * (imported file paths plus persisted session ids); the capped per-session
12
+ * list is deliberately not used as the dedupe key.
13
+ *
14
+ * Node-only: reads session files.
15
+ *
16
+ * @module usage/importSessionHistory
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.ACTIVE_SESSION_MTIME_THRESHOLD_MS = void 0;
20
+ exports.importSessionHistory = importSessionHistory;
21
+ const historicalStore_1 = require("../historicalStore");
22
+ const sessionPreviews_1 = require("../sessionPreviews");
23
+ const sessionStats_1 = require("../sessionStats");
24
+ /** Files modified more recently than this are skipped: they may still be live. */
25
+ exports.ACTIVE_SESSION_MTIME_THRESHOLD_MS = 60_000;
26
+ function yieldToEventLoop() {
27
+ return new Promise((resolve) => setImmediate(resolve));
28
+ }
29
+ async function importSessionHistory(options) {
30
+ const now = options.now ?? new Date();
31
+ const threshold = options.activeFileThresholdMs ?? exports.ACTIVE_SESSION_MTIME_THRESHOLD_MS;
32
+ const listed = await (0, sessionPreviews_1.listSessionPreviewsAsync)(options.providers, {
33
+ since: options.since,
34
+ workspacePath: options.workspacePath,
35
+ limit: Number.MAX_SAFE_INTEGER,
36
+ });
37
+ const providerById = new Map(options.providers.map((provider) => [provider.id, provider]));
38
+ const result = {
39
+ filesFound: listed.previews.length,
40
+ filesProcessed: 0,
41
+ filesSkipped: 0,
42
+ filesUnavailable: 0,
43
+ sessionsImported: 0,
44
+ messagesImported: 0,
45
+ diagnostics: [...listed.diagnostics],
46
+ };
47
+ const total = listed.previews.length;
48
+ let loaded = 0;
49
+ for (const preview of listed.previews) {
50
+ loaded += 1;
51
+ const provider = providerById.get(preview.provider);
52
+ const modifiedMs = Date.parse(preview.modifiedAt);
53
+ const recentlyModified = Number.isFinite(modifiedMs) && now.getTime() - modifiedMs < threshold;
54
+ if (!provider || recentlyModified || options.isImported(preview.sessionId, preview.filePath)) {
55
+ result.filesSkipped += 1;
56
+ options.onProgress?.(loaded, total);
57
+ continue;
58
+ }
59
+ const stats = (0, sessionStats_1.readSessionFileStats)(provider, preview.filePath);
60
+ result.filesProcessed += 1;
61
+ if (stats.availability === 'unavailable') {
62
+ result.filesUnavailable += 1;
63
+ result.diagnostics.push({
64
+ providerId: preview.provider,
65
+ kind: 'read_failed',
66
+ severity: 'warning',
67
+ phase: 'read',
68
+ message: `${preview.provider} session ${preview.sessionId}: ${stats.unavailableReason ?? 'unavailable'}`,
69
+ });
70
+ }
71
+ else if (Object.keys(stats.modelUsage).length === 0) {
72
+ // No usage record at all (for example a prompt that never got an
73
+ // answer): nothing to credit, but mark the file so it is not re-read
74
+ // on every run.
75
+ result.filesUnavailable += 1;
76
+ options.markImported(preview.filePath);
77
+ }
78
+ else {
79
+ options.applySummary((0, historicalStore_1.sessionSummaryFromStats)(stats, { project: preview.workspacePath }), preview.filePath);
80
+ options.markImported(preview.filePath);
81
+ result.sessionsImported += 1;
82
+ result.messagesImported += stats.messageCount;
83
+ }
84
+ options.onProgress?.(loaded, total);
85
+ await yieldToEventLoop();
86
+ }
87
+ return result;
88
+ }
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Usage events collected from session logs, cached per session.
3
+ *
4
+ * Feeds the billing-block view and the log-derived daily/weekly/monthly
5
+ * reports, so CLI-only users get numbers without the extension's history
6
+ * store. Each session is read once through its provider reader; the
7
+ * extracted usage is cached under `<configDir>/usage-cache/` keyed by the
8
+ * session's size and mtime, so a repeat run only re-reads sessions that
9
+ * changed. Token counts are cached raw and priced at load time, so a pricing
10
+ * catalog refresh never leaves stale costs behind. Cache files are touched on
11
+ * every hit and pruned least-recently-used, once per collection.
12
+ *
13
+ * Node-only: reads session files and the cache directory.
14
+ *
15
+ * @module usage/usageEvents
16
+ */
17
+ import type { ProviderId, SessionProviderBase, SessionProviderDiagnostic } from '../providers/types';
18
+ import type { TokenTotals } from '../types/historicalData';
19
+ import type { PricingProvenance } from '../usageNormalization';
20
+ /** Bump when the cached record shape changes; older files are re-read. */
21
+ export declare const USAGE_CACHE_VERSION = 1;
22
+ /**
23
+ * Most-recently-used cache files kept on disk. Sized for a busy month of
24
+ * sessions (files are a few KB each); a collection larger than this still
25
+ * completes, it just re-reads what was evicted. Pruning runs once after a
26
+ * collection, never during one, so a working set is never evicted mid-run.
27
+ */
28
+ export declare const MAX_USAGE_CACHE_FILES = 5000;
29
+ /** One priced usage event from a session log. */
30
+ export interface UsageEventRecord {
31
+ /** Event time in ms since epoch. */
32
+ timestamp: number;
33
+ provider: ProviderId;
34
+ sessionId: string;
35
+ /** Workspace path recorded in the session, when known. */
36
+ project: string | null;
37
+ model: string;
38
+ /** Four buckets plus the provider-semantics-aware total. */
39
+ tokens: TokenTotals & {
40
+ totalTokens: number;
41
+ };
42
+ costUsd: number | null;
43
+ costProvenance: PricingProvenance;
44
+ }
45
+ /** One session that contributed events. */
46
+ export interface UsageSessionRecord {
47
+ provider: ProviderId;
48
+ sessionId: string;
49
+ filePath: string;
50
+ project: string | null;
51
+ fingerprint: string;
52
+ firstTimestamp: number | null;
53
+ lastTimestamp: number | null;
54
+ eventCount: number;
55
+ fromCache: boolean;
56
+ }
57
+ export interface CollectUsageEventsOptions {
58
+ providers: SessionProviderBase[];
59
+ /** Only sessions modified after this instant, and only events at or after it. */
60
+ since?: Date | string;
61
+ /** Only events at or before this instant. */
62
+ until?: Date | string;
63
+ /** Restrict to one workspace's sessions. */
64
+ workspacePath?: string;
65
+ /** Preview-read concurrency (see `listSessionPreviewsAsync`). */
66
+ concurrency?: number;
67
+ /** Cache directory (default `<configDir>/usage-cache`). */
68
+ cacheDir?: string;
69
+ /** Skip the on-disk cache entirely. */
70
+ noCache?: boolean;
71
+ onDiagnostic?: (diagnostic: SessionProviderDiagnostic) => void;
72
+ }
73
+ export interface CollectUsageEventsResult {
74
+ /** Events within the window, oldest first. */
75
+ events: UsageEventRecord[];
76
+ sessions: UsageSessionRecord[];
77
+ diagnostics: SessionProviderDiagnostic[];
78
+ cacheHits: number;
79
+ cacheMisses: number;
80
+ }
81
+ export declare function getUsageCacheDir(): string;
82
+ /** Deletes all but the `keep` most recently used cache files (by mtime). Best-effort. */
83
+ export declare function pruneUsageCache(keep?: number, dir?: string): number;
84
+ /**
85
+ * Collect priced usage events for every session touched in the window.
86
+ *
87
+ * Sessions are enumerated with `listSessionPreviewsAsync` (the `since`
88
+ * cutoff applies to the session mtime there and to the event timestamp
89
+ * here), read once each unless the cache already holds their fingerprint,
90
+ * and yielded between reads so long-lived hosts stay responsive.
91
+ */
92
+ export declare function collectUsageEvents(options: CollectUsageEventsOptions): Promise<CollectUsageEventsResult>;