sidekick-shared 0.27.3 → 0.27.4
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 +8 -0
- package/README.md +33 -11
- package/dist/node.d.ts +4 -1
- package/dist/node.js +5 -1
- package/dist/usage/usageEvents.d.ts +7 -0
- package/dist/usage/usageEvents.js +4 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,14 @@ All notable changes to sidekick-shared will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.27.4] - 2026-09-23
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `sidekick-shared/node` exports `createSessionProviders()`, the `CreateSessionProvidersOptions` / `CreateSessionProvidersResult` types, `SYNTHETIC_MODEL`, and the `ProviderId` / `SessionProviderBase` / `SessionProviderDiagnostic` types, re-exported from their own modules. `collectUsageEvents()` callers no longer need the package root, a CommonJS barrel that bundlers cannot tree-shake (about 420 KB minified saved in one esbuild consumer). Root exports are unchanged.
|
|
13
|
+
- `CollectUsageEventsOptions.signal` (optional `AbortSignal`): `collectUsageEvents()` checks it before listing sessions and between sessions, and rejects with the signal's reason (`AbortError` by default). Only fully read sessions are cached. Without a signal nothing changes; counting, pricing, and the cache format (`USAGE_CACHE_VERSION` 2) are the same.
|
|
14
|
+
- A packaging test walks every relative `require` reachable from `dist/node.js` and fails if it reaches `dist/index.js`.
|
|
15
|
+
|
|
8
16
|
## [0.27.3] - 2026-09-23
|
|
9
17
|
|
|
10
18
|
### Fixed
|
package/README.md
CHANGED
|
@@ -9,6 +9,7 @@ Types, parsers, providers, readers, formatters, aggregation, search, reporting,
|
|
|
9
9
|
|
|
10
10
|
## Recent additions
|
|
11
11
|
|
|
12
|
+
- **0.27.4: usage events from the Node entry** — `sidekick-shared/node` now exports `createSessionProviders()`, `SYNTHETIC_MODEL`, and the `ProviderId` / `SessionProviderBase` / `SessionProviderDiagnostic` / `CreateSessionProviders*` types, so `collectUsageEvents()` callers never import the package root (a CommonJS barrel that bundlers cannot tree-shake). `collectUsageEvents()` accepts an optional `signal` that stops the collection before listing and between sessions.
|
|
12
13
|
- **0.27.3: honest session totals** — Claude Code split lines are counted once: `ClaudeUsageDeduper` keeps a `message.id`'s first usage, strips identical repeats, and turns streamed growth into a `usageKind: 'correction'` delta that `EventAggregator` adds to tokens and cost without counting another call. `resolveCodexCallUsage()` drops duplicate Codex `token_count` events. `collectSessionTokenTotals()` (root and Node) returns `mainThread`, per-`subagents`, `subagentTotal`, and `combined` in the `summarizeTokens()` vocabulary, and `formatTokenBreakdown()` renders one line whose parts add up to the headline. `TokenSummary` gains `reasoning` / `billedOutsideBuckets`, and `SubagentStats` from every provider now carries cache, reasoning, and total tokens. The session dumps and `HtmlReportOptions` accept `subagents`, `readSessionReportInputs()` returns them, `collectUsageEvents()` reads Claude Code subagent transcripts, and `USAGE_CACHE_VERSION` 2 re-reads caches built with the old counting.
|
|
13
14
|
- **0.27.2: streamed prompt history** — `collectPromptHistory()` reads session logs of any size in bounded, resumable passes instead of skipping files over `maxFileBytes`: every call keeps what it read, the cursor (`version: 3`) continues where each file stopped, and a pending prompt keeps its answer state so a far-away answer still settles it. Adds `maxRecordBytes` and `maxEntries` bounds, `hasMore`, permanently skipped records in `exclusions`, and rewrite detection.
|
|
14
15
|
- **0.27.1: late prompt metadata** — `collectPromptHistory()` returns a prompt again, with the same provider, sessionId, ordinal, timestamp, and text, when its first answering call is written after an earlier collection, and entries gain `metadataStatus` (`pending` / `provisional` / `final`). The cursor becomes `version: 2`, keeps a replay offset and metadata digest for the one open prompt per file (no prompt text), and still accepts 0.27.0 cursors.
|
|
@@ -130,17 +131,17 @@ returns the platform default that both overrides bypass.
|
|
|
130
131
|
|
|
131
132
|
`sidekick-shared` ships three public entry points plus a few convenience subpaths. Pick the one that matches your runtime. As of 0.25.0 every documented subpath declares explicit `types` / `import` / `require` / `default` export conditions and resolves under Vite and TypeScript's legacy `moduleResolution: node` without consumer-side aliases.
|
|
132
133
|
|
|
133
|
-
| Path | Runtime | What it exposes
|
|
134
|
-
| ------------------------------ | -------------------------- |
|
|
135
|
-
| `sidekick-shared` | Node (CLI, extension host) | Full public API (readers, providers, parsers, pricing, …).
|
|
136
|
-
| `sidekick-shared/browser` | **Browser / webview** | Pure helpers: usage normalization/pricing, token estimation, transcript and assistant-turn projection, model/context math, `parseMcpToolName()`.
|
|
137
|
-
| `sidekick-shared/node` | Node only | LiteLLM pricing and context-window hydration, public provider service status (`fetchProviderServiceStatus()`), observed context-window persistence, recent-session/transcript reads, human prompt history (`collectPromptHistory()`), session previews (`listSessionPreviews()` / `readSessionPreview()` plus the bounded-concurrency `listSessionPreviewsAsync()` / `readSessionPreviewAsync()`), Codex history/rollout lookup (`readCodexHistory()`, `findCodexRolloutFile()`), and resilient observed-session collection (`fs` + providers). |
|
|
138
|
-
| `sidekick-shared/phrases` | Any runtime | Phrase arrays + `getRandomPhrase()`.
|
|
139
|
-
| `sidekick-shared/modelContext` | Any runtime | Direct access to the context-window module.
|
|
140
|
-
| `sidekick-shared/modelInfo` | Any runtime | Direct access to model parsing and cost math.
|
|
141
|
-
| `sidekick-shared/formatting` | Any runtime | Direct access to pure token and duration display helpers.
|
|
142
|
-
| `sidekick-shared/schemas` | Any runtime | Pure Zod boundary schemas (session events, assistant turns, observed-session V1, quota, account status, account management, quota history, the `state.json` contract) — fs-free, no Node builtins.
|
|
143
|
-
| `sidekick-shared/statusline` | Node only | Cache-only statusline surface: account status + quota snapshot readers and writers, `formatStatusline()`, burn-rate estimates, quota freshness helpers, `parseClaudeStatuslinePayload()` / `quotaFromStatuslinePayload()`, and `readStateFile()` / `writeStateFile()`.
|
|
134
|
+
| Path | Runtime | What it exposes |
|
|
135
|
+
| ------------------------------ | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
136
|
+
| `sidekick-shared` | Node (CLI, extension host) | Full public API (readers, providers, parsers, pricing, …). |
|
|
137
|
+
| `sidekick-shared/browser` | **Browser / webview** | Pure helpers: usage normalization/pricing, token estimation, transcript and assistant-turn projection, model/context math, `parseMcpToolName()`. |
|
|
138
|
+
| `sidekick-shared/node` | Node only | LiteLLM pricing and context-window hydration, public provider service status (`fetchProviderServiceStatus()`), observed context-window persistence, recent-session/transcript reads, human prompt history (`collectPromptHistory()`), usage events from session logs (`collectUsageEvents()` with `createSessionProviders()` and `SYNTHETIC_MODEL`), session previews (`listSessionPreviews()` / `readSessionPreview()` plus the bounded-concurrency `listSessionPreviewsAsync()` / `readSessionPreviewAsync()`), Codex history/rollout lookup (`readCodexHistory()`, `findCodexRolloutFile()`), and resilient observed-session collection (`fs` + providers). |
|
|
139
|
+
| `sidekick-shared/phrases` | Any runtime | Phrase arrays + `getRandomPhrase()`. |
|
|
140
|
+
| `sidekick-shared/modelContext` | Any runtime | Direct access to the context-window module. |
|
|
141
|
+
| `sidekick-shared/modelInfo` | Any runtime | Direct access to model parsing and cost math. |
|
|
142
|
+
| `sidekick-shared/formatting` | Any runtime | Direct access to pure token and duration display helpers. |
|
|
143
|
+
| `sidekick-shared/schemas` | Any runtime | Pure Zod boundary schemas (session events, assistant turns, observed-session V1, quota, account status, account management, quota history, the `state.json` contract) — fs-free, no Node builtins. |
|
|
144
|
+
| `sidekick-shared/statusline` | Node only | Cache-only statusline surface: account status + quota snapshot readers and writers, `formatStatusline()`, burn-rate estimates, quota freshness helpers, `parseClaudeStatuslinePayload()` / `quotaFromStatuslinePayload()`, and `readStateFile()` / `writeStateFile()`. |
|
|
144
145
|
|
|
145
146
|
### Browser / webview runtimes
|
|
146
147
|
|
|
@@ -481,6 +482,27 @@ const { providers, diagnostics } = createSessionProviders({
|
|
|
481
482
|
Repeated identical degradations are coalesced, so the diagnostic stream stays
|
|
482
483
|
bounded across long-lived polling and subscription cycles.
|
|
483
484
|
|
|
485
|
+
### Collect usage events from the Node entry
|
|
486
|
+
|
|
487
|
+
Everything `collectUsageEvents()` needs is exported from `sidekick-shared/node`,
|
|
488
|
+
which never loads the package root, so bundlers keep only what you use:
|
|
489
|
+
|
|
490
|
+
```typescript
|
|
491
|
+
import { collectUsageEvents, createSessionProviders, SYNTHETIC_MODEL } from 'sidekick-shared/node';
|
|
492
|
+
|
|
493
|
+
const { providers } = createSessionProviders({ providerIds: ['claude-code', 'codex'] });
|
|
494
|
+
const { events } = await collectUsageEvents({
|
|
495
|
+
providers,
|
|
496
|
+
since: '2026-09-01',
|
|
497
|
+
workspacePath: '/path/to/repo',
|
|
498
|
+
signal: AbortSignal.timeout(30_000), // optional: stop before listing and between sessions
|
|
499
|
+
});
|
|
500
|
+
const priced = events.filter((event) => event.model !== SYNTHETIC_MODEL);
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
On abort the promise rejects with the signal's reason (an `AbortError` by
|
|
504
|
+
default); sessions read before the abort keep their cache entries.
|
|
505
|
+
|
|
484
506
|
### Detect the active session provider
|
|
485
507
|
|
|
486
508
|
For a single-provider surface, auto-detect and construct just one:
|
package/dist/node.d.ts
CHANGED
|
@@ -46,6 +46,9 @@ export { ObservedSessionCollector, observedSessionSourceFromProvider, fileFinger
|
|
|
46
46
|
export type { KnownObservedSessionFingerprint, ObservedSessionChange, ObservedSessionChangeBatch, ObservedSessionChangeType, ObservedSessionReference, ObservedSessionFingerprintParts, ObservedSessionSourceSubscribeOptions, ObservedSessionSubscribeOptions, ObservedSessionCollectionSource, ProviderObservedSessionCollectionSource, ObservedSessionDiagnosticKind, ObservedSessionDiagnosticPhase, ObservedSessionDiagnosticSeverity, ObservedSessionDiagnostic, ObservedSessionCollection, ObservedSessionCollectorOptions, ObservedSessionCollectOptions, ObservedSessionDiscoverOptions, ObservedSessionDiscoveryStats, ObservedSessionDiscoveryTrigger, ObservedSessionSourceSignal, ObservedSessionSourceListener, ObservedSessionResolution, } from './observedSessionCollector';
|
|
47
47
|
export { DirectoryListingCache, splitWatchedPath } from './providers/directoryListingCache';
|
|
48
48
|
export type { CachedDirectoryListing, CachedFileStat, DirectoryListingCacheOptions, DirectoryListingCounters, ListDirectoryOptions, } from './providers/directoryListingCache';
|
|
49
|
-
export type { ListSessionFilesOptions, SessionEnumerationCounters, WatchedSessionFile, } from './providers/types';
|
|
49
|
+
export type { ListSessionFilesOptions, ProviderId, SessionEnumerationCounters, SessionProviderBase, SessionProviderDiagnostic, WatchedSessionFile, } from './providers/types';
|
|
50
|
+
export { createSessionProviders } from './providers/factory';
|
|
51
|
+
export type { CreateSessionProvidersOptions, CreateSessionProvidersResult, } from './providers/factory';
|
|
52
|
+
export { SYNTHETIC_MODEL } from './usage/claudeUsageDedupe';
|
|
50
53
|
export type { ProviderServiceSeverity, ProviderServiceComponent, ProviderServiceIncident, ProviderServiceStatusFailureReason, ObservedProviderServiceStatus, UnavailableProviderServiceStatus, ProviderServiceStatus, FetchProviderServiceStatusOptions, } from './providerServiceStatusTypes';
|
|
51
54
|
export { fetchProviderServiceStatus } from './providerServiceStatus';
|
package/dist/node.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.summarizeUsageRows = exports.bucketUsage = exports.importSessionHistory = exports.ACTIVE_SESSION_MTIME_THRESHOLD_MS = exports.sessionSummaryFromStats = exports.removeSessionSummary = exports.markFileImported = exports.isFileImported = exports.applySessionSummary = exports.subagentTokenTotals = exports.scanSessionSubagents = exports.readMainThreadTokenTotals = exports.combineSessionTokenTotals = exports.collectSessionTokenTotals = exports.pruneUsageCache = exports.getUsageCacheDir = exports.collectUsageEvents = exports.USAGE_CACHE_VERSION = exports.MAX_USAGE_CACHE_FILES = exports.findActiveBillingBlock = exports.computeBillingBlocks = exports.BILLING_BLOCK_DURATION_MS = exports.writeStateFile = exports.readStateFile = exports.quotaToStateFile = exports.getStateFilePath = exports.billingBlockToStateFile = exports.STATE_FILE_SCHEMA_VERSION = exports.STATE_FILE_NAME = exports.sessionFingerprintParts = exports.fingerprintString = exports.readSessionReportInputs = exports.readSessionFileStats = exports.providerContextSizeFn = exports.firstUserPrompt = exports.computeSessionFileStats = exports.isHumanPrompt = exports.humanPromptText = exports.HUMAN_CODEX_SOURCES = exports.HUMAN_CLAUDE_ENTRYPOINTS = exports.collectPromptHistory = exports.readSessionTranscript = exports.listRecentSessions = exports.getObservedContextWindowPath = exports.recordObservedContextWindow = exports.loadObservedContextWindows = exports.LITELLM_CATALOG_URL = exports.normalizeLiteLlmContextWindows = exports.normalizeLiteLlmCatalog = exports.hydratePricingCatalog = void 0;
|
|
11
|
-
exports.fetchProviderServiceStatus = exports.splitWatchedPath = exports.DirectoryListingCache = exports.fileFingerprintParts = exports.fileFingerprint = exports.observedSessionSourceFromProvider = exports.ObservedSessionCollector = exports.readSessionPreviewAsync = exports.readSessionPreview = exports.listSessionPreviewsAsync = exports.listSessionPreviews = exports.readCodexHistory = exports.walkRolloutFilesAsync = exports.walkRolloutFiles = exports.findCodexRolloutFile = exports.weekKey = exports.usageBucketKey = void 0;
|
|
11
|
+
exports.fetchProviderServiceStatus = exports.SYNTHETIC_MODEL = exports.createSessionProviders = exports.splitWatchedPath = exports.DirectoryListingCache = exports.fileFingerprintParts = exports.fileFingerprint = exports.observedSessionSourceFromProvider = exports.ObservedSessionCollector = exports.readSessionPreviewAsync = exports.readSessionPreview = exports.listSessionPreviewsAsync = exports.listSessionPreviews = exports.readCodexHistory = exports.walkRolloutFilesAsync = exports.walkRolloutFiles = exports.findCodexRolloutFile = exports.weekKey = exports.usageBucketKey = void 0;
|
|
12
12
|
var pricingCatalog_1 = require("./pricingCatalog");
|
|
13
13
|
Object.defineProperty(exports, "hydratePricingCatalog", { enumerable: true, get: function () { return pricingCatalog_1.hydratePricingCatalog; } });
|
|
14
14
|
Object.defineProperty(exports, "normalizeLiteLlmCatalog", { enumerable: true, get: function () { return pricingCatalog_1.normalizeLiteLlmCatalog; } });
|
|
@@ -96,5 +96,9 @@ Object.defineProperty(exports, "fileFingerprintParts", { enumerable: true, get:
|
|
|
96
96
|
var directoryListingCache_1 = require("./providers/directoryListingCache");
|
|
97
97
|
Object.defineProperty(exports, "DirectoryListingCache", { enumerable: true, get: function () { return directoryListingCache_1.DirectoryListingCache; } });
|
|
98
98
|
Object.defineProperty(exports, "splitWatchedPath", { enumerable: true, get: function () { return directoryListingCache_1.splitWatchedPath; } });
|
|
99
|
+
var factory_1 = require("./providers/factory");
|
|
100
|
+
Object.defineProperty(exports, "createSessionProviders", { enumerable: true, get: function () { return factory_1.createSessionProviders; } });
|
|
101
|
+
var claudeUsageDedupe_1 = require("./usage/claudeUsageDedupe");
|
|
102
|
+
Object.defineProperty(exports, "SYNTHETIC_MODEL", { enumerable: true, get: function () { return claudeUsageDedupe_1.SYNTHETIC_MODEL; } });
|
|
99
103
|
var providerServiceStatus_1 = require("./providerServiceStatus");
|
|
100
104
|
Object.defineProperty(exports, "fetchProviderServiceStatus", { enumerable: true, get: function () { return providerServiceStatus_1.fetchProviderServiceStatus; } });
|
|
@@ -78,6 +78,13 @@ export interface CollectUsageEventsOptions {
|
|
|
78
78
|
/** Skip the on-disk cache entirely. */
|
|
79
79
|
noCache?: boolean;
|
|
80
80
|
onDiagnostic?: (diagnostic: SessionProviderDiagnostic) => void;
|
|
81
|
+
/**
|
|
82
|
+
* Stops the collection before listing and between sessions; the promise
|
|
83
|
+
* rejects with the signal's reason (an `AbortError` by default). Sessions
|
|
84
|
+
* read before the abort keep their cache entries; no partial session is
|
|
85
|
+
* cached.
|
|
86
|
+
*/
|
|
87
|
+
signal?: AbortSignal;
|
|
81
88
|
}
|
|
82
89
|
export interface CollectUsageEventsResult {
|
|
83
90
|
/** Events within the window, oldest first. */
|
|
@@ -290,12 +290,15 @@ async function collectUsageEvents(options) {
|
|
|
290
290
|
const untilMs = toMs(options.until, 'until');
|
|
291
291
|
const cacheDir = options.cacheDir ?? getUsageCacheDir();
|
|
292
292
|
const useCache = !options.noCache;
|
|
293
|
+
const signal = options.signal;
|
|
294
|
+
signal?.throwIfAborted();
|
|
293
295
|
const listed = await (0, sessionPreviews_1.listSessionPreviewsAsync)(options.providers, {
|
|
294
296
|
since: options.since,
|
|
295
297
|
workspacePath: options.workspacePath,
|
|
296
298
|
limit: Number.MAX_SAFE_INTEGER,
|
|
297
299
|
concurrency: options.concurrency,
|
|
298
300
|
});
|
|
301
|
+
signal?.throwIfAborted();
|
|
299
302
|
const diagnostics = [...listed.diagnostics];
|
|
300
303
|
for (const diagnostic of listed.diagnostics)
|
|
301
304
|
options.onDiagnostic?.(diagnostic);
|
|
@@ -306,6 +309,7 @@ async function collectUsageEvents(options) {
|
|
|
306
309
|
let cacheMisses = 0;
|
|
307
310
|
let wroteCache = false;
|
|
308
311
|
for (const preview of listed.previews) {
|
|
312
|
+
signal?.throwIfAborted();
|
|
309
313
|
const provider = providerById.get(preview.provider);
|
|
310
314
|
if (!provider)
|
|
311
315
|
continue;
|