sidekick-shared 0.24.3 → 0.24.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 +412 -0
- package/LICENSE +21 -0
- package/README.md +87 -16
- package/dist/index.d.ts +3 -3
- package/dist/index.js +12 -7
- package/dist/modelInfo.js +11 -2
- package/dist/observedContextWindows.d.ts +7 -4
- package/dist/observedContextWindows.js +34 -7
- package/dist/paths.d.ts +36 -1
- package/dist/paths.js +59 -3
- package/dist/peakHours.d.ts +16 -2
- package/dist/peakHours.js +18 -3
- package/dist/pricingCatalog.d.ts +7 -3
- package/dist/pricingCatalog.js +3 -2
- package/dist/zaiQuota.d.ts +87 -0
- package/dist/zaiQuota.js +49 -0
- package/dist/zaiQuotaWatcher.d.ts +7 -0
- package/dist/zaiQuotaWatcher.js +3 -0
- package/package.json +60 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to sidekick-shared will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.24.4] - 2026-07-25
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- `fetchPeakHoursStatus()` had no request timeout. It was the only network call in the package without one, it targets a third-party host (promoclock.co), and `MultiProviderQuotaService` calls it on every poll, so a hung host stalled the caller indefinitely and repeatedly. It now uses the same abort-timeout shape as every other fetch here, configurable via `FetchPeakHoursOptions.timeoutMs` (default 10s)
|
|
13
|
+
- `recordObservedContextWindow()` deduplicated its write against the process-global override table from `modelContext`, which is not keyed by `cacheDir`. Two cache directories in one process — two temp dirs in a test suite, a multi-tenant host, a CLI and extension host sharing a process — meant the second store was silently never written. The same early return also swallowed retries: because the global was updated before the write was attempted, a transient `EACCES` left the value marked as recorded and no later call tried again. The persistence dedupe is now keyed by resolved store path and recorded only after a successful write
|
|
14
|
+
- `parseModelId()` reported version `"4"` for every hyphenated Anthropic model ID (`claude-sonnet-4-6-20260321`, `claude-sonnet-4-5-20250929`, `claude-opus-4-1-20250805`). The version pattern accepted dots but not hyphens, while the adjacent legacy pattern already normalized both. Pricing and context windows are unaffected — both resolve from the full ID by longest-prefix match — but `parseModelId().version`, `getModelInfo().version`, and the version ordering behind model comparison all change, where 4.5 and 4.6 previously tied at `"4"`
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- The config directory is now overridable. `setConfigDir()` redirects it for the process and `SIDEKICK_CONFIG_DIR` does the same from the environment, with `getDefaultConfigDir()` exposing the unmodified platform default. Both routes trim their input, so a padded value resolves to the same root rather than to a relative path under the current directory. Every reader, writer, account-registry path, quota snapshot, and migration resolves the root lazily through `getConfigDir()`, so a single seam covers the whole package. Consumers previously had no way to point the library anywhere but `~/.config/sidekick`, which blocked test isolation, sandboxing, and multi-tenant use
|
|
19
|
+
- The published tarball ships `LICENSE` and `CHANGELOG.md`. `files: ["dist"]` excluded both, and npm only auto-includes a LICENSE from the package directory — so the MIT declaration in `package.json` shipped with nothing behind it
|
|
20
|
+
- `repository` (with `directory`, so npm's source link lands on this package), `homepage`, `bugs`, `keywords`, `author`, and `engines` are declared
|
|
21
|
+
- `typesVersions` maps every non-wildcard `exports` subpath for consumers whose tsconfig still uses `moduleResolution: "node"`, which cannot read `exports` maps at all. Modern resolvers ignore it entirely
|
|
22
|
+
- Every export of the legacy z.ai estimator (`zaiQuota`, `zaiQuotaWatcher`) is marked `@deprecated`. The deprecation was previously recorded in module prose only, so consumers reaching it through the `./dist/*` wildcard got no editor signal
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- `engines` declares Node >= 20, driven by zod 4 and matching the sibling CLI. It is advisory unless a consumer sets `engine-strict`, but it will surface an `EBADENGINE` warning on Node 18
|
|
27
|
+
- `HydrateOptions.cacheDir` is optional and defaults to the config directory, so pricing hydration follows the same override seam
|
|
28
|
+
|
|
29
|
+
### Documentation
|
|
30
|
+
|
|
31
|
+
- Four README examples were wrong and are corrected: `readTasks` was shown with the wrong first argument and no `await`; `readClaudeMaxCredentials` was shown without `await`, so the always-truthy Promise made `accessToken` undefined and surfaced later as an auth failure; the documented context window was 200000 rather than 1000000; and the documented cost output was never reachable from the stated inputs
|
|
32
|
+
- The headline cost example uses `normalizeProviderUsage` and `calculateNormalizedUsageCost` instead of the deprecated `calculateCost`
|
|
33
|
+
- The external `sqlite3` requirement is documented. `OpenCodeProvider` and `CodexProvider` shell out to it and return empty results rather than an error when it is missing, which is indistinguishable from an empty workspace unless the consumer knows to call `getRuntimeStatus()`
|
|
34
|
+
|
|
35
|
+
## [0.24.3] - 2026-07-24
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
- Static pricing for `gpt-5.6-luna` ($1/$6 in/out, $1.25/$0.10 cache write/read). Without an entry of its own, `getModelPricing('gpt-5.6-luna')` longest-prefix-matched `gpt-5.6` and returned `gpt-5.6-sol`'s $5/$30 — roughly 5× too high, and indistinguishable from a correct result at the call site
|
|
40
|
+
- Static pricing for `gpt-5.5-pro` and `gpt-5.4-pro` ($30/$180 each) and `gpt-5.4-nano` ($0.20/$1.25), which inherited `gpt-5.5` and `gpt-5.4` the same way. Rates verified against the LiteLLM catalog's bare top-level keys
|
|
41
|
+
- `getModelPricing('claude-sonnet-5')` returned $3/$15 against its actual $2/$10 (cache write $2.50, cache read $0.20). The entry assumed the $3/$15 shared by every earlier Sonnet; all eleven Sonnet 5 rows in the catalog agree on $2/$10
|
|
42
|
+
- A sweep of every bare catalog key against the static table found twelve more chat models resolving through a shorter prefix. New entries: `gpt-5-mini`, `gpt-5-nano`, `gpt-5-pro`, `gpt-5.1-codex-mini`, `gpt-5.2`, `gpt-5.2-pro`, `gpt-5.3-chat-latest`, `gpt-4.1-mini`, `gpt-4.1-nano`, `gpt-4o-2024-05-13`, `o1-pro`, `o3-pro`, and `o3-deep-research`. Overstatements reached 25× (`gpt-5-nano`) and understatements 17× (`gpt-5.2-pro`)
|
|
43
|
+
- Corrected values on two keys that already existed: `gpt-5.3-codex` to $1.75/$14 and `o1-mini` to $1.10/$4.40. No bare catalog key settles `o1-mini` — Azure's $1.21/$4.84 is its standard 1.1× uplift on that rate, and Replicate's OpenAI passthrough reports it directly
|
|
44
|
+
- Because keys are matched longest-first, each new entry also captures its own dated and fine-tuned variants — `gpt-5.6-luna-20260501` now resolves to Luna rather than to `gpt-5.6`, and one `gpt-5.2` entry covers `gpt-5.2-codex` and the `gpt-5.2-chat*` ids, which bill at the same rate
|
|
45
|
+
|
|
46
|
+
### Added
|
|
47
|
+
|
|
48
|
+
- `MODEL_CONTEXT_SIZES` entry for `gpt-5.6-luna` at its published 1,050,000 maximum. The value equals what the `gpt-5.6` prefix already returned; it is pinned so a later edit to that entry cannot silently move Luna. Observed per-tier windows still outrank it
|
|
49
|
+
|
|
50
|
+
### Notes
|
|
51
|
+
|
|
52
|
+
- The `-tts`, `-transcribe`, and `-realtime-preview` variants of `gpt-4o`/`gpt-4o-mini` also bill above the key they inherit and are deliberately not carried in the static table: no coding agent routes to them, and catalog hydration prices them correctly. `gpt-5.3` keeps an estimated rate because the catalog ships no bare key for it
|
|
53
|
+
|
|
54
|
+
## [0.24.2] - 2026-07-24
|
|
55
|
+
|
|
56
|
+
### Added
|
|
57
|
+
|
|
58
|
+
- `hydratePricingCatalog()` also builds a context-window override map from the LiteLLM catalog's `max_input_tokens`, so new models resolve without a code change. `HydrateResult` gains `contextWindowEntries`
|
|
59
|
+
- `normalizeLiteLlmContextWindows()` — catalog payload to model → context-window map, exported alongside `normalizeLiteLlmCatalog()`
|
|
60
|
+
- `loadObservedContextWindows()`, `recordObservedContextWindow()`, and `getObservedContextWindowPath()` on `sidekick-shared/node` — a persisted record of the context window a provider actually reported, which outranks the catalog's published maximum. The Codex provider records it from `model_context_window` on `token_count` events
|
|
61
|
+
- Static pricing for `claude-opus-5`, `claude-sonnet-5`, `gpt-5.6`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.5`, and `gpt-5.4-mini`. Sonnet 5 carries the standard $3/$15 rather than the introductory rate, which arrives via hydration
|
|
62
|
+
|
|
63
|
+
### Changed
|
|
64
|
+
|
|
65
|
+
- `getModelContextWindowSize()` resolution is `[1m]` marker → observed → catalog → static, and tries every layer for an exact match before any layer's prefix match. `GPT-5.4` pricing is corrected to its published $2.50/$15
|
|
66
|
+
- Cache files written before this release have no `contextWindows` key and still load; they contribute no context overrides until the next refresh
|
|
67
|
+
|
|
68
|
+
### Fixed
|
|
69
|
+
|
|
70
|
+
- An exact entry in the static table is no longer shadowed by a catalog key that happens to be a prefix of the model ID. The catalog has no `claude-sonnet-4-7`, so Sonnet 4.7 was resolving through `claude-sonnet-4` to 128K instead of its real 1,000,000
|
|
71
|
+
- `normalizeLiteLlmContextWindows()` drops a bare-model alias when the `provider/model` entries behind it disagree, rather than taking whichever appeared first in the JSON. A `provider/model` entry describes that provider's deployment window — often a truncation — and the live catalog carries five conflicting windows for `claude-sonnet-4`, from GitHub Copilot's 128K to Vertex's 1M. A top-level catalog entry always wins over a derived alias
|
|
72
|
+
|
|
73
|
+
## [0.24.1] - 2026-07-22
|
|
74
|
+
|
|
75
|
+
### Added
|
|
76
|
+
|
|
77
|
+
- Canonical transcripts retain provider/session provenance for safe human-prompt filtering, including entrypoint, meta/sidechain flags, original message roles, cwd, and git branch
|
|
78
|
+
- Provider-backed observed-session collection sources expose their adapter's `ProviderCapabilitiesV1` record
|
|
79
|
+
|
|
80
|
+
## [0.24.0] - 2026-07-22
|
|
81
|
+
|
|
82
|
+
### Added
|
|
83
|
+
|
|
84
|
+
- `normalizeProviderUsage()`, `extractNormalizedUsage()`, and `calculateNormalizedUsageCost()` with explicit cache/reasoning semantics and pricing provenance
|
|
85
|
+
- `estimateTextTokens()` / `estimateSerializedTokens()`, canonical transcript/history APIs, transcript schemas, and `ObservedSessionCollector`
|
|
86
|
+
|
|
87
|
+
### Changed
|
|
88
|
+
|
|
89
|
+
- `SessionEvent` and its Zod schema are discriminated; valid message-less summaries and nested progress envelopes parse directly
|
|
90
|
+
- Claude Code, Codex, OpenCode, report transcripts, observed sessions, and EventAggregator share normalized usage and canonical projection paths
|
|
91
|
+
- Aggregator snapshots advance to schema v4 so older ambiguous-cost snapshots are replayed from source events
|
|
92
|
+
- Provider-reported session costs — including zero — are authoritative and skip catalog pricing, so subscription sessions that report $0 display $0 instead of a catalog estimate
|
|
93
|
+
- `ObservedAgentSessionV1` `usage.costUsd` is now nullable for unpriced usage (still `schemaVersion: 1`); validators built against the earlier number-only shape should accept `null`
|
|
94
|
+
|
|
95
|
+
### Deprecated
|
|
96
|
+
|
|
97
|
+
- `calculateCost()`, `calculateCostWithPricing()`, `calculateCostWithProvenance()`, `CostTokenUsage`, and `CostProvenanceInput` retain their legacy reasoning-additive behavior for compatibility
|
|
98
|
+
|
|
99
|
+
## [0.23.1] - 2026-07-21
|
|
100
|
+
|
|
101
|
+
### Security
|
|
102
|
+
|
|
103
|
+
- Markdown report links refuse `javascript:`/`data:` URLs, and browser opening spawns the platform opener with argument arrays instead of an interpolated shell string
|
|
104
|
+
|
|
105
|
+
### Fixed
|
|
106
|
+
|
|
107
|
+
- **2026-07 review backlog (shared portion)**: crash guards across parsers, watchers, and readers for malformed rows; index-safe SQL substitution; hardened atomic writers and quota snapshot persistence; and hardened quota polling and provider watchers
|
|
108
|
+
- **Observed-session message-less events**: `derivePendingUserRequestV1()` now tolerates Claude Code summary and other bookkeeping rows without a `message`, continues scanning for unresolved requests, and retains top-level tool requests with a stable event-index fallback ID
|
|
109
|
+
- Hyphenated `claude-opus-4-5` model IDs price at Opus 4.5 rates instead of falling back to legacy Opus pricing, and Codex cache tokens are counted once in usage rollups
|
|
110
|
+
- macOS keychain credential writes escape the secret correctly for the `security -i` tokenizer (single quotes and backslashes in stored JSON no longer corrupt the entry), and the secret is passed over stdin instead of argv
|
|
111
|
+
|
|
112
|
+
### Changed
|
|
113
|
+
|
|
114
|
+
- Token metric definitions are more truthful: Codex `input_tokens` excludes cached input, per-model totals include cache read/write tokens, and follow-event message counts include only user/assistant messages — dashboard numbers may shift after upgrade
|
|
115
|
+
|
|
116
|
+
## [0.23.0] - 2026-07-18
|
|
117
|
+
|
|
118
|
+
### Added
|
|
119
|
+
|
|
120
|
+
- **Observed-session V1 public API**: `ProviderSessionAdapterV1`, `ObservedAgentSessionV1`, `ProviderCapabilitiesV1`, `PendingUserRequestV1`, `SessionEvidenceRefV1`, provenance/confidence values, adapters for all session providers, and corresponding Zod schemas
|
|
121
|
+
- **Shared operational primitives**: atomic and lock-coordinated task/decision/note writers, canonical project identity, typed doctor reports, status-line and burn-rate formatting, identifier-only external-handoff URL rendering, and a public `SessionMonitor`
|
|
122
|
+
- **Analytics engines**: categorized per-tool/hour/model failure rollups and append-only error history, beta quality scoring with weekly trends, historical schema v3 session records, code-impact and per-model churn/cost metrics, and compaction-ledger estimates
|
|
123
|
+
- **Consumer contract tests** for quota, accounts, sessions, assets, costs, turn/reasoning, and observed-session APIs
|
|
124
|
+
|
|
125
|
+
### Changed
|
|
126
|
+
|
|
127
|
+
- Codex compaction events retain exact before/after counts with reported/heuristic provenance; aggregator snapshots advance to v3; heuristic compactions are recorded once and completed with the next observed context size instead of double-counting
|
|
128
|
+
- Shared ingest owns tool-error taxonomy across Claude Code, OpenCode, and Codex; OpenCode provider errors, retries, and finish reasons are normalized for analytics
|
|
129
|
+
- Canonical symlink-aware project identity replaces duplicated slug probing; OpenCode SQL substitution is index-safe; Codex/OpenCode database row shapes have one source
|
|
130
|
+
- Legacy raw-slug project stores migrate automatically to the canonical slug on first write (`migrateLegacyProjectStores`), so symlinked workspaces keep their existing tasks, decisions, notes, and handoffs
|
|
131
|
+
- Plan aggregation now records per-step start/completion time, duration, tokens, tool calls, and cost
|
|
132
|
+
|
|
133
|
+
### Removed
|
|
134
|
+
|
|
135
|
+
- **Potentially breaking**: deprecated observed-traffic z.ai estimator exports were removed from the package root. Use `resolveZaiQuota()` and the authoritative quota API surface instead
|
|
136
|
+
|
|
137
|
+
## [0.22.0] - 2026-07-02
|
|
138
|
+
|
|
139
|
+
### Changed
|
|
140
|
+
|
|
141
|
+
- **Version bump to 0.22.0**: No functional changes. This release only keeps the shared library in lockstep with the VS Code extension and CLI (which ship user-facing changes this cycle); the published API and behavior are identical to 0.21.6
|
|
142
|
+
|
|
143
|
+
## [0.21.6] - 2026-07-02
|
|
144
|
+
|
|
145
|
+
### Added
|
|
146
|
+
|
|
147
|
+
- **Codex reset credits**: New `fetchCodexResetCreditsFromApi()` reads ChatGPT's `wham/rate-limit-reset-credits` endpoint and returns a `CodexResetCreditsSnapshot` (available count plus per-credit title/status/expiry), with the new `CodexResetCredit` / `CodexResetCreditsSnapshot` types and `codexResetCreditSchema` / `codexResetCreditsSnapshotSchema` Zod validators. `fetchCodexQuotaFromApi()` now attaches this snapshot to the returned `QuotaState` (`resetCredits`), authenticating with the Codex `auth.json` `account_id` (sent as `ChatGPT-Account-ID`) when present. `writeQuotaSnapshot`, the `CodexQuotaWatcher`, and the Codex session provider preserve an existing reset-credits snapshot when a session-sourced write omits it (Codex-only), so local session updates never wipe API-fetched credits. Degrades gracefully — every reset-credit fetch failure is swallowed and leaves the quota otherwise intact
|
|
148
|
+
|
|
149
|
+
## [0.21.5] - 2026-06-30
|
|
150
|
+
|
|
151
|
+
### Added
|
|
152
|
+
|
|
153
|
+
- **`isAggregateCodexLimit(limitId)`**: Exported helper that identifies the aggregate Codex plan-quota family (`limit_id` `codex`, or absent on older payloads) versus model/feature-specific families (e.g. `codex_bengalfox`, `premium`)
|
|
154
|
+
|
|
155
|
+
### Fixed
|
|
156
|
+
|
|
157
|
+
- **Prefer the aggregate Codex rate-limit family over model-specific ones**: Codex emits multiple rate-limit families per session keyed by `limit_id` — the aggregate plan quota plus per-model/feature families that can read 0% while the plan is busy. Every local-data selector previously read "the latest `rate_limits`" without inspecting `limit_id`, so a freshly-used per-model family at 0% with a later-resetting window could win the newest-window comparison and mask the real plan quota. The aggregate family is now ranked first in every selection site — `readLatestQuotaFromRollout`, the live `CodexRolloutParser`, the cross-file `isPreferredQuotaHit` ranker, and the `shouldKeepExistingSnapshot` retention guard — falling back to a model-specific sample only when no aggregate one exists. No-op for Claude (no `limit_id`) and z.ai (`zai-*`), where every sample shares the same aggregate-ness
|
|
158
|
+
|
|
159
|
+
## [0.21.4] - 2026-06-30
|
|
160
|
+
|
|
161
|
+
### Fixed
|
|
162
|
+
|
|
163
|
+
- **Live-first active-account resolution**: New `resolveActiveClaudeAccount()` / `resolveActiveCodexAccount()` and the `ResolvedActiveAccount` type resolve the currently logged-in account from the live provider auth (`~/.claude/.claude.json` oauthAccount; the `~/.codex/auth.json` id_token JWT — a cheap JWT decode, never the slow `codex login status` subprocess) and fall back to the saved registry. On an unambiguous match they self-heal the stale active pointer (best-effort, never throwing, never creating or deleting profiles) so quota history and auto-switch track the real account. `getActiveAccountStatus()`, the multi-provider Claude path, and the Codex quota watcher now route through them
|
|
164
|
+
|
|
165
|
+
## [0.21.3] - 2026-06-23
|
|
166
|
+
|
|
167
|
+
### Added
|
|
168
|
+
|
|
169
|
+
- **Quota projection helpers**: New exported `projectQuotaWindow()` and `withQuotaProjections()`, plus the `FIVE_HOUR_WINDOW_MS` / `SEVEN_DAY_WINDOW_MS` constants and the `QuotaProjectionInput` type, generalize the previously Claude-only end-of-window utilization projection. Codex (`quotaFromCodexRateLimits`, using each window's real `window_minutes`) and z.ai (`quotaStateFromZaiQuotaLimitPayload`) quota states now populate `projectedFiveHour` / `projectedSevenDay`. Projection is idempotent (it only fills fields that are still null, so it never double-counts) and honors a `capturedAt` timestamp so cached snapshots project from capture time
|
|
170
|
+
|
|
171
|
+
### Fixed
|
|
172
|
+
|
|
173
|
+
- **Bounded synchronous CLI probes**: Every synchronous `execFileSync` / `spawnSync` / `execSync` probe — keychain reads/writes (`credentialIO`, `claudeProfiles`), Codex login status and `pgrep` (`codexProfiles`), `git rev-list` (`providers/openCode`), and `sqlite3` (`providers/codexDatabase`, `providers/openCodeDatabase`) — now runs with `timeout: 4000` and `killSignal: 'SIGKILL'`, so a hung CLI, keychain prompt, or database can no longer block the caller indefinitely
|
|
174
|
+
|
|
175
|
+
### Security
|
|
176
|
+
|
|
177
|
+
- **npm audit**: Bumped `vitest` to `^4.1.9` to clear reported dev-dependency advisories
|
|
178
|
+
|
|
179
|
+
## [0.21.2] - 2026-06-22
|
|
180
|
+
|
|
181
|
+
### Changed
|
|
182
|
+
|
|
183
|
+
- **Authoritative z.ai quota API**: new `zaiQuotaApi.ts` reads z.ai's `api/monitor/usage/quota/limit` endpoint and exports `resolveZaiQuota()`, `fetchZaiQuotaFromApi()`, `readZaiCredentials()`, and `quotaStateFromZaiQuotaLimitPayload()`, mapping the returned `TOKENS_LIMIT` percentages and `nextResetTime` values into the 5-Hour / Weekly `QuotaState` model. Credentials are discovered from OpenCode's stored `zai-coding-plan` → `zai` token, then `ANTHROPIC_BASE_URL` / `ANTHROPIC_AUTH_TOKEN`; API failures fall back to a cached snapshot
|
|
184
|
+
- **Deprecated observed-traffic estimator**: `zaiQuota.ts` and `zaiQuotaWatcher.ts` (and their exports — `accumulateZaiUsage`, `inferZaiQuotaState`, `resolveZaiTier`, `ZaiQuotaWatcher`, `ZAI_TIER_BUDGETS`, …) remain available for compatibility but are no longer used for product quota display
|
|
185
|
+
|
|
186
|
+
## [0.21.1] - 2026-06-21
|
|
187
|
+
|
|
188
|
+
### Added
|
|
189
|
+
|
|
190
|
+
- **z.ai Coding Plan quota derivation**: New `zaiQuota.ts` and `zaiQuotaWatcher.ts` modules derive an estimated `QuotaState` for z.ai coding plans from OpenCode assistant turns tagged `providerID ∈ {zai, zai-coding-plan}`. Because z.ai exposes no quota/usage HTTP API (verified against `docs.z.ai/openapi.json`), utilization is computed by accumulating per-turn tokens into 5-hour and 7-day rolling windows and comparing against the published per-tier prompt budgets (Lite 80/400, Pro 400/2000, Max 1600/8000 prompts per 5h/week). Authoritative reset timestamps are extracted from trapped `1308`/`1310`/`1313`/`1309` business error codes when present. Exports include `accumulateZaiUsage()`, `inferZaiQuotaState()`, `parseZaiQuotaError()`, `resolveZaiTier()`, `ZaiQuotaWatcher`, `ZAI_TIER_BUDGETS`, and `ZAI_PROMPT_INVOCATIONS`
|
|
191
|
+
- **`OpenCodeProvider.getZaiQuotaState()`**: The shared OpenCode provider now derives z.ai quota on demand from the on-disk `opencode.db`. `OpenCodeSessionProvider.getQuotaFromSession()` (VS Code wrapper) wires the derived state into the existing session-based quota pipeline so the dashboard, snapshot, and history see z.ai samples automatically
|
|
192
|
+
- **`OpenCodeDatabase.getAssistantMessagesByProviderId()`**: New query method returns assistant rows tagged with the given providerID(s), used by the z.ai accumulator to walk per-turn token records
|
|
193
|
+
- **Runtime quota provider `'zai'`**: `RuntimeQuotaProvider`, `QuotaHistoryRuntimeProvider`, `QuotaState.providerId`, `ProviderQuotaMap`, and the corresponding Zod schemas all accept `'zai'`. `MultiProviderQuotaService` accepts an optional `zaiWatcher` and a new `updateProviderQuota('zai', …)` overload. `QuotaSnapshotProviderId` widens the snapshot store key to `AccountProviderId | 'zai'` so the derived z.ai quota persists across sessions
|
|
194
|
+
- **`getOpenCodeDataDir()` exported**: Now a public helper
|
|
195
|
+
|
|
196
|
+
### Fixed
|
|
197
|
+
|
|
198
|
+
- **OpenCode data directory resolution**: `getOpenCodeDataDir()` (now exported) probes both the macOS-default `~/Library/Application Support/opencode` and Linux-style `~/.local/share/opencode` candidate paths and returns whichever actually contains `opencode.db`. Previously it returned the platform default unconditionally, which failed on machines where OpenCode writes to the Linux-style path even on macOS
|
|
199
|
+
|
|
200
|
+
### Limitations
|
|
201
|
+
|
|
202
|
+
- z.ai quota is **estimated, not authoritative**: it is derived only from OpenCode traffic observed on this machine (z.ai exposes no usage API) and compared against provisional per-tier prompt budgets (`ZAI_PROMPT_INVOCATIONS` is a midpoint estimate, not validated). z.ai is **observed-only** — there is no z.ai inference provider and no z.ai account management in this release (`zaiQuotaWatcher.ts`: "z.ai has no full account management in v1"). Auto-tier resolution under-reports early in a weekly cycle; reset times are approximate unless a `1308`/`1310`/`1313`/`1309` error is trapped
|
|
203
|
+
|
|
204
|
+
## [0.21.0] - 2026-06-21
|
|
205
|
+
|
|
206
|
+
### Added
|
|
207
|
+
|
|
208
|
+
- **Account Management 2.0 acquisition facade**: New provider-neutral helpers `beginAccountLogin()`, `getAccountLoginStatus()`, `finalizeAccountLogin()`, and `spawnAccountLogin()` let hosts acquire Claude Max and Codex accounts through isolated profile directories before activating them
|
|
209
|
+
- **Provider-neutral account switching**: `listAllAccounts()` and `switchAccount()` expose a single surface over Claude saved accounts and Codex saved profiles. Claude switching now applies canonical profile homes back to the live Claude home, with legacy flat-backup migration handled by `reconcileClaudeAuthState()`
|
|
210
|
+
- **Claude profile primitives**: `getClaudeProfilesDir()`, `getClaudeProfileHome()`, `claudeKeychainSuffix()`, `claudeKeychainService()`, `isClaudeProfileAuthenticated()`, and `readClaudeProfileIdentity()` are exported for hosts that need lower-level profile inspection
|
|
211
|
+
- **Terminal sync helpers**: Opt-in terminal account pointers, shell hook installation/removal, and launcher creation/removal are available through `setTerminalActiveProfile()`, `installShellHook()`, `uninstallShellHook()`, `isShellHookInstalled()`, `writeLauncher()`, and `removeLauncher()`
|
|
212
|
+
- **Quota auto-switch primitives**: `decideAutoSwitch()` and `AutoSwitchController` provide a default-off policy for switching to a healthier saved account after quota crosses a configured threshold
|
|
213
|
+
- **Account Zod schemas**: `sidekick-shared/schemas` and the package root now export `accountProviderIdSchema`, `beginAccountLoginResultSchema`, `accountLoginStatusSchema`, `accountManagerResultSchema`, `accountEntrySchema`, `savedAccountProfileSchema`, and `listAllAccountsResultSchema`
|
|
214
|
+
|
|
215
|
+
## [0.20.0] - 2026-06-17
|
|
216
|
+
|
|
217
|
+
### Added
|
|
218
|
+
|
|
219
|
+
- **Actionable session asset extraction**: New Node-only APIs for extracting URLs, filesystem-validated file paths, commands the agent suggested for the user to run, and plan-mode plans from recent Claude Code and Codex sessions for exactly one cwd. `gatherAssetsForCwd()` merges supported agents with recency sorting, dedupe, and per-type caps; `readClaudeAssets()`, `readCodexAssets()`, `claudeSessions()`, `codexSessions()`, `extractUrls()`, `extractFilePaths()`, and `extractCommands()` are exported for lower-level use. These APIs are safe for CLI and VS Code extension-host code, but not for browser/webview bundles
|
|
220
|
+
- **Session asset provenance**: `ExtractedAsset` now includes optional `agent`, `sessionPath`, and `source` metadata while keeping `type`, `text`, `display`, and `timestamp` stable for existing consumers
|
|
221
|
+
- **Test coverage**: Added extractor tests for command parsing, URL cleanup, filesystem-validated paths, message-text file paths, exact-cwd isolation, Codex `CODEX_HOME` discovery, merge caps, and packaging-contract exports
|
|
222
|
+
|
|
223
|
+
Thanks to [@B33pBeeps](https://github.com/B33pBeeps) (Juan Fourie) for contributing this feature in [#17](https://github.com/cesarandreslopez/sidekick-agent-hub/pull/17), adapted from his MIT-licensed [`trawl`](https://github.com/B33pBeeps/trawl) project.
|
|
224
|
+
|
|
225
|
+
## [0.19.3] - 2026-06-17
|
|
226
|
+
|
|
227
|
+
### Added
|
|
228
|
+
|
|
229
|
+
- **Assistant turn timeline**: `segmentAssistantTurn()` now emits a required v2 `timeline` array that preserves reasoning, narration, and tool groups in original arrival order while keeping the final answer text excluded. The mirrored Zod schemas and public type exports include the new timeline contract for browser and IPC consumers
|
|
230
|
+
|
|
231
|
+
## [0.18.1] - 2026-05-08
|
|
232
|
+
|
|
233
|
+
### Added
|
|
234
|
+
|
|
235
|
+
- **Shared display formatting**: `formatTokenCount()` and `formatDurationMs()` are now public from the root, browser, and `formatting` entrypoints, giving CLI, webview, and downstream consumers a single source of truth for compact token and duration rendering
|
|
236
|
+
- **Raw JSONL tailing (`createJsonlTail()`)**: offset-tracked incremental JSONL reads with optional Zod validation, debounced `fs.watch` plus catch-up polling, and a post-batch callback for aggregation-driven consumers that need to defer expensive work until parsing for a chunk is complete
|
|
237
|
+
|
|
238
|
+
## [0.18.0] - 2026-05-08
|
|
239
|
+
|
|
240
|
+
### Added
|
|
241
|
+
|
|
242
|
+
- **Provider-aware quota orchestration**: `MultiProviderQuotaService` coordinates Claude polling, peak-hours enrichment, account labels, transient-failure fallback, and optional Codex quota watcher updates behind one typed `{ claude?, codex? }` event stream
|
|
243
|
+
- **Codex quota watcher**: `CodexQuotaWatcher` discovers the active Codex rollout for a workspace, watches it for live rate-limit updates, persists account-scoped snapshots, and falls back to cached or unavailable states when no live data exists
|
|
244
|
+
- **Account status helper**: `getActiveAccountStatus()` returns a single Claude/Codex account status shape for startup and setup flows
|
|
245
|
+
- **Tool-call extraction helper**: `extractToolCall()` extracts top-level `tool_use` events, complementing the existing `extractToolCalls()` assistant-content-block helper
|
|
246
|
+
- **Cost/model helpers**: `calculateCostWithProvenance()`, `mergeCostSources()`, `shortModelName()`, `getModelDisplayInfo()`, `compareModelIds()`, and `sortModelIds()` provide reusable UI and accounting primitives next to pricing
|
|
247
|
+
- **Phrase categories**: `PHRASE_CATEGORIES` exposes the category structure behind the existing flat `ALL_PHRASES`
|
|
248
|
+
|
|
249
|
+
### Changed
|
|
250
|
+
|
|
251
|
+
- **Model parsing**: `parseModelId()` now recognizes legacy Claude IDs such as `claude-3-opus-20240229` and `claude-3-5-sonnet-20241022`
|
|
252
|
+
|
|
253
|
+
## [0.17.7] - 2026-04-28
|
|
254
|
+
|
|
255
|
+
### Fixed
|
|
256
|
+
|
|
257
|
+
- **Quota snapshot write race**: `writeQuotaSnapshot()` now writes through a per-process unique temp suffix (PID + timestamp + 8 bytes from `crypto.randomBytes`) before atomically renaming to `quota-snapshots.json`, and best-effort removes the temp file if the rename fails. This eliminates fixed-temp collisions and `ENOENT` when multiple Node processes (e.g., the VS Code extension and the CLI) write cached Codex quota snapshots at the same time, and prevents partial writes from leaking orphan `.tmp` files into the config directory
|
|
258
|
+
|
|
259
|
+
## [0.17.6] - 2026-04-19
|
|
260
|
+
|
|
261
|
+
### Added
|
|
262
|
+
|
|
263
|
+
- **`fetchPeakHoursStatus()` API**: New top-level export from `sidekick-shared` that fetches Claude's current peak-hours state from the public `promoclock.co/api/status` endpoint (third-party, unaffiliated with Anthropic). Single-shot fetcher — callers own polling. Returns a fully-normalized `PeakHoursState` with a `unavailable: true` fallback on network errors, HTTP non-2xx, or parse failures, so call sites never need try/catch
|
|
264
|
+
- **`PeakHoursState` type**: Exported type covering `status` (`'peak' | 'off_peak' | 'unknown'`), `isPeak`, `sessionLimitSpeed` (`'normal' | 'faster' | 'unknown'`), `label`, `peakHoursDescription`, `nextChange`, `minutesUntilChange`, `note`, `updatedAt`, and `unavailable`. Unexpected upstream values collapse to `'unknown'` rather than widening the union
|
|
265
|
+
- **Test coverage**: `peakHours.test.ts` adds five vitest cases — peak, off-peak, HTTP 500, network error, and unexpected-enum-value handling — mirroring the existing `providerStatus.test.ts` pattern with `vi.stubGlobal('fetch', …)`
|
|
266
|
+
|
|
267
|
+
## [0.17.5] - 2026-04-18
|
|
268
|
+
|
|
269
|
+
### Added
|
|
270
|
+
|
|
271
|
+
- **`ensureDefaultAccounts()` API**: New top-level export from `sidekick-shared` that auto-registers the first system Claude Code and Codex credentials as a "Default" saved account when no active account exists for that provider. Idempotent across repeated calls; never overwrites accounts that were manually saved; cleans up orphaned Codex profile directories if `prepareCodexAccount` succeeds but still reports `needsLogin`. Accepts an optional `{ logger }` for diagnostic output — every failure path returns a `'error'` status and is routed through the logger rather than thrown
|
|
272
|
+
- **Account bootstrap types**: `EnsureDefaultAccountsResult`, `EnsureDefaultAccountStatus` (`'registered' | 'skipped' | 'error'`), and `EnsureDefaultAccountsOptions` exported from the package root
|
|
273
|
+
- **Packaging contract coverage**: `packagingContract.test.ts` now asserts `ensureDefaultAccounts` is reachable from the built `dist/index.js`, so the API can't silently drop out of the published artifact
|
|
274
|
+
- **Test coverage**: `ensureDefaultAccounts.test.ts` adds six vitest cases covering happy path, idempotency, Claude-only, Codex-only, respect-existing-accounts, and error-swallowing — using the existing `credentialIO` mock pattern so the suite stays portable across macOS and file-based platforms
|
|
275
|
+
|
|
276
|
+
Thanks to [@B33pBeeps](https://github.com/B33pBeeps) (Juan Fourie) for contributing this feature in [#16](https://github.com/cesarandreslopez/sidekick-agent-hub/pull/16).
|
|
277
|
+
|
|
278
|
+
## [0.16.1] - 2026-03-27
|
|
279
|
+
|
|
280
|
+
### Fixed
|
|
281
|
+
|
|
282
|
+
- **Account test portability**: `accounts.test.ts` now mocks credential storage through `credentialIO`, so the shared test suite passes consistently on macOS and file-based platforms
|
|
283
|
+
|
|
284
|
+
## [0.16.0] - 2026-03-23
|
|
285
|
+
|
|
286
|
+
### Added
|
|
287
|
+
|
|
288
|
+
- **Zod schemas for session events**: `sessionEventSchema`, `messageUsageSchema`, `sessionMessageSchema`, and `permissionModeSchema` for runtime JSONL validation
|
|
289
|
+
- **Token usage extractor**: Pure function `extractTokenUsage()` normalizes snake_case API usage fields from a single event
|
|
290
|
+
- **Tool call extractor**: Pure function `extractToolCalls()` extracts tool_use content blocks with `toolUseId` from a single event
|
|
291
|
+
- **Model info & pricing module**: `getModelInfo()`, `parseModelId()`, `getModelPricing()`, `calculateCost()`, `calculateCostWithPricing()`, and `formatCost()` — ported from VS Code extension with zero VS Code dependencies
|
|
292
|
+
- **Typed JSONL parser**: Optional `schema` parameter on `JsonlParser` for Zod-validated event parsing; invalid events route to `onError()`
|
|
293
|
+
- **QuotaPoller class**: Reusable polling service with exponential backoff, active/idle interval switching, cached fallback on transient errors, and automatic stop on auth failures
|
|
294
|
+
|
|
295
|
+
### Changed
|
|
296
|
+
|
|
297
|
+
- **ToolCall type**: Added optional `toolUseId` and `output` fields for tool result correlation
|
|
298
|
+
|
|
299
|
+
## [0.13.8] - 2026-03-12
|
|
300
|
+
|
|
301
|
+
### Added
|
|
302
|
+
|
|
303
|
+
- **Structured quota failure metadata**: `QuotaState` unavailable results now optionally include `failureKind`, `httpStatus`, and `retryAfterMs`, and `fetchQuota()` classifies `401`, `429`, `5xx`, other non-OK responses, and transport failures without changing its non-throwing contract
|
|
304
|
+
- **Quota failure presentation helper**: New `describeQuotaFailure()` export maps unavailable quota states to consistent first-party severity, title/message/detail copy, retryability hints, and stable alert keys for CLI and VS Code consumers
|
|
305
|
+
|
|
306
|
+
## [0.13.7] - 2026-03-11
|
|
307
|
+
|
|
308
|
+
_No shared-specific changes in this release._
|
|
309
|
+
|
|
310
|
+
## [0.13.6] - 2026-03-11
|
|
311
|
+
|
|
312
|
+
### Fixed
|
|
313
|
+
|
|
314
|
+
- **OpenCode DB-backed resolution**: OpenCode project discovery now matches DB projects by worktree, sandboxes, and session directory, and synthetic `db-sessions/<projectId>` folders are treated as monitorable paths
|
|
315
|
+
- **OpenCode runtime status**: DB-backed consumers can now distinguish `db_missing` from `sqlite_missing`, `sqlite_blocked`, and `query_failed`, enabling OpenCode-only actionable runtime notices instead of silent fallback to legacy file scanning
|
|
316
|
+
|
|
317
|
+
## [0.13.5] - 2026-03-10
|
|
318
|
+
|
|
319
|
+
### Added
|
|
320
|
+
|
|
321
|
+
- **Provider Status module**: `fetchProviderStatus()` for checking Claude API health via `status.claude.com` — returns indicator, affected components, active incidents, with graceful fallback on errors
|
|
322
|
+
|
|
323
|
+
## [0.13.4] - 2026-03-08
|
|
324
|
+
|
|
325
|
+
_No shared-specific changes in this release._
|
|
326
|
+
|
|
327
|
+
## [0.13.2] - 2026-03-04
|
|
328
|
+
|
|
329
|
+
### Added
|
|
330
|
+
|
|
331
|
+
- **Credentials module**: `readClaudeMaxCredentials()` and `readClaudeMaxAccessTokenSync()` for reading Claude Max OAuth credentials from `~/.claude/.credentials.json`
|
|
332
|
+
- **Quota module**: `fetchQuota()` for fetching Claude Max subscription quota (5-hour and 7-day windows)
|
|
333
|
+
- **Vitest config**: Added vitest configuration for shared library tests
|
|
334
|
+
|
|
335
|
+
## [0.13.1] - 2026-03-04
|
|
336
|
+
|
|
337
|
+
### Added
|
|
338
|
+
|
|
339
|
+
- **Quota types**: `QuotaWindow` and `QuotaState` types exported for CLI and extension consumption
|
|
340
|
+
|
|
341
|
+
## [0.13.0] - 2026-03-03
|
|
342
|
+
|
|
343
|
+
### Changed
|
|
344
|
+
|
|
345
|
+
- **Refactoring**: Removed dead code, cached hot paths, centralized constants across shared modules
|
|
346
|
+
|
|
347
|
+
## [0.12.10] - 2026-03-01
|
|
348
|
+
|
|
349
|
+
### Added
|
|
350
|
+
|
|
351
|
+
- **Event aggregation**: `EventAggregator` with frequency tracking, activity heatmaps, and pattern extraction
|
|
352
|
+
- **Analytics engines**: `FrequencyTracker`, `HeatmapTracker`, `PatternExtractor` for session analytics
|
|
353
|
+
- **Snapshot persistence**: `saveSnapshot` / `loadSnapshot` for aggregator state serialization
|
|
354
|
+
|
|
355
|
+
## [0.12.9] - 2026-02-28
|
|
356
|
+
|
|
357
|
+
### Added
|
|
358
|
+
|
|
359
|
+
- **Cross-session search**: `searchSessions()` for full-text search across session data
|
|
360
|
+
- **Advanced filter**: `FilterEngine` with substring, fuzzy, regex, and date range modes
|
|
361
|
+
- **Context composer**: `composeContext()` for assembling tasks, decisions, notes, and handoff into a single output
|
|
362
|
+
|
|
363
|
+
## [0.12.8] - 2026-02-28
|
|
364
|
+
|
|
365
|
+
_No shared-specific changes in this release._
|
|
366
|
+
|
|
367
|
+
## [0.12.7] - 2026-02-27
|
|
368
|
+
|
|
369
|
+
### Added
|
|
370
|
+
|
|
371
|
+
- **HTML report generation**: `generateHtmlReport()` produces self-contained HTML session reports with transcript, stats, and tool summaries
|
|
372
|
+
- **Plan extraction**: `PlanExtractor` for cross-provider plan capture (Claude Code, OpenCode, Codex)
|
|
373
|
+
- **Changelog parser**: `parseChangelog()` for reading Keep a Changelog formatted files
|
|
374
|
+
|
|
375
|
+
## [0.12.6] - 2026-02-26
|
|
376
|
+
|
|
377
|
+
### Added
|
|
378
|
+
|
|
379
|
+
- **Session dump formatters**: `formatSessionText`, `formatSessionMarkdown`, `formatSessionJson` for exporting session data
|
|
380
|
+
- **Noise classifier**: Event classification for filtering noise from session streams
|
|
381
|
+
- **Event highlighter**: Keyword coloring for session event summaries
|
|
382
|
+
- **Plans reader**: `readPlans`, `readClaudeCodePlanFiles` for plan file discovery
|
|
383
|
+
- **Phrase library**: Shared phrase content moved from CLI to shared library
|
|
384
|
+
|
|
385
|
+
## [0.12.5] - 2026-02-24
|
|
386
|
+
|
|
387
|
+
_No shared-specific changes in this release._
|
|
388
|
+
|
|
389
|
+
## [0.12.4] - 2026-02-24
|
|
390
|
+
|
|
391
|
+
_No shared-specific changes in this release._
|
|
392
|
+
|
|
393
|
+
## [0.12.3] - 2026-02-24
|
|
394
|
+
|
|
395
|
+
### Added
|
|
396
|
+
|
|
397
|
+
- **Subagent trace parser**: `scanSubagentTraces()` for parsing agent trace files
|
|
398
|
+
- **Session activity detector**: `detectSessionActivity()` for determining session state
|
|
399
|
+
- **Debug log parser**: `parseDebugLog`, `filterByLevel`, `discoverDebugLogs` for Claude Code debug log analysis
|
|
400
|
+
|
|
401
|
+
## [0.11.0] - 2026-02-19
|
|
402
|
+
|
|
403
|
+
### Added
|
|
404
|
+
|
|
405
|
+
- **Initial release**: Shared data access library extracted from the VS Code extension
|
|
406
|
+
- Session event types and persistence schemas
|
|
407
|
+
- JSONL, OpenCode, and Codex parsers
|
|
408
|
+
- Claude Code, OpenCode, and Codex session providers
|
|
409
|
+
- Task, decision, note, history, and handoff readers
|
|
410
|
+
- Session path resolution and subagent scanning
|
|
411
|
+
- Watcher framework for live session file monitoring
|
|
412
|
+
- Tool summary formatter
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Cesar Andres Lopez
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -28,6 +28,52 @@ See the [full changelog](https://github.com/cesarandreslopez/sidekick-agent-hub/
|
|
|
28
28
|
npm install sidekick-shared
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
+
Requires Node 20 or newer. The only npm dependency is `zod` (v4) — if your app
|
|
32
|
+
also uses zod, keep it on `^4` so schemas from this package validate against
|
|
33
|
+
your instance.
|
|
34
|
+
|
|
35
|
+
### External runtime requirement: `sqlite3`
|
|
36
|
+
|
|
37
|
+
`OpenCodeProvider` and the database helpers behind it read their session store by
|
|
38
|
+
shelling out to an executable **`sqlite3` on `PATH`**. There is no bundled
|
|
39
|
+
driver. `CodexProvider` shells out to the same binary, but only for an optional
|
|
40
|
+
index.
|
|
41
|
+
|
|
42
|
+
Without it `OpenCodeProvider` returns **empty results rather than an error**,
|
|
43
|
+
which is indistinguishable from an empty workspace. Call `getRuntimeStatus()`,
|
|
44
|
+
implemented by `OpenCodeProvider` only, to tell the two apart:
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
const status = provider.getRuntimeStatus?.();
|
|
48
|
+
// status.kind: 'available' | 'db_missing' | 'sqlite_missing'
|
|
49
|
+
// | 'sqlite_blocked' | 'query_failed'
|
|
50
|
+
if (status && status.kind !== 'available') {
|
|
51
|
+
console.warn(`Session data unavailable: ${status.kind}`);
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`CodexProvider` uses the Codex `state.sqlite` database only as an index and
|
|
56
|
+
falls back to scanning rollout JSONL files, so it keeps working without
|
|
57
|
+
`sqlite3`. `ClaudeCodeProvider` reads JSONL transcripts directly and needs
|
|
58
|
+
nothing extra.
|
|
59
|
+
|
|
60
|
+
### Overriding the config directory
|
|
61
|
+
|
|
62
|
+
Every reader and writer resolves `~/.config/sidekick` (`%APPDATA%/sidekick` on
|
|
63
|
+
Windows) lazily through `getConfigDir()`. Redirect it with either:
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
import { setConfigDir } from 'sidekick-shared';
|
|
67
|
+
|
|
68
|
+
setConfigDir('/tmp/sidekick-fixture'); // in-process; pass null to clear
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
or the `SIDEKICK_CONFIG_DIR` environment variable, which takes effect for the
|
|
72
|
+
whole process and is read fresh on every call. `setConfigDir()` wins when both
|
|
73
|
+
are set. `getConfigDir()` returns the resolved root, `getConfigDirOverride()`
|
|
74
|
+
returns the active in-process override or `null`, and `getDefaultConfigDir()`
|
|
75
|
+
returns the platform default that both overrides bypass.
|
|
76
|
+
|
|
31
77
|
## API Overview
|
|
32
78
|
|
|
33
79
|
| Module | Description |
|
|
@@ -49,7 +95,7 @@ npm install sidekick-shared
|
|
|
49
95
|
| **Assistant Turns** | Browser-safe timeline/process/answer projection for provider-normalized assistant turns (`segmentAssistantTurn()`, `assistantTurnEventsFromSessionEvents()`), including interleaved reasoning, compact tool groups, and Claude `Task` subagent refs without prompt leakage |
|
|
50
96
|
| **Report** | Self-contained HTML session report generation |
|
|
51
97
|
| **Credentials** | Claude Max OAuth credential reading from `~/.claude/.credentials.json` |
|
|
52
|
-
| **Quota** | Claude Max subscription quota fetching (5-hour and 7-day windows), Codex rate-limit extraction from event streams (plus Codex reset credits via `fetchCodexResetCreditsFromApi()`, attached to quota state by `fetchCodexQuotaFromApi()`), and authoritative z.ai Coding Plan quota fetching via `resolveZaiQuota()` / `fetchZaiQuotaFromApi()` (reads z.ai's `api/monitor/usage/quota/limit` endpoint with cached-snapshot fallback). The
|
|
98
|
+
| **Quota** | Claude Max subscription quota fetching (5-hour and 7-day windows), Codex rate-limit extraction from event streams (plus Codex reset credits via `fetchCodexResetCreditsFromApi()`, attached to quota state by `fetchCodexQuotaFromApi()`), and authoritative z.ai Coding Plan quota fetching via `resolveZaiQuota()` / `fetchZaiQuotaFromApi()` (reads z.ai's `api/monitor/usage/quota/limit` endpoint with cached-snapshot fallback). The observed-traffic z.ai estimator was removed from the package root exports in 0.23.0 and every remaining export of it is `@deprecated` — `resolveZaiQuota()` is the single supported z.ai quota API |
|
|
53
99
|
| **Provider Status** | API health checking via status.claude.com and status.openai.com (indicator, components, incidents) |
|
|
54
100
|
| **Doctor** | Typed cross-provider health diagnostics — `runDoctor()` checks project identity, sessions, accounts, providers, and dependencies into a `HealthReport`; `formatHealthReport()` renders it and `getSessionDiagnostics()` exposes the per-provider session probe |
|
|
55
101
|
| **Schemas** | Zod schemas for runtime validation of data crossing process/IPC boundaries — JSONL session events (`sessionEventSchema`, `messageUsageSchema`, `sessionMessageSchema`), assistant turns, observed-session V1 records, quota, account status, and quota history — plus `extractSessionEvents()` to unwrap `progress`-wrapped events. Also published fs-free via the [`sidekick-shared/schemas`](#supported-import-paths) subpath |
|
|
@@ -108,9 +154,10 @@ Hydrate the model catalog from the `node` subpath. One fetch covers both prices
|
|
|
108
154
|
```typescript
|
|
109
155
|
import { hydratePricingCatalog, loadObservedContextWindows } from 'sidekick-shared/node';
|
|
110
156
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
157
|
+
// cacheDir defaults to the Sidekick config dir, which honors
|
|
158
|
+
// SIDEKICK_CONFIG_DIR and setConfigDir(). Pass it only to place the cache
|
|
159
|
+
// somewhere else — and pass a real path, since `~` is not expanded.
|
|
160
|
+
const { entries, contextWindowEntries } = await hydratePricingCatalog();
|
|
114
161
|
|
|
115
162
|
// Context windows a provider reported on an earlier run. These outrank the
|
|
116
163
|
// catalog, which only knows each model's published maximum — Codex reports the
|
|
@@ -238,10 +285,13 @@ const sessions = provider.findAllSessions('/path/to/project');
|
|
|
238
285
|
### Read persisted tasks
|
|
239
286
|
|
|
240
287
|
```typescript
|
|
241
|
-
import { readTasks,
|
|
288
|
+
import { readTasks, resolveProjectIdentity } from 'sidekick-shared';
|
|
242
289
|
|
|
243
|
-
|
|
244
|
-
|
|
290
|
+
// A bare string is treated as an already-encoded slug. Pass a project
|
|
291
|
+
// identity to resolve a working directory — that also gets you the
|
|
292
|
+
// legacy-slug fallback for stores written before symlink resolution.
|
|
293
|
+
const project = resolveProjectIdentity('/path/to/project');
|
|
294
|
+
const tasks = await readTasks(project, { status: 'pending' });
|
|
245
295
|
console.log(`Found ${tasks.length} tasks`);
|
|
246
296
|
```
|
|
247
297
|
|
|
@@ -277,7 +327,10 @@ if (!peak.unavailable && peak.isPeak) {
|
|
|
277
327
|
```typescript
|
|
278
328
|
import { fetchQuota, readClaudeMaxCredentials } from 'sidekick-shared';
|
|
279
329
|
|
|
280
|
-
|
|
330
|
+
// Returns a Promise — without `await`, the object is always truthy and
|
|
331
|
+
// `accessToken` is undefined, which surfaces later as an auth failure.
|
|
332
|
+
// Use `readClaudeMaxAccessTokenSync()` from a synchronous call site.
|
|
333
|
+
const creds = await readClaudeMaxCredentials();
|
|
281
334
|
if (creds) {
|
|
282
335
|
const quota = await fetchQuota(creds.accessToken);
|
|
283
336
|
if (quota.available) {
|
|
@@ -299,18 +352,36 @@ For first-party style messaging, `describeQuotaFailure()` maps unavailable quota
|
|
|
299
352
|
### Model info and cost calculation
|
|
300
353
|
|
|
301
354
|
```typescript
|
|
302
|
-
import {
|
|
355
|
+
import {
|
|
356
|
+
getModelInfo,
|
|
357
|
+
normalizeProviderUsage,
|
|
358
|
+
calculateNormalizedUsageCost,
|
|
359
|
+
formatCost,
|
|
360
|
+
} from 'sidekick-shared';
|
|
303
361
|
|
|
304
362
|
const info = getModelInfo('claude-sonnet-4-6-20260321');
|
|
305
|
-
console.log(info.family, info.version, info.contextWindow); // "sonnet" "4.6"
|
|
363
|
+
console.log(info.family, info.version, info.contextWindow); // "sonnet" "4.6" 1000000
|
|
306
364
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
365
|
+
// Normalize first: providers disagree about whether cached and reasoning
|
|
366
|
+
// tokens are already counted in the input/output totals.
|
|
367
|
+
const usage = normalizeProviderUsage({
|
|
368
|
+
inputTokens: 1000,
|
|
369
|
+
outputTokens: 500,
|
|
370
|
+
cacheReadTokens: 200,
|
|
371
|
+
cacheWriteTokens: 0,
|
|
372
|
+
semantics: 'anthropic',
|
|
373
|
+
});
|
|
374
|
+
const { costUsd } = calculateNormalizedUsageCost({
|
|
375
|
+
usage,
|
|
376
|
+
modelId: 'claude-sonnet-4-6-20260321',
|
|
377
|
+
});
|
|
378
|
+
console.log(formatCost(costUsd)); // "$0.01"
|
|
312
379
|
```
|
|
313
380
|
|
|
381
|
+
`calculateCost()` still works but is deprecated — it predates the
|
|
382
|
+
cache/reasoning normalization above and misprices OpenAI-style usage, where
|
|
383
|
+
cached tokens are already included in the input count.
|
|
384
|
+
|
|
314
385
|
### Extract token usage and tool calls from events
|
|
315
386
|
|
|
316
387
|
```typescript
|
|
@@ -360,7 +431,7 @@ const snapshot = readSessionContextSnapshot(provider, '/path/to/session.jsonl');
|
|
|
360
431
|
|
|
361
432
|
console.log(snapshot.pressure); // 'low' | 'medium' | 'high'
|
|
362
433
|
console.log(snapshot.contextTokens, '/', snapshot.contextWindow);
|
|
363
|
-
console.log(snapshot.capabilities.
|
|
434
|
+
console.log(snapshot.capabilities.observedTools, snapshot.capabilities.mcpServers);
|
|
364
435
|
console.log(snapshot.sources.length, 'evidence sources');
|
|
365
436
|
```
|
|
366
437
|
|
package/dist/index.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ export type { HistoricalDataStore, DailyData, HourlyData, MonthlyData, AllTimeSt
|
|
|
25
25
|
export { HISTORICAL_DATA_SCHEMA_VERSION, HISTORICAL_SESSION_RETENTION_LIMIT, createEmptyTokenTotals, createEmptyDataStore, } from './types/historicalData';
|
|
26
26
|
export type { PersistedPlan, PersistedPlanStep, PlanHistoryStore, PlanStepStatus, PlanStatus, PlanSource, PlanStepComplexity, } from './types/plan';
|
|
27
27
|
export { PLAN_SCHEMA_VERSION, MAX_PLANS_PER_PROJECT } from './types/plan';
|
|
28
|
-
export { getConfigDir, getProjectDataPath, getGlobalDataPath, encodeWorkspacePath, getProjectSlug, getProjectSlugRaw, resolveProjectIdentity, } from './paths';
|
|
28
|
+
export { CONFIG_DIR_ENV_VAR, getConfigDir, getConfigDirOverride, getDefaultConfigDir, setConfigDir, getProjectDataPath, getGlobalDataPath, encodeWorkspacePath, getProjectSlug, getProjectSlugRaw, resolveProjectIdentity, } from './paths';
|
|
29
29
|
export type { ProjectIdentity } from './paths';
|
|
30
30
|
export { migrateLegacyProjectStores } from './projectMigration';
|
|
31
31
|
export { readTasks } from './readers/tasks';
|
|
@@ -188,5 +188,5 @@ export { fetchProviderStatus, fetchOpenAIStatus } from './providerStatus';
|
|
|
188
188
|
export type { ProviderStatusState } from './providerStatus';
|
|
189
189
|
export { formatHealthReport, getSessionDiagnostics, runDoctor } from './doctor';
|
|
190
190
|
export type { DeprecatedSetting, DoctorOptions, HealthCheck, HealthCheckStatus, HealthReport, SessionDiagnostics, } from './doctor';
|
|
191
|
-
export { createPeakHoursNotApplicableState, fetchPeakHoursStatus, isClaudeCodeSessionProvider, scopePeakHoursToSessionProvider, } from './peakHours';
|
|
192
|
-
export type { PeakHoursState } from './peakHours';
|
|
191
|
+
export { createPeakHoursNotApplicableState, DEFAULT_PEAK_HOURS_TIMEOUT_MS, fetchPeakHoursStatus, isClaudeCodeSessionProvider, scopePeakHoursToSessionProvider, } from './peakHours';
|
|
192
|
+
export type { FetchPeakHoursOptions, PeakHoursState } from './peakHours';
|