sidekick-shared 0.26.5 → 0.26.6
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 +35 -0
- package/README.md +56 -51
- package/dist/accountChanges.js +21 -2
- package/dist/accountHealth.d.ts +72 -0
- package/dist/accountHealth.js +286 -0
- package/dist/accountLaunch.d.ts +30 -0
- package/dist/accountLaunch.js +124 -0
- package/dist/accountManager.d.ts +33 -8
- package/dist/accountManager.js +183 -50
- package/dist/accountRegistry.d.ts +10 -0
- package/dist/accountRegistry.js +42 -22
- package/dist/accountSwitch.d.ts +43 -0
- package/dist/accountSwitch.js +115 -0
- package/dist/accountSync.d.ts +30 -0
- package/dist/accountSync.js +180 -0
- package/dist/accountSyncTypes.d.ts +25 -0
- package/dist/accountSyncTypes.js +7 -0
- package/dist/accounts.d.ts +58 -6
- package/dist/accounts.js +408 -189
- package/dist/claudeCredentials.d.ts +38 -0
- package/dist/claudeCredentials.js +74 -0
- package/dist/claudeProfiles.d.ts +40 -0
- package/dist/claudeProfiles.js +102 -10
- package/dist/codexAuth.d.ts +32 -0
- package/dist/codexAuth.js +127 -0
- package/dist/codexPaths.d.ts +21 -0
- package/dist/codexPaths.js +117 -0
- package/dist/codexProfiles.d.ts +58 -5
- package/dist/codexProfiles.js +574 -289
- package/dist/credentialIO.d.ts +12 -5
- package/dist/credentialIO.js +63 -29
- package/dist/credentials.d.ts +8 -0
- package/dist/credentials.js +28 -32
- package/dist/ensureDefaultAccounts.d.ts +8 -0
- package/dist/ensureDefaultAccounts.js +42 -82
- package/dist/index.d.ts +27 -10
- package/dist/index.js +61 -9
- package/dist/keepAlive.d.ts +44 -0
- package/dist/keepAlive.js +106 -0
- package/dist/processDetection.d.ts +32 -0
- package/dist/processDetection.js +210 -0
- package/dist/schemas/accountManager.d.ts +283 -1
- package/dist/schemas/accountManager.js +122 -1
- package/dist/schemas/assistantTurn.d.ts +2 -2
- package/dist/schemas/index.d.ts +6 -1
- package/dist/schemas/index.js +14 -1
- package/dist/schemas/observedSessionV1.d.ts +21 -21
- package/dist/schemas/quota.d.ts +18 -18
- package/dist/schemas/quotaHistory.d.ts +1 -1
- package/dist/schemas/stateFile.d.ts +5 -5
- package/dist/terminalSync.d.ts +5 -5
- package/dist/terminalSync.js +7 -112
- package/dist/writers/atomic.d.ts +2 -0
- package/dist/writers/atomic.js +49 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,41 @@ 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.26.6] - 2026-09-16
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `syncLiveAccountState()` reconciles the live Claude Code and Codex logins with the saved profiles: it registers logins the registry has never seen (label = email, `metadata.origin: 'live-sync'`), folds rotated tokens back into their profile when newer, merges duplicate Codex profiles for one workspace (oldest keeps id and label; losers are stashed), and re-points the active pointer. `ensureDefaultAccounts()` runs it at startup after `cleanupAbandonedLogins()`, and `onAccountsChanged()` runs it on filesystem and poll events.
|
|
13
|
+
- Per-account credential health: `getAccountHealth()` and `listAccountsWithHealth()` report `fresh | expiring | expired | unknown | missing` with access/refresh expiry from a secret-free `health.json` sidecar written by every credential store; `AccountView` and `AccountHealth` types and schemas.
|
|
14
|
+
- `SwitchAccountResult`: switches are two-phase (fold the outgoing login, install, verify by re-reading the store, then move the pointer), refuse targets whose stored credential is `expired`/`missing` (`needsLogin`, `--force` to override), report `runningConsumers` (`claude-cli`, `claude-desktop`, `codex-cli`, `codex-app`, `vscode-extension-host`) with reachability text, and return an `undoToken`; `undoLastSwitch()` and `getLastSwitch()` revert the last switch per provider.
|
|
15
|
+
- `detectRunningAccountConsumers()` / `findRunningProcesses()` detect running CLIs and desktop apps on macOS, Linux (`ps`), and Windows (`tasklist`), including npm-installed `claude` under `node`.
|
|
16
|
+
- `getAccountLaunchEnv()` builds an isolated `CLAUDE_CONFIG_DIR` / `CODEX_HOME` environment for running a CLI as a saved account without switching; `refreshInactiveAccounts()` is an opt-in keep-alive that refreshes inactive profiles through the official CLIs.
|
|
17
|
+
- `getCodexCredentialStoreMode()`; Codex profiles get a `config.toml` forced to `cli_auth_credentials_store = "file"`, and adding an account in keyring mode is refused with the fix.
|
|
18
|
+
- `beginAccountLogin()` accepts `existingAccountId` to re-authenticate a saved profile in place and defaults an empty label to the signed-in email; `readClaudeMaxCredentialsRaw()`, `getLiveClaudeHome()`, `claudeKeychainAccountName()`, `deleteStoredCredentials()`, pure `parseClaudeCredentialBlob()` / Codex auth helpers.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- Claude logins run `claude auth login` instead of `claude /login` (override with `SIDEKICK_CLAUDE_LOGIN_ARGS`); the isolated home is seeded past first-run onboarding; `spawnAccountLogin` treats `timeoutMs` as an inactivity budget with a 900 s `maxTimeoutMs` ceiling and removes the pending profile on failure.
|
|
23
|
+
- The Claude Keychain service suffix hashes the NFC-normalised config directory and the no-argument form follows `CLAUDE_CONFIG_DIR`, matching Claude Code 2.1.x; macOS reads fall back to `.credentials.json` when the Keychain item is missing; the Keychain account name is sanitised like the CLI does.
|
|
24
|
+
- Atomic writes retry transient `EPERM`/`EBUSY`/`EACCES` renames on Windows; `credentialIO` file writes go through the atomic writer.
|
|
25
|
+
- `prepareCodexAccount` folds a re-add of an already saved login into the existing profile instead of creating a duplicate; the switch preflight warns on stale Codex backups and refuses dead ones.
|
|
26
|
+
- `addCurrentAccount` / `removeAccount` keep their read-modify-write in one registry lock through new `*Unlocked` registry helpers.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- Codex profile `config.toml` files get `cli_auth_credentials_store = "file"` at the top level; it was appended after the last `[table]`, where Codex ignored it, so isolated logins on Codex ≥ 0.140 still went to the OS keyring.
|
|
31
|
+
- Adding a Codex account whose login is already saved no longer fails with "was not prepared": finalizing an already-finalized profile activates it (or reports success with `activate: false`).
|
|
32
|
+
- A Codex switch records the account that was really live as `previousAccountId` (read after the phase-one sync, as the Claude path already did), so undo and rollback return to it instead of to a stale pointer.
|
|
33
|
+
- Switching refuses to run while `CLAUDE_CONFIG_DIR` / `CODEX_HOME` point inside sidekick's own profile homes (for example a shell that ran `eval "$(sidekick accounts env …)"`), instead of overwriting that profile with the target's credentials.
|
|
34
|
+
- A finished or discarded isolated Claude login deletes its temporary Keychain item instead of orphaning live tokens (macOS).
|
|
35
|
+
- `ensureDefaultAccounts()` reports a keyring-mode Codex login as `skipped` rather than `error` and no longer logs it as a failure at every startup.
|
|
36
|
+
- `findRunningProcessesSync()` allows a 16 MiB process listing like its async twin, so busy hosts do not silently report no running consumers.
|
|
37
|
+
- The Claude live-state fingerprint no longer includes the mtime of `~/.claude.json`, which Claude Code rewrites on nearly every prompt; watch-triggered syncs (and the macOS Keychain read behind them) now run only when the identity or credential file changes, or when the Keychain fold interval elapses.
|
|
38
|
+
|
|
39
|
+
### Removed
|
|
40
|
+
|
|
41
|
+
- `setTerminalActiveProfile`, `installShellHook`, `uninstallShellHook`, and `isShellHookInstalled` (no consumers; a global export would silently move the live home). `writeLauncher` / `removeLauncher` remain and now unset `CLAUDE_SECURESTORAGE_CONFIG_DIR`.
|
|
42
|
+
|
|
8
43
|
## [0.26.5] - 2026-09-15
|
|
9
44
|
|
|
10
45
|
### Added
|
package/README.md
CHANGED
|
@@ -9,10 +9,11 @@ Types, parsers, providers, readers, formatters, aggregation, search, reporting,
|
|
|
9
9
|
|
|
10
10
|
## Recent additions
|
|
11
11
|
|
|
12
|
+
- **0.26.6: verified account switching** — `syncLiveAccountState()` reconciles the live Claude Code and Codex logins with saved profiles (registers unknown logins under their email, folds rotated tokens, merges duplicate Codex profiles, re-points the active pointer) and runs at startup, on account-change events, and as phase one of every switch; `getAccountHealth()` / `listAccountsWithHealth()` report secret-free `fresh | expiring | expired | unknown | missing` health; `switchAccount[Async]()` returns a `SwitchAccountResult` with verification, `runningConsumers`, `needsLogin`, and an `undoToken` for `undoLastSwitch()`; `detectRunningAccountConsumers()`, `getAccountLaunchEnv()`, `refreshInactiveAccounts()`, and `getCodexCredentialStoreMode()` are new. Claude logins run `claude auth login`, the Keychain suffix follows Claude Code 2.1.x, and the unused shell-hook helpers were removed.
|
|
12
13
|
- **0.26.5: event-scoped collection** — `ObservedSessionCollector.subscribe()` reconciles each watch event with one `statWatchedSessionFile()` stat and runs a full `discover()` only for unknown paths, catch-up polls, and the initial pass, gated by `minReconcileGapMs`; `discover({ limit, since })` / `collect({ limit, since })` bound a pass, `maxCacheEntries` / `maxCacheBytes` bound the parse cache, `DirectoryListingCache` makes a full pass one stat per unchanged directory, and the info-severity `provider-discovery-completed` diagnostic reports what each pass cost.
|
|
13
14
|
- **0.26.3–0.26.4: provider failure diagnosis and service status** — `diagnoseProviderFailure()` (root and browser) classifies caller-designated terminal errors into bounded diagnosis and recovery identifiers with evidence provenance; `fetchProviderServiceStatus()` (root and Node) returns explicit observed/unavailable public status with component and incident associations. 0.26.4 recognizes expired-login and re-authentication messages, gives explicit refresh-token rejection precedence over conversation-expiry wording, and classifies `denied by policy` as `execution_policy_denied`.
|
|
14
15
|
- **0.26.2: reliable monitoring and search** — complete-line JSONL cursors preserve Unicode and Codex parser context; watcher `onBatchComplete` signals a delivered batch. `searchSessions()` adds workspace-path filtering and cancellation, and Doctor accepts an explicit session provider.
|
|
15
|
-
- **One token vocabulary and cost provenance (0.26.0)** — `summarizeTokens()` gives every surface the same `total` (input + output + cache writes + cache reads) and `context` (input + cache) figures; `AggregatedTokens.costUsd` carries `costProvenance` so reports can say whether a cost was provider-reported or estimated; `parseClaudeStatuslinePayload()` / `quotaFromStatuslinePayload()` turn Claude Code's status-line JSON into an official `statusline` quota source; `readQuotaSnapshot()` reports `ageMs` / `freshness` and keeps the sample's origin as `capturedSource`; `resolveQuota()` shares quota resolution across CLI, MCP, and dashboard startup, with default local-sample preferences and an API-first option used by one-shot Codex queries; `readSessionFileStats()` / `computeSessionFileStats()` give every provider one `readSessionStats()` over the shared aggregator, with `availability`, `costProvenance`, and `toolFailures` on `SessionFileStats`; `collectUsageEvents()` reads priced usage events from session logs with a per-session cache, `computeBillingBlocks()` groups them into five-hour billing blocks, and `bucketUsage()` turns them into day, week, month, or session rows; `applySessionSummary()` and `importSessionHistory()` let any host fold finished sessions into `historical-data.json` the way the extension does; observed sessions are read once per discovery, re-read only when their fingerprint changes, and classified from events by `classifySessionActivity()`; `readSessionReportInputs()` derives report metrics and transcript from one read; `writeStateFile()` / `readStateFile()` (also on the `statusline` subpath) maintain the public, versioned `state.json` for external tools, validated by `sidekickStateFileSchema`; `getScheduledPeakHoursState()` and `evaluateQuotaThresholds()` are shared by the CLI and extension dashboards.
|
|
16
|
+
- **One token vocabulary and cost provenance (0.26.0–0.26.1)** — `summarizeTokens()` gives every surface the same `total` (input + output + cache writes + cache reads) and `context` (input + cache) figures; `AggregatedTokens.costUsd` carries `costProvenance` so reports can say whether a cost was provider-reported or estimated; `parseClaudeStatuslinePayload()` / `quotaFromStatuslinePayload()` turn Claude Code's status-line JSON into an official `statusline` quota source; `readQuotaSnapshot()` reports `ageMs` / `freshness` and keeps the sample's origin as `capturedSource`; `resolveQuota()` shares quota resolution across CLI, MCP, and dashboard startup, with default local-sample preferences and an API-first option used by one-shot Codex queries; `readSessionFileStats()` / `computeSessionFileStats()` give every provider one `readSessionStats()` over the shared aggregator, with `availability`, `costProvenance`, and `toolFailures` on `SessionFileStats`; `collectUsageEvents()` reads priced usage events from session logs with a per-session cache, `computeBillingBlocks()` groups them into five-hour billing blocks, and `bucketUsage()` turns them into day, week, month, or session rows; `applySessionSummary()` and `importSessionHistory()` let any host fold finished sessions into `historical-data.json` the way the extension does; observed sessions are read once per discovery, re-read only when their fingerprint changes, and classified from events by `classifySessionActivity()`; `readSessionReportInputs()` derives report metrics and transcript from one read; `writeStateFile()` / `readStateFile()` (also on the `statusline` subpath) maintain the public, versioned `state.json` for external tools, validated by `sidekickStateFileSchema` from `sidekick-shared/schemas`; `getScheduledPeakHoursState()` and `evaluateQuotaThresholds()` are shared by the CLI and extension dashboards.
|
|
16
17
|
- **Host-safe APIs (0.25.0)** — `listSessionPreviewsAsync()` / `readSessionPreviewAsync()` read previews with bounded concurrency and cooperative yielding; `ObservedSessionCollector.subscribe()` and `SessionMonitor.subscribe()` replace host polling loops with debounced change batches; `createSessionProviders({ onDiagnostic })` constructs every usable provider with structured diagnostics instead of throwing; `findSessionById()` resolves one session without scanning; `exportResolvedModelCatalog()` / `importResolvedModelCatalog()` and `registerModelAlias()` transfer context/pricing resolutions across realms; `onAccountsChanged()` reports login/logout/switch events; provider constructors perform no environment I/O, and quota pollers stay dormant without an account.
|
|
17
18
|
- **Native session-file helpers** — `encodeClaudeWorkspacePath()` / `getClaudeSessionDirectory()` locate Claude Code's `~/.claude/projects/` directories with the real on-disk encoding, `findCodexRolloutFile()` resolves a Codex session id to its rollout path, `readCodexHistory()` tail-reads `~/.codex/history.jsonl`, `listSessionPreviews()` / `readSessionPreview()` build a cheap stat-first recent-sessions index across providers, and `parseMcpToolName()` splits `mcp__<server>__<tool>` identifiers (browser-safe).
|
|
18
19
|
- **Non-blocking account APIs & locked sync writers** — every login/switch entry point gains an async variant (`switchAccountAsync()`, `getAccountLoginStatusAsync()`, `finalizeAccountLoginAsync()`, `prepareCodexAccountAsync()`, `finalizeCodexAccountAsync()`, `switchToCodexAccountAsync()`) that keeps `codex` CLI probes off the event loop, and synchronous callers get the same cross-process store lock via `atomicWriteFileSync()` / `updateJsonStoreAtomicSync()` / `withFileLockSync()`, with progress-based timeouts and abandoned-lock reclaim.
|
|
@@ -24,7 +25,7 @@ Types, parsers, providers, readers, formatters, aggregation, search, reporting,
|
|
|
24
25
|
- **Doctor report** — `runDoctor()` builds a typed cross-provider health report (project identity, sessions, accounts, providers, dependencies); `formatHealthReport()` renders it for terminals.
|
|
25
26
|
- **Analytics engines** — `scoreSessionQuality()` (beta) with weekly trends via `calculateQualityTrend()`, `calculateCodeImpact()` for cost per changed line and per-model churn, and `calculateCompactionLedger()` for reported-vs-heuristic compaction accounting.
|
|
26
27
|
- **Error taxonomy & history** — `categorizeError()` assigns one shared taxonomy at ingest, and `appendErrorHistory()` / `getTopFailingTools()` keep an append-only per-project failure history.
|
|
27
|
-
- **Statusline & burn rate** — `formatStatusline()` and `BurnRateCalculator` render a cache-only account/quota/burn footer, importable from the
|
|
28
|
+
- **Statusline & burn rate** — `formatStatusline()` and `BurnRateCalculator` render a cache-only account/quota/burn footer, importable from the [`sidekick-shared/statusline`](#supported-import-paths) subpath.
|
|
28
29
|
- **Codex reset credits** — `fetchCodexResetCreditsFromApi()` reads ChatGPT's reset-credit endpoint into a `CodexResetCreditsSnapshot`, and `fetchCodexQuotaFromApi()` attaches it to the returned quota state (preserved across session-sourced snapshot writes).
|
|
29
30
|
|
|
30
31
|
See the [full changelog](https://github.com/cesarandreslopez/sidekick-agent-hub/blob/main/CHANGELOG.md) for everything.
|
|
@@ -86,56 +87,56 @@ returns the platform default that both overrides bypass.
|
|
|
86
87
|
|
|
87
88
|
## API Overview
|
|
88
89
|
|
|
89
|
-
| Module
|
|
90
|
-
|
|
|
91
|
-
| **Types**
|
|
92
|
-
| **Paths**
|
|
93
|
-
| **Readers**
|
|
94
|
-
| **Writers**
|
|
95
|
-
| **Providers**
|
|
96
|
-
| **Observed Sessions (V1)**
|
|
97
|
-
| **Parsers**
|
|
98
|
-
| **Watchers**
|
|
99
|
-
| **Formatters**
|
|
100
|
-
| **Search**
|
|
101
|
-
| **Aggregation**
|
|
102
|
-
| **Analytics**
|
|
103
|
-
| **Error History**
|
|
104
|
-
| **Session Context**
|
|
105
|
-
| **Assistant Turns**
|
|
106
|
-
| **Report**
|
|
107
|
-
| **Credentials**
|
|
108
|
-
| **Quota**
|
|
109
|
-
| **Provider Status**
|
|
110
|
-
| **Doctor**
|
|
111
|
-
| **Schemas**
|
|
112
|
-
| **Extractors**
|
|
113
|
-
| **Model Info & Pricing**
|
|
114
|
-
| **Quota Polling**
|
|
115
|
-
| **Multi-Provider Quota**
|
|
116
|
-
| **Accounts**
|
|
117
|
-
| **Account Management 2.0**
|
|
118
|
-
| **
|
|
119
|
-
| **Codex Profiles**
|
|
120
|
-
| **Quota Snapshots**
|
|
121
|
-
| **Statusline**
|
|
122
|
-
| **Phrases**
|
|
90
|
+
| Module | Description |
|
|
91
|
+
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
92
|
+
| **Types** | Session events, OpenCode/Codex format types, persistence schemas (tasks, decisions, notes, plans, historical data) |
|
|
93
|
+
| **Paths** | Config directory resolution, project data paths, workspace encoding |
|
|
94
|
+
| **Readers** | Read tasks, decisions, notes, history, handoff, and plans from `~/.config/sidekick/` |
|
|
95
|
+
| **Writers** | Atomic persistence writers — `atomicWriteJson()` / `updateJsonStoreAtomic()` and their synchronous twins `atomicWriteJsonSync()` / `atomicWriteFileSync()` / `updateJsonStoreAtomicSync()` / `withFileLockSync()` (same cross-process lock file, progress-based timeouts, abandoned-lock reclaim), plus lock-coordinated capture helpers `addTask()`, `completeTask()`, `addDecision()`, `addNote()` that merge into the shared stores without clobbering concurrent writers |
|
|
96
|
+
| **Providers** | Session provider abstraction with Claude Code, OpenCode, and Codex implementations; auto-detection via filesystem. As of 0.25.0 constructors perform no environment I/O — build them all with `createSessionProviders({ onDiagnostic })`, which reports unavailable providers as structured diagnostics instead of failing; `findSessionById()` resolves one session through provider-native indexes; stable provider-id const arrays (`SESSION_PROVIDER_IDS`, `ACCOUNT_PROVIDER_IDS`, `QUOTA_PROVIDER_IDS`, `MODEL_PROVIDER_IDS`) accompany the derived unions. As of 0.26.5 Claude Code and Codex enumerate through a per-instance `DirectoryListingCache` (one stat per unchanged directory) and implement `statWatchedSessionFile()` so a watch event resolves with one stat; `splitWatchedPath()` and the `ListSessionFilesOptions` / `WatchedSessionFile` / `SessionEnumerationCounters` types are exported alongside |
|
|
97
|
+
| **Observed Sessions (V1)** | Versioned provider-neutral observation contracts — `createProviderSessionAdapterV1()` / `derivePendingUserRequestV1()` with `ObservedAgentSessionV1`, `ProviderCapabilitiesV1`, `PendingUserRequestV1`, `SessionEvidenceRefV1`, and provenance/confidence wrapper types (Zod schemas in `sidekick-shared/schemas`) |
|
|
98
|
+
| **Parsers** | JSONL event parsing, OpenCode/Codex format normalization, subagent scanning, session path resolution, debug log parsing |
|
|
99
|
+
| **Watchers** | Live session file watching with event bridging, plus `createJsonlTail()` for raw incremental JSONL consumers |
|
|
100
|
+
| **Formatters** | Display helpers (`formatTokenCount()`, `formatDurationMs()`), tool summary, noise classification, session dump (text/markdown/JSON), event highlighting |
|
|
101
|
+
| **Search** | Cross-session full-text search, advanced filtering (substring, fuzzy, regex, date) |
|
|
102
|
+
| **Aggregation** | Event aggregation, frequency tracking, activity heatmaps, pattern extraction |
|
|
103
|
+
| **Analytics** | Session-quality scoring (beta) with factor contributions and weekly trends (`scoreSessionQuality()`, `calculateQualityTrend()`), code-impact metrics including cost per changed line and per-model churn/cost (`calculateCodeImpact()`), and reported-vs-heuristic compaction accounting (`calculateCompactionLedger()`, `formatCompactionLedger()`) |
|
|
104
|
+
| **Error History** | Shared error taxonomy (`categorizeError()`, `extractErrorMessage()`) plus append-only per-project failure history (`appendErrorHistory()`, `readErrorHistory()`, `getTopFailingTools()`) behind per-tool/hour/model error rollups |
|
|
105
|
+
| **Session Context** | Provider-neutral context evidence snapshots (`buildSessionContextSnapshot()`, `calculateSessionContextPressure()`, `createSessionContextProjector()`, `readSessionContextSnapshot()`): layered evidence sources, low/medium/high context pressure, and observed capabilities (tools, MCP servers, permission mode, rate limits) |
|
|
106
|
+
| **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 |
|
|
107
|
+
| **Report** | Self-contained HTML session report generation |
|
|
108
|
+
| **Credentials** | Claude Max OAuth credential reading (macOS Keychain with a `~/.claude/.credentials.json` fallback; the file on Linux and Windows) |
|
|
109
|
+
| **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 |
|
|
110
|
+
| **Provider Status** | `fetchProviderServiceStatus()` returns explicit observed/unavailable public status with components and unresolved incidents from status.claude.com and status.openai.com; `fetchProviderStatus()` / `fetchOpenAIStatus()` remain as lossy legacy projections (`toLegacyProviderStatus()`) |
|
|
111
|
+
| **Doctor** | Typed cross-provider health diagnostics — `runDoctor()` checks project identity, sessions, accounts, providers, and dependencies into a `HealthReport`; `formatHealthReport()` renders it and `getSessionDiagnostics()` retains the legacy Claude Code path probe; `runDoctor({ provider })` diagnoses the selected session provider |
|
|
112
|
+
| **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, account management, quota history, and the public `state.json` contract (`sidekickStateFileSchema`, exported only from `sidekick-shared/schemas`) — plus `extractSessionEvents()` to unwrap `progress`-wrapped events. Account and quota APIs guarantee results valid against the same-release schemas. Also published fs-free via the [`sidekick-shared/schemas`](#supported-import-paths) subpath |
|
|
113
|
+
| **Extractors** | Pure functions for single-event processing: `extractTokenUsage()`, `extractToolCall()` (top-level `tool_use`), `extractToolCalls()` (assistant content blocks), plus Node-only session asset extraction (`gatherAssetsForCwd()`, `readClaudeAssets()`, `readCodexAssets()`) for URLs, file paths, commands, and plans |
|
|
114
|
+
| **Model Info & Pricing** | Model family parsing (Anthropic / OpenAI / Google, including legacy `claude-3-opus-…` and `claude-3-5-sonnet-…` IDs), context-window lookup (including Fable 5 / Opus 4.8 / Opus 4.7 / Sonnet 4.7 1M and GPT-5.x variants), pricing tables with optional LiteLLM hydration, normalized non-double-counting cost (`calculateNormalizedUsageCost()`, fed by `normalizeProviderUsage()` / `extractNormalizedUsage()`), legacy cost helpers retained but deprecated (`calculateCost()`, `calculateCostWithProvenance()`), `mergeCostSources()`, display helpers (`shortModelName()`, `getModelDisplayInfo()`, `compareModelIds()`, `sortModelIds()`, `formatCost()`), and cross-realm catalog transfer — `exportResolvedModelCatalog()` / `importResolvedModelCatalog()` move resolved context windows and pricing (with provenance, prefix inheritance explicit) between Node and browser realms, and `registerModelAlias()` resolves short or host-specific names to canonical ids |
|
|
115
|
+
| **Quota Polling** | `QuotaPoller` class with exponential backoff, active/idle intervals, and cached fallback. Stays dormant while no account exists and wakes through the account-change signal |
|
|
116
|
+
| **Multi-Provider Quota** | `MultiProviderQuotaService` orchestrates Claude polling + peak-hours + account labels + Codex/z.ai quota updates behind one typed event stream. `CodexQuotaWatcher` watches the active Codex rollout for live rate limits with snapshot fallback; z.ai quota uses the API resolver with snapshot fallback. All three stay dormant without a matching account and wake on account changes |
|
|
117
|
+
| **Accounts** | Multi-provider account registry (v2) with per-provider active account, save/switch/remove, v1 migration, `ensureDefaultAccounts()` for startup bootstrap (migrations, abandoned-login cleanup, then `syncLiveAccountState()`), `syncLiveAccountState()` to register live logins the registry has never seen under their email, fold rotated tokens into their profile, and merge duplicate Codex profiles, `getAccountHealth()` / `listAccountsWithHealth()` for secret-free `fresh`/`expiring`/`expired`/`unknown`/`missing` health with access/refresh expiry,`getActiveAccountStatus()` for a single-pass active-account read across providers,`onAccountsChanged()`for push-based login/logout/switch notification (process-local mutations, filesystem watches, and a catch-up poll), and live-first`resolveActiveClaudeAccount()`/`resolveActiveCodexAccount()` that report the currently logged-in account (self-healing the saved pointer) for display |
|
|
118
|
+
| **Account Management 2.0** | Provider-neutral acquisition + switching: `beginAccountLogin()` / `getAccountLoginStatus()` / `finalizeAccountLogin()` / `spawnAccountLogin()` drive a TTY-less, profile-isolated login that doesn't disturb the active account until finalization; `listAllAccounts()` and `switchAccount()` expose a shared switcher across Claude and Codex; as of 0.26.6 switches are two-phase and verified, return a `SwitchAccountResult` with `runningConsumers`, `needsLogin`, and an `undoToken` (`undoLastSwitch()`), refuse expired or missing credentials unless forced, and `beginAccountLogin({ existingAccountId })` re-authenticates a saved profile in place. Every status/finalize/switch entry point also has an `-Async` variant (`getAccountLoginStatusAsync()`, `finalizeAccountLoginAsync()`, `switchAccountAsync()`, …) that keeps `codex` CLI probes off the event loop — prefer those from hosts with a UI loop. Claude accounts get canonical profile homes with account-scoped macOS keychain suffixes and startup migration from legacy flat backups |
|
|
119
|
+
| **Isolated launch & auto-switch** | `getAccountLaunchEnv()` builds an isolated `CLAUDE_CONFIG_DIR` / `CODEX_HOME` environment (plus `envUnset`) for running a CLI as a saved account without switching, `writeLauncher()` / `removeLauncher()` write POSIX launcher scripts, `detectRunningAccountConsumers()` / `findRunningProcesses()` find CLIs and desktop apps that hold a login (`ps` / `tasklist`), `refreshInactiveAccounts()` is an opt-in keep-alive through the official CLIs, and a default-off `AutoSwitchController` (`decideAutoSwitch()`) moves to a healthier saved account when quota crosses a configured threshold; its `switchAccount` callback may return a Promise and defaults to `switchAccountAsync()` |
|
|
120
|
+
| **Codex Profiles** | Codex account lifecycle — prepare, finalize, switch, remove — switching atomically swaps the profile's backed-up credentials into the system `~/.codex/auth.json`, with rotated-token staleness protection, one-time dual-home migration, and legacy multi-home session monitoring |
|
|
121
|
+
| **Quota Snapshots** | Persistent quota caching per provider/account for offline fallback |
|
|
122
|
+
| **Statusline** | Cache-only one-line account/quota/burn footer — `formatStatusline()`, `selectStatuslineAccount()`, `BurnRateCalculator`, and `estimateTimeToQuota()`, also published via the [`sidekick-shared/statusline`](#supported-import-paths) subpath for fast per-prompt rendering |
|
|
123
|
+
| **Phrases** | Curated humorous phrases for loading/idle states, available as a flat `ALL_PHRASES` array or grouped via `PHRASE_CATEGORIES` for category-aware UI |
|
|
123
124
|
|
|
124
125
|
## Supported import paths
|
|
125
126
|
|
|
126
127
|
`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.
|
|
127
128
|
|
|
128
|
-
| Path | Runtime | What it exposes
|
|
129
|
-
| ------------------------------ | -------------------------- |
|
|
130
|
-
| `sidekick-shared` | Node (CLI, extension host) | Full public API (readers, providers, parsers, pricing, …).
|
|
131
|
-
| `sidekick-shared/browser` | **Browser / webview** | Pure helpers: usage normalization/pricing, token estimation, transcript and assistant-turn projection, model/context math, `parseMcpToolName()`.
|
|
132
|
-
| `sidekick-shared/node` | Node only | LiteLLM pricing and context-window hydration, observed context-window persistence, recent-session/transcript reads, session previews (`listSessionPreviews()` / `readSessionPreview()` plus the bounded-concurrency `listSessionPreviewsAsync()` / `readSessionPreviewAsync()`), Codex history/rollout lookup (`readCodexHistory()`, `findCodexRolloutFile()`), and resilient observed-session collection (`fs` + providers). |
|
|
133
|
-
| `sidekick-shared/phrases` | Any runtime | Phrase arrays + `getRandomPhrase()`.
|
|
134
|
-
| `sidekick-shared/modelContext` | Any runtime | Direct access to the context-window module.
|
|
135
|
-
| `sidekick-shared/modelInfo` | Any runtime | Direct access to model parsing and cost math.
|
|
136
|
-
| `sidekick-shared/formatting` | Any runtime | Direct access to pure token and duration display helpers.
|
|
137
|
-
| `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.
|
|
138
|
-
| `sidekick-shared/statusline` | Node only | Cache-only statusline surface: account status + quota snapshot readers, `formatStatusline()`,
|
|
129
|
+
| Path | Runtime | What it exposes |
|
|
130
|
+
| ------------------------------ | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
131
|
+
| `sidekick-shared` | Node (CLI, extension host) | Full public API (readers, providers, parsers, pricing, …). |
|
|
132
|
+
| `sidekick-shared/browser` | **Browser / webview** | Pure helpers: usage normalization/pricing, token estimation, transcript and assistant-turn projection, model/context math, `parseMcpToolName()`. |
|
|
133
|
+
| `sidekick-shared/node` | Node only | LiteLLM pricing and context-window hydration, public provider service status (`fetchProviderServiceStatus()`), observed context-window persistence, recent-session/transcript reads, session previews (`listSessionPreviews()` / `readSessionPreview()` plus the bounded-concurrency `listSessionPreviewsAsync()` / `readSessionPreviewAsync()`), Codex history/rollout lookup (`readCodexHistory()`, `findCodexRolloutFile()`), and resilient observed-session collection (`fs` + providers). |
|
|
134
|
+
| `sidekick-shared/phrases` | Any runtime | Phrase arrays + `getRandomPhrase()`. |
|
|
135
|
+
| `sidekick-shared/modelContext` | Any runtime | Direct access to the context-window module. |
|
|
136
|
+
| `sidekick-shared/modelInfo` | Any runtime | Direct access to model parsing and cost math. |
|
|
137
|
+
| `sidekick-shared/formatting` | Any runtime | Direct access to pure token and duration display helpers. |
|
|
138
|
+
| `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. |
|
|
139
|
+
| `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()`. |
|
|
139
140
|
|
|
140
141
|
### Browser / webview runtimes
|
|
141
142
|
|
|
@@ -217,10 +218,10 @@ const usage = normalizeProviderUsage({
|
|
|
217
218
|
reasoningTokens: 40,
|
|
218
219
|
});
|
|
219
220
|
|
|
220
|
-
//
|
|
221
|
+
// uncachedInputTokens=700, cacheReadTokens=300, billableOutputTokens=200, totalTokens=1200.
|
|
221
222
|
// Reasoning remains visible but is not counted twice because OpenAI includes it in output.
|
|
222
223
|
const priced = calculateNormalizedUsageCost({ usage });
|
|
223
|
-
// { costUsd: number | null, source: 'provider-reported' | 'model-catalog' |
|
|
224
|
+
// { costUsd: number | null, source: 'provider-reported' | 'model-catalog' | 'explicit-pricing' | 'unpriced' }
|
|
224
225
|
```
|
|
225
226
|
|
|
226
227
|
For `SessionEvent`s, `extractNormalizedUsage(event)` prefers the parser-attached `message.normalizedUsage` and falls back to normalizing the event's raw `usage` with `sidekick` semantics.
|
|
@@ -371,7 +372,7 @@ Discovery and reads are isolated, retries use bounded 30-second-to-5-minute expo
|
|
|
371
372
|
|
|
372
373
|
As of 0.25.0, parses are cached by fingerprint — a second `collect()` over unchanged files performs no content reads (cache hits refresh `observedAt` and activity state; `contentObservedAt` reports how old the cached usage/model data actually is, and `cacheHit` marks them). Observations expose structured `fingerprintParts: { sizeBytes, mtimeMs }` alongside the opaque fingerprint string, and diagnostics carry `severity` and `phase` in addition to their existing `kind`.
|
|
373
374
|
|
|
374
|
-
As of 0.26.5, the parse cache is bounded (`maxCacheEntries`, default 20,000; `maxCacheBytes`, default 128 MiB — keep both above your session count) and a pass can be bounded with `discover({ limit, since })` / `collect({ limit, since })`. Every discovery emits an info-severity `provider-discovery-completed` diagnostic with `trigger`, `durationMs`, `referenceCount`, and the `directoriesListed` / `directoriesStatted` / `filesStatted` counters, so a host can see what each pass cost; hosts that surface every diagnostic should branch on `severity`.
|
|
375
|
+
As of 0.26.5, the parse cache is bounded (`maxCacheEntries`, default 20,000; `maxCacheBytes`, default 128 MiB — keep both above your session count) and a pass can be bounded with `discover({ limit, since })` / `collect({ limit, since })`. Every discovery emits an info-severity `provider-discovery-completed` diagnostic with `trigger`, `durationMs`, `referenceCount`, `partial`, and the `directoriesListed` / `directoriesStatted` / `filesStatted` counters, so a host can see what each pass cost; hosts that surface every diagnostic should branch on `severity`.
|
|
375
376
|
|
|
376
377
|
Instead of a host polling loop, subscribe to debounced change batches. Each change carries the previous and current fingerprints. A recursive-watch event is reconciled with one stat when the provider implements `statWatchedSessionFile()`; a full `discover()` runs only for unknown paths, the catch-up poll (for filesystems that drop events), and the initial pass, at most once per `minReconcileGapMs` (2 s ceiling, scaled down to four times the last walk's duration for cheap sources):
|
|
377
378
|
|
|
@@ -536,7 +537,9 @@ Consumers own caching, stale-evidence presentation, polling, and request coalesc
|
|
|
536
537
|
import { fetchPeakHoursStatus } from 'sidekick-shared';
|
|
537
538
|
|
|
538
539
|
// Third-party endpoint: promoclock.co/api/status (unaffiliated with Anthropic).
|
|
539
|
-
//
|
|
540
|
+
// Falls back to the published weekday schedule (source: 'schedule') on any network,
|
|
541
|
+
// timeout, or parse error; unavailable: true only if the schedule itself cannot be
|
|
542
|
+
// evaluated. Cached 10 min; pass { force: true } to bypass.
|
|
540
543
|
const peak = await fetchPeakHoursStatus();
|
|
541
544
|
if (!peak.unavailable && peak.isPeak) {
|
|
542
545
|
console.log(`${peak.label} — off-peak in ${peak.minutesUntilChange}m`);
|
|
@@ -885,6 +888,8 @@ Compiles TypeScript to `dist/` via `tsc`.
|
|
|
885
888
|
npm test
|
|
886
889
|
```
|
|
887
890
|
|
|
891
|
+
`npm test` builds first (`pretest` runs `npm run build`), so a cold run includes the `tsc` step.
|
|
892
|
+
|
|
888
893
|
Uses Vitest. Run `npm run test:watch` for watch mode.
|
|
889
894
|
|
|
890
895
|
## See Also
|
package/dist/accountChanges.js
CHANGED
|
@@ -41,7 +41,9 @@ const path = __importStar(require("path"));
|
|
|
41
41
|
const accountChangeSignal_1 = require("./accountChangeSignal");
|
|
42
42
|
const accountStatus_1 = require("./accountStatus");
|
|
43
43
|
const accountRegistry_1 = require("./accountRegistry");
|
|
44
|
-
const
|
|
44
|
+
const accountSync_1 = require("./accountSync");
|
|
45
|
+
const claudeProfiles_1 = require("./claudeProfiles");
|
|
46
|
+
const codexPaths_1 = require("./codexPaths");
|
|
45
47
|
const listeners = new Set();
|
|
46
48
|
let watchers = [];
|
|
47
49
|
let pollTimer;
|
|
@@ -130,7 +132,12 @@ function stopMonitoring() {
|
|
|
130
132
|
activePollIntervalMs = DEFAULT_POLL_INTERVAL_MS;
|
|
131
133
|
}
|
|
132
134
|
function watchTargets() {
|
|
133
|
-
return Array.from(new Set([
|
|
135
|
+
return Array.from(new Set([
|
|
136
|
+
(0, accountRegistry_1.getAccountsDir)(),
|
|
137
|
+
(0, claudeProfiles_1.getLiveClaudeHome)(),
|
|
138
|
+
path.join(os.homedir(), '.claude'),
|
|
139
|
+
(0, codexPaths_1.getSystemCodexHome)(),
|
|
140
|
+
]));
|
|
134
141
|
}
|
|
135
142
|
function scheduleCheck(reason) {
|
|
136
143
|
if (debounceTimer)
|
|
@@ -145,6 +152,18 @@ function scheduleCheck(reason) {
|
|
|
145
152
|
debounceTimer.unref?.();
|
|
146
153
|
}
|
|
147
154
|
function emitIfChanged(reason, force = false, singleListener) {
|
|
155
|
+
// External CLIs write the live homes directly: fold their logins into the
|
|
156
|
+
// saved profiles before reporting status, so a native `claude /login` is
|
|
157
|
+
// registered and its rotated tokens are backed up without a host round-trip.
|
|
158
|
+
// `local` signals come from our own registry writes and need no sync.
|
|
159
|
+
if (reason === 'filesystem' || reason === 'poll') {
|
|
160
|
+
try {
|
|
161
|
+
(0, accountSync_1.syncLiveAccountStateSync)({ reason: reason === 'poll' ? 'poll' : 'watch' });
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
// Sync problems surface through the health model, never through the watcher.
|
|
165
|
+
}
|
|
166
|
+
}
|
|
148
167
|
const status = (0, accountStatus_1.getActiveAccountStatus)();
|
|
149
168
|
const nextFingerprint = fingerprint(status);
|
|
150
169
|
if (!force && nextFingerprint === lastFingerprint)
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { type ClaudeOauthCredentials } from './claudeCredentials';
|
|
2
|
+
import { type AccountProviderId } from './accountRegistry';
|
|
3
|
+
export type AccountHealthState = 'fresh' | 'expiring' | 'expired' | 'unknown' | 'missing';
|
|
4
|
+
export type AccountHealthSource = 'live-sync' | 'login' | 'switch' | 'keepalive' | 'migration';
|
|
5
|
+
export interface AccountHealthSidecar {
|
|
6
|
+
version: 1;
|
|
7
|
+
capturedAt: number;
|
|
8
|
+
accessExpiresAt?: number;
|
|
9
|
+
refreshExpiresAt?: number;
|
|
10
|
+
/** True when `refreshExpiresAt` was estimated rather than recorded by the CLI. */
|
|
11
|
+
refreshExpiryEstimated?: boolean;
|
|
12
|
+
lastRefreshAt?: number;
|
|
13
|
+
hasRefreshToken?: boolean;
|
|
14
|
+
authMode?: 'chatgpt' | 'api-key' | 'oauth';
|
|
15
|
+
source: AccountHealthSource;
|
|
16
|
+
}
|
|
17
|
+
export interface AccountHealth {
|
|
18
|
+
providerId: AccountProviderId;
|
|
19
|
+
accountId: string;
|
|
20
|
+
state: AccountHealthState;
|
|
21
|
+
accessExpiresAt?: number;
|
|
22
|
+
refreshExpiresAt?: number;
|
|
23
|
+
refreshExpiryEstimated?: boolean;
|
|
24
|
+
lastRefreshAt?: number;
|
|
25
|
+
checkedAt: number;
|
|
26
|
+
/** True when this profile is the account the live home is logged in to. */
|
|
27
|
+
isLive: boolean;
|
|
28
|
+
reason?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface AccountView {
|
|
31
|
+
id: string;
|
|
32
|
+
providerId: AccountProviderId;
|
|
33
|
+
label?: string;
|
|
34
|
+
email?: string;
|
|
35
|
+
planType?: string;
|
|
36
|
+
isActive: boolean;
|
|
37
|
+
health: AccountHealth;
|
|
38
|
+
/** `learned` = registered automatically from a login sidekick observed. */
|
|
39
|
+
source: 'registered' | 'learned';
|
|
40
|
+
addedAt: string;
|
|
41
|
+
}
|
|
42
|
+
export interface AccountHealthOptions {
|
|
43
|
+
/**
|
|
44
|
+
* `cache` (default for {@link getAccountHealth}) reads only the sidecar;
|
|
45
|
+
* `store` re-reads the stored credential (a bounded Keychain call on macOS)
|
|
46
|
+
* and rewrites the sidecar; `auto` (default for {@link listAccountsWithHealth})
|
|
47
|
+
* probes the store only for profiles that have no sidecar yet, so the cost
|
|
48
|
+
* is paid once per profile and never on a hot path that opts into `cache`.
|
|
49
|
+
*/
|
|
50
|
+
probe?: 'cache' | 'store' | 'auto';
|
|
51
|
+
now?: number;
|
|
52
|
+
}
|
|
53
|
+
export declare function getHealthSidecarPath(provider: AccountProviderId, accountId: string): string;
|
|
54
|
+
export declare function readHealthSidecar(provider: AccountProviderId, accountId: string): AccountHealthSidecar | null;
|
|
55
|
+
/** Build the sidecar for a Claude credential blob. */
|
|
56
|
+
export declare function claudeHealthSidecarFromBlob(blob: unknown, source: AccountHealthSource, now?: number): AccountHealthSidecar | null;
|
|
57
|
+
/** Record the health of a Claude profile from the credential just stored. */
|
|
58
|
+
export declare function writeClaudeHealthSidecar(accountId: string, blob: unknown, source: AccountHealthSource, now?: number): AccountHealthSidecar | null;
|
|
59
|
+
/** Build the sidecar for a raw Codex `auth.json`. */
|
|
60
|
+
export declare function codexHealthSidecarFromAuth(authRaw: string | null, source: AccountHealthSource, now?: number, fallbackPath?: string): AccountHealthSidecar | null;
|
|
61
|
+
/** Record the health of a Codex profile from the auth file just stored. */
|
|
62
|
+
export declare function writeCodexHealthSidecar(accountId: string, authRaw: string | null, source: AccountHealthSource, now?: number): AccountHealthSidecar | null;
|
|
63
|
+
/**
|
|
64
|
+
* Health of one saved account. `probe: 'cache'` never spawns anything; a
|
|
65
|
+
* missing sidecar on a profile that has credentials is reported as `unknown`
|
|
66
|
+
* (never `expired`) until a store probe or the next sync rewrites it.
|
|
67
|
+
*/
|
|
68
|
+
export declare function getAccountHealth(provider: AccountProviderId, accountId: string, options?: AccountHealthOptions): AccountHealth;
|
|
69
|
+
/** Saved accounts with their health, in registry order, grouped by provider. */
|
|
70
|
+
export declare function listAccountsWithHealth(provider?: AccountProviderId, options?: AccountHealthOptions): AccountView[];
|
|
71
|
+
/** Sidecar helper shared by the credential chokepoints: extracts the Claude credential shape. */
|
|
72
|
+
export declare function describeClaudeCredential(blob: unknown): ClaudeOauthCredentials | null;
|