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
@@ -0,0 +1,305 @@
1
+ /**
2
+ * Pure mutations of the `historical-data.json` store.
3
+ *
4
+ * Ported verbatim from the VS Code extension's HistoricalDataService so the
5
+ * CLI importer and the extension apply session summaries the same way:
6
+ * a session's previous contribution is subtracted before the new one is
7
+ * added (idempotent replacement), daily, hourly, monthly, and all-time
8
+ * buckets are updated together, and the per-session record list is capped
9
+ * at `HISTORICAL_SESSION_RETENTION_LIMIT`. Browser-safe: no Node imports.
10
+ *
11
+ * @module historicalStore
12
+ */
13
+ import { formatLocalDateKey } from './formatting';
14
+ import { HISTORICAL_SESSION_RETENTION_LIMIT, createEmptyTokenTotals } from './types/historicalData';
15
+ function mergeModelUsage(existing, incoming) {
16
+ const map = new Map();
17
+ for (const record of existing)
18
+ map.set(record.model, { ...record });
19
+ for (const record of incoming) {
20
+ const current = map.get(record.model);
21
+ if (current) {
22
+ current.calls += record.calls;
23
+ current.tokens += record.tokens;
24
+ current.cost += record.cost;
25
+ // Unpriced taints: if either side was unpriced, the merged row is too.
26
+ // Legacy v1 records (priced === undefined) are assumed priced.
27
+ if (record.priced === false || current.priced === false)
28
+ current.priced = false;
29
+ }
30
+ else {
31
+ map.set(record.model, { ...record });
32
+ }
33
+ }
34
+ return Array.from(map.values());
35
+ }
36
+ function mergeToolUsage(existing, incoming) {
37
+ const map = new Map();
38
+ for (const record of existing)
39
+ map.set(record.tool, { ...record });
40
+ for (const record of incoming) {
41
+ const current = map.get(record.tool);
42
+ if (current) {
43
+ current.calls += record.calls;
44
+ current.successCount += record.successCount;
45
+ current.failureCount += record.failureCount;
46
+ }
47
+ else {
48
+ map.set(record.tool, { ...record });
49
+ }
50
+ }
51
+ return Array.from(map.values());
52
+ }
53
+ function subtractTokenTotals(target, contribution) {
54
+ target.inputTokens = Math.max(0, target.inputTokens - contribution.inputTokens);
55
+ target.outputTokens = Math.max(0, target.outputTokens - contribution.outputTokens);
56
+ target.cacheWriteTokens = Math.max(0, target.cacheWriteTokens - contribution.cacheWriteTokens);
57
+ target.cacheReadTokens = Math.max(0, target.cacheReadTokens - contribution.cacheReadTokens);
58
+ }
59
+ function subtractModelUsage(existing, outgoing) {
60
+ const map = new Map(existing.map((record) => [record.model, { ...record }]));
61
+ for (const record of outgoing) {
62
+ const current = map.get(record.model);
63
+ if (!current)
64
+ continue;
65
+ current.calls = Math.max(0, current.calls - record.calls);
66
+ current.tokens = Math.max(0, current.tokens - record.tokens);
67
+ current.cost = Math.max(0, current.cost - record.cost);
68
+ if (current.calls === 0 && current.tokens === 0)
69
+ map.delete(record.model);
70
+ }
71
+ return [...map.values()];
72
+ }
73
+ function subtractToolUsage(existing, outgoing) {
74
+ const map = new Map(existing.map((record) => [record.tool, { ...record }]));
75
+ for (const record of outgoing) {
76
+ const current = map.get(record.tool);
77
+ if (!current)
78
+ continue;
79
+ current.calls = Math.max(0, current.calls - record.calls);
80
+ current.successCount = Math.max(0, current.successCount - record.successCount);
81
+ current.failureCount = Math.max(0, current.failureCount - record.failureCount);
82
+ if (current.calls === 0)
83
+ map.delete(record.tool);
84
+ }
85
+ return [...map.values()];
86
+ }
87
+ function subtractSummary(bucket, summary, now) {
88
+ subtractTokenTotals(bucket.tokens, summary.tokens);
89
+ bucket.totalCost = Math.max(0, bucket.totalCost - summary.totalCost);
90
+ bucket.messageCount = Math.max(0, bucket.messageCount - summary.messageCount);
91
+ bucket.sessionCount = Math.max(0, bucket.sessionCount - 1);
92
+ bucket.modelUsage = subtractModelUsage(bucket.modelUsage, summary.modelUsage);
93
+ bucket.toolUsage = subtractToolUsage(bucket.toolUsage, summary.toolUsage);
94
+ bucket.updatedAt = now.toISOString();
95
+ }
96
+ function accumulateSummary(bucket, summary, now) {
97
+ bucket.tokens.inputTokens += summary.tokens.inputTokens;
98
+ bucket.tokens.outputTokens += summary.tokens.outputTokens;
99
+ bucket.tokens.cacheWriteTokens += summary.tokens.cacheWriteTokens;
100
+ bucket.tokens.cacheReadTokens += summary.tokens.cacheReadTokens;
101
+ bucket.totalCost += summary.totalCost;
102
+ bucket.messageCount += summary.messageCount;
103
+ bucket.sessionCount += 1;
104
+ bucket.modelUsage = mergeModelUsage(bucket.modelUsage, summary.modelUsage);
105
+ bucket.toolUsage = mergeToolUsage(bucket.toolUsage, summary.toolUsage);
106
+ bucket.updatedAt = now.toISOString();
107
+ }
108
+ function emptyDaily(date, now) {
109
+ return {
110
+ date,
111
+ tokens: createEmptyTokenTotals(),
112
+ totalCost: 0,
113
+ messageCount: 0,
114
+ sessionCount: 0,
115
+ modelUsage: [],
116
+ toolUsage: [],
117
+ updatedAt: now.toISOString(),
118
+ };
119
+ }
120
+ function emptyMonthly(month, now) {
121
+ return {
122
+ month,
123
+ tokens: createEmptyTokenTotals(),
124
+ totalCost: 0,
125
+ messageCount: 0,
126
+ sessionCount: 0,
127
+ modelUsage: [],
128
+ toolUsage: [],
129
+ updatedAt: now.toISOString(),
130
+ };
131
+ }
132
+ function refreshAllTimeDateRange(store) {
133
+ const dates = Object.keys(store.daily).sort();
134
+ store.allTime.firstDate = dates[0] ?? '';
135
+ store.allTime.lastDate = dates[dates.length - 1] ?? '';
136
+ }
137
+ /** Subtract a previously saved session's contribution from every bucket. */
138
+ export function removeSessionSummary(store, record, now = new Date()) {
139
+ const summary = {
140
+ sessionId: record.sessionId,
141
+ startTime: record.startTime,
142
+ endTime: record.endTime,
143
+ tokens: { ...record.tokens },
144
+ totalCost: record.totalCost,
145
+ messageCount: record.messageCount,
146
+ modelUsage: record.modelUsage?.map((usage) => ({ ...usage })) ?? [],
147
+ toolUsage: record.toolUsage?.map((usage) => ({ ...usage })) ?? [],
148
+ unpricedModelIds: record.unpricedModelIds ? [...record.unpricedModelIds] : undefined,
149
+ };
150
+ const date = formatLocalDateKey(new Date(record.startTime));
151
+ const month = date.substring(0, 7);
152
+ const daily = store.daily[date];
153
+ if (daily) {
154
+ subtractSummary(daily, summary, now);
155
+ if (daily.sessionCount === 0)
156
+ delete store.daily[date];
157
+ }
158
+ const hourly = store.hourly?.[date];
159
+ if (hourly && store.hourly) {
160
+ const hour = new Date(record.startTime).getHours();
161
+ const bucket = hourly.find((entry) => entry.hour === hour);
162
+ if (bucket) {
163
+ subtractTokenTotals(bucket.tokens, summary.tokens);
164
+ bucket.totalCost = Math.max(0, bucket.totalCost - summary.totalCost);
165
+ bucket.messageCount = Math.max(0, bucket.messageCount - summary.messageCount);
166
+ bucket.sessionCount = Math.max(0, bucket.sessionCount - 1);
167
+ }
168
+ store.hourly[date] = hourly.filter((entry) => entry.sessionCount > 0);
169
+ if (store.hourly[date].length === 0)
170
+ delete store.hourly[date];
171
+ }
172
+ const monthly = store.monthly[month];
173
+ if (monthly) {
174
+ subtractSummary(monthly, summary, now);
175
+ if (monthly.sessionCount === 0)
176
+ delete store.monthly[month];
177
+ }
178
+ subtractSummary(store.allTime, summary, now);
179
+ }
180
+ /**
181
+ * Apply a completed session to the daily, hourly, monthly, and all-time
182
+ * buckets and the capped per-session list. Re-applying the same session id
183
+ * replaces its earlier contribution instead of double counting it.
184
+ *
185
+ * Returns the stored per-session record.
186
+ */
187
+ export function applySessionSummary(store, summary, options = {}) {
188
+ const now = options.now ?? new Date();
189
+ const retentionLimit = options.retentionLimit ?? HISTORICAL_SESSION_RETENTION_LIMIT;
190
+ const date = formatLocalDateKey(new Date(summary.startTime));
191
+ const month = date.substring(0, 7);
192
+ store.sessions ??= [];
193
+ const previous = store.sessions.find((session) => session.sessionId === summary.sessionId);
194
+ if (previous)
195
+ removeSessionSummary(store, previous, now);
196
+ // Daily
197
+ store.daily[date] ??= emptyDaily(date, now);
198
+ accumulateSummary(store.daily[date], summary, now);
199
+ // Hourly (by the session's local start hour)
200
+ store.hourly ??= {};
201
+ store.hourly[date] ??= [];
202
+ const hour = new Date(summary.startTime).getHours();
203
+ let hourly = store.hourly[date].find((entry) => entry.hour === hour);
204
+ if (!hourly) {
205
+ hourly = {
206
+ hour,
207
+ tokens: createEmptyTokenTotals(),
208
+ totalCost: 0,
209
+ messageCount: 0,
210
+ sessionCount: 0,
211
+ };
212
+ store.hourly[date].push(hourly);
213
+ }
214
+ hourly.tokens.inputTokens += summary.tokens.inputTokens;
215
+ hourly.tokens.outputTokens += summary.tokens.outputTokens;
216
+ hourly.tokens.cacheWriteTokens += summary.tokens.cacheWriteTokens;
217
+ hourly.tokens.cacheReadTokens += summary.tokens.cacheReadTokens;
218
+ hourly.totalCost += summary.totalCost;
219
+ hourly.messageCount += summary.messageCount;
220
+ hourly.sessionCount += 1;
221
+ // Monthly
222
+ store.monthly[month] ??= emptyMonthly(month, now);
223
+ accumulateSummary(store.monthly[month], summary, now);
224
+ // All-time
225
+ accumulateSummary(store.allTime, summary, now);
226
+ if (!store.allTime.firstDate || date < store.allTime.firstDate)
227
+ store.allTime.firstDate = date;
228
+ if (!store.allTime.lastDate || date > store.allTime.lastDate)
229
+ store.allTime.lastDate = date;
230
+ const record = {
231
+ sessionId: summary.sessionId,
232
+ provider: summary.provider ?? 'unknown',
233
+ project: summary.project ?? 'unknown',
234
+ startTime: summary.startTime,
235
+ endTime: summary.endTime,
236
+ tokens: { ...summary.tokens },
237
+ totalCost: summary.totalCost,
238
+ messageCount: summary.messageCount,
239
+ modelUsage: summary.modelUsage.map((usage) => ({ ...usage })),
240
+ toolUsage: summary.toolUsage.map((usage) => ({ ...usage })),
241
+ unpricedModelIds: summary.unpricedModelIds ? [...summary.unpricedModelIds] : undefined,
242
+ qualityScore: summary.qualityScore ?? 0,
243
+ qualityFactors: summary.qualityFactors ?? [],
244
+ additions: summary.additions ?? 0,
245
+ deletions: summary.deletions ?? 0,
246
+ costPerChangedLine: summary.costPerChangedLine ?? null,
247
+ };
248
+ store.sessions = [
249
+ ...store.sessions.filter((session) => session.sessionId !== summary.sessionId),
250
+ record,
251
+ ].slice(-retentionLimit);
252
+ refreshAllTimeDateRange(store);
253
+ return record;
254
+ }
255
+ /** Whether a session file has already been folded into the store. */
256
+ export function isFileImported(store, filePath) {
257
+ return store.importedFiles?.includes(filePath) ?? false;
258
+ }
259
+ /** Record a session file as imported. Returns false when it was already listed. */
260
+ export function markFileImported(store, filePath, now = new Date()) {
261
+ store.importedFiles ??= [];
262
+ if (store.importedFiles.includes(filePath))
263
+ return false;
264
+ store.importedFiles.push(filePath);
265
+ store.lastImportTimestamp = now.toISOString();
266
+ return true;
267
+ }
268
+ /**
269
+ * Build the summary the history store expects from unified session stats,
270
+ * so the CLI importer and the extension's first-activation import store the
271
+ * same per-model cost, tool success/failure split, and unpriced markers.
272
+ * Pending tool calls count as successes (stats only split out failures).
273
+ */
274
+ export function sessionSummaryFromStats(stats, options = {}) {
275
+ const modelUsage = Object.entries(stats.modelUsage).map(([model, usage]) => ({
276
+ model,
277
+ calls: usage.calls,
278
+ tokens: usage.tokens,
279
+ cost: usage.costUsd,
280
+ priced: usage.priced,
281
+ }));
282
+ const unpricedModelIds = modelUsage.filter((m) => m.priced === false).map((m) => m.model);
283
+ const toolUsage = Object.entries(stats.toolUsage).map(([tool, calls]) => {
284
+ const failureCount = stats.toolFailures[tool] ?? 0;
285
+ return { tool, calls, successCount: Math.max(0, calls - failureCount), failureCount };
286
+ });
287
+ return {
288
+ sessionId: stats.sessionId,
289
+ startTime: stats.startTime,
290
+ endTime: stats.endTime || stats.startTime,
291
+ tokens: {
292
+ inputTokens: stats.tokens.input,
293
+ outputTokens: stats.tokens.output,
294
+ cacheWriteTokens: stats.tokens.cacheWrite,
295
+ cacheReadTokens: stats.tokens.cacheRead,
296
+ },
297
+ totalCost: stats.costUsd,
298
+ messageCount: stats.messageCount,
299
+ modelUsage,
300
+ toolUsage,
301
+ ...(unpricedModelIds.length > 0 ? { unpricedModelIds } : {}),
302
+ provider: options.provider ?? stats.providerId,
303
+ project: options.project ?? 'unknown',
304
+ };
305
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * One shared definition of "a prompt a person typed" for Claude Code and
3
+ * Codex transcripts. Pure: no filesystem access, so it can classify messages
4
+ * from `readSessionTranscript()` or from `collectPromptHistory()` alike.
5
+ */
6
+ /**
7
+ * Claude Code `entrypoint` values treated as a person at the keyboard:
8
+ * the interactive CLI, Claude Desktop's Code surface, and `claude -p`.
9
+ * `sdk-ts` / `sdk-py` (Agent SDK programs) are excluded.
10
+ */
11
+ export const HUMAN_CLAUDE_ENTRYPOINTS = Object.freeze([
12
+ 'cli',
13
+ 'claude-desktop',
14
+ 'sdk-cli',
15
+ ]);
16
+ /**
17
+ * Codex `session_meta.source` values whose sessions carry typed prompts.
18
+ * Subagent sessions (`{ subagent: … }`) are excluded; they replay parent
19
+ * history. This is a session-level rule applied by `collectPromptHistory()`.
20
+ */
21
+ export const HUMAN_CODEX_SOURCES = Object.freeze(['cli', 'vscode', 'exec']);
22
+ /** Claude user text that is harness output rather than something typed. */
23
+ const CLAUDE_INJECTED_PREFIX = /^(?:<(?:local-command-stdout|local-command-stderr|local-command-caveat|task-notification|system-reminder|bash-input|bash-stdout|bash-stderr|user-prompt-submit-hook)\b|\[Request interrupted\b|This session is being continued from a previous conversation)/;
24
+ const COMMAND_NAME = /<command-name>\s*([\s\S]*?)\s*<\/command-name>/;
25
+ const COMMAND_ARGS = /<command-args>\s*([\s\S]*?)\s*<\/command-args>/;
26
+ /** Codex user-role blocks injected by the harness (context, instructions, markers). */
27
+ const CODEX_INJECTED_PREFIX = /^(?:# AGENTS\.md instructions\b|<(?:environment_context|user_instructions|recommended_plugins|turn_aborted|skill|subagent_notification|codex_internal_context|user_shell_command|permissions instructions|collaboration_mode)\b)/;
28
+ /** Codex wraps attached images as `<image name=…>` / `</image>` text blocks. */
29
+ const CODEX_IMAGE_WRAPPER = /^<\/?image\b[^>]*>$/;
30
+ /** Whether a canonical transcript message is a prompt a person typed. */
31
+ export function isHumanPrompt(message, provider) {
32
+ return humanPromptText(message, provider) !== null;
33
+ }
34
+ /**
35
+ * The visible text of a human prompt, or `null` when the message is not one.
36
+ * Claude slash commands are returned as typed (`/review foo`); Codex image
37
+ * wrappers and injected context blocks are dropped. Text is never truncated.
38
+ */
39
+ export function humanPromptText(message, provider) {
40
+ if (message.role !== 'user')
41
+ return null;
42
+ if ((message.source.originalRole ?? 'user') !== 'user')
43
+ return null;
44
+ return provider === 'claude-code' ? claudePromptText(message) : codexPromptText(message);
45
+ }
46
+ function claudePromptText(message) {
47
+ const source = message.source;
48
+ if (!source.entrypoint || !HUMAN_CLAUDE_ENTRYPOINTS.includes(source.entrypoint))
49
+ return null;
50
+ if (source.isMeta === true || source.isSidechain === true)
51
+ return null;
52
+ if (source.isCompactSummary === true)
53
+ return null;
54
+ if (source.originKind !== undefined && source.originKind !== 'human')
55
+ return null;
56
+ if (source.promptSource === 'system')
57
+ return null;
58
+ const text = textBlocks(message).join('\n');
59
+ const trimmed = text.trim();
60
+ if (!trimmed)
61
+ return null;
62
+ if (CLAUDE_INJECTED_PREFIX.test(trimmed))
63
+ return null;
64
+ const command = trimmed.match(COMMAND_NAME);
65
+ if (command && /^<command-(?:name|message)>/.test(trimmed)) {
66
+ const name = command[1].trim();
67
+ if (!name)
68
+ return null;
69
+ const args = trimmed.match(COMMAND_ARGS)?.[1].trim() ?? '';
70
+ const visible = name.startsWith('/') ? name : `/${name}`;
71
+ return args ? `${visible} ${args}` : visible;
72
+ }
73
+ return text;
74
+ }
75
+ function codexPromptText(message) {
76
+ const typed = textBlocks(message).filter((text) => {
77
+ const trimmed = text.trim();
78
+ return (trimmed.length > 0 &&
79
+ !CODEX_INJECTED_PREFIX.test(trimmed) &&
80
+ !CODEX_IMAGE_WRAPPER.test(trimmed));
81
+ });
82
+ return typed.length > 0 ? typed.join('\n') : null;
83
+ }
84
+ function textBlocks(message) {
85
+ return message.content
86
+ .filter((block) => block.type === 'text' && typeof block.text === 'string')
87
+ .map((block) => block.text);
88
+ }
@@ -0,0 +1,213 @@
1
+ /**
2
+ * Public API for sidekick-shared.
3
+ */
4
+ export { normalizeProviderUsage, extractNormalizedUsage, calculateNormalizedUsageCost, } from './usageNormalization';
5
+ export { formatTokenBreakdown, summarizeTokens, sumTokenTotals, TOKEN_CONTEXT_LABEL, TOKEN_MAIN_THREAD_LABEL, TOKEN_SESSION_TOTAL_LABEL, TOKEN_SUBAGENTS_LABEL, TOKEN_TOTAL_LABEL, } from './tokenSummary';
6
+ export { ASCII_CHARS_PER_TOKEN, estimateTextTokens, estimateSerializedTokens, } from './tokenEstimation';
7
+ export { projectSessionTranscript } from './transcript';
8
+ export { listRecentSessions, readSessionTranscript } from './sessionTranscripts';
9
+ export { collectPromptHistory, isPromptHistorySessionSettled, parsePromptHistoryCursor, } from './promptHistory';
10
+ export { collectSessionPromptHistory } from './sessionPromptHistory';
11
+ export { HUMAN_CLAUDE_ENTRYPOINTS, HUMAN_CODEX_SOURCES, humanPromptText, isHumanPrompt, } from './humanPrompt';
12
+ export { computeSessionFileStats, firstUserPrompt, providerContextSizeFn, readSessionFileStats, } from './sessionStats';
13
+ export { readSessionReportInputs } from './report/sessionReportInputs';
14
+ export { fingerprintString, sessionFingerprintParts } from './sessionFingerprint';
15
+ export { STATE_FILE_NAME, STATE_FILE_SCHEMA_VERSION, billingBlockToStateFile, getStateFilePath, quotaToStateFile, readStateFile, writeStateFile, } from './stateFile';
16
+ export { BILLING_BLOCK_DURATION_MS, computeBillingBlocks, findActiveBillingBlock, } from './usage/billingBlocks';
17
+ export { MAX_USAGE_CACHE_FILES, USAGE_CACHE_VERSION, collectUsageEvents, getUsageCacheDir, pruneUsageCache, } from './usage/usageEvents';
18
+ export { applySessionSummary, isFileImported, markFileImported, removeSessionSummary, sessionSummaryFromStats, } from './historicalStore';
19
+ export { ACTIVE_SESSION_MTIME_THRESHOLD_MS, importSessionHistory, } from './usage/importSessionHistory';
20
+ export { bucketUsage, summarizeUsageRows, usageBucketKey, weekKey } from './usage/usageReports';
21
+ export { ObservedSessionCollector, observedSessionSourceFromProvider, fileFingerprint, fileFingerprintParts, } from './observedSessionCollector';
22
+ export { DirectoryListingCache, splitWatchedPath } from './providers/directoryListingCache';
23
+ export { isAggregateCodexLimit } from './types/codex';
24
+ export { TASK_PERSISTENCE_SCHEMA_VERSION, normalizeTaskStatus } from './types/taskPersistence';
25
+ export { DECISION_LOG_SCHEMA_VERSION } from './types/decisionLog';
26
+ export { KNOWLEDGE_NOTE_SCHEMA_VERSION, IMPORTANCE_DECAY_FACTORS, STALENESS_THRESHOLDS, } from './types/knowledgeNote';
27
+ export { HISTORICAL_DATA_SCHEMA_VERSION, HISTORICAL_SESSION_RETENTION_LIMIT, createEmptyTokenTotals, createEmptyDataStore, } from './types/historicalData';
28
+ export { PLAN_SCHEMA_VERSION, MAX_PLANS_PER_PROJECT } from './types/plan';
29
+ // Paths
30
+ export { CONFIG_DIR_ENV_VAR, getConfigDir, getConfigDirOverride, getDefaultConfigDir, setConfigDir, getProjectDataPath, getGlobalDataPath, encodeWorkspacePath, getProjectSlug, getProjectSlugRaw, resolveProjectIdentity, } from './paths';
31
+ export { migrateLegacyProjectStores } from './projectMigration';
32
+ // Readers
33
+ export { readTasks } from './readers/tasks';
34
+ export { readDecisions } from './readers/decisions';
35
+ export { readNotes } from './readers/notes';
36
+ export { readHistory } from './readers/history';
37
+ export { readLatestHandoff } from './readers/handoff';
38
+ export { readPlans, getLatestPlan, writePlans, getPlanAnalytics, readClaudeCodePlanFiles, } from './readers/plans';
39
+ // Atomic persistence writers
40
+ export { atomicWriteJson, atomicWriteJsonSync, atomicWriteFileSync, updateJsonStoreAtomic, updateJsonStoreAtomicSync, withFileLockSync, } from './writers/atomic';
41
+ export { addTask, completeTask } from './writers/tasks';
42
+ export { addDecision, decisionFingerprint } from './writers/decisions';
43
+ export { addNote } from './writers/notes';
44
+ export { renderHandoffUrlTemplate } from './handoffUrl';
45
+ export { SESSION_PROVIDER_IDS } from './providers/types';
46
+ export { createSessionProviders } from './providers/factory';
47
+ export { createProviderSessionAdapterV1, derivePendingUserRequestV1, getObservedActivityReason, } from './types/observedSessionV1';
48
+ export { _resetProviderDetectionCache, detectProvider, getAllDetectedProviders, } from './providers/detect';
49
+ export { ClaudeCodeProvider } from './providers/claudeCode';
50
+ export { OpenCodeProvider, getOpenCodeDataDir } from './providers/openCode';
51
+ export { CodexProvider, findCodexRolloutFile } from './providers/codex';
52
+ export { walkRolloutFiles, walkRolloutFilesAsync } from './providers/rolloutWalker';
53
+ // Parsers — JSONL
54
+ export { JsonlParser, TRUNCATION_PATTERNS } from './parsers/jsonl';
55
+ // Parsers — OpenCode
56
+ export { normalizeToolName, normalizeToolInput, detectPlanModeFromText, convertOpenCodeMessage, parseDbMessageData, parseDbPartData, } from './parsers/openCodeParser';
57
+ // Parsers — Codex
58
+ export { CodexRolloutParser, DEFAULT_MAX_TRACKED_TOOL_CALLS, extractPatchFilePaths, normalizeCodexToolName, normalizeCodexToolInput, resolveCodexCallUsage, } from './parsers/codexParser';
59
+ // Parsers — Subagent scanning
60
+ export { scanSubagentDir, extractTaskInfo, readAgentMeta } from './parsers/subagentScanner';
61
+ // Usage — split-line dedupe, subagent tokens, session totals
62
+ export { ClaudeUsageDeduper, SYNTHETIC_MODEL, dedupedRawClaudeUsage, normalizeClaudeUsage, } from './usage/claudeUsageDedupe';
63
+ export { addUsageToSubagent } from './usage/subagentUsage';
64
+ export { collectSessionTokenTotals, combineSessionTokenTotals, readMainThreadTokenTotals, scanSessionSubagents, subagentTokenTotals, } from './sessionTokenTotals';
65
+ // Parsers — Session activity detection
66
+ export { classifySessionActivity, detectSessionActivity, refreshSessionActivityState, SESSION_ACTIVITY_GRACE_PERIOD_MS, SESSION_ACTIVITY_STALENESS_MS, } from './parsers/sessionActivityDetector';
67
+ // Parsers — Session path resolution (Claude Code)
68
+ export { encodeWorkspacePath as encodeClaudeWorkspacePath, getSessionDirectory as getClaudeSessionDirectory, discoverSessionDirectory, findActiveSession as findActiveClaudeSession, findAllSessions as findAllClaudeSessions, findSessionsInDirectory, findSessionFilesWithStats, findSubdirectorySessionDirs, getMostRecentlyActiveSessionDir, decodeEncodedPath, getAllProjectFolders as getAllClaudeProjectFolders, resolveWorktreeMainRepo, discoverWorktreeSiblings, findAllSessionsWithWorktrees, } from './parsers/sessionPathResolver';
69
+ // Parsers — Subagent traces
70
+ export { scanSubagentTraces } from './parsers/subagentTraceParser';
71
+ // Parsers — MCP tool names
72
+ export { parseMcpToolName } from './parsers/mcpToolName';
73
+ // Parsers — Codex native history
74
+ export { readCodexHistory } from './parsers/codexHistory';
75
+ // Session previews (bounded, stat-first)
76
+ export { listSessionPreviews, listSessionPreviewsAsync, readSessionPreview, readSessionPreviewAsync, } from './sessionPreviews';
77
+ // Parsers — Debug log parsing
78
+ export { parseDebugLog, filterByLevel, collapseDuplicates, discoverDebugLogs, } from './parsers/debugLogParser';
79
+ // Database wrappers
80
+ export { OpenCodeDatabase } from './providers/openCodeDatabase';
81
+ export { CodexDatabase } from './providers/codexDatabase';
82
+ // Search
83
+ export { searchSessions } from './search/sessionSearch';
84
+ export { FilterEngine } from './search/advancedFilter';
85
+ // Context
86
+ export { composeContext } from './context/composer';
87
+ export { buildSessionContextSnapshot, calculateSessionContextPressure, createSessionContextProjector, readSessionContextSnapshot, } from './context/sessionContext';
88
+ // Assistant turn projection
89
+ export { assistantTurnEventsFromSessionEvents, extractTurnSubagents, isAssistantTurnSubagentTool, reasoningSummary, segmentAssistantTurn, } from './turns/assistantTurn';
90
+ // Plan Extraction
91
+ export { PlanExtractor, parsePlanMarkdown as parsePlanMarkdownShared, extractProposedPlan as extractProposedPlanShared, } from './parsers/planExtractor';
92
+ // Changelog Parsing
93
+ export { parseChangelog } from './parsers/changelogParser';
94
+ export { createWatcher, resolveSessionPath } from './watchers/factory';
95
+ export { toFollowEvents } from './watchers/eventBridge';
96
+ export { createJsonlTail, DEFAULT_JSONL_TAIL_MAX_LINE_BYTES, DEFAULT_JSONL_TAIL_READ_BYTES, } from './watchers/jsonlTail';
97
+ // Formatters
98
+ export { addLocalDays, formatDurationMs, formatLocalDateKey, formatTokenCount, parseLocalDateKey, } from './formatting';
99
+ export { formatToolSummary } from './formatters/toolSummary';
100
+ export { isHardNoise, isHardNoiseFollowEvent, getSoftNoiseReason, classifyMessage, classifyFollowEvent, shouldMergeWithPrevious, classifyNoise, } from './formatters/noiseClassifier';
101
+ export { formatSessionText, formatSessionMarkdown, formatSessionJson, } from './formatters/sessionDump';
102
+ export { highlight as highlightEvent, clearHighlightCache, HIGHLIGHT_CSS, } from './formatters/eventHighlighter';
103
+ // Phrases
104
+ export { ALL_PHRASES, PHRASE_CATEGORIES, getRandomPhrase } from './phrases';
105
+ // Aggregation
106
+ export { EventAggregator, parseTodoDependencies } from './aggregation/EventAggregator';
107
+ export { SessionMonitor } from './sessionMonitor';
108
+ export { saveSnapshot, loadSnapshot, deleteSnapshot, isSnapshotValid, pruneSnapshots, MAX_SNAPSHOT_FILES, getSnapshotPath, } from './aggregation/snapshot';
109
+ export { ERROR_HISTORY_SCHEMA_VERSION, MAX_ERROR_HISTORY_SESSIONS, appendErrorHistory, getTopFailingTools, readErrorHistory, } from './errorHistory';
110
+ // Aggregation — analytics engines
111
+ export { FrequencyTracker } from './aggregation/FrequencyTracker';
112
+ export { HeatmapTracker } from './aggregation/HeatmapTracker';
113
+ export { PatternExtractor } from './aggregation/PatternExtractor';
114
+ export { calculateQualityTrend, scoreSessionQuality } from './analytics/qualityScore';
115
+ export { calculateCodeImpact } from './analytics/codeImpact';
116
+ export { classifyCostProvenance, describeCostProvenance } from './aggregation/costProvenance';
117
+ export { calculateCompactionLedger, formatCompactionLedger } from './analytics/compactionLedger';
118
+ // Report — HTML session report generation
119
+ export { generateHtmlReport, parseTranscript, parseTranscriptFromEvents, openInBrowser, } from './report';
120
+ // Credential I/O (platform-aware: Keychain on macOS, file on Linux/Windows)
121
+ export { readActiveCredentials, readClaudeCredentialStore, writeActiveCredentials, deleteStoredCredentials, ClaudeCredentialWriteError, SIDEKICK_KEYCHAIN_COMMENT_PREFIX, } from './credentialIO';
122
+ export { decideLiveClaudeWrite } from './claudeLiveGuard';
123
+ export { readClaudeCredentialLedger, getClaudeCredentialLedgerPath, } from './claudeCredentialLedger';
124
+ export { inspectClaudeCredentialStores, repairClaudeCredentialStores, parseKeychainDump, } from './claudeCredentialDoctor';
125
+ // Credentials
126
+ export { readClaudeMaxCredentials, readClaudeMaxCredentialsRaw, readClaudeMaxAccessTokenSync, } from './credentials';
127
+ export { parseClaudeCredentialBlob, claudeCredentialFreshness, isNewerClaudeCredential, resolveClaudeRefreshExpiry, claudeRefreshFingerprint, claudeLoginOnly, mergeClaudeLoginIntoLive, CLAUDE_ACCESS_TOKEN_LIFETIME_MS, CLAUDE_REFRESH_TOKEN_LIFETIME_ESTIMATE_MS, } from './claudeCredentials';
128
+ export { parseAuthJson as parseCodexAuthJson, readAuthIdentityFromRaw as readCodexAuthIdentity, readLastRefresh as readCodexLastRefresh, readAccessTokenExpiry as readCodexAccessTokenExpiry, identitiesMatch as codexIdentitiesMatch, } from './codexAuth';
129
+ // Accounts
130
+ export { ensureDefaultAccounts } from './ensureDefaultAccounts';
131
+ export { readAccountRegistry, writeAccountRegistry, readActiveClaudeAccount, addCurrentAccount, switchToAccount, switchToAccountAsync, syncClaudeLiveState, cleanupAbandonedClaudeLogins, resolveActiveClaudeHome, applyActiveClaudeToLiveHome, reconcileClaudeAuthState, removeAccount, listAccounts, getActiveAccount, resolveActiveClaudeAccount, isMultiAccountEnabled, } from './accounts';
132
+ export { beginAccountLogin, getAccountLoginStatus, getAccountLoginStatusAsync, finalizeAccountLogin, finalizeAccountLoginAsync, spawnAccountLogin, switchAccount, switchAccountAsync, undoLastSwitch, getLastSwitch, listAllAccounts, resolveClaudeLoginCommand, discardAccountLogin, } from './accountManager';
133
+ export { readLastSwitch, getLastSwitchPath } from './accountSwitch';
134
+ export { syncLiveAccountState, syncLiveAccountStateSync, cleanupAbandonedLogins, } from './accountSync';
135
+ export { getAccountHealth, listAccountsWithHealth, readHealthSidecar, getHealthSidecarPath, } from './accountHealth';
136
+ export { getAccountLaunchEnv } from './accountLaunch';
137
+ export { refreshInactiveAccounts, keepAliveCommand } from './keepAlive';
138
+ export { findRunningProcesses, findRunningProcessesSync, detectRunningAccountConsumers, detectRunningAccountConsumersSync, describeAccountConsumer, ACCOUNT_CONSUMER_REACHABILITY, } from './processDetection';
139
+ export { getAccountsDir, readSavedAccountRegistry, writeSavedAccountRegistry, listSavedAccountProfiles, getActiveSavedAccount, upsertSavedAccountProfile, setActiveSavedAccount, replaceSavedAccountProfiles, removeSavedAccountProfile, } from './accountRegistry';
140
+ export { ACCOUNT_PROVIDER_IDS } from './accountRegistry';
141
+ export { getActiveAccountStatus } from './accountStatus';
142
+ export { onAccountsChanged } from './accountChanges';
143
+ export { getClaudeProfilesDir, getClaudeProfileHome, getClaudeConfigPath, claudeKeychainSuffix, claudeKeychainService, claudeKeychainAccountName, buildClaudeChildEnv, CLAUDE_SECURESTORAGE_CONFIG_DIR_ENV, isClaudeProfileAuthenticated, readClaudeProfileIdentity, readLiveClaudeIdentity, } from './claudeProfiles';
144
+ export { getLiveClaudeHome, getDefaultClaudeHome, isDefaultClaudeHome, getClaudeProjectsDir, } from './claudePaths';
145
+ export { getCodexProfilesDir, getCodexProfileHome, getCodexMonitoringHomes, getSystemCodexHome, listCodexAccounts, getActiveCodexAccount, resolveActiveCodexAccount, resolveSidekickCodexHome, getCodexExecutionEnv, prepareCodexAccount, prepareCodexAccountAsync, finalizeCodexAccount, finalizeCodexAccountAsync, switchToCodexAccount, switchToCodexAccountAsync, removeCodexAccount, syncCodexLiveState, cleanupAbandonedCodexLogins, getCodexCredentialStoreMode, CODEX_KEYRING_FIX_HINT, } from './codexProfiles';
146
+ export { writeAccountLauncher, writeLauncher, removeLauncher } from './terminalSync';
147
+ export { DEFAULT_AUTO_SWITCH_CONFIG, decideAutoSwitch, AutoSwitchController } from './autoSwitch';
148
+ // Quota
149
+ export { FIVE_HOUR_WINDOW_MS, QUOTA_PROVIDER_IDS, SEVEN_DAY_WINDOW_MS, fetchQuota, projectQuotaWindow, withQuotaProjections, } from './quota';
150
+ export { describeQuotaFailure } from './quotaPresentation';
151
+ export { QuotaPoller } from './quotaPoller';
152
+ export { readQuotaSnapshot, writeQuotaSnapshot } from './quotaSnapshots';
153
+ export { resolveQuota } from './quotaResolver';
154
+ export { classifyQuotaFreshness, formatQuotaAge, QUOTA_AGING_MAX_AGE_MS, QUOTA_FRESH_MAX_AGE_MS, } from './quota';
155
+ export { DEFAULT_QUOTA_THRESHOLDS, describeQuotaThresholdAlert, evaluateQuotaThresholds, } from './quotaThresholds';
156
+ export { parseClaudeStatuslinePayload, quotaFromStatuslinePayload, } from './statusline/claudeStatuslinePayload';
157
+ export { appendQuotaHistorySample, readQuotaHistoryRange, readQuotaHistoryDailyBuckets, pruneQuotaHistory, getWorkspaceIdFromPath, } from './quotaHistory';
158
+ export { fetchCodexResetCreditsFromApi, fetchCodexQuotaFromApi, quotaFromCodexRateLimits, readLatestCodexQuotaFromRollouts, resolveCodexQuota, resolveCodexQuotaFromLocalSources, } from './codexQuota';
159
+ export { CodexQuotaWatcher } from './codexQuotaWatcher';
160
+ export { fetchZaiQuotaFromApi, quotaStateFromZaiQuotaLimitPayload, readZaiCredentials, resolveZaiQuota, } from './zaiQuotaApi';
161
+ export { MultiProviderQuotaService } from './multiProviderQuotaService';
162
+ export { RUNTIME_QUOTA_PROVIDER_IDS } from './providerQuota';
163
+ export { BurnRateCalculator, estimateTimeToQuota } from './statusline/BurnRateCalculator';
164
+ export { formatStatusline, selectStatuslineAccount } from './statusline/formatter';
165
+ // Model Context
166
+ export { getModelContextWindowSize, resolveModelContextWindow, DEFAULT_CONTEXT_WINDOW, } from './modelContext';
167
+ // Model Info & Pricing
168
+ export { parseModelId, getModelPricing, resolveModelPricing, getModelInfo, calculateCost, calculateCostWithPricing, calculateCostWithProvenance, mergeCostSources, shortModelName, getModelDisplayInfo, compareModelIds, sortModelIds, formatCost, MODEL_PROVIDER_IDS, } from './modelInfo';
169
+ export { exportResolvedModelCatalog, importResolvedModelCatalog, registerModelAlias, resolveModelAlias, RESOLVED_MODEL_CATALOG_SCHEMA_VERSION, } from './modelCatalog';
170
+ // Pricing Catalog (LiteLLM hydration) — Node-only. Safe for extension host
171
+ // and CLI; do NOT import from browser bundles (webviews).
172
+ export { hydratePricingCatalog, normalizeLiteLlmCatalog, normalizeLiteLlmContextWindows, LITELLM_CATALOG_URL, } from './pricingCatalog';
173
+ // Observed context windows (provider-reported, persisted) — Node-only.
174
+ export { loadObservedContextWindows, recordObservedContextWindow, getObservedContextWindowPath, } from './observedContextWindows';
175
+ // Extractors — per-event token usage and tool call extraction
176
+ export { extractTokenUsage } from './extractors/tokenUsage';
177
+ // Extractors — actionable session assets. Node-only: safe for CLI and
178
+ // extension-host code, not for browser/webview bundles.
179
+ export { extractUrls, extractFilePaths, extractCommands } from './extractors/sessionAssets';
180
+ export { readClaudeAssets, claudeSessions } from './extractors/sources/claudeAssets';
181
+ export { readCodexAssets, codexSessions } from './extractors/sources/codexAssets';
182
+ export { gatherAssetsForCwd } from './extractors/gatherAssets';
183
+ export { categorizeError, extractErrorMessage } from './extractors/errorTaxonomy';
184
+ export { extractToolCall, extractToolCalls, ToolCallTracker } from './extractors/toolCall';
185
+ // Schemas — Zod runtime validation for session events
186
+ export { messageUsageSchema, sessionMessageSchema, sessionEventSchema, permissionModeSchema, extractSessionEvents, } from './schemas/sessionEvent';
187
+ // Schemas — Zod runtime validation for quota / provider quota / peak hours
188
+ export { quotaWindowSchema, quotaStateSchema, quotaFailureKindSchema, quotaProviderIdSchema, quotaSourceSchema, codexResetCreditSchema, codexResetCreditsSnapshotSchema, peakHoursStateSchema, quotaFailureDescriptorSchema, runtimeQuotaProviderSchema, providerQuotaStateSchema, claudeProviderQuotaStateSchema, codexProviderQuotaStateSchema, zaiProviderQuotaStateSchema, providerQuotaMapSchema, } from './schemas/quota';
189
+ // Schemas — Zod runtime validation for quota history
190
+ export { quotaHistoryRuntimeProviderSchema, quotaHistorySampleSchema, quotaHistoryDailyBucketSchema, } from './schemas/quotaHistory';
191
+ // Schemas — Zod runtime validation for provider-failure diagnoses
192
+ export { providerAuthenticationEvidenceSchema, providerFailureEvidenceSchema, providerRetryAfterSchema, providerFailureDiagnosisSchema, } from './schemas/providerFailure';
193
+ // Schemas — Zod runtime validation for account status
194
+ export { activeProviderAccountStatusSchema, activeAccountStatusSchema, } from './schemas/accountStatus';
195
+ export { accountProviderIdSchema, accountManagerResultSchema, beginAccountLoginResultSchema, accountLoginStatusSchema, accountEntrySchema, savedAccountProfileSchema, listAllAccountsResultSchema, } from './schemas/accountManager';
196
+ export { assistantTurnEventSchema, assistantTurnEventTypeSchema, assistantTurnNarrationStepSchema, assistantTurnProcessSchema, assistantTurnProcessStepSchema, assistantTurnProjectionSchema, assistantTurnReasoningTimelineItemSchema, assistantTurnSubagentSchema, assistantTurnSubagentStatusSchema, assistantTurnTimelineItemSchema, assistantTurnToolGroupStepSchema, assistantTurnToolRefSchema, } from './schemas/assistantTurn';
197
+ // Provider Status
198
+ export { fetchProviderStatus, fetchOpenAIStatus, toLegacyProviderStatus } from './providerStatus';
199
+ // Shared diagnostics / health report
200
+ export { formatHealthReport, getSessionDiagnostics, runDoctor } from './doctor';
201
+ // Peak Hours (PromoClock — third-party)
202
+ export { _resetPeakHoursCache, createPeakHoursNotApplicableState, DEFAULT_PEAK_HOURS_TIMEOUT_MS, fetchPeakHoursStatus, getScheduledPeakHoursState, isClaudeCodeSessionProvider, PEAK_HOURS_CACHE_MS, PEAK_HOURS_DESCRIPTION, scopePeakHoursToSessionProvider, } from './peakHours';
203
+ export { FAILING_TOOL_TREND_ARROWS, failingToolTrend, mergeFailingToolWindows, } from './failingTools';
204
+ export { diagnoseProviderFailure, PROVIDER_AUTHENTICATION_SOURCES, PROVIDER_AUTHENTICATION_STATES, PROVIDER_CREDENTIAL_KINDS, PROVIDER_FAILURE_CODES, PROVIDER_FAILURE_EVIDENCE_SOURCES, PROVIDER_RECOVERY_ACTIONS, } from './providerFailure';
205
+ export { fetchProviderServiceStatus } from './providerServiceStatus';
206
+ export { inspectCodexCredentialStores, repairCodexCredentialStores } from './codexCredentialDoctor';
207
+ export { readStoredCodexAccount, syncCodexLiveStateAsync } from './codexProfiles';
208
+ // Codex rollout directories (live and archived)
209
+ export { getCodexSessionsDirs, CODEX_SESSIONS_SUBDIR, CODEX_ARCHIVED_SESSIONS_SUBDIR, } from './codexPaths';
210
+ // Tool categories across providers
211
+ export { classifyTool, TOOL_CATEGORIES } from './toolCategory';
212
+ // Workspace roots (realpath plus git worktree expansion)
213
+ export { resolveWorkspaceRoots } from './workspaceRoots';