sidekick-shared 0.29.0 → 0.29.1
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 +22 -0
- package/README.md +56 -25
- package/dist/aggregation/EventAggregator.d.ts +19 -0
- package/dist/aggregation/EventAggregator.js +174 -35
- package/dist/aggregation/snapshot.d.ts +37 -8
- package/dist/aggregation/snapshot.js +31 -9
- package/dist/aggregation/types.d.ts +13 -0
- package/dist/browser.d.ts +5 -1
- package/dist/browser.js +9 -3
- package/dist/context/sessionContext.js +4 -0
- package/dist/esm/aggregation/EventAggregator.js +174 -35
- package/dist/esm/aggregation/snapshot.js +31 -9
- package/dist/esm/browser.js +1 -0
- package/dist/esm/context/sessionContext.js +4 -0
- package/dist/esm/formatters/toolSummary.js +4 -1
- package/dist/esm/index.js +3 -1
- package/dist/esm/modelCatalog.js +5 -4
- package/dist/esm/modelContext.js +4 -3
- package/dist/esm/modelInfo.js +4 -3
- package/dist/esm/node.js +1 -1
- package/dist/esm/observedContextWindows.js +2 -1
- package/dist/esm/ownKey.js +26 -0
- package/dist/esm/parsers/codexParser.js +180 -4
- package/dist/esm/parsers/openCodeParser.js +2 -1
- package/dist/esm/parsers/subagentScanner.js +33 -12
- package/dist/esm/parsers/subagentTraceParser.js +97 -37
- package/dist/esm/pricingCatalog.js +3 -2
- package/dist/esm/providers/claudeCode.js +10 -2
- package/dist/esm/providers/codex.js +82 -38
- package/dist/esm/schemas/sessionEvent.js +35 -14
- package/dist/esm/subagentSpawn.js +163 -0
- package/dist/esm/transcript.js +4 -0
- package/dist/esm/turns/assistantTurn.js +3 -2
- package/dist/esm/usage/claudeUsageDedupe.js +68 -0
- package/dist/esm/watchers/eventBridge.js +15 -0
- package/dist/esm/watchers/factory.js +5 -3
- package/dist/esm/watchers/jsonlTail.js +73 -8
- package/dist/esm/watchers/jsonlWatcher.js +51 -4
- package/dist/esm/watchers/providerReaderWatcher.js +13 -0
- package/dist/esm/zaiQuota.js +2 -1
- package/dist/formatters/toolSummary.js +4 -1
- package/dist/index.d.ts +8 -3
- package/dist/index.js +18 -9
- package/dist/modelCatalog.js +5 -4
- package/dist/modelContext.js +4 -3
- package/dist/modelInfo.js +4 -3
- package/dist/node.d.ts +1 -1
- package/dist/node.js +3 -1
- package/dist/observedContextWindows.js +2 -1
- package/dist/ownKey.d.ts +16 -0
- package/dist/ownKey.js +30 -0
- package/dist/parsers/codexParser.d.ts +63 -0
- package/dist/parsers/codexParser.js +181 -4
- package/dist/parsers/openCodeParser.js +2 -1
- package/dist/parsers/subagentScanner.d.ts +19 -6
- package/dist/parsers/subagentScanner.js +33 -12
- package/dist/parsers/subagentTraceParser.d.ts +25 -5
- package/dist/parsers/subagentTraceParser.js +97 -37
- package/dist/pricingCatalog.js +3 -2
- package/dist/providers/claudeCode.js +9 -1
- package/dist/providers/codex.js +82 -38
- package/dist/providers/types.d.ts +14 -0
- package/dist/schemas/index.d.ts +1 -0
- package/dist/schemas/sessionEvent.d.ts +27 -10
- package/dist/schemas/sessionEvent.js +35 -14
- package/dist/subagentSpawn.d.ts +80 -0
- package/dist/subagentSpawn.js +174 -0
- package/dist/transcript.js +4 -0
- package/dist/turns/assistantTurn.d.ts +1 -0
- package/dist/turns/assistantTurn.js +3 -2
- package/dist/usage/claudeUsageDedupe.d.ts +31 -0
- package/dist/usage/claudeUsageDedupe.js +68 -0
- package/dist/watchers/eventBridge.js +15 -0
- package/dist/watchers/factory.d.ts +6 -0
- package/dist/watchers/factory.js +5 -3
- package/dist/watchers/jsonlTail.d.ts +27 -4
- package/dist/watchers/jsonlTail.js +75 -8
- package/dist/watchers/jsonlWatcher.d.ts +18 -1
- package/dist/watchers/jsonlWatcher.js +50 -3
- package/dist/watchers/providerReaderWatcher.d.ts +7 -0
- package/dist/watchers/providerReaderWatcher.js +13 -0
- package/dist/watchers/types.d.ts +12 -0
- package/dist/zaiQuota.js +2 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,28 @@ 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.29.1] - 2026-11-01
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **Claude Code `Agent` spawns are tracked.** Claude Code renamed its subagent tool from `Task` to `Agent`. `EventAggregator`, the subagent trace parser and scanner, the `Agent` tool summary and `isAssistantTurnSubagentTool()` recognize both names (OpenCode's `task` still maps to `Task`).
|
|
13
|
+
- **Background agents complete when they finish, not at launch.** An `Async agent launched` result keeps the lifecycle running and records the agent id; a `<task-notification>` completes it with `outcome: 'completed' | 'failed' | 'killed' | 'stopped'`. An interim notification keeps or puts the agent back to running. A foreground spawn still running at a snapshot completes after `restore()`.
|
|
14
|
+
- **Unknown permission modes no longer drop events.** `extractSessionEvents` rejected every line whose `permissionMode` it didn't know, such as Claude Code's `auto`, losing prompts, tool results and notifications. The unknown mode is now dropped and the line kept; `PermissionMode` is unchanged.
|
|
15
|
+
- **Lookups keyed by ids that match `Object.prototype` members.** `getModelPricing`, `resolveModelPricing` (which returned no `provenance` for `constructor` and `__proto__`), `getModelContextWindowSize` / `resolveModelContextWindow`, `getModelInfo`, `normalizeToolName`, `formatToolSummary` and `parseZaiQuotaError` read only own keys, and catalog, observed-window and LiteLLM tables store a `__proto__` id as data.
|
|
16
|
+
- **Snapshot resume can verify the source file.** `isSnapshotValid(snapshot, size, sourcePath)` also checks the file's identity, the digest of its first 4 KiB and the newline before the offset, and rejects a snapshot without `sourceCheckpoint`; without `sourcePath` it behaves as before. Restoring `readerState` keeps the Claude usage deduper and the Codex parser state, so a response split across the snapshot point is counted once.
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- `isSubagentSpawnTool()`, `SUBAGENT_SPAWN_TOOL_NAMES`, `parseTaskNotification()`, `taskNotificationFromEvent()`, `isTaskNotificationSystemEvent()` and the `TaskNotification` / `SubagentOutcome` types (root and `browser`).
|
|
21
|
+
- `extractSessionEvents(raw, { includeTaskNotifications })` (`ExtractSessionEventsOptions`, also from `sidekick-shared/schemas`) and `CreateWatcherOptions.includeTaskNotifications`. When enabled, Claude Code's mid-turn `queued_command` task-notification attachments become one `system` event with `origin: { kind: 'task-notification' }`. The Claude Code provider's reader enables it; the default is off.
|
|
22
|
+
- `SubagentLifecycle.agentId` / `background` / `outcome`; `SubagentTrace.filePath` / `spawnToolUseId` / `parentAgentId` / `background` / `finished` / `stoppedByUser`. `readAgentMeta()` (type `AgentMeta`) also returns `toolUseId`, `parentAgentId`, `requestShape`, `finished` and `stoppedByUser`. `scanSubagentTraces` links traces exactly by meta `parentAgentId` and spawn id before falling back to heuristics.
|
|
23
|
+
- `captureJsonlCheckpoint(filePath, offset)` and `verifyJsonlCheckpoint(filePath, checkpoint)` (root and `node`); `SessionSnapshot.sourceCheckpoint` and `readerState`.
|
|
24
|
+
- Optional `getResumeState()` / `restoreResumeState(state)` on `SessionReader` and `SessionWatcher`, implemented by the Claude Code and Codex readers and the JSONL and reader-backed watchers. `ClaudeUsageDeduper.exportState()` / `importState()` (`ClaudeUsageDedupeState`) and `CodexRolloutParser.exportResumeState()` / `importResumeState()` (`CodexRolloutResumeState`). `CodexReader.seekTo()` defers its re-parse to the first read, which a successful `restoreResumeState()` makes unnecessary.
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- `SubagentTrace.parentToolUseId` holds the spawning tool-use id from Claude Code's meta file when present, as its documentation says. Heuristic links keep storing the parent's agent id there and also set `parentAgentId`; top-level traces are those without a parent agent.
|
|
29
|
+
|
|
8
30
|
## [0.29.0] - 2026-11-01
|
|
9
31
|
|
|
10
32
|
### Fixed
|
package/README.md
CHANGED
|
@@ -9,6 +9,12 @@ Types, parsers, providers, readers, formatters, aggregation, search, reporting,
|
|
|
9
9
|
|
|
10
10
|
## Recent additions
|
|
11
11
|
|
|
12
|
+
- **0.29.1: background agents, `Agent` spawns, and verified resume**
|
|
13
|
+
- **Subagents:** Claude Code's `Agent` tool (the new name of `Task`) is tracked wherever `Task` was; `isSubagentSpawnTool()` / `SUBAGENT_SPAWN_TOOL_NAMES` name both. A background agent stays running until its `<task-notification>`, and `SubagentLifecycle` records `agentId`, `background`, and `outcome` (`completed`, `failed`, `killed`, `stopped`). `parseTaskNotification()`, `taskNotificationFromEvent()`, and `isTaskNotificationSystemEvent()` read the notices.
|
|
14
|
+
- **Traces:** `SubagentTrace` gains `filePath`, `spawnToolUseId`, `parentAgentId`, `background`, `finished`, and `stoppedByUser` from Claude Code's meta file (`readAgentMeta()`). Traces are linked by that metadata before the heuristics run, and `parentToolUseId` now holds the spawning tool-use id when the meta file records one.
|
|
15
|
+
- **Events:** `extractSessionEvents(raw, { includeTaskNotifications: true })` and `createWatcher({ includeTaskNotifications: true })` turn mid-turn task-notification attachments into `system` events. A `permissionMode` this release doesn't know (Claude Code's `auto`) no longer drops the line.
|
|
16
|
+
- **Resume:** `captureJsonlCheckpoint()` / `verifyJsonlCheckpoint()`, `SessionSnapshot.sourceCheckpoint` / `readerState`, `isSnapshotValid(snapshot, size, sourcePath)`, and optional `getResumeState()` / `restoreResumeState()` on readers and watchers. A resumed session counts a split Claude response once and keeps its Codex parser context.
|
|
17
|
+
- **Lookups:** pricing, context-window, model-info, tool-name, and z.ai error tables read only their own keys, so an id such as `constructor` or `__proto__` is treated as unknown instead of matching an `Object.prototype` member.
|
|
12
18
|
- **0.29.0: lean entries, usage attribution, and honest pricing**
|
|
13
19
|
- **New subpaths:**
|
|
14
20
|
- `sidekick-shared/pricing`: pure, 8 modules. Pricing, model identity, usage cost, cost provenance, formatting and token estimates.
|
|
@@ -127,21 +133,21 @@ returns the platform default that both overrides bypass.
|
|
|
127
133
|
| **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 |
|
|
128
134
|
| **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 |
|
|
129
135
|
| **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`) |
|
|
130
|
-
| **Parsers** | JSONL event parsing, OpenCode/Codex format normalization, subagent scanning, session path resolution, debug log parsing
|
|
131
|
-
| **Watchers** | Live session file watching with event bridging
|
|
136
|
+
| **Parsers** | JSONL event parsing, OpenCode/Codex format normalization, subagent scanning (`scanSubagentDir()`, `scanSubagentTraces()`, `readAgentMeta()`), session path resolution, debug log parsing |
|
|
137
|
+
| **Watchers** | Live session file watching with event bridging (`createWatcher()`, with `includeTaskNotifications` for Claude Code mid-turn task notifications) and optional `getResumeState()` / `restoreResumeState()`, plus `createJsonlTail()` for raw incremental JSONL consumers and `captureJsonlCheckpoint()` / `verifyJsonlCheckpoint()` for readers that keep their own offset |
|
|
132
138
|
| **Formatters** | Display helpers (`formatTokenCount()`, `formatDurationMs()`), the shared token vocabulary (`summarizeTokens()`, `formatTokenBreakdown()`, `TOKEN_*_LABEL`s) and session totals incl. subagents (`collectSessionTokenTotals()`), tool summary, noise classification, session dump (text/markdown/JSON), event highlighting |
|
|
133
139
|
| **Search** | Cross-session full-text search, advanced filtering (substring, fuzzy, regex, date) |
|
|
134
|
-
| **Aggregation** | Event aggregation, frequency tracking, activity heatmaps, pattern extraction
|
|
140
|
+
| **Aggregation** | Event aggregation (including subagent lifecycles that follow background agents to their task notification), frequency tracking, activity heatmaps, pattern extraction, and session snapshots (`saveSnapshot()`, `loadSnapshot()`, `isSnapshotValid()`) |
|
|
135
141
|
| **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()`) |
|
|
136
142
|
| **Error History** | Shared error taxonomy (`categorizeError()`, `extractErrorMessage()`) plus append-only per-project failure history (`appendErrorHistory()`, `readErrorHistory()`, `getTopFailingTools()`) behind per-tool/hour/model error rollups |
|
|
137
143
|
| **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) |
|
|
138
|
-
| **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
|
|
144
|
+
| **Assistant Turns** | Browser-safe timeline/process/answer projection for provider-normalized assistant turns (`segmentAssistantTurn()`, `assistantTurnEventsFromSessionEvents()`), including interleaved reasoning, compact tool groups, and Claude Code `Agent` / `Task` subagent refs without prompt leakage |
|
|
139
145
|
| **Report** | Self-contained HTML session report generation; `readSessionReportInputs()` returns metrics, transcript, and `subagents` for the session total |
|
|
140
146
|
| **Credentials** | Claude subscription (Pro / Max / Ultra) OAuth credential reading (macOS Keychain with a `~/.claude/.credentials.json` fallback; the file on Linux and Windows). `readClaudeCredentialStore()` returns `ok` / `absent` / `corrupt` / `error`; `writeActiveCredentials()` requires a config directory and reads every write back (`ClaudeCredentialWriteError`). `decideLiveClaudeWrite()`, `claudeRefreshFingerprint()`, `claudeLoginOnly()`, and `mergeClaudeLoginIntoLive()` expose the live-write policy. As of 0.27.6, `inspectClaudeCredentialStores()` / `repairClaudeCredentialStores()` and `inspectCodexCredentialStores()` / `repairCodexCredentialStores()` find and repair unused, duplicate, and unreadable stores Sidekick provably owns (repairs are dry runs unless `dryRun: false`), with Claude ownership recorded by `readClaudeCredentialLedger()` |
|
|
141
147
|
| **Quota** | Claude subscription quota fetching (5-hour and 7-day windows; `fiveHour.absent` on plans without a 5-hour limit such as Ultra; server meters in `limits`, `extraUsage`, and `planLabel`), 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 |
|
|
142
148
|
| **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()`) |
|
|
143
149
|
| **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 |
|
|
144
|
-
| **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
|
|
150
|
+
| **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 (and, with `{ includeTaskNotifications: true }`, mid-turn task-notification attachments). 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 |
|
|
145
151
|
| **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 |
|
|
146
152
|
| **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.1 / Opus 5.5 / Opus 5 / Opus 4.8 / Opus 4.7 1M and GPT-5.x / GPT-6 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 |
|
|
147
153
|
| **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 |
|
|
@@ -158,22 +164,22 @@ returns the platform default that both overrides bypass.
|
|
|
158
164
|
|
|
159
165
|
`sidekick-shared` ships three main entry points (the root, `/browser`, `/node`) plus narrower single-purpose 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.
|
|
160
166
|
|
|
161
|
-
| Path | Runtime | What it exposes
|
|
162
|
-
| ------------------------------------ | -------------------------- |
|
|
163
|
-
| `sidekick-shared` | Node (CLI, extension host) | Full public API (readers, providers, parsers, pricing, …).
|
|
164
|
-
| `sidekick-shared/browser` | **Browser / webview** | Pure helpers: usage normalization/pricing, token estimation, transcript and assistant-turn projection, model/context math, `parseMcpToolName()`, the `CodexRolloutParser` with the Codex rollout and session-event types, human-prompt detection (`isHumanPrompt()` / `humanPromptText()`), `renderHandoffUrlTemplate()`, and the quota window helpers (`quotaWindowApplies()`, `quotaWindowHasData()`, `quotaWindowLabel()`, `quotaWindowShortLabel()`, `extraQuotaRows()`, `formatExtraUsage()`, `claudePlanLabel()`).
|
|
165
|
-
| `sidekick-shared/node` | Node only | LiteLLM pricing and context-window hydration, public provider service status (`fetchProviderServiceStatus()`), observed context-window persistence, recent-session/transcript reads, human prompt history (`collectPromptHistory()`, and whole sessions with `collectSessionPromptHistory()`), tool-call origins (`findToolCallOrigins()`), usage events from session logs (`collectUsageEvents()` with `createSessionProviders()` and `SYNTHETIC_MODEL`), session previews (`listSessionPreviews()` / `readSessionPreview()` plus the bounded-concurrency `listSessionPreviewsAsync()` / `readSessionPreviewAsync()`), Codex history/rollout lookup (`readCodexHistory()`, `findCodexRolloutFile()`), resilient observed-session collection (`fs` + providers), the provider homes the CLIs read (`getLiveClaudeHome()`, `getClaudeProjectsDir()`, `getSystemCodexHome()`, `getCodexMonitoringHomes()`, `getCodexExecutionEnv()`), Codex `auth.json` and credential-store helpers (`codexRefreshFingerprint()`, `compareCodexAuthFreshness()`, `getCodexCredentialStoreMode()`, `forceFileCredentialStore()`), the atomic JSON writers, Claude session-directory encoding (`encodeClaudeWorkspacePath()`, `getClaudeSessionDirectory()`), and the config root (`getConfigDir()`, `CONFIG_DIR_ENV_VAR`). |
|
|
166
|
-
| `sidekick-shared/phrases` | Any runtime | Phrase arrays + `getRandomPhrase()`.
|
|
167
|
-
| `sidekick-shared/modelContext` | Any runtime | Direct access to the context-window module.
|
|
168
|
-
| `sidekick-shared/modelInfo` | Any runtime | Direct access to model parsing and cost math.
|
|
169
|
-
| `sidekick-shared/formatting` | Any runtime | Direct access to pure cost, token, and duration display helpers (`formatCost()`, `formatTokenCount()`, `formatDurationMs()`).
|
|
170
|
-
| `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.
|
|
171
|
-
| `sidekick-shared/statusline` | Node only | Cache-only statusline surface: account status + quota snapshot readers and writers, `formatStatusline()`, burn-rate estimates, quota freshness and window helpers (`quotaWindowApplies()`, `quotaWindowHasData()`, `quotaWindowShortLabel()`, `quotaHistoryWindow()`), `parseClaudeStatuslinePayload()` / `quotaFromStatuslinePayload()`, and `readStateFile()` / `writeStateFile()`.
|
|
172
|
-
| `sidekick-shared/testing` | Node test runners | `installCredentialGuard()` keeps a test process away from the real `security` / `claude` / `codex` binaries and the real Claude, Codex, and Sidekick homes, and the Claude Code / Codex session-log builders (`createSessionLogFixtures()`, `writeJsonl()`, …). Framework-free.
|
|
173
|
-
| `sidekick-shared/pricing` | Any runtime | Pure,
|
|
174
|
-
| `sidekick-shared/codex` | Node only | 13 modules, no Zod: Codex homes and the child-process env (`getSystemCodexHome()`, `resolveSidekickCodexHome()`, `getCodexExecutionEnv()`), `auth.json` helpers (`parseCodexAuthJson()`, `codexRefreshFingerprint()`, `compareCodexAuthFreshness()`), `getCodexCredentialStoreMode()` / `forceFileCredentialStore()`, `findCodexRolloutFile()`, `codexRolloutOrigin()`, `parseCodexLoginStatus()` / `parseClaudeAuthStatus()`, and `atomicWriteJson()`.
|
|
175
|
-
| `sidekick-shared/providerFailure` | Any runtime | Pure, 1 module: `diagnoseProviderFailure()`, `decodeCodexErrorInfo()`, and the identifier lists.
|
|
176
|
-
| `sidekick-shared/statusline/payload` | Any runtime | Pure, 2 modules: `parseClaudeStatuslinePayload()` / `quotaFromStatuslinePayload()` without the account, credential, or snapshot code the full `statusline` entry loads.
|
|
167
|
+
| Path | Runtime | What it exposes |
|
|
168
|
+
| ------------------------------------ | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
169
|
+
| `sidekick-shared` | Node (CLI, extension host) | Full public API (readers, providers, parsers, pricing, …). |
|
|
170
|
+
| `sidekick-shared/browser` | **Browser / webview** | Pure helpers: usage normalization/pricing, token estimation, transcript and assistant-turn projection, model/context math, `parseMcpToolName()`, the `CodexRolloutParser` with the Codex rollout and session-event types, human-prompt detection (`isHumanPrompt()` / `humanPromptText()`), `renderHandoffUrlTemplate()`, the subagent-spawn and task-notification helpers (`isSubagentSpawnTool()`, `parseTaskNotification()`, `taskNotificationFromEvent()`, `isTaskNotificationSystemEvent()`), `ClaudeUsageDeduper`, and the quota window helpers (`quotaWindowApplies()`, `quotaWindowHasData()`, `quotaWindowLabel()`, `quotaWindowShortLabel()`, `extraQuotaRows()`, `formatExtraUsage()`, `claudePlanLabel()`). |
|
|
171
|
+
| `sidekick-shared/node` | Node only | LiteLLM pricing and context-window hydration, public provider service status (`fetchProviderServiceStatus()`), observed context-window persistence, recent-session/transcript reads, human prompt history (`collectPromptHistory()`, and whole sessions with `collectSessionPromptHistory()`), tool-call origins (`findToolCallOrigins()`), usage events from session logs (`collectUsageEvents()` with `createSessionProviders()` and `SYNTHETIC_MODEL`), session previews (`listSessionPreviews()` / `readSessionPreview()` plus the bounded-concurrency `listSessionPreviewsAsync()` / `readSessionPreviewAsync()`), Codex history/rollout lookup (`readCodexHistory()`, `findCodexRolloutFile()`), resilient observed-session collection (`fs` + providers), the provider homes the CLIs read (`getLiveClaudeHome()`, `getClaudeProjectsDir()`, `getSystemCodexHome()`, `getCodexMonitoringHomes()`, `getCodexExecutionEnv()`), Codex `auth.json` and credential-store helpers (`codexRefreshFingerprint()`, `compareCodexAuthFreshness()`, `getCodexCredentialStoreMode()`, `forceFileCredentialStore()`), the bounded JSONL tail and its checkpoints (`createJsonlTail()`, `captureJsonlCheckpoint()`, `verifyJsonlCheckpoint()`), the atomic JSON writers, Claude session-directory encoding (`encodeClaudeWorkspacePath()`, `getClaudeSessionDirectory()`), and the config root (`getConfigDir()`, `CONFIG_DIR_ENV_VAR`). |
|
|
172
|
+
| `sidekick-shared/phrases` | Any runtime | Phrase arrays + `getRandomPhrase()`. |
|
|
173
|
+
| `sidekick-shared/modelContext` | Any runtime | Direct access to the context-window module. |
|
|
174
|
+
| `sidekick-shared/modelInfo` | Any runtime | Direct access to model parsing and cost math. |
|
|
175
|
+
| `sidekick-shared/formatting` | Any runtime | Direct access to pure cost, token, and duration display helpers (`formatCost()`, `formatTokenCount()`, `formatDurationMs()`). |
|
|
176
|
+
| `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. |
|
|
177
|
+
| `sidekick-shared/statusline` | Node only | Cache-only statusline surface: account status + quota snapshot readers and writers, `formatStatusline()`, burn-rate estimates, quota freshness and window helpers (`quotaWindowApplies()`, `quotaWindowHasData()`, `quotaWindowShortLabel()`, `quotaHistoryWindow()`), `parseClaudeStatuslinePayload()` / `quotaFromStatuslinePayload()`, and `readStateFile()` / `writeStateFile()`. |
|
|
178
|
+
| `sidekick-shared/testing` | Node test runners | `installCredentialGuard()` keeps a test process away from the real `security` / `claude` / `codex` binaries and the real Claude, Codex, and Sidekick homes, and the Claude Code / Codex session-log builders (`createSessionLogFixtures()`, `writeJsonl()`, …). Framework-free. |
|
|
179
|
+
| `sidekick-shared/pricing` | Any runtime | Pure, 9 modules, no Zod: model pricing and identity (`canonicalModelId()`, `parseModelId()`, `compareModelIds()`, `resolveModelPricing()`, `registerModelPricing()`, `getPricingCatalogInfo()`), usage normalization and cost (`normalizeProviderUsage()`, `calculateNormalizedUsageCost()`), cost provenance (`costSourceFromPricingProvenance()`, `mergeCostComponents()`, `mergeCostSources()`), `formatCost()` / `formatTokenCount()` / `formatDurationMs()`, and `estimateTextTokens()`. |
|
|
180
|
+
| `sidekick-shared/codex` | Node only | 13 modules, no Zod: Codex homes and the child-process env (`getSystemCodexHome()`, `resolveSidekickCodexHome()`, `getCodexExecutionEnv()`), `auth.json` helpers (`parseCodexAuthJson()`, `codexRefreshFingerprint()`, `compareCodexAuthFreshness()`), `getCodexCredentialStoreMode()` / `forceFileCredentialStore()`, `findCodexRolloutFile()`, `codexRolloutOrigin()`, `parseCodexLoginStatus()` / `parseClaudeAuthStatus()`, and `atomicWriteJson()`. |
|
|
181
|
+
| `sidekick-shared/providerFailure` | Any runtime | Pure, 1 module: `diagnoseProviderFailure()`, `decodeCodexErrorInfo()`, and the identifier lists. |
|
|
182
|
+
| `sidekick-shared/statusline/payload` | Any runtime | Pure, 2 modules: `parseClaudeStatuslinePayload()` / `quotaFromStatuslinePayload()` without the account, credential, or snapshot code the full `statusline` entry loads. |
|
|
177
183
|
|
|
178
184
|
Since 0.28.0 every subpath also has a `module` condition pointing at an ES-module build in `dist/esm/`. Bundlers that read it (esbuild, Vite, Rollup, webpack) tree-shake unused exports, so importing one helper from `sidekick-shared/node` bundles a few hundred bytes instead of the whole entry. Node itself never reads `module` and keeps loading the CommonJS build for both `require` and `import`, so a process never holds two copies of module state.
|
|
179
185
|
|
|
@@ -999,9 +1005,28 @@ const projection = segmentAssistantTurn(assistantTurnEventsFromSessionEvents(ses
|
|
|
999
1005
|
console.log(projection.answer);
|
|
1000
1006
|
console.log(projection.timeline);
|
|
1001
1007
|
console.log(projection.process.steps);
|
|
1002
|
-
console.log(projection.subagents); // Claude Task spawns, prompt text omitted
|
|
1008
|
+
console.log(projection.subagents); // Claude Code Agent / Task spawns, prompt text omitted
|
|
1003
1009
|
```
|
|
1004
1010
|
|
|
1011
|
+
### Follow subagents and background agents
|
|
1012
|
+
|
|
1013
|
+
Claude Code spawns subagents with its `Agent` tool (`Task` is the earlier name, and OpenCode's `task` normalizes to it). `isSubagentSpawnTool(name)` and `SUBAGENT_SPAWN_TOOL_NAMES` name both, and `EventAggregator`, the trace scanner, `formatToolSummary()`, and `isAssistantTurnSubagentTool()` use them.
|
|
1014
|
+
|
|
1015
|
+
```typescript
|
|
1016
|
+
import { scanSubagentTraces } from 'sidekick-shared';
|
|
1017
|
+
|
|
1018
|
+
for (const agent of aggregator.getMetrics().subagents) {
|
|
1019
|
+
// { id, description, subagentType, spawnTime, status, completionTime?, durationMs?, agentId?, background?, outcome? }
|
|
1020
|
+
}
|
|
1021
|
+
const traces = scanSubagentTraces(sessionDir, sessionId); // top-level traces; children nested
|
|
1022
|
+
// { agentId, agentType?, description?, filePath?, spawnToolUseId?, parentToolUseId?, parentAgentId?,
|
|
1023
|
+
// background?, finished?, stoppedByUser?, events, children, stats }
|
|
1024
|
+
```
|
|
1025
|
+
|
|
1026
|
+
- **Background agents.** Since 0.29.1 a spawn whose result is `Async agent launched successfully.` stays `running` with `background: true` and the reported `agentId`. Its `<task-notification>` completes it with an `outcome` of `completed`, `failed`, `killed`, or `stopped`. A foreground spawn ends on its result, with `failed` when that result is an error. An interim notification, sent when the agent is waiting on background work of its own, keeps it `running` or puts it back.
|
|
1027
|
+
- **Task notifications.** Most arrive as their own user line. One that lands mid-turn is recorded only as a `queued_command` attachment. `extractSessionEvents(raw, { includeTaskNotifications: true })` and `createWatcher({ …, includeTaskNotifications: true })` turn that attachment into a `system` event with `origin: { kind: 'task-notification' }`. The option is off by default, and the Claude Code provider's reader always turns it on. Transcripts, context snapshots, and the aggregator's counters skip that event. `parseTaskNotification(text)` returns `{ taskId, toolUseId?, status?, summary?, interim }`, `taskNotificationFromEvent(event)` finds a notification in a user or system event, and `isTaskNotificationSystemEvent(event)` recognizes the synthetic event. These helpers and the `TaskNotification` / `SubagentOutcome` types are on the root and `/browser`.
|
|
1028
|
+
- **Traces.** `readAgentMeta()` reads Claude Code's `agent-<id>.meta.json` and returns an `AgentMeta` with `agentType`, `description`, `toolUseId`, `parentAgentId`, `requestShape`, `finished`, and `stoppedByUser`. `scanSubagentTraces()` places a trace under the agent its meta file names, then under the trace that holds its spawn call, and falls back to heuristics only after that. `parentToolUseId` is the spawning tool-use id when the meta file records one. A heuristic link stores the parent's agent id there, as before, and also sets `parentAgentId`.
|
|
1029
|
+
|
|
1005
1030
|
### Format shared dashboard values
|
|
1006
1031
|
|
|
1007
1032
|
```typescript
|
|
@@ -1024,7 +1049,7 @@ const parser = new JsonlParser(
|
|
|
1024
1049
|
parser.processChunk(rawData);
|
|
1025
1050
|
```
|
|
1026
1051
|
|
|
1027
|
-
The boundary schemas — `sessionEventSchema` plus the quota, account-status, account-management, and quota-history schemas — are also importable fs-free from `sidekick-shared/schemas`, which keeps Zod out of bundles that only need the pure math/formatting helpers. Account and quota APIs are guaranteed to return values valid against the schemas exported in the same release, so consumers do not need to parse those library results again. Additive account or quota fields are added to the matching exported schema in the same release. `extractSessionEvents()` from the same subpath unwraps Claude Code `progress`-wrapped events into canonical `SessionEvent[]
|
|
1052
|
+
The boundary schemas — `sessionEventSchema` plus the quota, account-status, account-management, and quota-history schemas — are also importable fs-free from `sidekick-shared/schemas`, which keeps Zod out of bundles that only need the pure math/formatting helpers. Account and quota APIs are guaranteed to return values valid against the schemas exported in the same release, so consumers do not need to parse those library results again. Additive account or quota fields are added to the matching exported schema in the same release. `extractSessionEvents()` from the same subpath unwraps Claude Code `progress`-wrapped events into canonical `SessionEvent[]`; its second argument is still the starting depth or, since 0.29.1, `ExtractSessionEventsOptions` (`{ includeTaskNotifications }`). Since 0.29.1 `sessionEventSchema` drops a `permissionMode` it does not know (Claude Code's `auto`) instead of rejecting the line; `permissionModeSchema` and `PermissionMode` are unchanged.
|
|
1028
1053
|
|
|
1029
1054
|
### Tail raw JSONL events incrementally
|
|
1030
1055
|
|
|
@@ -1045,7 +1070,7 @@ const tail = createJsonlTail({
|
|
|
1045
1070
|
tail.start();
|
|
1046
1071
|
```
|
|
1047
1072
|
|
|
1048
|
-
A poll reads from the last position to the end of the file in chunks of `maxReadBytes` (default 1 MiB), so a cold start on a large file never allocates more than one chunk plus one line. `onEvent` receives each line's `{ offset, length }` as its second argument. A line longer than `maxLineBytes` (default 16 MiB) is skipped as it streams past, even while it is still being written, and reported to `onError`. The tail also checks that it is still reading the same content. When the path now names another file (`replaced`), the file shrank (`truncated`), or its first 4 KiB or the byte before the resume point changed (`rewritten`), it starts over (from offset 0 by default; see `onRewrite`) and calls `onReset({ reason, previousOffset })` before the events from the start arrive. `createJsonlTail()` is also exported from
|
|
1073
|
+
A poll reads from the last position to the end of the file in chunks of `maxReadBytes` (default 1 MiB), so a cold start on a large file never allocates more than one chunk plus one line. `onEvent` receives each line's `{ offset, length }` as its second argument. A line longer than `maxLineBytes` (default 16 MiB) is skipped as it streams past, even while it is still being written, and reported to `onError`. The tail also checks that it is still reading the same content. When the path now names another file (`replaced`), the file shrank (`truncated`), or its first 4 KiB or the byte before the resume point changed (`rewritten`), it starts over (from offset 0 by default; see `onRewrite`) and calls `onReset({ reason, previousOffset })` before the events from the start arrive. `createJsonlTail()` is also exported from the package root.
|
|
1049
1074
|
|
|
1050
1075
|
Since 0.29.0:
|
|
1051
1076
|
|
|
@@ -1054,7 +1079,13 @@ Since 0.29.0:
|
|
|
1054
1079
|
- `checkpoint()` returns a JSON-serializable `{ version: 1, offset, identity, prefixDigest }`. A new tail's `resumeFrom(checkpoint)` continues from it after a restart, and returns false (applying the rewrite policy) when the file is no longer the one checkpointed.
|
|
1055
1080
|
- `read()` is an async pull that returns the new complete lines.
|
|
1056
1081
|
|
|
1057
|
-
|
|
1082
|
+
#### Resume readers and snapshots
|
|
1083
|
+
|
|
1084
|
+
Since 0.29.1, readers that keep their own byte offset can use the same check without a tail: `captureJsonlCheckpoint(path, offset)` returns a checkpoint for a resume-safe offset (or `null`), and `verifyJsonlCheckpoint(path, checkpoint)` reports whether it still matches the file. Store one as `SessionSnapshot.sourceCheckpoint` when you save a snapshot (`saveSnapshot()` writes what it is given); `isSnapshotValid(snapshot, size, sourcePath)` then rejects a snapshot whose file was replaced or rewritten, or that has no checkpoint for its `readerPosition`; without `sourcePath` it keeps the size-only check.
|
|
1085
|
+
|
|
1086
|
+
Also since 0.29.1, a position alone does not resume every reader correctly: Claude Code writes one response as several lines that repeat its usage, so a reader resumed between them would count it again. `SessionReader` and `SessionWatcher` gain optional `getResumeState()` / `restoreResumeState(state)`: persist the state with the position (snapshots carry it as `readerState`), call `restoreResumeState()` right after `seekTo()` (for a watcher, before `start()`), and replay from the start when it returns false. The Claude Code reader and watcher carry their `ClaudeUsageDeduper` state (`exportState()` / `importState()`, a `ClaudeUsageDedupeState`); the Codex reader, and the reader-backed watcher `createWatcher()` builds for Codex, carry `CodexRolloutParser.exportResumeState()` / `importResumeState()` (a `CodexRolloutResumeState`). The Codex reader's `seekTo()` now waits until the first read to re-parse the rollout prefix, and a successful `restoreResumeState()` skips that re-parse.
|
|
1087
|
+
|
|
1088
|
+
`SessionWatcherCallbacks.onBatchComplete` is also available through `createWatcher()`. Save aggregation state only after a complete event batch and only when the state includes the full history (a completed replay or a compatible restored checkpoint). Live-only state is incomplete and must not replace a full-history checkpoint. JSONL positions end at complete lines; a Codex reader rebuilds parser context from the rollout prefix on its first read after seeking, unless `restoreResumeState()` supplied it. OpenCode's SQLite timestamp cursor does not persist row-version deduplication, so the dashboards replay OpenCode history instead of restoring a snapshot.
|
|
1058
1089
|
|
|
1059
1090
|
### Search a workspace and diagnose its provider
|
|
1060
1091
|
|
|
@@ -226,7 +226,26 @@ export declare class EventAggregator {
|
|
|
226
226
|
private isGoalGateTask;
|
|
227
227
|
private extractSubagentFromEvent;
|
|
228
228
|
private extractSubagentFromFollowEvent;
|
|
229
|
+
private trackSubagentSpawn;
|
|
230
|
+
/**
|
|
231
|
+
* The spawning tool call's result. A foreground agent ends here; a
|
|
232
|
+
* background launch only reports the agent id, and the agent keeps running
|
|
233
|
+
* until its task notification arrives.
|
|
234
|
+
*/
|
|
235
|
+
private resolveSubagentResult;
|
|
236
|
+
private markBackgroundLaunch;
|
|
229
237
|
private completeSubagent;
|
|
238
|
+
private finishSubagent;
|
|
239
|
+
/**
|
|
240
|
+
* Applies a background task's notification to the subagent it reports on,
|
|
241
|
+
* matched by the spawning tool_use id (or by agent id when the notification
|
|
242
|
+
* has none). The latest notification wins: an interim one ("waiting on its
|
|
243
|
+
* own background work") keeps or puts the agent back to running, a final one
|
|
244
|
+
* completes it. Notifications for background shell tasks match nothing.
|
|
245
|
+
*/
|
|
246
|
+
private applyTaskNotification;
|
|
247
|
+
private findNotifiedSubagent;
|
|
248
|
+
private addTaskNotificationTimeline;
|
|
230
249
|
private extractPlanFromSessionEvent;
|
|
231
250
|
private processPlanFollowEvent;
|
|
232
251
|
private convertExtractedPlanToPlanState;
|