sidekick-shared 0.27.5 → 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 (314) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +93 -52
  3. package/dist/accountHealth.d.ts +14 -0
  4. package/dist/accountHealth.js +61 -14
  5. package/dist/accountLaunch.d.ts +6 -0
  6. package/dist/accountLaunch.js +61 -4
  7. package/dist/accountLease.d.ts +5 -0
  8. package/dist/accountLease.js +98 -0
  9. package/dist/accountManager.d.ts +7 -0
  10. package/dist/accountManager.js +226 -89
  11. package/dist/accountSync.d.ts +1 -5
  12. package/dist/accountSync.js +22 -6
  13. package/dist/accountSyncTypes.d.ts +9 -0
  14. package/dist/accounts.d.ts +75 -18
  15. package/dist/accounts.js +712 -189
  16. package/dist/browser.d.ts +13 -2
  17. package/dist/browser.js +30 -2
  18. package/dist/claudeCredentialDoctor.d.ts +50 -0
  19. package/dist/claudeCredentialDoctor.js +277 -0
  20. package/dist/claudeCredentialLedger.d.ts +15 -0
  21. package/dist/claudeCredentialLedger.js +130 -0
  22. package/dist/claudeCredentials.d.ts +20 -3
  23. package/dist/claudeCredentials.js +50 -3
  24. package/dist/claudeLiveGuard.d.ts +33 -0
  25. package/dist/claudeLiveGuard.js +46 -0
  26. package/dist/claudePaths.d.ts +11 -0
  27. package/dist/claudePaths.js +61 -0
  28. package/dist/claudeProfiles.d.ts +15 -8
  29. package/dist/claudeProfiles.js +30 -23
  30. package/dist/claudeRefreshLock.d.ts +15 -0
  31. package/dist/claudeRefreshLock.js +145 -0
  32. package/dist/codexAuth.d.ts +4 -0
  33. package/dist/codexAuth.js +18 -0
  34. package/dist/codexCredentialDoctor.d.ts +33 -0
  35. package/dist/codexCredentialDoctor.js +302 -0
  36. package/dist/codexCredentialStore.d.ts +29 -0
  37. package/dist/codexCredentialStore.js +213 -0
  38. package/dist/codexKeepAlive.d.ts +2 -0
  39. package/dist/codexKeepAlive.js +116 -0
  40. package/dist/codexPaths.d.ts +30 -2
  41. package/dist/codexPaths.js +118 -7
  42. package/dist/codexProfiles.d.ts +38 -35
  43. package/dist/codexProfiles.js +848 -715
  44. package/dist/credentialIO.d.ts +67 -7
  45. package/dist/credentialIO.js +211 -47
  46. package/dist/doctor.js +2 -2
  47. package/dist/ensureDefaultAccounts.js +1 -8
  48. package/dist/esm/accountChangeSignal.js +15 -0
  49. package/dist/esm/accountChanges.js +152 -0
  50. package/dist/esm/accountHealth.js +288 -0
  51. package/dist/esm/accountLaunch.js +145 -0
  52. package/dist/esm/accountLease.js +60 -0
  53. package/dist/esm/accountManager.js +606 -0
  54. package/dist/esm/accountRegistry.js +214 -0
  55. package/dist/esm/accountStatus.js +51 -0
  56. package/dist/esm/accountSwitch.js +74 -0
  57. package/dist/esm/accountSync.js +156 -0
  58. package/dist/esm/accountSyncTypes.js +4 -0
  59. package/dist/esm/accounts.js +1291 -0
  60. package/dist/esm/aggregation/EventAggregator.js +2034 -0
  61. package/dist/esm/aggregation/FrequencyTracker.js +69 -0
  62. package/dist/esm/aggregation/HeatmapTracker.js +89 -0
  63. package/dist/esm/aggregation/PatternExtractor.js +168 -0
  64. package/dist/esm/aggregation/costProvenance.js +31 -0
  65. package/dist/esm/aggregation/snapshot.js +161 -0
  66. package/dist/esm/aggregation/types.js +5 -0
  67. package/dist/esm/analytics/codeImpact.js +18 -0
  68. package/dist/esm/analytics/compactionLedger.js +37 -0
  69. package/dist/esm/analytics/qualityScore.js +112 -0
  70. package/dist/esm/autoSwitch.js +185 -0
  71. package/dist/esm/browser.js +34 -0
  72. package/dist/esm/claudeCredentialDoctor.js +239 -0
  73. package/dist/esm/claudeCredentialLedger.js +91 -0
  74. package/dist/esm/claudeCredentials.js +111 -0
  75. package/dist/esm/claudeLiveGuard.js +43 -0
  76. package/dist/esm/claudePaths.js +22 -0
  77. package/dist/esm/claudeProfiles.js +142 -0
  78. package/dist/esm/claudeRefreshLock.js +106 -0
  79. package/dist/esm/codexAuth.js +101 -0
  80. package/dist/esm/codexCredentialDoctor.js +265 -0
  81. package/dist/esm/codexCredentialStore.js +164 -0
  82. package/dist/esm/codexKeepAlive.js +112 -0
  83. package/dist/esm/codexPaths.js +172 -0
  84. package/dist/esm/codexProfiles.js +1251 -0
  85. package/dist/esm/codexQuota.js +564 -0
  86. package/dist/esm/codexQuotaWatcher.js +363 -0
  87. package/dist/esm/context/composer.js +71 -0
  88. package/dist/esm/context/sessionContext.js +546 -0
  89. package/dist/esm/credentialIO.js +283 -0
  90. package/dist/esm/credentials.js +49 -0
  91. package/dist/esm/doctor.js +305 -0
  92. package/dist/esm/ensureDefaultAccounts.js +62 -0
  93. package/dist/esm/errorHistory.js +56 -0
  94. package/dist/esm/extractors/errorTaxonomy.js +43 -0
  95. package/dist/esm/extractors/gatherAssets.js +32 -0
  96. package/dist/esm/extractors/sessionAssets.js +176 -0
  97. package/dist/esm/extractors/sources/claudeAssets.js +158 -0
  98. package/dist/esm/extractors/sources/codexAssets.js +234 -0
  99. package/dist/esm/extractors/tokenUsage.js +41 -0
  100. package/dist/esm/extractors/toolCall.js +142 -0
  101. package/dist/esm/failingTools.js +65 -0
  102. package/dist/esm/fileHead.js +27 -0
  103. package/dist/esm/formatters/eventHighlighter.js +332 -0
  104. package/dist/esm/formatters/noiseClassifier.js +209 -0
  105. package/dist/esm/formatters/sessionDump.js +328 -0
  106. package/dist/esm/formatters/toolSummary.js +226 -0
  107. package/dist/esm/formatting.js +82 -0
  108. package/dist/esm/handoffUrl.js +23 -0
  109. package/dist/esm/historicalStore.js +305 -0
  110. package/dist/esm/humanPrompt.js +88 -0
  111. package/dist/esm/index.js +213 -0
  112. package/dist/esm/keepAlive.js +189 -0
  113. package/dist/esm/liveCredentialGuard.js +33 -0
  114. package/dist/esm/modelAliases.js +51 -0
  115. package/dist/esm/modelCatalog.js +139 -0
  116. package/dist/esm/modelContext.js +280 -0
  117. package/dist/esm/modelInfo.js +832 -0
  118. package/dist/esm/multiProviderQuotaService.js +450 -0
  119. package/dist/esm/node.js +46 -0
  120. package/dist/esm/observedContextWindows.js +165 -0
  121. package/dist/esm/observedSessionCollector.js +939 -0
  122. package/dist/esm/parsers/changelogParser.js +71 -0
  123. package/dist/esm/parsers/codexHistory.js +89 -0
  124. package/dist/esm/parsers/codexParser.js +906 -0
  125. package/dist/esm/parsers/debugLogParser.js +126 -0
  126. package/dist/esm/parsers/jsonl.js +66 -0
  127. package/dist/esm/parsers/mcpToolName.js +28 -0
  128. package/dist/esm/parsers/openCodeParser.js +625 -0
  129. package/dist/esm/parsers/planExtractor.js +335 -0
  130. package/dist/esm/parsers/sessionActivityDetector.js +246 -0
  131. package/dist/esm/parsers/sessionPathResolver.js +713 -0
  132. package/dist/esm/parsers/subagentScanner.js +360 -0
  133. package/dist/esm/parsers/subagentStatsCache.js +45 -0
  134. package/dist/esm/parsers/subagentTraceParser.js +325 -0
  135. package/dist/esm/paths.js +134 -0
  136. package/dist/esm/peakHours.js +194 -0
  137. package/dist/esm/phrases.js +1330 -0
  138. package/dist/esm/pricingCatalog.js +247 -0
  139. package/dist/esm/processDetection.js +200 -0
  140. package/dist/esm/projectMigration.js +59 -0
  141. package/dist/esm/promptHistory.js +1221 -0
  142. package/dist/esm/providerFailure.js +362 -0
  143. package/dist/esm/providerIds.js +6 -0
  144. package/dist/esm/providerQuota.js +1 -0
  145. package/dist/esm/providerServiceStatus.js +145 -0
  146. package/dist/esm/providerServiceStatusTypes.js +1 -0
  147. package/dist/esm/providerStatus.js +117 -0
  148. package/dist/esm/providers/claudeCode.js +575 -0
  149. package/dist/esm/providers/claudeListing.js +121 -0
  150. package/dist/esm/providers/codex.js +1034 -0
  151. package/dist/esm/providers/codexDatabase.js +297 -0
  152. package/dist/esm/providers/codexRollouts.js +215 -0
  153. package/dist/esm/providers/detect.js +185 -0
  154. package/dist/esm/providers/diagnostics.js +83 -0
  155. package/dist/esm/providers/directoryListingCache.js +206 -0
  156. package/dist/esm/providers/factory.js +54 -0
  157. package/dist/esm/providers/openCode.js +2008 -0
  158. package/dist/esm/providers/openCodeDatabase.js +419 -0
  159. package/dist/esm/providers/rolloutWalker.js +252 -0
  160. package/dist/esm/providers/types.js +12 -0
  161. package/dist/esm/quota.js +182 -0
  162. package/dist/esm/quotaHistory.js +364 -0
  163. package/dist/esm/quotaPoller.js +230 -0
  164. package/dist/esm/quotaPresentation.js +97 -0
  165. package/dist/esm/quotaResolver.js +231 -0
  166. package/dist/esm/quotaSnapshots.js +130 -0
  167. package/dist/esm/quotaThresholds.js +85 -0
  168. package/dist/esm/readers/decisions.js +24 -0
  169. package/dist/esm/readers/handoff.js +20 -0
  170. package/dist/esm/readers/helpers.js +27 -0
  171. package/dist/esm/readers/history.js +9 -0
  172. package/dist/esm/readers/notes.js +48 -0
  173. package/dist/esm/readers/plans.js +225 -0
  174. package/dist/esm/readers/tasks.js +19 -0
  175. package/dist/esm/report/htmlHelpers.js +280 -0
  176. package/dist/esm/report/htmlReportGenerator.js +704 -0
  177. package/dist/esm/report/index.js +7 -0
  178. package/dist/esm/report/logo.js +2 -0
  179. package/dist/esm/report/openBrowser.js +19 -0
  180. package/dist/esm/report/sessionReportInputs.js +33 -0
  181. package/dist/esm/report/transcriptParser.js +83 -0
  182. package/dist/esm/report/types.js +4 -0
  183. package/dist/esm/schemas/accountManager.js +204 -0
  184. package/dist/esm/schemas/accountStatus.js +25 -0
  185. package/dist/esm/schemas/assistantTurn.js +74 -0
  186. package/dist/esm/schemas/index.js +25 -0
  187. package/dist/esm/schemas/observedSessionV1.js +77 -0
  188. package/dist/esm/schemas/providerFailure.js +37 -0
  189. package/dist/esm/schemas/quota.js +132 -0
  190. package/dist/esm/schemas/quotaHistory.js +40 -0
  191. package/dist/esm/schemas/sessionEvent.js +216 -0
  192. package/dist/esm/schemas/stateFile.js +75 -0
  193. package/dist/esm/schemas/tokenEstimation.js +7 -0
  194. package/dist/esm/schemas/transcript.js +86 -0
  195. package/dist/esm/schemas/usageNormalization.js +38 -0
  196. package/dist/esm/search/advancedFilter.js +197 -0
  197. package/dist/esm/search/sessionSearch.js +66 -0
  198. package/dist/esm/sessionFingerprint.js +40 -0
  199. package/dist/esm/sessionMonitor.js +198 -0
  200. package/dist/esm/sessionPreviews.js +522 -0
  201. package/dist/esm/sessionPromptHistory.js +254 -0
  202. package/dist/esm/sessionPromptSignals.js +364 -0
  203. package/dist/esm/sessionStats.js +160 -0
  204. package/dist/esm/sessionTokenTotals.js +98 -0
  205. package/dist/esm/sessionTranscripts.js +49 -0
  206. package/dist/esm/stateFile.js +119 -0
  207. package/dist/esm/statusline/BurnRateCalculator.js +40 -0
  208. package/dist/esm/statusline/claudeStatuslinePayload.js +148 -0
  209. package/dist/esm/statusline/formatter.js +122 -0
  210. package/dist/esm/statusline/index.js +8 -0
  211. package/dist/esm/terminalSync.js +95 -0
  212. package/dist/esm/testing/credentialGuard.js +197 -0
  213. package/dist/esm/testing/index.js +12 -0
  214. package/dist/esm/testing/sessionLogFixtures.js +128 -0
  215. package/dist/esm/tokenEstimation.js +67 -0
  216. package/dist/esm/tokenSummary.js +113 -0
  217. package/dist/esm/toolCategory.js +82 -0
  218. package/dist/esm/transcript.js +257 -0
  219. package/dist/esm/turns/assistantTurn.js +373 -0
  220. package/dist/esm/types/codex.js +23 -0
  221. package/dist/esm/types/decisionLog.js +5 -0
  222. package/dist/esm/types/historicalData.js +47 -0
  223. package/dist/esm/types/knowledgeNote.js +15 -0
  224. package/dist/esm/types/observedSessionV1.js +257 -0
  225. package/dist/esm/types/opencode.js +12 -0
  226. package/dist/esm/types/plan.js +7 -0
  227. package/dist/esm/types/sessionEvent.js +10 -0
  228. package/dist/esm/types/taskPersistence.js +12 -0
  229. package/dist/esm/usage/billingBlocks.js +148 -0
  230. package/dist/esm/usage/claudeUsageDedupe.js +189 -0
  231. package/dist/esm/usage/importSessionHistory.js +84 -0
  232. package/dist/esm/usage/subagentUsage.js +18 -0
  233. package/dist/esm/usage/usageEvents.js +402 -0
  234. package/dist/esm/usage/usageReports.js +202 -0
  235. package/dist/esm/usageNormalization.js +95 -0
  236. package/dist/esm/watchers/eventBridge.js +219 -0
  237. package/dist/esm/watchers/factory.js +63 -0
  238. package/dist/esm/watchers/jsonlTail.js +289 -0
  239. package/dist/esm/watchers/jsonlWatcher.js +435 -0
  240. package/dist/esm/watchers/providerReaderWatcher.js +118 -0
  241. package/dist/esm/watchers/sqliteWatcher.js +285 -0
  242. package/dist/esm/watchers/types.js +4 -0
  243. package/dist/esm/workspaceRoots.js +56 -0
  244. package/dist/esm/writers/atomic.js +375 -0
  245. package/dist/esm/writers/decisions.js +51 -0
  246. package/dist/esm/writers/notes.js +46 -0
  247. package/dist/esm/writers/tasks.js +63 -0
  248. package/dist/esm/zaiQuota.js +323 -0
  249. package/dist/esm/zaiQuotaApi.js +271 -0
  250. package/dist/esm/zaiQuotaWatcher.js +265 -0
  251. package/dist/fileHead.d.ts +22 -0
  252. package/dist/fileHead.js +33 -0
  253. package/dist/index.d.ts +30 -11
  254. package/dist/index.js +72 -15
  255. package/dist/keepAlive.d.ts +2 -1
  256. package/dist/keepAlive.js +116 -29
  257. package/dist/liveCredentialGuard.d.ts +28 -0
  258. package/dist/liveCredentialGuard.js +36 -0
  259. package/dist/node.d.ts +13 -1
  260. package/dist/node.js +43 -2
  261. package/dist/parsers/codexHistory.js +2 -2
  262. package/dist/parsers/codexParser.d.ts +12 -0
  263. package/dist/parsers/codexParser.js +34 -12
  264. package/dist/parsers/debugLogParser.js +2 -2
  265. package/dist/parsers/sessionPathResolver.js +5 -4
  266. package/dist/processDetection.d.ts +10 -3
  267. package/dist/processDetection.js +44 -11
  268. package/dist/promptHistory.d.ts +32 -0
  269. package/dist/promptHistory.js +115 -59
  270. package/dist/providerFailure.d.ts +12 -6
  271. package/dist/providerFailure.js +45 -0
  272. package/dist/providers/claudeCode.js +7 -99
  273. package/dist/providers/claudeListing.d.ts +22 -0
  274. package/dist/providers/claudeListing.js +158 -0
  275. package/dist/providers/codex.d.ts +3 -1
  276. package/dist/providers/codex.js +26 -227
  277. package/dist/providers/codexRollouts.d.ts +44 -0
  278. package/dist/providers/codexRollouts.js +261 -0
  279. package/dist/providers/detect.js +4 -4
  280. package/dist/readers/plans.js +3 -3
  281. package/dist/schemas/accountManager.d.ts +22 -0
  282. package/dist/schemas/accountManager.js +4 -0
  283. package/dist/schemas/assistantTurn.d.ts +2 -2
  284. package/dist/schemas/index.d.ts +2 -0
  285. package/dist/schemas/index.js +7 -2
  286. package/dist/schemas/providerFailure.d.ts +154 -0
  287. package/dist/schemas/providerFailure.js +40 -0
  288. package/dist/sessionPromptHistory.d.ts +12 -7
  289. package/dist/sessionPromptHistory.js +15 -3
  290. package/dist/sessionPromptSignals.d.ts +9 -0
  291. package/dist/sessionPromptSignals.js +13 -0
  292. package/dist/terminalSync.d.ts +12 -2
  293. package/dist/terminalSync.js +27 -2
  294. package/dist/testing/credentialGuard.d.ts +23 -0
  295. package/dist/testing/credentialGuard.js +233 -0
  296. package/dist/testing/index.d.ts +14 -0
  297. package/dist/testing/index.js +22 -0
  298. package/dist/testing/sessionLogFixtures.d.ts +28 -0
  299. package/dist/testing/sessionLogFixtures.js +169 -0
  300. package/dist/tokenEstimation.d.ts +2 -0
  301. package/dist/tokenEstimation.js +21 -11
  302. package/dist/toolCategory.d.ts +18 -0
  303. package/dist/toolCategory.js +86 -0
  304. package/dist/types/codex.d.ts +4 -0
  305. package/dist/usage/usageEvents.d.ts +16 -0
  306. package/dist/usage/usageEvents.js +53 -9
  307. package/dist/watchers/jsonlTail.d.ts +26 -1
  308. package/dist/watchers/jsonlTail.js +136 -28
  309. package/dist/watchers/jsonlWatcher.js +7 -0
  310. package/dist/watchers/providerReaderWatcher.js +1 -0
  311. package/dist/watchers/types.d.ts +6 -0
  312. package/dist/workspaceRoots.d.ts +23 -0
  313. package/dist/workspaceRoots.js +93 -0
  314. package/package.json +22 -2
@@ -0,0 +1,33 @@
1
+ export type LiveClaudeWriteIntent = 'switch' | 'relogin' | 'repair' | 'rollback';
2
+ /** The live store as read just before the write. */
3
+ export type LiveClaudeStoreState = {
4
+ status: 'ok';
5
+ blob: unknown;
6
+ } | {
7
+ status: 'absent';
8
+ } | {
9
+ status: 'corrupt';
10
+ } | {
11
+ status: 'error';
12
+ };
13
+ export interface LiveClaudeWriteRequest {
14
+ intent: LiveClaudeWriteIntent;
15
+ live: LiveClaudeStoreState;
16
+ /** Account uuid of the live identity (`oauthAccount`), null when logged out. */
17
+ liveAccountUuid: string | null;
18
+ candidate: unknown;
19
+ candidateAccountUuid: string;
20
+ /** `switch`: the outgoing live credential was saved and verified. */
21
+ capturedOutgoing?: boolean;
22
+ /** `rollback`: the blob the failed switch wrote. */
23
+ written?: unknown;
24
+ }
25
+ export type LiveClaudeWriteRefusal = 'live-unreadable' | 'invalid-candidate' | 'same-account' | 'different-account' | 'same-link' | 'not-captured' | 'not-newer' | 'live-changed';
26
+ export type LiveClaudeWriteDecision = {
27
+ allow: true;
28
+ } | {
29
+ allow: false;
30
+ code: LiveClaudeWriteRefusal;
31
+ reason: string;
32
+ };
33
+ export declare function decideLiveClaudeWrite(request: LiveClaudeWriteRequest): LiveClaudeWriteDecision;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.decideLiveClaudeWrite = decideLiveClaudeWrite;
4
+ /**
5
+ * The decision every write into the live Claude credential store must pass.
6
+ * Pure: callers read the stores, this decides.
7
+ *
8
+ * Claude Code rotates the refresh token on every refresh, so the live store
9
+ * always holds the newest link of its chain. Writing an older link over it
10
+ * destroys a working login, and installing another account without saving the
11
+ * live one first loses that account's chain. The rules:
12
+ *
13
+ * - `switch`: another account replaces live. Allowed only after the outgoing
14
+ * live credential was captured (whenever live holds one), and never with a
15
+ * candidate that is the same refresh-token link as live.
16
+ * - `relogin` / `repair`: the same account's credential replaces live. Allowed
17
+ * only when the candidate is strictly fresher (a different refresh token
18
+ * with a later expiry); otherwise live is kept.
19
+ * - `rollback`: restore what a failed switch displaced. Allowed only while the
20
+ * live store still holds exactly what that switch wrote (or is empty or
21
+ * unparseable); a write Claude Code made in between is never clobbered.
22
+ * - An unreadable live store (`error`: timeout, locked Keychain) refuses all.
23
+ */
24
+ const liveCredentialGuard_1 = require("./liveCredentialGuard");
25
+ const claudeCredentials_1 = require("./claudeCredentials");
26
+ function decideLiveClaudeWrite(request) {
27
+ const candidate = (0, claudeCredentials_1.parseClaudeCredentialBlob)(request.candidate);
28
+ const live = request.live.status === 'ok' ? (0, claudeCredentials_1.parseClaudeCredentialBlob)(request.live.blob) : null;
29
+ const liveFp = (0, claudeCredentials_1.claudeRefreshFingerprint)(live);
30
+ return (0, liveCredentialGuard_1.decideLiveCredentialWrite)({
31
+ provider: 'Claude',
32
+ intent: request.intent,
33
+ liveStatus: request.live.status,
34
+ candidateValid: candidate !== null,
35
+ liveHasCredential: live !== null,
36
+ liveAccountId: request.liveAccountUuid,
37
+ candidateAccountId: request.candidateAccountUuid,
38
+ sameLink: liveFp !== null && liveFp === (0, claudeCredentials_1.claudeRefreshFingerprint)(candidate),
39
+ strictlyNewer: (0, claudeCredentials_1.claudeCredentialFreshness)(candidate) > (0, claudeCredentials_1.claudeCredentialFreshness)(live),
40
+ capturedOutgoing: request.capturedOutgoing,
41
+ matchesWritten: request.live.status === 'ok' &&
42
+ JSON.stringify(request.live.blob) === JSON.stringify(request.written),
43
+ allowNonOkRollback: true,
44
+ requireDifferentLinkForAdvance: true,
45
+ });
46
+ }
@@ -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,18 +10,23 @@ 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;
13
+ export declare function getClaudeProfilesDir(): string;
14
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.
15
+ * True when the live home is one of sidekick's own profile homes: a shell
16
+ * that eval'd `sidekick accounts env` or runs inside `sidekick accounts shell`.
17
+ * That profile's store then reads as the live store, so sync, re-login, and
18
+ * switching must not treat it as live: they would delete the shell's only
19
+ * usable copy and re-point the active account at it.
18
20
  */
19
- export declare function getLiveClaudeHome(): string;
20
- export declare function getClaudeProfilesDir(): string;
21
+ export declare function isLiveClaudeHomeSidekickProfile(): boolean;
21
22
  export declare function getClaudeProfileDir(uuid: string): string;
22
23
  export declare function getClaudeProfileHome(uuid: string): string;
24
+ /**
25
+ * Sidekick's private backup of a profile's credential. Claude Code never reads
26
+ * it, so it is not a CLI-usable copy: this is where the live account's
27
+ * credential is mirrored while its profile home stays empty.
28
+ */
29
+ export declare function getClaudeCredentialBackupPath(uuid: string): string;
23
30
  export declare function ensureClaudeProfileDirs(uuid: string): void;
24
31
  /**
25
32
  * Claude Code hashes the NFC-normalised config directory; macOS hands paths
@@ -33,13 +33,12 @@ 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;
38
+ exports.isLiveClaudeHomeSidekickProfile = isLiveClaudeHomeSidekickProfile;
41
39
  exports.getClaudeProfileDir = getClaudeProfileDir;
42
40
  exports.getClaudeProfileHome = getClaudeProfileHome;
41
+ exports.getClaudeCredentialBackupPath = getClaudeCredentialBackupPath;
43
42
  exports.ensureClaudeProfileDirs = ensureClaudeProfileDirs;
44
43
  exports.claudeKeychainSuffix = claudeKeychainSuffix;
45
44
  exports.claudeKeychainService = claudeKeychainService;
@@ -56,6 +55,10 @@ const fs = __importStar(require("fs"));
56
55
  const os = __importStar(require("os"));
57
56
  const path = __importStar(require("path"));
58
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; } });
59
62
  const DEFAULT_CLAUDE_KEYCHAIN_SERVICE = 'Claude Code-credentials';
60
63
  const KEYCHAIN_ACCOUNT_PATTERN = /^[a-zA-Z0-9._-]+$/;
61
64
  const KEYCHAIN_FALLBACK_ACCOUNT = 'claude-code-user';
@@ -65,24 +68,20 @@ const KEYCHAIN_FALLBACK_ACCOUNT = 'claude-code-user';
65
68
  * inherit it, or the login would land in an item nobody else reads.
66
69
  */
67
70
  exports.CLAUDE_SECURESTORAGE_CONFIG_DIR_ENV = 'CLAUDE_SECURESTORAGE_CONFIG_DIR';
68
- function getDefaultClaudeHome() {
69
- return path.join(os.homedir(), '.claude');
70
- }
71
- /** True when this process runs against the default `~/.claude` home. */
72
- function isDefaultClaudeHome() {
73
- return !process.env.CLAUDE_CONFIG_DIR?.trim();
71
+ function getClaudeProfilesDir() {
72
+ return path.join((0, accountRegistry_1.getAccountsDir)(), 'claude', 'profiles');
74
73
  }
75
74
  /**
76
- * The home the `claude` CLI reads and writes for this process: `CLAUDE_CONFIG_DIR`
77
- * when set, else `~/.claude`. Every "live" credential or identity read goes
78
- * through this so sidekick follows the same home the CLI does.
75
+ * True when the live home is one of sidekick's own profile homes: a shell
76
+ * that eval'd `sidekick accounts env` or runs inside `sidekick accounts shell`.
77
+ * That profile's store then reads as the live store, so sync, re-login, and
78
+ * switching must not treat it as live: they would delete the shell's only
79
+ * usable copy and re-point the active account at it.
79
80
  */
80
- function getLiveClaudeHome() {
81
- const explicit = process.env.CLAUDE_CONFIG_DIR?.trim();
82
- return explicit ? explicit : getDefaultClaudeHome();
83
- }
84
- function getClaudeProfilesDir() {
85
- return path.join((0, accountRegistry_1.getAccountsDir)(), 'claude', 'profiles');
81
+ function isLiveClaudeHomeSidekickProfile() {
82
+ const liveHome = path.resolve((0, claudePaths_1.getLiveClaudeHome)());
83
+ const profilesDir = path.resolve(getClaudeProfilesDir());
84
+ return liveHome === profilesDir || liveHome.startsWith(profilesDir + path.sep);
86
85
  }
87
86
  function getClaudeProfileDir(uuid) {
88
87
  return path.join(getClaudeProfilesDir(), uuid);
@@ -90,6 +89,14 @@ function getClaudeProfileDir(uuid) {
90
89
  function getClaudeProfileHome(uuid) {
91
90
  return path.join(getClaudeProfileDir(uuid), 'home');
92
91
  }
92
+ /**
93
+ * Sidekick's private backup of a profile's credential. Claude Code never reads
94
+ * it, so it is not a CLI-usable copy: this is where the live account's
95
+ * credential is mirrored while its profile home stays empty.
96
+ */
97
+ function getClaudeCredentialBackupPath(uuid) {
98
+ return path.join((0, accountRegistry_1.getAccountsDir)(), 'credentials', `${uuid}.credentials.json`);
99
+ }
93
100
  function ensureClaudeProfileDirs(uuid) {
94
101
  fs.mkdirSync(getClaudeProfileHome(uuid), { recursive: true, mode: 0o700 });
95
102
  }
@@ -107,7 +114,7 @@ function claudeKeychainSuffix(configDir) {
107
114
  * `~/.claude` — so the no-argument form follows the process environment.
108
115
  */
109
116
  function claudeKeychainService(configDir) {
110
- const dir = configDir ?? (isDefaultClaudeHome() ? undefined : getLiveClaudeHome());
117
+ const dir = configDir ?? ((0, claudePaths_1.isDefaultClaudeHome)() ? undefined : (0, claudePaths_1.getLiveClaudeHome)());
111
118
  return dir
112
119
  ? `${DEFAULT_CLAUDE_KEYCHAIN_SERVICE}-${claudeKeychainSuffix(dir)}`
113
120
  : DEFAULT_CLAUDE_KEYCHAIN_SERVICE;
@@ -145,11 +152,11 @@ function readOauthAccount(configPath) {
145
152
  * when it carries an identity, otherwise fall back to the legacy location for
146
153
  * the default home only.
147
154
  */
148
- function getClaudeConfigPath(home = getLiveClaudeHome()) {
155
+ function getClaudeConfigPath(home = (0, claudePaths_1.getLiveClaudeHome)()) {
149
156
  const primary = path.join(home, '.claude.json');
150
157
  if (readOauthAccount(primary))
151
158
  return primary;
152
- if (path.resolve(home) === path.resolve(getDefaultClaudeHome())) {
159
+ if (path.resolve(home) === path.resolve((0, claudePaths_1.getDefaultClaudeHome)())) {
153
160
  return path.join(os.homedir(), '.claude.json');
154
161
  }
155
162
  return primary;
@@ -160,7 +167,7 @@ function identityFromOauthAccount(oauthAccount) {
160
167
  return typeof email === 'string' && typeof uuid === 'string' ? { email, uuid } : null;
161
168
  }
162
169
  /** Identity of the account currently logged in to a Claude home (default: the live home). */
163
- function readLiveClaudeIdentity(home = getLiveClaudeHome()) {
170
+ function readLiveClaudeIdentity(home = (0, claudePaths_1.getLiveClaudeHome)()) {
164
171
  return identityFromOauthAccount(readOauthAccount(getClaudeConfigPath(home)));
165
172
  }
166
173
  function readClaudeProfileIdentity(home) {
@@ -0,0 +1,15 @@
1
+ /** Claude Code treats a lock older than this as abandoned (proper-lockfile `stale`). */
2
+ export declare const CLAUDE_REFRESH_LOCK_STALE_MS = 60000;
3
+ /** Claude Code is refreshing a login in one of the homes; retry shortly. */
4
+ export declare class ClaudeRefreshLockBusyError extends Error {
5
+ constructor(lockPath: string);
6
+ }
7
+ export declare function claudeRefreshLockPaths(home: string): string[];
8
+ /**
9
+ * Run `operation` holding the refresh locks of every existing home (a home
10
+ * that does not exist has no CLI using it). Throws
11
+ * {@link ClaudeRefreshLockBusyError} when a lock stays held past `waitMs`.
12
+ */
13
+ export declare function withClaudeRefreshLocksSync<T>(homes: string[], operation: () => T, options?: {
14
+ waitMs?: number;
15
+ }): T;
@@ -0,0 +1,145 @@
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.ClaudeRefreshLockBusyError = exports.CLAUDE_REFRESH_LOCK_STALE_MS = void 0;
37
+ exports.claudeRefreshLockPaths = claudeRefreshLockPaths;
38
+ exports.withClaudeRefreshLocksSync = withClaudeRefreshLocksSync;
39
+ /**
40
+ * Borrow Claude Code's own token-refresh lock while Sidekick reads and
41
+ * replaces a home's credential.
42
+ *
43
+ * Claude Code 2.1.x serialises refreshes per config directory with a
44
+ * proper-lockfile directory lock at `<configDir>/.oauth_refresh.lock` (stale
45
+ * after 60 s) plus a legacy `<realpath(configDir)>.lock`. Under that lock it
46
+ * re-reads the store before refreshing and adopts a token someone else wrote,
47
+ * so holding both locks keeps a refresh (which rotates the refresh token) out
48
+ * of the window between Sidekick's read and its write.
49
+ *
50
+ * Best effort by construction: this layers on Claude Code internals. If they
51
+ * change we lose only the exclusion; the callers' fingerprint re-checks still
52
+ * catch a store that moved. Held briefly (a few `security` calls), well under
53
+ * the 60 s stale window, and released on every exit.
54
+ */
55
+ const fs = __importStar(require("fs"));
56
+ const path = __importStar(require("path"));
57
+ /** Claude Code treats a lock older than this as abandoned (proper-lockfile `stale`). */
58
+ exports.CLAUDE_REFRESH_LOCK_STALE_MS = 60_000;
59
+ const DEFAULT_WAIT_MS = 5_000;
60
+ const POLL_MS = 50;
61
+ const sleepView = new Int32Array(new SharedArrayBuffer(4));
62
+ /** Claude Code is refreshing a login in one of the homes; retry shortly. */
63
+ class ClaudeRefreshLockBusyError extends Error {
64
+ constructor(lockPath) {
65
+ super(`Claude Code is refreshing a login (${lockPath} is held); try again in a few seconds.`);
66
+ this.name = 'ClaudeRefreshLockBusyError';
67
+ }
68
+ }
69
+ exports.ClaudeRefreshLockBusyError = ClaudeRefreshLockBusyError;
70
+ function claudeRefreshLockPaths(home) {
71
+ let real = path.resolve(home);
72
+ try {
73
+ real = fs.realpathSync(home);
74
+ }
75
+ catch {
76
+ /* keep the resolved path */
77
+ }
78
+ return [path.join(home, '.oauth_refresh.lock'), `${real}.lock`];
79
+ }
80
+ function tryAcquire(lockPath, now) {
81
+ try {
82
+ fs.mkdirSync(lockPath);
83
+ return true;
84
+ }
85
+ catch (error) {
86
+ if (error.code !== 'EEXIST')
87
+ throw error;
88
+ }
89
+ try {
90
+ const stat = fs.statSync(lockPath);
91
+ if (now - stat.mtimeMs > exports.CLAUDE_REFRESH_LOCK_STALE_MS) {
92
+ // proper-lockfile's own recovery: an abandoned lock is removed and retaken.
93
+ fs.rmSync(lockPath, { recursive: true, force: true });
94
+ fs.mkdirSync(lockPath);
95
+ return true;
96
+ }
97
+ }
98
+ catch {
99
+ /* released or retaken between checks; poll again */
100
+ }
101
+ return false;
102
+ }
103
+ /**
104
+ * Run `operation` holding the refresh locks of every existing home (a home
105
+ * that does not exist has no CLI using it). Throws
106
+ * {@link ClaudeRefreshLockBusyError} when a lock stays held past `waitMs`.
107
+ */
108
+ function withClaudeRefreshLocksSync(homes, operation, options = {}) {
109
+ const waitMs = options.waitMs ?? DEFAULT_WAIT_MS;
110
+ const lockPaths = [
111
+ ...new Set(homes
112
+ .filter((home) => {
113
+ try {
114
+ return fs.statSync(home).isDirectory();
115
+ }
116
+ catch {
117
+ return false;
118
+ }
119
+ })
120
+ .flatMap(claudeRefreshLockPaths)),
121
+ ];
122
+ const held = [];
123
+ try {
124
+ const deadline = Date.now() + waitMs;
125
+ for (const lockPath of lockPaths) {
126
+ while (!tryAcquire(lockPath, Date.now())) {
127
+ if (Date.now() >= deadline)
128
+ throw new ClaudeRefreshLockBusyError(lockPath);
129
+ Atomics.wait(sleepView, 0, 0, POLL_MS);
130
+ }
131
+ held.push(lockPath);
132
+ }
133
+ return operation();
134
+ }
135
+ finally {
136
+ for (const lockPath of held.reverse()) {
137
+ try {
138
+ fs.rmSync(lockPath, { recursive: true, force: true });
139
+ }
140
+ catch {
141
+ /* Claude Code recovers a stale lock after 60 s */
142
+ }
143
+ }
144
+ }
145
+ }
@@ -30,3 +30,7 @@ export declare function identitiesMatch(a: {
30
30
  email?: string;
31
31
  workspaceId?: string;
32
32
  } | null | undefined): boolean;
33
+ /** Non-secret chain-link identifier; raw token values never belong in diagnostics. */
34
+ export declare function codexRefreshFingerprint(raw: string | null): string | null;
35
+ /** Compare evidence, never filesystem timestamps. Incomparable credentials tie. */
36
+ export declare function compareCodexAuthFreshness(a: string | null, b: string | null): number;
package/dist/codexAuth.js CHANGED
@@ -40,11 +40,14 @@ exports.readAuthIdentityFromRaw = readAuthIdentityFromRaw;
40
40
  exports.readLastRefresh = readLastRefresh;
41
41
  exports.readAccessTokenExpiry = readAccessTokenExpiry;
42
42
  exports.identitiesMatch = identitiesMatch;
43
+ exports.codexRefreshFingerprint = codexRefreshFingerprint;
44
+ exports.compareCodexAuthFreshness = compareCodexAuthFreshness;
43
45
  /**
44
46
  * Pure helpers over the Codex CLI `auth.json` payload. No filesystem access
45
47
  * beyond an optional mtime fallback, no child processes.
46
48
  */
47
49
  const fs = __importStar(require("fs"));
50
+ const crypto_1 = require("crypto");
48
51
  // Codex refreshes OAuth tokens at most every 8 days; a stored refresh token
49
52
  // older than that may already be rejected by the auth server.
50
53
  exports.STALE_AUTH_THRESHOLD_MS = 8 * 24 * 60 * 60 * 1000;
@@ -125,3 +128,18 @@ function identitiesMatch(a, b) {
125
128
  return a.workspaceId === b.workspaceId;
126
129
  return Boolean(a.email && b.email && a.email === b.email);
127
130
  }
131
+ /** Non-secret chain-link identifier; raw token values never belong in diagnostics. */
132
+ function codexRefreshFingerprint(raw) {
133
+ const token = parseAuthJson(raw)?.tokens?.refresh_token;
134
+ return typeof token === 'string' && token
135
+ ? (0, crypto_1.createHash)('sha256').update(token).digest('hex').slice(0, 16)
136
+ : null;
137
+ }
138
+ /** Compare evidence, never filesystem timestamps. Incomparable credentials tie. */
139
+ function compareCodexAuthFreshness(a, b) {
140
+ const ar = readLastRefresh(a), br = readLastRefresh(b);
141
+ if (ar !== null && br !== null && ar !== br)
142
+ return ar > br ? 1 : -1;
143
+ const ae = readAccessTokenExpiry(a), be = readAccessTokenExpiry(b);
144
+ return ae !== null && be !== null && ae !== be ? (ae > be ? 1 : -1) : 0;
145
+ }
@@ -0,0 +1,33 @@
1
+ import type { ProviderSyncReport } from './accountSyncTypes';
2
+ export interface CodexCredentialFinding {
3
+ kind: 'live-duplicate' | 'stale-stash' | 'orphan' | 'corrupt' | 'unreadable' | 'pending-switch';
4
+ configDir: string;
5
+ /** Present for old timestamped stash files. */
6
+ file?: string;
7
+ ownership: 'profile-home' | 'login-home' | 'stash' | 'live' | 'journal' | 'backup';
8
+ accountId?: string;
9
+ email?: string;
10
+ fingerprint?: string;
11
+ detail: string;
12
+ action: string;
13
+ }
14
+ export interface CodexCredentialInspection {
15
+ findings: CodexCredentialFinding[];
16
+ homesChecked: number;
17
+ }
18
+ export interface CodexCredentialRepairResult extends CodexCredentialInspection {
19
+ dryRun: boolean;
20
+ repaired: Array<{
21
+ finding: CodexCredentialFinding;
22
+ ok: boolean;
23
+ error?: string;
24
+ }>;
25
+ sync?: ProviderSyncReport;
26
+ }
27
+ export declare function inspectCodexCredentialStores(options?: {
28
+ now?: number;
29
+ }): CodexCredentialInspection;
30
+ export declare function repairCodexCredentialStores(options?: {
31
+ now?: number;
32
+ dryRun?: boolean;
33
+ }): CodexCredentialRepairResult;