sidekick-shared 0.27.6 → 0.28.0

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.
Files changed (269) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +58 -18
  3. package/dist/browser.d.ts +13 -2
  4. package/dist/browser.js +30 -2
  5. package/dist/claudePaths.d.ts +11 -0
  6. package/dist/claudePaths.js +61 -0
  7. package/dist/claudeProfiles.d.ts +2 -9
  8. package/dist/claudeProfiles.js +10 -25
  9. package/dist/codexPaths.d.ts +22 -0
  10. package/dist/codexPaths.js +67 -0
  11. package/dist/codexProfiles.d.ts +1 -4
  12. package/dist/codexProfiles.js +5 -43
  13. package/dist/doctor.js +2 -2
  14. package/dist/esm/accountChangeSignal.js +15 -0
  15. package/dist/esm/accountChanges.js +152 -0
  16. package/dist/esm/accountHealth.js +288 -0
  17. package/dist/esm/accountLaunch.js +145 -0
  18. package/dist/esm/accountLease.js +60 -0
  19. package/dist/esm/accountManager.js +606 -0
  20. package/dist/esm/accountRegistry.js +214 -0
  21. package/dist/esm/accountStatus.js +51 -0
  22. package/dist/esm/accountSwitch.js +74 -0
  23. package/dist/esm/accountSync.js +156 -0
  24. package/dist/esm/accountSyncTypes.js +4 -0
  25. package/dist/esm/accounts.js +1291 -0
  26. package/dist/esm/aggregation/EventAggregator.js +2034 -0
  27. package/dist/esm/aggregation/FrequencyTracker.js +69 -0
  28. package/dist/esm/aggregation/HeatmapTracker.js +89 -0
  29. package/dist/esm/aggregation/PatternExtractor.js +168 -0
  30. package/dist/esm/aggregation/costProvenance.js +31 -0
  31. package/dist/esm/aggregation/snapshot.js +161 -0
  32. package/dist/esm/aggregation/types.js +5 -0
  33. package/dist/esm/analytics/codeImpact.js +18 -0
  34. package/dist/esm/analytics/compactionLedger.js +37 -0
  35. package/dist/esm/analytics/qualityScore.js +112 -0
  36. package/dist/esm/autoSwitch.js +185 -0
  37. package/dist/esm/browser.js +34 -0
  38. package/dist/esm/claudeCredentialDoctor.js +239 -0
  39. package/dist/esm/claudeCredentialLedger.js +91 -0
  40. package/dist/esm/claudeCredentials.js +111 -0
  41. package/dist/esm/claudeLiveGuard.js +43 -0
  42. package/dist/esm/claudePaths.js +22 -0
  43. package/dist/esm/claudeProfiles.js +142 -0
  44. package/dist/esm/claudeRefreshLock.js +106 -0
  45. package/dist/esm/codexAuth.js +101 -0
  46. package/dist/esm/codexCredentialDoctor.js +265 -0
  47. package/dist/esm/codexCredentialStore.js +164 -0
  48. package/dist/esm/codexKeepAlive.js +112 -0
  49. package/dist/esm/codexPaths.js +172 -0
  50. package/dist/esm/codexProfiles.js +1251 -0
  51. package/dist/esm/codexQuota.js +564 -0
  52. package/dist/esm/codexQuotaWatcher.js +363 -0
  53. package/dist/esm/context/composer.js +71 -0
  54. package/dist/esm/context/sessionContext.js +546 -0
  55. package/dist/esm/credentialIO.js +283 -0
  56. package/dist/esm/credentials.js +49 -0
  57. package/dist/esm/doctor.js +305 -0
  58. package/dist/esm/ensureDefaultAccounts.js +62 -0
  59. package/dist/esm/errorHistory.js +56 -0
  60. package/dist/esm/extractors/errorTaxonomy.js +43 -0
  61. package/dist/esm/extractors/gatherAssets.js +32 -0
  62. package/dist/esm/extractors/sessionAssets.js +176 -0
  63. package/dist/esm/extractors/sources/claudeAssets.js +158 -0
  64. package/dist/esm/extractors/sources/codexAssets.js +234 -0
  65. package/dist/esm/extractors/tokenUsage.js +41 -0
  66. package/dist/esm/extractors/toolCall.js +142 -0
  67. package/dist/esm/failingTools.js +65 -0
  68. package/dist/esm/fileHead.js +27 -0
  69. package/dist/esm/formatters/eventHighlighter.js +332 -0
  70. package/dist/esm/formatters/noiseClassifier.js +209 -0
  71. package/dist/esm/formatters/sessionDump.js +328 -0
  72. package/dist/esm/formatters/toolSummary.js +226 -0
  73. package/dist/esm/formatting.js +82 -0
  74. package/dist/esm/handoffUrl.js +23 -0
  75. package/dist/esm/historicalStore.js +305 -0
  76. package/dist/esm/humanPrompt.js +88 -0
  77. package/dist/esm/index.js +213 -0
  78. package/dist/esm/keepAlive.js +189 -0
  79. package/dist/esm/liveCredentialGuard.js +33 -0
  80. package/dist/esm/modelAliases.js +51 -0
  81. package/dist/esm/modelCatalog.js +139 -0
  82. package/dist/esm/modelContext.js +280 -0
  83. package/dist/esm/modelInfo.js +832 -0
  84. package/dist/esm/multiProviderQuotaService.js +450 -0
  85. package/dist/esm/node.js +46 -0
  86. package/dist/esm/observedContextWindows.js +165 -0
  87. package/dist/esm/observedSessionCollector.js +939 -0
  88. package/dist/esm/parsers/changelogParser.js +71 -0
  89. package/dist/esm/parsers/codexHistory.js +89 -0
  90. package/dist/esm/parsers/codexParser.js +906 -0
  91. package/dist/esm/parsers/debugLogParser.js +126 -0
  92. package/dist/esm/parsers/jsonl.js +66 -0
  93. package/dist/esm/parsers/mcpToolName.js +28 -0
  94. package/dist/esm/parsers/openCodeParser.js +625 -0
  95. package/dist/esm/parsers/planExtractor.js +335 -0
  96. package/dist/esm/parsers/sessionActivityDetector.js +246 -0
  97. package/dist/esm/parsers/sessionPathResolver.js +713 -0
  98. package/dist/esm/parsers/subagentScanner.js +360 -0
  99. package/dist/esm/parsers/subagentStatsCache.js +45 -0
  100. package/dist/esm/parsers/subagentTraceParser.js +325 -0
  101. package/dist/esm/paths.js +134 -0
  102. package/dist/esm/peakHours.js +194 -0
  103. package/dist/esm/phrases.js +1330 -0
  104. package/dist/esm/pricingCatalog.js +247 -0
  105. package/dist/esm/processDetection.js +200 -0
  106. package/dist/esm/projectMigration.js +59 -0
  107. package/dist/esm/promptHistory.js +1221 -0
  108. package/dist/esm/providerFailure.js +362 -0
  109. package/dist/esm/providerIds.js +6 -0
  110. package/dist/esm/providerQuota.js +1 -0
  111. package/dist/esm/providerServiceStatus.js +145 -0
  112. package/dist/esm/providerServiceStatusTypes.js +1 -0
  113. package/dist/esm/providerStatus.js +117 -0
  114. package/dist/esm/providers/claudeCode.js +575 -0
  115. package/dist/esm/providers/claudeListing.js +121 -0
  116. package/dist/esm/providers/codex.js +1034 -0
  117. package/dist/esm/providers/codexDatabase.js +297 -0
  118. package/dist/esm/providers/codexRollouts.js +215 -0
  119. package/dist/esm/providers/detect.js +185 -0
  120. package/dist/esm/providers/diagnostics.js +83 -0
  121. package/dist/esm/providers/directoryListingCache.js +206 -0
  122. package/dist/esm/providers/factory.js +54 -0
  123. package/dist/esm/providers/openCode.js +2008 -0
  124. package/dist/esm/providers/openCodeDatabase.js +419 -0
  125. package/dist/esm/providers/rolloutWalker.js +252 -0
  126. package/dist/esm/providers/types.js +12 -0
  127. package/dist/esm/quota.js +182 -0
  128. package/dist/esm/quotaHistory.js +364 -0
  129. package/dist/esm/quotaPoller.js +230 -0
  130. package/dist/esm/quotaPresentation.js +97 -0
  131. package/dist/esm/quotaResolver.js +231 -0
  132. package/dist/esm/quotaSnapshots.js +130 -0
  133. package/dist/esm/quotaThresholds.js +85 -0
  134. package/dist/esm/readers/decisions.js +24 -0
  135. package/dist/esm/readers/handoff.js +20 -0
  136. package/dist/esm/readers/helpers.js +27 -0
  137. package/dist/esm/readers/history.js +9 -0
  138. package/dist/esm/readers/notes.js +48 -0
  139. package/dist/esm/readers/plans.js +225 -0
  140. package/dist/esm/readers/tasks.js +19 -0
  141. package/dist/esm/report/htmlHelpers.js +280 -0
  142. package/dist/esm/report/htmlReportGenerator.js +704 -0
  143. package/dist/esm/report/index.js +7 -0
  144. package/dist/esm/report/logo.js +2 -0
  145. package/dist/esm/report/openBrowser.js +19 -0
  146. package/dist/esm/report/sessionReportInputs.js +33 -0
  147. package/dist/esm/report/transcriptParser.js +83 -0
  148. package/dist/esm/report/types.js +4 -0
  149. package/dist/esm/schemas/accountManager.js +204 -0
  150. package/dist/esm/schemas/accountStatus.js +25 -0
  151. package/dist/esm/schemas/assistantTurn.js +74 -0
  152. package/dist/esm/schemas/index.js +25 -0
  153. package/dist/esm/schemas/observedSessionV1.js +77 -0
  154. package/dist/esm/schemas/providerFailure.js +37 -0
  155. package/dist/esm/schemas/quota.js +132 -0
  156. package/dist/esm/schemas/quotaHistory.js +40 -0
  157. package/dist/esm/schemas/sessionEvent.js +216 -0
  158. package/dist/esm/schemas/stateFile.js +75 -0
  159. package/dist/esm/schemas/tokenEstimation.js +7 -0
  160. package/dist/esm/schemas/transcript.js +86 -0
  161. package/dist/esm/schemas/usageNormalization.js +38 -0
  162. package/dist/esm/search/advancedFilter.js +197 -0
  163. package/dist/esm/search/sessionSearch.js +66 -0
  164. package/dist/esm/sessionFingerprint.js +40 -0
  165. package/dist/esm/sessionMonitor.js +198 -0
  166. package/dist/esm/sessionPreviews.js +522 -0
  167. package/dist/esm/sessionPromptHistory.js +254 -0
  168. package/dist/esm/sessionPromptSignals.js +364 -0
  169. package/dist/esm/sessionStats.js +160 -0
  170. package/dist/esm/sessionTokenTotals.js +98 -0
  171. package/dist/esm/sessionTranscripts.js +49 -0
  172. package/dist/esm/stateFile.js +119 -0
  173. package/dist/esm/statusline/BurnRateCalculator.js +40 -0
  174. package/dist/esm/statusline/claudeStatuslinePayload.js +148 -0
  175. package/dist/esm/statusline/formatter.js +122 -0
  176. package/dist/esm/statusline/index.js +8 -0
  177. package/dist/esm/terminalSync.js +95 -0
  178. package/dist/esm/testing/credentialGuard.js +197 -0
  179. package/dist/esm/testing/index.js +12 -0
  180. package/dist/esm/testing/sessionLogFixtures.js +128 -0
  181. package/dist/esm/tokenEstimation.js +67 -0
  182. package/dist/esm/tokenSummary.js +113 -0
  183. package/dist/esm/toolCategory.js +82 -0
  184. package/dist/esm/transcript.js +257 -0
  185. package/dist/esm/turns/assistantTurn.js +373 -0
  186. package/dist/esm/types/codex.js +23 -0
  187. package/dist/esm/types/decisionLog.js +5 -0
  188. package/dist/esm/types/historicalData.js +47 -0
  189. package/dist/esm/types/knowledgeNote.js +15 -0
  190. package/dist/esm/types/observedSessionV1.js +257 -0
  191. package/dist/esm/types/opencode.js +12 -0
  192. package/dist/esm/types/plan.js +7 -0
  193. package/dist/esm/types/sessionEvent.js +10 -0
  194. package/dist/esm/types/taskPersistence.js +12 -0
  195. package/dist/esm/usage/billingBlocks.js +148 -0
  196. package/dist/esm/usage/claudeUsageDedupe.js +189 -0
  197. package/dist/esm/usage/importSessionHistory.js +84 -0
  198. package/dist/esm/usage/subagentUsage.js +18 -0
  199. package/dist/esm/usage/usageEvents.js +402 -0
  200. package/dist/esm/usage/usageReports.js +202 -0
  201. package/dist/esm/usageNormalization.js +95 -0
  202. package/dist/esm/watchers/eventBridge.js +219 -0
  203. package/dist/esm/watchers/factory.js +63 -0
  204. package/dist/esm/watchers/jsonlTail.js +289 -0
  205. package/dist/esm/watchers/jsonlWatcher.js +435 -0
  206. package/dist/esm/watchers/providerReaderWatcher.js +118 -0
  207. package/dist/esm/watchers/sqliteWatcher.js +285 -0
  208. package/dist/esm/watchers/types.js +4 -0
  209. package/dist/esm/workspaceRoots.js +56 -0
  210. package/dist/esm/writers/atomic.js +375 -0
  211. package/dist/esm/writers/decisions.js +51 -0
  212. package/dist/esm/writers/notes.js +46 -0
  213. package/dist/esm/writers/tasks.js +63 -0
  214. package/dist/esm/zaiQuota.js +323 -0
  215. package/dist/esm/zaiQuotaApi.js +271 -0
  216. package/dist/esm/zaiQuotaWatcher.js +265 -0
  217. package/dist/fileHead.d.ts +22 -0
  218. package/dist/fileHead.js +33 -0
  219. package/dist/index.d.ts +16 -7
  220. package/dist/index.js +49 -15
  221. package/dist/node.d.ts +13 -1
  222. package/dist/node.js +43 -2
  223. package/dist/parsers/codexHistory.js +2 -2
  224. package/dist/parsers/codexParser.d.ts +12 -0
  225. package/dist/parsers/codexParser.js +34 -12
  226. package/dist/parsers/debugLogParser.js +2 -2
  227. package/dist/parsers/sessionPathResolver.js +5 -4
  228. package/dist/promptHistory.d.ts +32 -0
  229. package/dist/promptHistory.js +115 -59
  230. package/dist/providerFailure.d.ts +12 -6
  231. package/dist/providerFailure.js +45 -0
  232. package/dist/providers/claudeCode.js +7 -99
  233. package/dist/providers/claudeListing.d.ts +22 -0
  234. package/dist/providers/claudeListing.js +158 -0
  235. package/dist/providers/codex.d.ts +3 -1
  236. package/dist/providers/codex.js +26 -227
  237. package/dist/providers/codexRollouts.d.ts +44 -0
  238. package/dist/providers/codexRollouts.js +261 -0
  239. package/dist/providers/detect.js +4 -4
  240. package/dist/readers/plans.js +3 -3
  241. package/dist/schemas/index.d.ts +2 -0
  242. package/dist/schemas/index.js +7 -2
  243. package/dist/schemas/providerFailure.d.ts +154 -0
  244. package/dist/schemas/providerFailure.js +40 -0
  245. package/dist/sessionPromptHistory.d.ts +12 -7
  246. package/dist/sessionPromptHistory.js +15 -3
  247. package/dist/sessionPromptSignals.d.ts +9 -0
  248. package/dist/sessionPromptSignals.js +13 -0
  249. package/dist/testing/credentialGuard.d.ts +23 -0
  250. package/dist/testing/credentialGuard.js +233 -0
  251. package/dist/testing/index.d.ts +14 -0
  252. package/dist/testing/index.js +22 -0
  253. package/dist/testing/sessionLogFixtures.d.ts +28 -0
  254. package/dist/testing/sessionLogFixtures.js +169 -0
  255. package/dist/tokenEstimation.d.ts +2 -0
  256. package/dist/tokenEstimation.js +21 -11
  257. package/dist/toolCategory.d.ts +18 -0
  258. package/dist/toolCategory.js +86 -0
  259. package/dist/types/codex.d.ts +4 -0
  260. package/dist/usage/usageEvents.d.ts +16 -0
  261. package/dist/usage/usageEvents.js +53 -9
  262. package/dist/watchers/jsonlTail.d.ts +26 -1
  263. package/dist/watchers/jsonlTail.js +136 -28
  264. package/dist/watchers/jsonlWatcher.js +7 -0
  265. package/dist/watchers/providerReaderWatcher.js +1 -0
  266. package/dist/watchers/types.d.ts +6 -0
  267. package/dist/workspaceRoots.d.ts +23 -0
  268. package/dist/workspaceRoots.js +93 -0
  269. package/package.json +22 -2
package/CHANGELOG.md CHANGED
@@ -5,6 +5,34 @@ 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.28.0] - 2026-10-18
9
+
10
+ ### Added
11
+
12
+ - **Tree-shakable ES modules for bundlers.** Every exports subpath gains a `module` condition pointing at an ES-module build in `dist/esm/` (esbuild, Vite, Rollup, and webpack read it ahead of `import`/`require`). Node never reads `module` and keeps loading CommonJS, so a process cannot hold two copies of module state; `./dist/esm/*` is blocked from the `dist/*` wildcard. One helper from `/node` now bundles in hundreds of bytes instead of about 366 KB.
13
+ - **Narrow-entry exports.** `sidekick-shared/browser`: `CodexRolloutParser` (with `DEFAULT_MAX_TRACKED_TOOL_CALLS` and `CodexRolloutParserOptions`), the Codex tool-name helpers, the session-event and Codex rollout types (including `CompactionEvent` and `ContextAttribution`), `isAggregateCodexLimit()`, `isHumanPrompt()` / `humanPromptText()` and the human entrypoint lists, `renderHandoffUrlTemplate()`, the provider-failure identifier arrays, `ASCII_CHARS_PER_TOKEN`, and `classifyTool()`. `sidekick-shared/node`: `getLiveClaudeHome()`, `getDefaultClaudeHome()`, `isDefaultClaudeHome()`, `getClaudeProjectsDir()`, `getSystemCodexHome()`, `getCodexMonitoringHomes()`, `resolveSidekickCodexHome()`, `getCodexExecutionEnv()`, `getCodexSessionsDirs()`, `getConfigDir()` / `CONFIG_DIR_ENV_VAR`, `encodeClaudeWorkspacePath()` / `getClaudeSessionDirectory()`, `resolveWorkspaceRoots()`, `resolveWorktreeMainRepo()` / `discoverWorktreeSiblings()`, and `createJsonlTail()`.
14
+ - **`sidekick-shared/testing`.** `installCredentialGuard()` keeps a test process away from the real `security` / `claude` / `codex` binaries and the real Claude, Codex, and Sidekick homes (framework-free; Node 20.16+, or CommonJS on older Node; temp home removed on exit; `SIDEKICK_CONFIG_DIR` cleared), plus the Claude Code and Codex session-log builders. The internal vitest setup is now a thin shim over it.
15
+ - **Provider-failure schema.** `PROVIDER_FAILURE_CODES`, `PROVIDER_RECOVERY_ACTIONS`, `PROVIDER_CREDENTIAL_KINDS`, `PROVIDER_AUTHENTICATION_STATES`, `PROVIDER_AUTHENTICATION_SOURCES`, and `PROVIDER_FAILURE_EVIDENCE_SOURCES` define the existing union types, and `providerFailureDiagnosisSchema` (plus the evidence, authentication, and retry-after schemas) on `sidekick-shared/schemas` is built from them.
16
+ - **Prompt-history change reporting.** `collectPromptHistory()` results add `changed`, `progressed`, and `roots`; entries, whole sessions, `unread`, and `changed` carry an opaque `sessionKey`; `collectSessionPromptHistory()` accepts `sessionRefs` matched on (provider, sessionId) or one file; `isPromptHistorySessionSettled()` and `parsePromptHistoryCursor()` are exported.
17
+ - **Tool categories on signals.** `classifyTool(name, { mcpServer })` and `TOOL_CATEGORIES`; prompt-history signals that name a tool carry `toolCategory` and, for MCP calls, `mcpServer` (Codex's `invocation.server` / `server` was dropped before).
18
+ - **Multi-root usage.** `collectUsageEvents({ workspacePaths, includeWorktrees })` lists several roots in one call and counts each session file once; results add `roots`, and events add `filePath`.
19
+ - **Bounded JSONL tail.** `createJsonlTail()` gains `maxReadBytes` (1 MiB chunks), `maxLineBytes` (16 MiB, longer lines skipped and reported), each line's `{ offset, length }` as `onEvent`'s second argument, and `onReset({ reason, previousOffset })` for `truncated`, `rewritten` (first 4 KiB or the byte before the resume point changed), and `replaced` (another inode) files.
20
+ - `SessionWatcherCallbacks.onReset`: the JSONL and provider-reader watchers call it when the session file is truncated, rewritten, or replaced and its events are delivered again from the start.
21
+ - `getCodexSessionsDirs()`, `CODEX_SESSIONS_SUBDIR`, `CODEX_ARCHIVED_SESSIONS_SUBDIR`, and `CodexDbThread.archived` / `archived_at`.
22
+
23
+ ### Fixed
24
+
25
+ - **`CLAUDE_CONFIG_DIR`.** Claude session discovery, path resolution, provider detection, doctor, plans, and debug logs hard-coded `~/.claude`; they now use the live Claude home, as every credential and identity read already did.
26
+ - **Archived Codex rollouts.** Rollout lookup, listings, and watch roots include each home's `archived_sessions/`, and a prompt-history cursor entry follows a session whose file moved there (when the new file starts with the recorded head) instead of re-reading it as new. An `archived_sessions/` directory created after a watcher starts is picked up by its catch-up poll.
27
+ - `getCodexExecutionEnv(baseEnv)` keeps a non-blank `CODEX_HOME` from `baseEnv`.
28
+ - `CodexRolloutParser` bounds its emitted-tool, expanded-patch, and pending exec/MCP tables (`maxTrackedToolCalls`, default 4096).
29
+ - The session watcher resets its Claude usage de-duplication and Codex state when its tail starts over.
30
+
31
+ ### Changed
32
+
33
+ - `sidekick-shared/node` no longer reaches the account-switching modules: Codex home resolution moved to `codexPaths` (re-exported from `codexProfiles`), and prompt history lists files through standalone `listClaudeSessionFilesAsync()` / `listCodexSessionFilesAsync()` instead of constructing providers (`collectPromptHistory` bundles in 30 KB instead of 170 KB).
34
+ - `estimateTextTokens()` counts a leading ASCII run without regex tests (about 15× faster, identical results).
35
+
8
36
  ## [0.27.6] - 2026-09-26
9
37
 
10
38
  ### Fixed
package/README.md CHANGED
@@ -9,6 +9,7 @@ Types, parsers, providers, readers, formatters, aggregation, search, reporting,
9
9
 
10
10
  ## Recent additions
11
11
 
12
+ - **0.28.0: ES modules, narrow entries, and new readers** — a `module` export condition gives bundlers a tree-shakable ES-module build (Node keeps CommonJS); browser-safe parsers and helpers move onto `/browser` and the provider-home helpers onto `/node`; `sidekick-shared/testing` publishes the credential guard; `providerFailureDiagnosisSchema` joins `/schemas`; prompt history reports `changed` / `progressed` / `roots` and takes `sessionRefs`; signals carry `toolCategory` and `mcpServer`; `collectUsageEvents()` takes `workspacePaths`; `createJsonlTail()` is bounded and reports resets; and Claude sessions follow `CLAUDE_CONFIG_DIR` while Codex lookups include `archived_sessions/`.
12
13
  - **0.27.6: one usable copy per login** — Claude Code and Codex rotate refresh tokens, so a second usable copy of a login invalidates the first ("Not logged in · Please run /login"). The live account now keeps no profile-home credential, only a private backup; `syncLiveAccountState()` demotes a leftover copy (installing it first when it is newer) and reports `demoted`, `repaired`, and `journal`. Live writes pass `decideLiveClaudeWrite()` or the Codex equivalent: a switch captures the outgoing login first even with `force`, holds Claude Code's refresh lock, is journaled so the next sync finishes or rolls it back, and keeps live MCP tokens. Claude Keychain writes use Claude Code's hex method and are read back (`ClaudeCredentialWriteError`), so blobs over about 4 KB are no longer truncated. New root APIs: `readClaudeCredentialStore()`, `inspectClaudeCredentialStores()` / `repairClaudeCredentialStores()`, `inspectCodexCredentialStores()` / `repairCodexCredentialStores()`, `readClaudeCredentialLedger()`, `readStoredCodexAccount()`, `syncCodexLiveStateAsync()`, `discardAccountLogin()`, `writeAccountLauncher()`, and non-persisting health inspection (`persist: false`). `writeActiveCredentials()` now requires a config directory; `writeLauncher()`, `applyActiveClaudeToLiveHome()`, and `resolveActiveClaudeHome()` are deprecated.
13
14
  - **0.27.5: whole-session prompt history** — `collectSessionPromptHistory()` (root and Node) returns every human prompt of each matching Claude Code or Codex session, grouped by session and read from the start with the `collectPromptHistory()` scanners, so text, scope, model and usage, and ordinals are identical. Select with `sessionIds`, `since` (file mtime), or `limit`; each session carries `startedAt` / `lastActivityAt`, `cwds`, `gitBranches`, `models`, and `complete` / `truncated` / `droppedPrompts` / `excludedRecords`. `include.replies` adds the agent's last text for each prompt, and `include.signals` adds `interrupt`, `toolRejected`, `toolError`, `compaction`, `apiError`, and `rollback` signals. Sessions that `maxSessions`, `maxTotalBytes`, the deadline, or an abort cut off are listed in `unread` instead of being returned partially.
14
15
  - **0.27.4: usage events from the Node entry** — `sidekick-shared/node` now exports `createSessionProviders()`, `SYNTHETIC_MODEL`, and the `ProviderId` / `SessionProviderBase` / `SessionProviderDiagnostic` / `CreateSessionProviders*` types, so `collectUsageEvents()` callers never import the package root (a CommonJS barrel that bundlers cannot tree-shake). `collectUsageEvents()` accepts an optional `signal` that stops the collection before listing and between sessions.
@@ -133,17 +134,36 @@ returns the platform default that both overrides bypass.
133
134
 
134
135
  `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.
135
136
 
136
- | Path | Runtime | What it exposes |
137
- | ------------------------------ | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
138
- | `sidekick-shared` | Node (CLI, extension host) | Full public API (readers, providers, parsers, pricing, …). |
139
- | `sidekick-shared/browser` | **Browser / webview** | Pure helpers: usage normalization/pricing, token estimation, transcript and assistant-turn projection, model/context math, `parseMcpToolName()`. |
140
- | `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()`), 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()`), and resilient observed-session collection (`fs` + providers). |
141
- | `sidekick-shared/phrases` | Any runtime | Phrase arrays + `getRandomPhrase()`. |
142
- | `sidekick-shared/modelContext` | Any runtime | Direct access to the context-window module. |
143
- | `sidekick-shared/modelInfo` | Any runtime | Direct access to model parsing and cost math. |
144
- | `sidekick-shared/formatting` | Any runtime | Direct access to pure token and duration display helpers. |
145
- | `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. |
146
- | `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()`. |
137
+ | Path | Runtime | What it exposes |
138
+ | ------------------------------ | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
139
+ | `sidekick-shared` | Node (CLI, extension host) | Full public API (readers, providers, parsers, pricing, …). |
140
+ | `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()`), and `renderHandoffUrlTemplate()`. |
141
+ | `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()`), 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()`), Claude session-directory encoding (`encodeClaudeWorkspacePath()`, `getClaudeSessionDirectory()`), and the config root (`getConfigDir()`, `CONFIG_DIR_ENV_VAR`). |
142
+ | `sidekick-shared/phrases` | Any runtime | Phrase arrays + `getRandomPhrase()`. |
143
+ | `sidekick-shared/modelContext` | Any runtime | Direct access to the context-window module. |
144
+ | `sidekick-shared/modelInfo` | Any runtime | Direct access to model parsing and cost math. |
145
+ | `sidekick-shared/formatting` | Any runtime | Direct access to pure token and duration display helpers. |
146
+ | `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. |
147
+ | `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()`. |
148
+ | `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. |
149
+
150
+ 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.
151
+
152
+ Prefer these paths over `sidekick-shared/dist/*` deep imports. The `dist/*` wildcard still resolves for compatibility, but module files behind it can move between releases without notice.
153
+
154
+ ### Test suites
155
+
156
+ `sidekick-shared/testing` is for test suites that run sidekick-shared code against session data. Install the guard once per test process, before anything reads a home or spawns a CLI, and check it after each test:
157
+
158
+ ```typescript
159
+ // vitest setupFiles entry (with `globals: true`)
160
+ import { installCredentialGuard } from 'sidekick-shared/testing';
161
+
162
+ const guard = installCredentialGuard();
163
+ afterEach(() => guard.assertNoViolations());
164
+ ```
165
+
166
+ The guard points `HOME` (and `USERPROFILE`, `APPDATA`, `LOCALAPPDATA`) at a temp directory it removes on exit, unsets `CLAUDE_CONFIG_DIR`, `CLAUDE_SECURESTORAGE_CONFIG_DIR`, `CODEX_HOME`, and `SIDEKICK_CONFIG_DIR`, and patches the real `child_process` and `fs` modules. Spawning `security`, `claude`, or `codex` throws, writing under the real `~/.claude`, `~/.claude.json`, `~/.codex`, or `~/.config/sidekick` throws, and reads there are recorded. Production code often swallows errors, so `assertNoViolations()` reports what was recorded even when nothing threw. A `vi.mock('child_process')` factory replaces the module and bypasses the guard for that file.
147
167
 
148
168
  ### Browser / webview runtimes
149
169
 
@@ -345,11 +365,13 @@ const result = await collectPromptHistory({
345
365
  });
346
366
 
347
367
  for (const entry of result.entries) {
348
- // { provider, sessionId, ordinal, timestamp, text, cwd, gitBranch?, model?, usage?, metadataStatus }
368
+ // { provider, sessionId, ordinal, timestamp, text, cwd, gitBranch?, model?, usage?, metadataStatus, sessionKey }
349
369
  // Upsert by (provider, sessionId, ordinal): a prompt comes back when its answer metadata changes.
350
370
  }
351
371
  saveCursor(result.cursor); // sensitive local state; fully read unchanged files are skipped next time
352
372
  if (result.hasMore) scheduleAnotherCall(); // a bound stopped the pass; the cursor resumes it
373
+ // result.changed: sessions whose cursor entry moved this call; result.progressed: anything new was read;
374
+ // result.roots: the realpaths scanned after worktree expansion
353
375
  for (const exclusion of result.exclusions) console.warn('record left out', exclusion); // permanent
354
376
  ```
355
377
 
@@ -360,6 +382,8 @@ for (const exclusion of result.exclusions) console.warn('record left out', exclu
360
382
  - **Late answers enrich the same prompt.** A prompt can be collected before its answer is written. `metadataStatus` is `pending` (no answering call yet), `provisional` (Claude call still being written, `stop_reason: null`), or `final`. While a file's last prompt is not final, the cursor keeps the byte offset and length of its line, its timestamp, and its answer state so far (first-answer message id, model, and usage, never prompt or answer text). The next call continues from where the file stopped, however far the answer is, and returns the prompt again with the same provider, sessionId, ordinal, timestamp, and text only when its model, usage, or status changed; the text comes from re-reading that one line. A prompt closed by the next prompt without an answer comes back once as `final` with no usage. Consumers should upsert by identity.
361
383
  - **Large files are streamed and resumable.** Files are read in 1 MiB chunks and every pass stops after a complete line, so memory stays near one chunk plus one record whatever the file size. `maxFileBytes` is the most one file may read in one call: a file with more left keeps what it returned, records `backlog` in its cursor, is counted in `stats.filesOverSizeLimit`, and continues on the next call even if its size and mtime have not changed. `maxSessions`, `maxTotalBytes`, `maxEntries`, the deadline, and an abort stop the whole call the same way, and `cursor.next` makes the next call start with the file that was stopped, so a large or busy session cannot starve the others. The first file of a call always finishes its first record, so a record larger than the budget still moves forward. Bytes appended during a call and a half-written final line wait for the next call. `boundsHit` lists these resumable stops and `hasMore` says whether calling again would read more. No bound throws.
362
384
  - **Permanent exclusions are reported.** A record over `maxRecordBytes` is skipped as it streams past without being buffered, even when it is still being written, and a complete line that is not JSON is skipped. Each is counted (`stats.recordsOverSizeLimit`, `stats.recordsMalformed`) and listed in `exclusions` with its byte offset. A prompt inside such a record is lost and does not consume an ordinal. A file that shrank or whose first 4 KiB changed is treated as rewritten: it is read again from the start with fresh ordinals and counted in `stats.sessionsRewritten`.
385
+ - **Change reporting.** `changed` lists the sessions (provider, sessionId, `sessionKey`) whose cursor entry this call added, advanced, moved, or dropped after a rewrite, so a consumer never has to diff cursor internals. `progressed` is false when nothing new was read, which tells a stalled `hasMore` loop apart from one that is moving. `sessionKey` is opaque and equal to the cursor key; it tells apart two files that carry the same session id. `isPromptHistorySessionSettled(cursor.sessions[key])` says whether a cursor entry is fully read with no prompt waiting for its answer, and `parsePromptHistoryCursor(stored)` validates a stored cursor (versions 1 to 3) and returns it as `version: 3` with malformed entries dropped, or `undefined`.
386
+ - **Moved files.** A session whose file is listed again under another path (Codex moves an archived thread's rollout to `archived_sessions/`) keeps its cursor entry and ordinals instead of being read again as a new session.
363
387
  - **Cursor versions.** Output is `version: 3`. Cursors from 0.27.0 (`version: 1`) and 0.27.1 (`version: 2`) are accepted: each file is re-verified once, and a 0.27.1 pending prompt is replayed from its line in resumable passes, so it now settles even when its answer is far away. Files 0.27.1 skipped for size were never in its cursor and are read in full on the first call. Metadata that 0.27.1 already gave up on (a pending replay that exceeded `maxFileBytes`) was not saved and cannot be recovered, and a 0.27.0 cursor still cannot recover prompts it returned without metadata.
364
388
 
365
389
  ### Collect whole sessions of prompts
@@ -373,7 +397,8 @@ const result = await collectSessionPromptHistory({
373
397
  workspacePaths: ['/Users/me/code/app'], // plus git worktree siblings
374
398
  providers: ['claude-code', 'codex'], // default: both
375
399
  since: new Date('2026-09-01'), // sessions whose file changed since then, returned whole
376
- // sessionIds: ['…'], // or exact session ids
400
+ // sessionIds: ['…'], // or exact session ids (any provider)
401
+ // sessionRefs: result.changed, // or (provider, sessionId), pinned to one file by sessionKey
377
402
  // limit: 20, // most recent sessions with prompts
378
403
  include: { signals: true, replies: true }, // default: prompts only
379
404
  bounds: {
@@ -385,18 +410,18 @@ const result = await collectSessionPromptHistory({
385
410
  });
386
411
 
387
412
  for (const session of result.sessions) {
388
- // { provider, sessionId, startedAt, lastActivityAt, cwds, gitBranches, models,
413
+ // { provider, sessionId, sessionKey, startedAt, lastActivityAt, cwds, gitBranches, models,
389
414
  // prompts: [{ ordinal, timestamp, text, cwd, gitBranch?, model?, usage?, metadataStatus, reply? }],
390
- // signals?: [{ kind, timestamp, afterOrdinal, tool?, text?, textTruncated? }],
415
+ // signals?: [{ kind, timestamp, afterOrdinal, tool?, toolCategory?, mcpServer?, text?, textTruncated? }],
391
416
  // complete, truncated, droppedPrompts, excludedRecords }
392
417
  }
393
418
  if (result.unread.length > 0) {
394
419
  // A bound stopped the call, or a session changed while it was read:
395
- // pass these back as `sessionIds` to continue.
420
+ // pass these back as `sessionRefs` to continue.
396
421
  }
397
422
  ```
398
423
 
399
- - **Whole sessions, no cursor.** Every call reads each session from its first line and never resumes one mid-file. `since` selects files by modification time and never drops older prompts from a returned session. A long-lived consumer can use the `collectPromptHistory()` cursor to learn which sessions changed, then fetch those sessions whole by `sessionIds`.
424
+ - **Whole sessions, no cursor.** Every call reads each session from its first line and never resumes one mid-file. `since` selects files by modification time and never drops older prompts from a returned session. A long-lived consumer can keep a `collectPromptHistory()` cursor, then fetch the sessions in its result's `changed` whole with `sessionRefs: result.changed`. `sessionRefs` match on provider and id, or on one file when `sessionKey` is set; `sessionIds` match on id alone across providers.
400
425
  - **Bounds.** `maxSessions`, `maxTotalBytes`, the deadline, and an abort stop the call. Any session they interrupt is listed in `unread` rather than returned partially, and `boundsHit` names the bound. A session that changed while it was being read is also listed in `unread`, with no `boundsHit` entry. A session longer than `maxSessionBytes` is returned with `truncated: true`, and `boundsHit` includes `maxSessionBytes`; keep `maxSessionBytes` at or below `maxTotalBytes`, or a session larger than `maxTotalBytes` is never read. A record over `maxRecordBytes` (default 16 MiB) is skipped and counted in `excludedRecords`.
401
426
  - **Completeness.** `complete` is false when the session was truncated, when `droppedPrompts` > 0 (prompts out of scope or without a timestamp, visible as gaps in `ordinal`), or when `excludedRecords` > 0 (oversized or malformed records).
402
427
  - **Replies** (`include.replies`): the agent's last text for the prompt's turn. For Claude Code this is the last assistant message with text before the next prompt, with split records joined. For Codex it is `task_complete.last_agent_message`, falling back to the last agent message.
@@ -404,6 +429,7 @@ if (result.unread.length > 0) {
404
429
  - `interrupt`: Claude `[Request interrupted by user…]`, or Codex `turn_aborted`.
405
430
  - `toolRejected`: Claude only. Carries the rejection reason the person typed, in full. A rejection without a reason and the interrupt Claude Code writes after it count as one signal.
406
431
  - `toolError`: a failed tool call, with the tool name and the error text cut to 1024 characters (`textTruncated`).
432
+ - Signals that name a tool also carry `toolCategory` (`shell`, `file_read`, `file_edit`, `search`, `web`, `subagent`, `planning`, `mcp`, or `other`, from `classifyTool()`) and, for MCP calls, `mcpServer`. Claude Code names MCP tools `mcp__<server>__<tool>`; Codex names the bare tool and records the server separately, so `mcpServer` is the only way to tell a Codex MCP tool from a built-in one. `classifyTool(name, { mcpServer })` is exported from the root, `/browser`, and `/node`.
407
433
  - `compaction`, `apiError` (including Codex usage-limit errors), and `rollback` (Codex `thread_rolled_back`).
408
434
  - **Scope fails closed.** Sessions with no prompt inside the roots are omitted. Replies and signals that follow an out-of-scope prompt are dropped.
409
435
 
@@ -550,6 +576,15 @@ const priced = events.filter((event) => event.model !== SYNTHETIC_MODEL);
550
576
  On abort the promise rejects with the signal's reason (an `AbortError` by
551
577
  default); sessions read before the abort keep their cache entries.
552
578
 
579
+ To cover several workspaces in one call, pass `workspacePaths` instead of
580
+ `workspacePath`. Each root is realpath-resolved and, unless
581
+ `includeWorktrees: false`, expanded with its main checkout and git
582
+ worktrees (`resolveWorkspaceRoots()`, also on `sidekick-shared/node`). Each
583
+ root is listed, and a session file found under several overlapping roots
584
+ is read and counted once. The result's `roots` names what was listed, and
585
+ every event carries the `filePath` of its session. When no root resolves,
586
+ no session is read.
587
+
553
588
  ### Detect the active session provider
554
589
 
555
590
  For a single-provider surface, auto-detect and construct just one:
@@ -591,6 +626,8 @@ console.log(`Found ${tasks.length} tasks`);
591
626
 
592
627
  `diagnoseProviderFailure()` is a pure, synchronous helper exported from `sidekick-shared` and `sidekick-shared/browser`. The caller decides whether an SDK event is terminal: a Codex `ErrorItem`, including a reconnect notice, must not become terminal merely because its message can be classified.
593
628
 
629
+ The identifier lists behind the result types are exported alongside it as readonly arrays (`PROVIDER_FAILURE_CODES`, `PROVIDER_RECOVERY_ACTIONS`, `PROVIDER_CREDENTIAL_KINDS`, `PROVIDER_AUTHENTICATION_STATES`, `PROVIDER_AUTHENTICATION_SOURCES`, `PROVIDER_FAILURE_EVIDENCE_SOURCES`). To validate a diagnosis that crossed a process boundary, use `providerFailureDiagnosisSchema` from `sidekick-shared/schemas`; it is built from the same arrays, so it accepts every value a given release can return.
630
+
594
631
  ```typescript
595
632
  import { diagnoseProviderFailure } from 'sidekick-shared/browser';
596
633
 
@@ -861,7 +898,8 @@ The boundary schemas — `sessionEventSchema` plus the quota, account-status, ac
861
898
  Use `createJsonlTail()` when a consumer needs raw parsed events and owns its own aggregation lifecycle. `onBatchComplete` fires once after each drained byte chunk, which lets callers defer expensive UI or metrics updates until parsing for that chunk is complete.
862
899
 
863
900
  ```typescript
864
- import { createJsonlTail, sessionEventSchema } from 'sidekick-shared';
901
+ import { createJsonlTail } from 'sidekick-shared/node';
902
+ import { sessionEventSchema } from 'sidekick-shared/schemas';
865
903
 
866
904
  const tail = createJsonlTail({
867
905
  path: '/path/to/session.jsonl',
@@ -874,6 +912,8 @@ const tail = createJsonlTail({
874
912
  tail.start();
875
913
  ```
876
914
 
915
+ 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 and calls `onReset({ reason, previousOffset })` before the events from the start arrive. `createJsonlTail()` is also exported from `sidekick-shared/node`.
916
+
877
917
  `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; Codex readers reconstruct parser context when seeking. OpenCode's SQLite timestamp cursor does not persist row-version deduplication, so the dashboards replay OpenCode history instead of restoring a snapshot.
878
918
 
879
919
  ### Search a workspace and diagnose its provider
package/dist/browser.d.ts CHANGED
@@ -14,7 +14,7 @@ export type { UsageProvider, UsageSemantics, UsageNormalizationProvenance, Provi
14
14
  export { formatTokenBreakdown, summarizeTokens, sumTokenTotals, TOKEN_CONTEXT_LABEL, TOKEN_MAIN_THREAD_LABEL, TOKEN_SESSION_TOTAL_LABEL, TOKEN_SUBAGENTS_LABEL, TOKEN_TOTAL_LABEL, } from './tokenSummary';
15
15
  export type { TokenSummary, TokenTotalsLike } from './tokenSummary';
16
16
  export { ClaudeUsageDeduper, SYNTHETIC_MODEL } from './usage/claudeUsageDedupe';
17
- export { estimateTextTokens, estimateSerializedTokens } from './tokenEstimation';
17
+ export { ASCII_CHARS_PER_TOKEN, estimateTextTokens, estimateSerializedTokens, } from './tokenEstimation';
18
18
  export type { ExactTokenCounterContext, ExactTokenCounter, TokenEstimationMethod, TokenEstimationConfidence, TokenEstimationOptions, TokenEstimate, } from './tokenEstimation';
19
19
  export { projectSessionTranscript } from './transcript';
20
20
  export type { TranscriptFidelity, TranscriptSourceProvenance, CanonicalTranscriptBlock, CanonicalTranscriptMessage, CanonicalToolCall, CanonicalTranscriptUsageTotals, CanonicalSessionTranscript, ProjectSessionTranscriptOptions, } from './transcript';
@@ -40,6 +40,17 @@ export { applySessionSummary, isFileImported, markFileImported, removeSessionSum
40
40
  export type { ApplySessionSummaryOptions, SessionSummaryFromStatsOptions } from './historicalStore';
41
41
  export { FAILING_TOOL_TREND_ARROWS, failingToolTrend, mergeFailingToolWindows, } from './failingTools';
42
42
  export type { FailingToolTrend, FailingToolTrendRow, FailingToolWindow } from './failingTools';
43
- export { diagnoseProviderFailure } from './providerFailure';
43
+ export { diagnoseProviderFailure, PROVIDER_AUTHENTICATION_SOURCES, PROVIDER_AUTHENTICATION_STATES, PROVIDER_CREDENTIAL_KINDS, PROVIDER_FAILURE_CODES, PROVIDER_FAILURE_EVIDENCE_SOURCES, PROVIDER_RECOVERY_ACTIONS, } from './providerFailure';
44
44
  export type { ProviderCredentialKind, ProviderAuthenticationEvidence, ProviderFailureInput, ProviderFailureCode, ProviderRecoveryAction, ProviderRetryAfter, ProviderFailureEvidence, ProviderFailureDiagnosis, } from './providerFailure';
45
45
  export type { ProviderServiceSeverity, ProviderServiceComponent, ProviderServiceIncident, ProviderServiceStatusFailureReason, ObservedProviderServiceStatus, UnavailableProviderServiceStatus, ProviderServiceStatus, FetchProviderServiceStatusOptions, } from './providerServiceStatusTypes';
46
+ export type { SessionEvent, ClaudeSessionEvent, MessageUsage, SessionMessage, SessionEventBase, MessageSessionEvent, UserSessionEvent, AssistantSessionEvent, SummarySessionEvent, SystemSessionEvent, ToolUseSessionEvent, ToolResultSessionEvent, TokenUsage, ToolCall, ToolAnalytics, TimelineEvent, PendingToolCall, TaskStatus as SessionTaskStatus, TrackedTask, TaskState, SubagentStats, PendingUserRequest, ResponseLatency, LatencyStats, PlanStep, PlanState, SessionStats, CompactionEvent, TruncationEvent, ContextAttribution, TurnAttribution, ContextSizePoint, PermissionMode, PermissionModeChange, } from './types/sessionEvent';
47
+ export type { CodexRolloutLine, CodexSessionMeta, CodexResponseItem, CodexMessageItem, CodexContentPart, CodexReasoningItem, CodexFunctionCallItem, CodexFunctionCallOutputItem, CodexLocalShellCallItem, CodexWebSearchCallItem, CodexCustomToolCallItem, CodexCustomToolCallOutputItem, CodexCompacted, CodexTurnContext, CodexEventMsg, CodexEvent, CodexTurnStartedEvent, CodexTurnCompleteEvent, CodexTaskStartedEvent, CodexTaskCompleteEvent, CodexTurnAbortedEvent, CodexTokenCountEvent, CodexTokenUsage, CodexRateLimits, CodexAgentMessageEvent, CodexAgentReasoningEvent, CodexUserMessageEvent, CodexExecCommandBeginEvent, CodexExecCommandEndEvent, CodexMcpToolCallBeginEvent, CodexMcpToolCallEndEvent, CodexErrorEvent, CodexContextCompactedEvent, CodexPatchAppliedEvent, CodexBackgroundEvent, CodexGenericEvent, CodexDbThread, CodexReasoningSummary, } from './types/codex';
48
+ export { isAggregateCodexLimit } from './types/codex';
49
+ export { CodexRolloutParser, DEFAULT_MAX_TRACKED_TOOL_CALLS, extractPatchFilePaths, normalizeCodexToolName, normalizeCodexToolInput, resolveCodexCallUsage, } from './parsers/codexParser';
50
+ export type { CodexRolloutParserOptions } from './parsers/codexParser';
51
+ export { HUMAN_CLAUDE_ENTRYPOINTS, HUMAN_CODEX_SOURCES, humanPromptText, isHumanPrompt, } from './humanPrompt';
52
+ export type { HumanPromptProvider } from './humanPrompt';
53
+ export { renderHandoffUrlTemplate } from './handoffUrl';
54
+ export type { HandoffUrlIdentifiers } from './handoffUrl';
55
+ export { classifyTool, TOOL_CATEGORIES } from './toolCategory';
56
+ export type { ClassifyToolOptions, ToolCategory } from './toolCategory';
package/dist/browser.js CHANGED
@@ -9,8 +9,8 @@
9
9
  * For pricing hydration (LiteLLM catalog refresh), use `sidekick-shared/node`.
10
10
  */
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.sortModelIds = exports.compareModelIds = exports.getModelDisplayInfo = exports.shortModelName = exports.mergeCostSources = exports.calculateCostWithProvenance = exports.calculateCostWithPricing = exports.calculateCost = exports.getModelInfo = exports.resolveModelPricing = exports.getModelPricing = exports.parseModelId = exports.segmentAssistantTurn = exports.reasoningSummary = exports.isAssistantTurnSubagentTool = exports.extractTurnSubagents = exports.assistantTurnEventsFromSessionEvents = exports.SESSION_PROVIDER_IDS = exports.RUNTIME_QUOTA_PROVIDER_IDS = exports.QUOTA_PROVIDER_IDS = exports.MODEL_PROVIDER_IDS = exports.ACCOUNT_PROVIDER_IDS = exports.createSessionContextProjector = exports.calculateSessionContextPressure = exports.buildSessionContextSnapshot = exports.parseMcpToolName = exports.parseLocalDateKey = exports.formatTokenCount = exports.formatLocalDateKey = exports.formatDurationMs = exports.addLocalDays = exports.projectSessionTranscript = exports.estimateSerializedTokens = exports.estimateTextTokens = exports.SYNTHETIC_MODEL = exports.ClaudeUsageDeduper = exports.TOKEN_TOTAL_LABEL = exports.TOKEN_SUBAGENTS_LABEL = exports.TOKEN_SESSION_TOTAL_LABEL = exports.TOKEN_MAIN_THREAD_LABEL = exports.TOKEN_CONTEXT_LABEL = exports.sumTokenTotals = exports.summarizeTokens = exports.formatTokenBreakdown = exports.calculateNormalizedUsageCost = exports.extractNormalizedUsage = exports.normalizeProviderUsage = exports.DEFAULT_CONTEXT_WINDOW = exports.resolveModelContextWindow = exports.getModelContextWindowSize = void 0;
13
- exports.diagnoseProviderFailure = exports.mergeFailingToolWindows = exports.failingToolTrend = exports.FAILING_TOOL_TREND_ARROWS = exports.sessionSummaryFromStats = exports.removeSessionSummary = exports.markFileImported = exports.isFileImported = exports.applySessionSummary = exports.weekKey = exports.usageBucketKey = exports.summarizeUsageRows = exports.bucketUsage = exports.findActiveBillingBlock = exports.computeBillingBlocks = exports.BILLING_BLOCK_DURATION_MS = exports.RESOLVED_MODEL_CATALOG_SCHEMA_VERSION = exports.resolveModelAlias = exports.registerModelAlias = exports.importResolvedModelCatalog = exports.exportResolvedModelCatalog = exports.formatCost = void 0;
12
+ exports.compareModelIds = exports.getModelDisplayInfo = exports.shortModelName = exports.mergeCostSources = exports.calculateCostWithProvenance = exports.calculateCostWithPricing = exports.calculateCost = exports.getModelInfo = exports.resolveModelPricing = exports.getModelPricing = exports.parseModelId = exports.segmentAssistantTurn = exports.reasoningSummary = exports.isAssistantTurnSubagentTool = exports.extractTurnSubagents = exports.assistantTurnEventsFromSessionEvents = exports.SESSION_PROVIDER_IDS = exports.RUNTIME_QUOTA_PROVIDER_IDS = exports.QUOTA_PROVIDER_IDS = exports.MODEL_PROVIDER_IDS = exports.ACCOUNT_PROVIDER_IDS = exports.createSessionContextProjector = exports.calculateSessionContextPressure = exports.buildSessionContextSnapshot = exports.parseMcpToolName = exports.parseLocalDateKey = exports.formatTokenCount = exports.formatLocalDateKey = exports.formatDurationMs = exports.addLocalDays = exports.projectSessionTranscript = exports.estimateSerializedTokens = exports.estimateTextTokens = exports.ASCII_CHARS_PER_TOKEN = exports.SYNTHETIC_MODEL = exports.ClaudeUsageDeduper = exports.TOKEN_TOTAL_LABEL = exports.TOKEN_SUBAGENTS_LABEL = exports.TOKEN_SESSION_TOTAL_LABEL = exports.TOKEN_MAIN_THREAD_LABEL = exports.TOKEN_CONTEXT_LABEL = exports.sumTokenTotals = exports.summarizeTokens = exports.formatTokenBreakdown = exports.calculateNormalizedUsageCost = exports.extractNormalizedUsage = exports.normalizeProviderUsage = exports.DEFAULT_CONTEXT_WINDOW = exports.resolveModelContextWindow = exports.getModelContextWindowSize = void 0;
13
+ exports.TOOL_CATEGORIES = exports.classifyTool = exports.renderHandoffUrlTemplate = exports.isHumanPrompt = exports.humanPromptText = exports.HUMAN_CODEX_SOURCES = exports.HUMAN_CLAUDE_ENTRYPOINTS = exports.resolveCodexCallUsage = exports.normalizeCodexToolInput = exports.normalizeCodexToolName = exports.extractPatchFilePaths = exports.DEFAULT_MAX_TRACKED_TOOL_CALLS = exports.CodexRolloutParser = exports.isAggregateCodexLimit = exports.PROVIDER_RECOVERY_ACTIONS = exports.PROVIDER_FAILURE_EVIDENCE_SOURCES = exports.PROVIDER_FAILURE_CODES = exports.PROVIDER_CREDENTIAL_KINDS = exports.PROVIDER_AUTHENTICATION_STATES = exports.PROVIDER_AUTHENTICATION_SOURCES = exports.diagnoseProviderFailure = exports.mergeFailingToolWindows = exports.failingToolTrend = exports.FAILING_TOOL_TREND_ARROWS = exports.sessionSummaryFromStats = exports.removeSessionSummary = exports.markFileImported = exports.isFileImported = exports.applySessionSummary = exports.weekKey = exports.usageBucketKey = exports.summarizeUsageRows = exports.bucketUsage = exports.findActiveBillingBlock = exports.computeBillingBlocks = exports.BILLING_BLOCK_DURATION_MS = exports.RESOLVED_MODEL_CATALOG_SCHEMA_VERSION = exports.resolveModelAlias = exports.registerModelAlias = exports.importResolvedModelCatalog = exports.exportResolvedModelCatalog = exports.formatCost = exports.sortModelIds = void 0;
14
14
  var modelContext_1 = require("./modelContext");
15
15
  Object.defineProperty(exports, "getModelContextWindowSize", { enumerable: true, get: function () { return modelContext_1.getModelContextWindowSize; } });
16
16
  Object.defineProperty(exports, "resolveModelContextWindow", { enumerable: true, get: function () { return modelContext_1.resolveModelContextWindow; } });
@@ -32,6 +32,7 @@ var claudeUsageDedupe_1 = require("./usage/claudeUsageDedupe");
32
32
  Object.defineProperty(exports, "ClaudeUsageDeduper", { enumerable: true, get: function () { return claudeUsageDedupe_1.ClaudeUsageDeduper; } });
33
33
  Object.defineProperty(exports, "SYNTHETIC_MODEL", { enumerable: true, get: function () { return claudeUsageDedupe_1.SYNTHETIC_MODEL; } });
34
34
  var tokenEstimation_1 = require("./tokenEstimation");
35
+ Object.defineProperty(exports, "ASCII_CHARS_PER_TOKEN", { enumerable: true, get: function () { return tokenEstimation_1.ASCII_CHARS_PER_TOKEN; } });
35
36
  Object.defineProperty(exports, "estimateTextTokens", { enumerable: true, get: function () { return tokenEstimation_1.estimateTextTokens; } });
36
37
  Object.defineProperty(exports, "estimateSerializedTokens", { enumerable: true, get: function () { return tokenEstimation_1.estimateSerializedTokens; } });
37
38
  var transcript_1 = require("./transcript");
@@ -101,3 +102,30 @@ Object.defineProperty(exports, "failingToolTrend", { enumerable: true, get: func
101
102
  Object.defineProperty(exports, "mergeFailingToolWindows", { enumerable: true, get: function () { return failingTools_1.mergeFailingToolWindows; } });
102
103
  var providerFailure_1 = require("./providerFailure");
103
104
  Object.defineProperty(exports, "diagnoseProviderFailure", { enumerable: true, get: function () { return providerFailure_1.diagnoseProviderFailure; } });
105
+ Object.defineProperty(exports, "PROVIDER_AUTHENTICATION_SOURCES", { enumerable: true, get: function () { return providerFailure_1.PROVIDER_AUTHENTICATION_SOURCES; } });
106
+ Object.defineProperty(exports, "PROVIDER_AUTHENTICATION_STATES", { enumerable: true, get: function () { return providerFailure_1.PROVIDER_AUTHENTICATION_STATES; } });
107
+ Object.defineProperty(exports, "PROVIDER_CREDENTIAL_KINDS", { enumerable: true, get: function () { return providerFailure_1.PROVIDER_CREDENTIAL_KINDS; } });
108
+ Object.defineProperty(exports, "PROVIDER_FAILURE_CODES", { enumerable: true, get: function () { return providerFailure_1.PROVIDER_FAILURE_CODES; } });
109
+ Object.defineProperty(exports, "PROVIDER_FAILURE_EVIDENCE_SOURCES", { enumerable: true, get: function () { return providerFailure_1.PROVIDER_FAILURE_EVIDENCE_SOURCES; } });
110
+ Object.defineProperty(exports, "PROVIDER_RECOVERY_ACTIONS", { enumerable: true, get: function () { return providerFailure_1.PROVIDER_RECOVERY_ACTIONS; } });
111
+ var codex_1 = require("./types/codex");
112
+ Object.defineProperty(exports, "isAggregateCodexLimit", { enumerable: true, get: function () { return codex_1.isAggregateCodexLimit; } });
113
+ // Codex rollout parsing (pure: no filesystem access)
114
+ var codexParser_1 = require("./parsers/codexParser");
115
+ Object.defineProperty(exports, "CodexRolloutParser", { enumerable: true, get: function () { return codexParser_1.CodexRolloutParser; } });
116
+ Object.defineProperty(exports, "DEFAULT_MAX_TRACKED_TOOL_CALLS", { enumerable: true, get: function () { return codexParser_1.DEFAULT_MAX_TRACKED_TOOL_CALLS; } });
117
+ Object.defineProperty(exports, "extractPatchFilePaths", { enumerable: true, get: function () { return codexParser_1.extractPatchFilePaths; } });
118
+ Object.defineProperty(exports, "normalizeCodexToolName", { enumerable: true, get: function () { return codexParser_1.normalizeCodexToolName; } });
119
+ Object.defineProperty(exports, "normalizeCodexToolInput", { enumerable: true, get: function () { return codexParser_1.normalizeCodexToolInput; } });
120
+ Object.defineProperty(exports, "resolveCodexCallUsage", { enumerable: true, get: function () { return codexParser_1.resolveCodexCallUsage; } });
121
+ var humanPrompt_1 = require("./humanPrompt");
122
+ Object.defineProperty(exports, "HUMAN_CLAUDE_ENTRYPOINTS", { enumerable: true, get: function () { return humanPrompt_1.HUMAN_CLAUDE_ENTRYPOINTS; } });
123
+ Object.defineProperty(exports, "HUMAN_CODEX_SOURCES", { enumerable: true, get: function () { return humanPrompt_1.HUMAN_CODEX_SOURCES; } });
124
+ Object.defineProperty(exports, "humanPromptText", { enumerable: true, get: function () { return humanPrompt_1.humanPromptText; } });
125
+ Object.defineProperty(exports, "isHumanPrompt", { enumerable: true, get: function () { return humanPrompt_1.isHumanPrompt; } });
126
+ var handoffUrl_1 = require("./handoffUrl");
127
+ Object.defineProperty(exports, "renderHandoffUrlTemplate", { enumerable: true, get: function () { return handoffUrl_1.renderHandoffUrlTemplate; } });
128
+ // Tool categories across providers
129
+ var toolCategory_1 = require("./toolCategory");
130
+ Object.defineProperty(exports, "classifyTool", { enumerable: true, get: function () { return toolCategory_1.classifyTool; } });
131
+ Object.defineProperty(exports, "TOOL_CATEGORIES", { enumerable: true, get: function () { return toolCategory_1.TOOL_CATEGORIES; } });
@@ -0,0 +1,11 @@
1
+ export declare function getDefaultClaudeHome(): string;
2
+ /** True when this process runs against the default `~/.claude` home. */
3
+ export declare function isDefaultClaudeHome(): boolean;
4
+ /**
5
+ * The home the `claude` CLI reads and writes for this process: `CLAUDE_CONFIG_DIR`
6
+ * when set, else `~/.claude`. Every "live" credential or identity read goes
7
+ * through this so sidekick follows the same home the CLI does.
8
+ */
9
+ export declare function getLiveClaudeHome(): string;
10
+ /** Where the `claude` CLI writes session transcripts for this process. */
11
+ export declare function getClaudeProjectsDir(): string;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.getDefaultClaudeHome = getDefaultClaudeHome;
37
+ exports.isDefaultClaudeHome = isDefaultClaudeHome;
38
+ exports.getLiveClaudeHome = getLiveClaudeHome;
39
+ exports.getClaudeProjectsDir = getClaudeProjectsDir;
40
+ const os = __importStar(require("os"));
41
+ const path = __importStar(require("path"));
42
+ function getDefaultClaudeHome() {
43
+ return path.join(os.homedir(), '.claude');
44
+ }
45
+ /** True when this process runs against the default `~/.claude` home. */
46
+ function isDefaultClaudeHome() {
47
+ return !process.env.CLAUDE_CONFIG_DIR?.trim();
48
+ }
49
+ /**
50
+ * The home the `claude` CLI reads and writes for this process: `CLAUDE_CONFIG_DIR`
51
+ * when set, else `~/.claude`. Every "live" credential or identity read goes
52
+ * through this so sidekick follows the same home the CLI does.
53
+ */
54
+ function getLiveClaudeHome() {
55
+ const explicit = process.env.CLAUDE_CONFIG_DIR?.trim();
56
+ return explicit ? explicit : getDefaultClaudeHome();
57
+ }
58
+ /** Where the `claude` CLI writes session transcripts for this process. */
59
+ function getClaudeProjectsDir() {
60
+ return path.join(getLiveClaudeHome(), 'projects');
61
+ }
@@ -1,3 +1,5 @@
1
+ import { getDefaultClaudeHome, getLiveClaudeHome, isDefaultClaudeHome } from './claudePaths';
2
+ export { getDefaultClaudeHome, getLiveClaudeHome, isDefaultClaudeHome };
1
3
  /**
2
4
  * Claude Code honours this variable ahead of `CLAUDE_CONFIG_DIR` when it
3
5
  * derives the keychain item name. Any `claude` child sidekick spawns must not
@@ -8,15 +10,6 @@ export interface ClaudeProfileIdentity {
8
10
  email: string;
9
11
  uuid: string;
10
12
  }
11
- export declare function getDefaultClaudeHome(): string;
12
- /** True when this process runs against the default `~/.claude` home. */
13
- export declare function isDefaultClaudeHome(): boolean;
14
- /**
15
- * The home the `claude` CLI reads and writes for this process: `CLAUDE_CONFIG_DIR`
16
- * when set, else `~/.claude`. Every "live" credential or identity read goes
17
- * through this so sidekick follows the same home the CLI does.
18
- */
19
- export declare function getLiveClaudeHome(): string;
20
13
  export declare function getClaudeProfilesDir(): string;
21
14
  /**
22
15
  * True when the live home is one of sidekick's own profile homes: a shell
@@ -33,10 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.CLAUDE_SECURESTORAGE_CONFIG_DIR_ENV = void 0;
37
- exports.getDefaultClaudeHome = getDefaultClaudeHome;
38
- exports.isDefaultClaudeHome = isDefaultClaudeHome;
39
- exports.getLiveClaudeHome = getLiveClaudeHome;
36
+ exports.CLAUDE_SECURESTORAGE_CONFIG_DIR_ENV = exports.isDefaultClaudeHome = exports.getLiveClaudeHome = exports.getDefaultClaudeHome = void 0;
40
37
  exports.getClaudeProfilesDir = getClaudeProfilesDir;
41
38
  exports.isLiveClaudeHomeSidekickProfile = isLiveClaudeHomeSidekickProfile;
42
39
  exports.getClaudeProfileDir = getClaudeProfileDir;
@@ -58,6 +55,10 @@ const fs = __importStar(require("fs"));
58
55
  const os = __importStar(require("os"));
59
56
  const path = __importStar(require("path"));
60
57
  const accountRegistry_1 = require("./accountRegistry");
58
+ const claudePaths_1 = require("./claudePaths");
59
+ Object.defineProperty(exports, "getDefaultClaudeHome", { enumerable: true, get: function () { return claudePaths_1.getDefaultClaudeHome; } });
60
+ Object.defineProperty(exports, "getLiveClaudeHome", { enumerable: true, get: function () { return claudePaths_1.getLiveClaudeHome; } });
61
+ Object.defineProperty(exports, "isDefaultClaudeHome", { enumerable: true, get: function () { return claudePaths_1.isDefaultClaudeHome; } });
61
62
  const DEFAULT_CLAUDE_KEYCHAIN_SERVICE = 'Claude Code-credentials';
62
63
  const KEYCHAIN_ACCOUNT_PATTERN = /^[a-zA-Z0-9._-]+$/;
63
64
  const KEYCHAIN_FALLBACK_ACCOUNT = 'claude-code-user';
@@ -67,22 +68,6 @@ const KEYCHAIN_FALLBACK_ACCOUNT = 'claude-code-user';
67
68
  * inherit it, or the login would land in an item nobody else reads.
68
69
  */
69
70
  exports.CLAUDE_SECURESTORAGE_CONFIG_DIR_ENV = 'CLAUDE_SECURESTORAGE_CONFIG_DIR';
70
- function getDefaultClaudeHome() {
71
- return path.join(os.homedir(), '.claude');
72
- }
73
- /** True when this process runs against the default `~/.claude` home. */
74
- function isDefaultClaudeHome() {
75
- return !process.env.CLAUDE_CONFIG_DIR?.trim();
76
- }
77
- /**
78
- * The home the `claude` CLI reads and writes for this process: `CLAUDE_CONFIG_DIR`
79
- * when set, else `~/.claude`. Every "live" credential or identity read goes
80
- * through this so sidekick follows the same home the CLI does.
81
- */
82
- function getLiveClaudeHome() {
83
- const explicit = process.env.CLAUDE_CONFIG_DIR?.trim();
84
- return explicit ? explicit : getDefaultClaudeHome();
85
- }
86
71
  function getClaudeProfilesDir() {
87
72
  return path.join((0, accountRegistry_1.getAccountsDir)(), 'claude', 'profiles');
88
73
  }
@@ -94,7 +79,7 @@ function getClaudeProfilesDir() {
94
79
  * usable copy and re-point the active account at it.
95
80
  */
96
81
  function isLiveClaudeHomeSidekickProfile() {
97
- const liveHome = path.resolve(getLiveClaudeHome());
82
+ const liveHome = path.resolve((0, claudePaths_1.getLiveClaudeHome)());
98
83
  const profilesDir = path.resolve(getClaudeProfilesDir());
99
84
  return liveHome === profilesDir || liveHome.startsWith(profilesDir + path.sep);
100
85
  }
@@ -129,7 +114,7 @@ function claudeKeychainSuffix(configDir) {
129
114
  * `~/.claude` — so the no-argument form follows the process environment.
130
115
  */
131
116
  function claudeKeychainService(configDir) {
132
- const dir = configDir ?? (isDefaultClaudeHome() ? undefined : getLiveClaudeHome());
117
+ const dir = configDir ?? ((0, claudePaths_1.isDefaultClaudeHome)() ? undefined : (0, claudePaths_1.getLiveClaudeHome)());
133
118
  return dir
134
119
  ? `${DEFAULT_CLAUDE_KEYCHAIN_SERVICE}-${claudeKeychainSuffix(dir)}`
135
120
  : DEFAULT_CLAUDE_KEYCHAIN_SERVICE;
@@ -167,11 +152,11 @@ function readOauthAccount(configPath) {
167
152
  * when it carries an identity, otherwise fall back to the legacy location for
168
153
  * the default home only.
169
154
  */
170
- function getClaudeConfigPath(home = getLiveClaudeHome()) {
155
+ function getClaudeConfigPath(home = (0, claudePaths_1.getLiveClaudeHome)()) {
171
156
  const primary = path.join(home, '.claude.json');
172
157
  if (readOauthAccount(primary))
173
158
  return primary;
174
- if (path.resolve(home) === path.resolve(getDefaultClaudeHome())) {
159
+ if (path.resolve(home) === path.resolve((0, claudePaths_1.getDefaultClaudeHome)())) {
175
160
  return path.join(os.homedir(), '.claude.json');
176
161
  }
177
162
  return primary;
@@ -182,7 +167,7 @@ function identityFromOauthAccount(oauthAccount) {
182
167
  return typeof email === 'string' && typeof uuid === 'string' ? { email, uuid } : null;
183
168
  }
184
169
  /** Identity of the account currently logged in to a Claude home (default: the live home). */
185
- function readLiveClaudeIdentity(home = getLiveClaudeHome()) {
170
+ function readLiveClaudeIdentity(home = (0, claudePaths_1.getLiveClaudeHome)()) {
186
171
  return identityFromOauthAccount(readOauthAccount(getClaudeConfigPath(home)));
187
172
  }
188
173
  function readClaudeProfileIdentity(home) {
@@ -2,6 +2,13 @@ export declare function getDefaultSystemCodexHome(): string;
2
2
  export declare function getExplicitCodexHome(): string | null;
3
3
  /** The home the `codex` CLI reads for this process: `CODEX_HOME` or `~/.codex`. */
4
4
  export declare function getSystemCodexHome(): string;
5
+ export declare function resolveSidekickCodexHome(): string;
6
+ /**
7
+ * The environment for spawning `codex`: `baseEnv` with `CODEX_HOME` set to the
8
+ * live home. A non-blank `CODEX_HOME` already in `baseEnv` is kept, so a caller
9
+ * that points one child at its own home does not have it overwritten.
10
+ */
11
+ export declare function getCodexExecutionEnv(baseEnv?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
5
12
  export declare function getCodexProfilesDir(): string;
6
13
  export declare function getCodexProfileDir(profileId: string): string;
7
14
  export declare function getCodexProfileHome(profileId: string): string;
@@ -25,3 +32,18 @@ export declare function getCodexLoginDir(id: string): string;
25
32
  /** Legacy pending profiles remain readable until finalized or discarded. */
26
33
  export declare function getCodexLoginHome(id: string): string;
27
34
  export declare function getCodexLoginStatePath(id: string): string;
35
+ export declare function getCodexMonitoringHomes(): string[];
36
+ /** Where Codex writes live rollouts, below each home. */
37
+ export declare const CODEX_SESSIONS_SUBDIR = "sessions";
38
+ /** Where Codex moves a rollout when its thread is archived, below each home. */
39
+ export declare const CODEX_ARCHIVED_SESSIONS_SUBDIR = "archived_sessions";
40
+ export interface CodexSessionsDirsOptions {
41
+ /** Also list each home's `archived_sessions` directory when it exists (default true). */
42
+ includeArchived?: boolean;
43
+ }
44
+ /**
45
+ * Every directory that may hold Codex rollouts: each home's `sessions`, then
46
+ * each home's `archived_sessions` that exists. Live directories come first so
47
+ * callers that pick one directory pick a live one.
48
+ */
49
+ export declare function getCodexSessionsDirs(homes?: string[], options?: CodexSessionsDirsOptions): string[];