Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

sidekick-shared

Package Overview
Dependencies
Maintainers
1
Versions
28
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

sidekick-shared

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

latest
npmnpm
Version
0.18.4
Version published
Weekly downloads
190
-41.36%
Maintainers
1
Weekly downloads
 
Created
Source

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

ModuleDescription
TypesSession events, OpenCode/Codex format types, persistence schemas (tasks, decisions, notes, plans, historical data)
PathsConfig directory resolution, project data paths, workspace encoding
ReadersRead tasks, decisions, notes, history, handoff, and plans from ~/.config/sidekick/
ProvidersSession provider abstraction with Claude Code, OpenCode, and Codex implementations; auto-detection via filesystem
ParsersJSONL event parsing, OpenCode/Codex format normalization, subagent scanning, session path resolution, debug log parsing
WatchersLive session file watching with event bridging, plus createJsonlTail() for raw incremental JSONL consumers
FormattersDisplay helpers (formatTokenCount(), formatDurationMs()), tool summary, noise classification, session dump (text/markdown/JSON), event highlighting
SearchCross-session full-text search, advanced filtering (substring, fuzzy, regex, date)
AggregationEvent aggregation, frequency tracking, activity heatmaps, pattern extraction
ReportSelf-contained HTML session report generation
CredentialsClaude Max OAuth credential reading from ~/.claude/.credentials.json
QuotaClaude Max subscription quota fetching (5-hour and 7-day windows) and Codex rate-limit extraction from event streams
Provider StatusAPI health checking via status.claude.com and status.openai.com (indicator, components, incidents)
SchemasZod schemas for runtime JSONL event validation (sessionEventSchema, messageUsageSchema, sessionMessageSchema)
ExtractorsPure functions for single-event processing: extractTokenUsage(), extractToolCall() (top-level tool_use), extractToolCalls() (assistant content blocks)
Model Info & PricingModel 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 PollingQuotaPoller class with exponential backoff, active/idle intervals, and cached fallback
Multi-Provider QuotaMultiProviderQuotaService 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
AccountsMulti-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 ProfilesCodex account lifecycle — prepare, finalize, switch, remove — with isolated CODEX_HOME directories and multi-home monitoring support
Quota SnapshotsPersistent quota caching per provider/account for offline fallback
PhrasesCurated 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.

PathRuntimeWhat it exposes
sidekick-sharedNode (CLI, extension host)Full public API (readers, providers, parsers, pricing, …).
sidekick-shared/browserBrowser / webviewPure helpers: context-window lookup, model parsing, cost math.
sidekick-shared/nodeNode onlyLiteLLM pricing catalog hydration (fs + path).
sidekick-shared/phrasesAny runtimePhrase arrays + getRandomPhrase().
sidekick-shared/modelContextAny runtimeDirect access to the context-window module.
sidekick-shared/modelInfoAny runtimeDirect access to model parsing and cost math.
sidekick-shared/formattingAny runtimeDirect 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

sidekick-shared@0.18.x 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

FAQs

Package last updated on 27 May 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts