npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

sidekick-shared

v0.18.1

Published

Shared data access layer for Sidekick — readers, types, providers, credentials, quota

Readme

sidekick-shared

Shared data access library for Sidekick Agent Hub.

npm version license

Types, parsers, providers, readers, formatters, aggregation, search, reporting, credentials, and quota for AI agent session monitoring. Used by both the VS Code extension and the CLI dashboard.

Installation

npm install sidekick-shared

API Overview

| Module | Description | |--------|-------------| | Types | Session events, OpenCode/Codex format types, persistence schemas (tasks, decisions, notes, plans, historical data) | | Paths | Config directory resolution, project data paths, workspace encoding | | Readers | Read tasks, decisions, notes, history, handoff, and plans from ~/.config/sidekick/ | | Providers | Session provider abstraction with Claude Code, OpenCode, and Codex implementations; auto-detection via filesystem | | Parsers | JSONL event parsing, OpenCode/Codex format normalization, subagent scanning, session path resolution, debug log parsing | | Watchers | Live session file watching with event bridging, plus createJsonlTail() for raw incremental JSONL consumers | | Formatters | Display helpers (formatTokenCount(), formatDurationMs()), tool summary, noise classification, session dump (text/markdown/JSON), event highlighting | | Search | Cross-session full-text search, advanced filtering (substring, fuzzy, regex, date) | | Aggregation | Event aggregation, frequency tracking, activity heatmaps, pattern extraction | | Report | Self-contained HTML session report generation | | Credentials | Claude Max OAuth credential reading from ~/.claude/.credentials.json | | Quota | Claude Max subscription quota fetching (5-hour and 7-day windows) and Codex rate-limit extraction from event streams | | Provider Status | API health checking via status.claude.com and status.openai.com (indicator, components, incidents) | | Schemas | Zod schemas for runtime JSONL event validation (sessionEventSchema, messageUsageSchema, sessionMessageSchema) | | Extractors | Pure functions for single-event processing: extractTokenUsage(), extractToolCall() (top-level tool_use), extractToolCalls() (assistant content blocks) | | Model Info & Pricing | Model family parsing (Anthropic / OpenAI / Google, including legacy claude-3-opus-… and claude-3-5-sonnet-… IDs), context-window lookup (including Opus 4.7 / Sonnet 4.7 1M and GPT-5.x variants), pricing tables with optional LiteLLM hydration, null-aware cost (calculateCost()), provenance-preserving cost (calculateCostWithProvenance(), mergeCostSources()), and display helpers (shortModelName(), getModelDisplayInfo(), compareModelIds(), sortModelIds(), formatCost()) | | Quota Polling | QuotaPoller class with exponential backoff, active/idle intervals, and cached fallback | | Multi-Provider Quota | MultiProviderQuotaService orchestrates Claude polling + peak-hours + account labels + Codex quota updates behind one typed { claude?, codex? } event stream. CodexQuotaWatcher watches the active Codex rollout for live rate limits with snapshot fallback | | Accounts | Multi-provider account registry (v2) with per-provider active account, save/switch/remove, v1 migration, ensureDefaultAccounts() for first-run bootstrap of the active system Claude/Codex credentials as a "Default" saved account, and getActiveAccountStatus() for a single-pass active-account read across providers | | Codex Profiles | Codex account lifecycle — prepare, finalize, switch, remove — with isolated CODEX_HOME directories and multi-home monitoring support | | Quota Snapshots | Persistent quota caching per provider/account for offline fallback | | Phrases | Curated humorous phrases for loading/idle states, available as a flat ALL_PHRASES array or grouped via PHRASE_CATEGORIES for category-aware UI |

Supported import paths

sidekick-shared ships three public entry points plus a few convenience subpaths. Pick the one that matches your runtime.

| Path | Runtime | What it exposes | |-----------------------------------|-----------------------------|--------------------------------------------------------------------| | sidekick-shared | Node (CLI, extension host) | Full public API (readers, providers, parsers, pricing, …). | | sidekick-shared/browser | Browser / webview | Pure helpers: context-window lookup, model parsing, cost math. | | sidekick-shared/node | Node only | LiteLLM pricing catalog hydration (fs + path). | | sidekick-shared/phrases | Any runtime | Phrase arrays + getRandomPhrase(). | | sidekick-shared/modelContext | Any runtime | Direct access to the context-window module. | | sidekick-shared/modelInfo | Any runtime | Direct access to model parsing and cost math. | | sidekick-shared/formatting | Any runtime | Direct access to pure token and duration display helpers. |

Browser / webview runtimes

Import from sidekick-shared/browser. Do not import the package root from browser code — the root re-exports Node-only pricing hydration and can drag node:fs / node:path into your bundle.

import {
  getModelContextWindowSize,
  DEFAULT_CONTEXT_WINDOW,
  parseModelId,
  calculateCost,
  formatCost,
  formatTokenCount,
  formatDurationMs,
} from 'sidekick-shared/browser';

Node / CLI / extension host

Hydrate the pricing catalog from the node subpath:

import { hydratePricingCatalog } from 'sidekick-shared/node';

await hydratePricingCatalog({ cacheDir: '~/.config/sidekick' });

Usage Examples

Detect the active session provider

import { detectProvider } from 'sidekick-shared';

const provider = await detectProvider('/path/to/project');
if (provider) {
  console.log(`Active provider: ${provider.id}`);
  const sessions = await provider.listSessions();
}

Read persisted tasks

import { readTasks, getProjectSlug } from 'sidekick-shared';

const slug = getProjectSlug('/path/to/project');
const tasks = readTasks({ projectSlug: slug });
console.log(`Found ${tasks.length} tasks`);

Check provider status

import { fetchProviderStatus } from 'sidekick-shared';

const status = await fetchProviderStatus();
if (status.indicator !== 'none') {
  console.log(`Claude API: ${status.description}`);
  for (const c of status.affectedComponents) {
    console.log(`  ${c.name}: ${c.status}`);
  }
}

Check Claude peak-hours state

import { fetchPeakHoursStatus } from 'sidekick-shared';

// Third-party endpoint: promoclock.co/api/status (unaffiliated with Anthropic).
// Returns a `unavailable: true` fallback on any network or parse error.
const peak = await fetchPeakHoursStatus();
if (!peak.unavailable && peak.isPeak) {
  console.log(`${peak.label} — off-peak in ${peak.minutesUntilChange}m`);
}

Fetch subscription quota

import { fetchQuota, readClaudeMaxCredentials } from 'sidekick-shared';

const creds = readClaudeMaxCredentials();
if (creds) {
  const quota = await fetchQuota(creds.accessToken);
  if (quota.available) {
    console.log(`5-hour utilization: ${quota.fiveHour.utilization}%`);
  } else {
    console.log(quota.failureKind, quota.httpStatus, quota.retryAfterMs);
  }
}

Unavailable quota responses remain non-throwing and may include:

  • failureKind: auth | network | rate_limit | server | unknown
  • httpStatus: HTTP response status when available
  • retryAfterMs: retry delay in milliseconds for 429 responses when the API provides Retry-After

For first-party style messaging, describeQuotaFailure() maps unavailable quota states to stable alert keys plus display-ready severity/title/message/detail fields for CLI and VS Code consumers.

Model info and cost calculation

import { getModelInfo, calculateCost, formatCost } from 'sidekick-shared';

const info = getModelInfo('claude-sonnet-4-6-20260321');
console.log(info.family, info.version, info.contextWindow); // "sonnet" "4.6" 200000

const cost = calculateCost(
  { inputTokens: 1000, outputTokens: 500, cacheReadTokens: 200, cacheWriteTokens: 0 },
  'claude-sonnet-4-6-20260321',
);
console.log(formatCost(cost)); // "$0.0045"

Extract token usage and tool calls from events

import { extractTokenUsage, extractToolCall, extractToolCalls } from 'sidekick-shared';

const usage = extractTokenUsage(event);          // TokenUsage | null
const tools = extractToolCalls(event);           // ToolCall[]    — assistant content blocks
const toolFromEvent = extractToolCall(event);    // ToolCall | null — top-level `tool_use` events

Format shared dashboard values

import { formatTokenCount, formatDurationMs, formatCost } from 'sidekick-shared';

console.log(formatTokenCount(15_000)); // "15.0k"
console.log(formatDurationMs(330_000)); // "5m 30s"
console.log(formatCost(0.0045)); // "$0.0045"

Validate JSONL events with Zod schemas

import { JsonlParser, sessionEventSchema } from 'sidekick-shared';

const parser = new JsonlParser(
  { onEvent: (e) => console.log(e), onError: (e) => console.warn(e) },
  { schema: sessionEventSchema },
);
parser.processChunk(rawData);

Tail raw JSONL events incrementally

Use createJsonlTail() when a consumer needs raw parsed events and owns its own aggregation lifecycle. onBatchComplete fires once after each drained byte chunk, which lets callers defer expensive UI or metrics updates until parsing for that chunk is complete.

import { createJsonlTail, sessionEventSchema } from 'sidekick-shared';

const tail = createJsonlTail({
  path: '/path/to/session.jsonl',
  schema: sessionEventSchema,
  onEvent: event => aggregator.processEvent(event),
  onBatchComplete: () => renderMetrics(aggregator.getMetrics()),
  onError: error => console.warn(error.message),
});

tail.start();

Poll quota with backoff

import { QuotaPoller } from 'sidekick-shared';

const poller = new QuotaPoller({
  activeIntervalMs: 300_000,
  idleIntervalMs: 300_000,
  getAccessToken: async () => token,
});
poller.onUpdate((state) => console.log(state));
poller.start();

Orchestrate quota across Claude and Codex

import { MultiProviderQuotaService } from 'sidekick-shared';

const service = new MultiProviderQuotaService({
  // Optional — when set, an internal CodexQuotaWatcher is created and managed.
  codexWorkspacePath: '/path/to/project',
});

service.onUpdate(({ claude, codex }) => {
  if (claude) console.log('Claude:', claude.fiveHour.utilization, claude.peakHours?.label);
  if (codex)  console.log('Codex:',  codex.fiveHour.utilization, codex.accountLabel);
});

service.startPolling();
// service.setPollingMode('active'); // tighter cadence while a session is live
// service.updateProviderQuota('codex', codexQuota); // externally push Codex quota snapshots
// service.dispose();

Or run the Codex watcher standalone (e.g. inside an existing polling loop):

import { CodexQuotaWatcher } from 'sidekick-shared';

const watcher = new CodexQuotaWatcher('/path/to/project');
watcher.onUpdate((state) => console.log(state.fiveHour.utilization, state.accountLabel));
watcher.start();

Read active account status across providers

import { getActiveAccountStatus } from 'sidekick-shared';

const status = getActiveAccountStatus();
if (!status.ok) console.log('No saved account active');
console.log(status.claude.present, status.claude.email);
console.log(status.codex.present, status.codex.label);

Track cost provenance for honest UI rollups

import { calculateCostWithProvenance, mergeCostSources, formatCost } from 'sidekick-shared';

const a = calculateCostWithProvenance({
  usage: { inputTokens: 1_000_000, outputTokens: 500_000, cacheReadTokens: 0, cacheWriteTokens: 0 },
  modelId: 'claude-sonnet-4-20250514',
  reportedCostUsd: 1.23, // provider-reported when available — wins over local estimate
});
const b = calculateCostWithProvenance({
  usage: { inputTokens: 200_000, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 },
  modelId: 'unknown-model', // no pricing → { source: 'unpriced' }
});

const total = (a.costUsd ?? 0) + (b.costUsd ?? 0);
const totalSource = mergeCostSources(a.source, b.source); // 'unpriced' wins (least certain)
console.log(formatCost(total), totalSource);

Deferred Contextful adoption note

[email protected] already exposes the quota primitives Contextful needs: MultiProviderQuotaService, ProviderQuotaMap, ProviderQuotaState, and CodexQuotaWatcher. Contextful should keep its local integration unchanged until a newer sidekick-shared release is published to npm, then migrate thin wrappers to these public APIs plus formatTokenCount(), formatDurationMs(), and createJsonlTail().

Building

npm run build

Compiles TypeScript to dist/ via tsc.

Testing

npm test

Uses Vitest. Run npm run test:watch for watch mode.

See Also

License

MIT