sidekick-shared 0.26.5 → 0.26.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +56 -51
  3. package/dist/accountChanges.js +21 -2
  4. package/dist/accountHealth.d.ts +72 -0
  5. package/dist/accountHealth.js +286 -0
  6. package/dist/accountLaunch.d.ts +30 -0
  7. package/dist/accountLaunch.js +124 -0
  8. package/dist/accountManager.d.ts +33 -8
  9. package/dist/accountManager.js +183 -50
  10. package/dist/accountRegistry.d.ts +10 -0
  11. package/dist/accountRegistry.js +42 -22
  12. package/dist/accountSwitch.d.ts +43 -0
  13. package/dist/accountSwitch.js +115 -0
  14. package/dist/accountSync.d.ts +30 -0
  15. package/dist/accountSync.js +180 -0
  16. package/dist/accountSyncTypes.d.ts +25 -0
  17. package/dist/accountSyncTypes.js +7 -0
  18. package/dist/accounts.d.ts +58 -6
  19. package/dist/accounts.js +408 -189
  20. package/dist/claudeCredentials.d.ts +38 -0
  21. package/dist/claudeCredentials.js +74 -0
  22. package/dist/claudeProfiles.d.ts +40 -0
  23. package/dist/claudeProfiles.js +102 -10
  24. package/dist/codexAuth.d.ts +32 -0
  25. package/dist/codexAuth.js +127 -0
  26. package/dist/codexPaths.d.ts +21 -0
  27. package/dist/codexPaths.js +117 -0
  28. package/dist/codexProfiles.d.ts +58 -5
  29. package/dist/codexProfiles.js +574 -289
  30. package/dist/credentialIO.d.ts +12 -5
  31. package/dist/credentialIO.js +63 -29
  32. package/dist/credentials.d.ts +8 -0
  33. package/dist/credentials.js +28 -32
  34. package/dist/ensureDefaultAccounts.d.ts +8 -0
  35. package/dist/ensureDefaultAccounts.js +42 -82
  36. package/dist/index.d.ts +27 -10
  37. package/dist/index.js +61 -9
  38. package/dist/keepAlive.d.ts +44 -0
  39. package/dist/keepAlive.js +106 -0
  40. package/dist/processDetection.d.ts +32 -0
  41. package/dist/processDetection.js +210 -0
  42. package/dist/schemas/accountManager.d.ts +283 -1
  43. package/dist/schemas/accountManager.js +122 -1
  44. package/dist/schemas/assistantTurn.d.ts +2 -2
  45. package/dist/schemas/index.d.ts +6 -1
  46. package/dist/schemas/index.js +14 -1
  47. package/dist/schemas/observedSessionV1.d.ts +21 -21
  48. package/dist/schemas/quota.d.ts +18 -18
  49. package/dist/schemas/quotaHistory.d.ts +1 -1
  50. package/dist/schemas/stateFile.d.ts +5 -5
  51. package/dist/terminalSync.d.ts +5 -5
  52. package/dist/terminalSync.js +7 -112
  53. package/dist/writers/atomic.d.ts +2 -0
  54. package/dist/writers/atomic.js +49 -2
  55. package/package.json +1 -1
@@ -2,8 +2,10 @@
2
2
  * Platform-aware credential I/O for Claude Code.
3
3
  *
4
4
  * On macOS, Claude Code stores OAuth credentials in the system Keychain
5
- * (service "Claude Code-credentials"). On Linux/WSL/Windows, credentials
6
- * live in ~/.claude/.credentials.json.
5
+ * (service "Claude Code-credentials", suffixed per config directory). On
6
+ * Linux/WSL/Windows, credentials live in `<home>/.credentials.json`. When the
7
+ * Keychain is unavailable (locked, SSH) Claude Code falls back to the file on
8
+ * macOS too, so reads consult the file after a Keychain miss.
7
9
  *
8
10
  * Both accounts.ts and credentials.ts consume this module so that all
9
11
  * credential access is platform-correct in one place.
@@ -12,8 +14,8 @@ export declare const KEYCHAIN_SERVICE = "Claude Code-credentials";
12
14
  /**
13
15
  * Read the active Claude Code credentials as a parsed object.
14
16
  *
15
- * - macOS: reads from system Keychain via the `security` CLI
16
- * - Linux / WSL / Windows: reads `~/.claude/.credentials.json`
17
+ * - macOS: reads from system Keychain via the `security` CLI, then the file
18
+ * - Linux / WSL / Windows: reads `<home>/.credentials.json`
17
19
  *
18
20
  * Returns `null` when credentials are absent or unreadable.
19
21
  */
@@ -22,8 +24,13 @@ export declare function readActiveCredentials(configDir?: string): unknown;
22
24
  * Write credentials to the active Claude Code credential store.
23
25
  *
24
26
  * - macOS: writes to system Keychain via the `security` CLI
25
- * - Linux / WSL / Windows: atomic-writes `~/.claude/.credentials.json`
27
+ * - Linux / WSL / Windows: atomic-writes `<home>/.credentials.json`
26
28
  *
27
29
  * Throws on failure.
28
30
  */
29
31
  export declare function writeActiveCredentials(credentials: unknown, configDir?: string): void;
32
+ /**
33
+ * Remove the credential store of a config directory (an abandoned isolated
34
+ * login, a removed profile). Best effort: never throws.
35
+ */
36
+ export declare function deleteStoredCredentials(configDir: string): void;
@@ -3,8 +3,10 @@
3
3
  * Platform-aware credential I/O for Claude Code.
4
4
  *
5
5
  * On macOS, Claude Code stores OAuth credentials in the system Keychain
6
- * (service "Claude Code-credentials"). On Linux/WSL/Windows, credentials
7
- * live in ~/.claude/.credentials.json.
6
+ * (service "Claude Code-credentials", suffixed per config directory). On
7
+ * Linux/WSL/Windows, credentials live in `<home>/.credentials.json`. When the
8
+ * Keychain is unavailable (locked, SSH) Claude Code falls back to the file on
9
+ * macOS too, so reads consult the file after a Keychain miss.
8
10
  *
9
11
  * Both accounts.ts and credentials.ts consume this module so that all
10
12
  * credential access is platform-correct in one place.
@@ -46,12 +48,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
46
48
  exports.KEYCHAIN_SERVICE = void 0;
47
49
  exports.readActiveCredentials = readActiveCredentials;
48
50
  exports.writeActiveCredentials = writeActiveCredentials;
51
+ exports.deleteStoredCredentials = deleteStoredCredentials;
49
52
  const fs = __importStar(require("fs"));
50
53
  const path = __importStar(require("path"));
51
- const os = __importStar(require("os"));
52
54
  const child_process_1 = require("child_process");
53
55
  const claudeProfiles_1 = require("./claudeProfiles");
56
+ const atomic_1 = require("./writers/atomic");
54
57
  exports.KEYCHAIN_SERVICE = 'Claude Code-credentials';
58
+ const SECURITY_TIMEOUT_MS = 4000;
55
59
  function quoteSecurityInteractiveArg(value) {
56
60
  // `security -i` is not a POSIX shell: adjacent quoted segments do NOT
57
61
  // concatenate (so the shell-style '\'' splice splits the token), and
@@ -59,39 +63,49 @@ function quoteSecurityInteractiveArg(value) {
59
63
  return `'${value.replace(/\\/g, '\\\\').replace(/'/g, `\\'`)}'`;
60
64
  }
61
65
  function getCredentialsFilePath(configDir) {
62
- return path.join(configDir ?? path.join(os.homedir(), '.claude'), '.credentials.json');
66
+ return path.join(configDir ?? (0, claudeProfiles_1.getLiveClaudeHome)(), '.credentials.json');
67
+ }
68
+ function readCredentialsFile(configDir) {
69
+ try {
70
+ return JSON.parse(fs.readFileSync(getCredentialsFilePath(configDir), 'utf8'));
71
+ }
72
+ catch {
73
+ return null;
74
+ }
75
+ }
76
+ function readKeychainItem(service) {
77
+ try {
78
+ const raw = (0, child_process_1.execFileSync)('security', ['find-generic-password', '-s', service, '-w'], {
79
+ encoding: 'utf8',
80
+ stdio: ['pipe', 'pipe', 'pipe'],
81
+ timeout: SECURITY_TIMEOUT_MS,
82
+ killSignal: 'SIGKILL',
83
+ });
84
+ return JSON.parse(raw.trim());
85
+ }
86
+ catch {
87
+ return null;
88
+ }
63
89
  }
64
90
  /**
65
91
  * Read the active Claude Code credentials as a parsed object.
66
92
  *
67
- * - macOS: reads from system Keychain via the `security` CLI
68
- * - Linux / WSL / Windows: reads `~/.claude/.credentials.json`
93
+ * - macOS: reads from system Keychain via the `security` CLI, then the file
94
+ * - Linux / WSL / Windows: reads `<home>/.credentials.json`
69
95
  *
70
96
  * Returns `null` when credentials are absent or unreadable.
71
97
  */
72
98
  function readActiveCredentials(configDir) {
73
99
  if (process.platform === 'darwin') {
74
- try {
75
- const raw = (0, child_process_1.execFileSync)('security', ['find-generic-password', '-s', (0, claudeProfiles_1.claudeKeychainService)(configDir), '-w'], { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 4000, killSignal: 'SIGKILL' });
76
- return JSON.parse(raw.trim());
77
- }
78
- catch {
79
- return null;
80
- }
81
- }
82
- // Linux / WSL / Windows — file-based
83
- try {
84
- return JSON.parse(fs.readFileSync(getCredentialsFilePath(configDir), 'utf8'));
85
- }
86
- catch {
87
- return null;
100
+ return readKeychainItem((0, claudeProfiles_1.claudeKeychainService)(configDir)) ?? readCredentialsFile(configDir);
88
101
  }
102
+ return readCredentialsFile(configDir);
89
103
  }
90
104
  /**
91
105
  * Write credentials to the active Claude Code credential store.
92
106
  *
93
107
  * - macOS: writes to system Keychain via the `security` CLI
94
- * - Linux / WSL / Windows: atomic-writes `~/.claude/.credentials.json`
108
+ * - Linux / WSL / Windows: atomic-writes `<home>/.credentials.json`
95
109
  *
96
110
  * Throws on failure.
97
111
  */
@@ -100,28 +114,48 @@ function writeActiveCredentials(credentials, configDir) {
100
114
  JSON.parse(json); // validate round-trip
101
115
  if (process.platform === 'darwin') {
102
116
  const service = (0, claudeProfiles_1.claudeKeychainService)(configDir);
103
- const account = process.env.USER || 'user';
104
117
  const command = [
105
118
  'add-generic-password',
106
119
  '-U',
107
120
  '-s',
108
121
  quoteSecurityInteractiveArg(service),
109
122
  '-a',
110
- quoteSecurityInteractiveArg(account),
123
+ quoteSecurityInteractiveArg((0, claudeProfiles_1.claudeKeychainAccountName)()),
111
124
  '-w',
112
125
  quoteSecurityInteractiveArg(json),
113
126
  ].join(' ');
114
127
  (0, child_process_1.execFileSync)('security', ['-i'], {
115
128
  input: command + '\n',
116
129
  stdio: ['pipe', 'pipe', 'pipe'],
117
- timeout: 4000,
130
+ timeout: SECURITY_TIMEOUT_MS,
118
131
  killSignal: 'SIGKILL',
119
132
  });
120
133
  return;
121
134
  }
122
- // Linux / WSL / Windows — file-based
123
- const credPath = getCredentialsFilePath(configDir);
124
- const tmp = credPath + '.tmp';
125
- fs.writeFileSync(tmp, json, { encoding: 'utf8', mode: 0o600 });
126
- fs.renameSync(tmp, credPath);
135
+ // Linux / WSL / Windows — file-based (tmp + fsync + rename, retried on Windows)
136
+ (0, atomic_1.atomicWriteFileSync)(getCredentialsFilePath(configDir), json, 0o600);
137
+ }
138
+ /**
139
+ * Remove the credential store of a config directory (an abandoned isolated
140
+ * login, a removed profile). Best effort: never throws.
141
+ */
142
+ function deleteStoredCredentials(configDir) {
143
+ if (process.platform === 'darwin') {
144
+ try {
145
+ (0, child_process_1.execFileSync)('security', ['delete-generic-password', '-s', (0, claudeProfiles_1.claudeKeychainService)(configDir)], {
146
+ stdio: ['ignore', 'ignore', 'ignore'],
147
+ timeout: SECURITY_TIMEOUT_MS,
148
+ killSignal: 'SIGKILL',
149
+ });
150
+ }
151
+ catch {
152
+ /* no item, or keychain unavailable */
153
+ }
154
+ }
155
+ try {
156
+ fs.rmSync(getCredentialsFilePath(configDir), { force: true });
157
+ }
158
+ catch {
159
+ /* best effort */
160
+ }
127
161
  }
@@ -7,8 +7,10 @@ export interface ClaudeMaxCredentials {
7
7
  accessToken: string;
8
8
  refreshToken?: string;
9
9
  expiresAt?: number;
10
+ refreshTokenExpiresAt?: number;
10
11
  scopes?: string[];
11
12
  subscriptionType?: string;
13
+ rateLimitTier?: string;
12
14
  }
13
15
  /**
14
16
  * Reads Claude Max OAuth credentials.
@@ -18,6 +20,12 @@ export interface ClaudeMaxCredentials {
18
20
  * absent, the token is missing, or the token is expired. Never throws.
19
21
  */
20
22
  export declare function readClaudeMaxCredentials(): Promise<ClaudeMaxCredentials | null>;
23
+ /**
24
+ * Like {@link readClaudeMaxCredentials} but returns the stored credential even
25
+ * when the access token has lapsed: the CLI refreshes it on next use, so an
26
+ * expired access token is still a valid login (until the refresh token expires).
27
+ */
28
+ export declare function readClaudeMaxCredentialsRaw(): ClaudeMaxCredentials | null;
21
29
  /**
22
30
  * Synchronous convenience — returns just the access token or `null`.
23
31
  */
@@ -6,8 +6,18 @@
6
6
  */
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
8
  exports.readClaudeMaxCredentials = readClaudeMaxCredentials;
9
+ exports.readClaudeMaxCredentialsRaw = readClaudeMaxCredentialsRaw;
9
10
  exports.readClaudeMaxAccessTokenSync = readClaudeMaxAccessTokenSync;
11
+ const claudeCredentials_1 = require("./claudeCredentials");
10
12
  const credentialIO_1 = require("./credentialIO");
13
+ function readParsed() {
14
+ try {
15
+ return (0, claudeCredentials_1.parseClaudeCredentialBlob)((0, credentialIO_1.readActiveCredentials)());
16
+ }
17
+ catch {
18
+ return null;
19
+ }
20
+ }
11
21
  /**
12
22
  * Reads Claude Max OAuth credentials.
13
23
  *
@@ -16,43 +26,29 @@ const credentialIO_1 = require("./credentialIO");
16
26
  * absent, the token is missing, or the token is expired. Never throws.
17
27
  */
18
28
  async function readClaudeMaxCredentials() {
19
- try {
20
- const raw = (0, credentialIO_1.readActiveCredentials)();
21
- if (!raw)
22
- return null;
23
- const oauth = raw.claudeAiOauth;
24
- if (!oauth?.accessToken)
25
- return null;
26
- if (oauth.expiresAt && Date.now() > oauth.expiresAt)
27
- return null;
28
- return {
29
- accessToken: oauth.accessToken,
30
- refreshToken: oauth.refreshToken,
31
- expiresAt: oauth.expiresAt,
32
- scopes: oauth.scopes,
33
- subscriptionType: oauth.subscriptionType,
34
- };
35
- }
36
- catch {
29
+ const parsed = readParsed();
30
+ if (!parsed)
37
31
  return null;
38
- }
32
+ if (parsed.expiresAt && Date.now() > parsed.expiresAt)
33
+ return null;
34
+ return parsed;
35
+ }
36
+ /**
37
+ * Like {@link readClaudeMaxCredentials} but returns the stored credential even
38
+ * when the access token has lapsed: the CLI refreshes it on next use, so an
39
+ * expired access token is still a valid login (until the refresh token expires).
40
+ */
41
+ function readClaudeMaxCredentialsRaw() {
42
+ return readParsed();
39
43
  }
40
44
  /**
41
45
  * Synchronous convenience — returns just the access token or `null`.
42
46
  */
43
47
  function readClaudeMaxAccessTokenSync() {
44
- try {
45
- const raw = (0, credentialIO_1.readActiveCredentials)();
46
- if (!raw)
47
- return null;
48
- const oauth = raw.claudeAiOauth;
49
- if (!oauth?.accessToken)
50
- return null;
51
- if (oauth.expiresAt && Date.now() > oauth.expiresAt)
52
- return null;
53
- return oauth.accessToken;
54
- }
55
- catch {
48
+ const parsed = readParsed();
49
+ if (!parsed)
56
50
  return null;
57
- }
51
+ if (parsed.expiresAt && Date.now() > parsed.expiresAt)
52
+ return null;
53
+ return parsed.accessToken;
58
54
  }
@@ -1,9 +1,17 @@
1
+ import type { SyncReport } from './accountSyncTypes';
1
2
  export type EnsureDefaultAccountStatus = 'registered' | 'skipped' | 'error';
2
3
  export interface EnsureDefaultAccountsResult {
3
4
  claude: EnsureDefaultAccountStatus;
4
5
  codex: EnsureDefaultAccountStatus;
6
+ /** The full sync report behind the two statuses. */
7
+ sync?: SyncReport;
5
8
  }
6
9
  export interface EnsureDefaultAccountsOptions {
7
10
  logger?: (message: string, error?: unknown) => void;
8
11
  }
12
+ /**
13
+ * Host startup hook: run the one-time on-disk migrations, drop abandoned
14
+ * isolated logins, then reconcile the live logins with the saved profiles
15
+ * (registering any login sidekick has never seen).
16
+ */
9
17
  export declare function ensureDefaultAccounts(options?: EnsureDefaultAccountsOptions): Promise<EnsureDefaultAccountsResult>;
@@ -1,45 +1,9 @@
1
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
2
  Object.defineProperty(exports, "__esModule", { value: true });
36
3
  exports.ensureDefaultAccounts = ensureDefaultAccounts;
37
- const fs = __importStar(require("fs"));
38
- const path = __importStar(require("path"));
39
4
  const accounts_1 = require("./accounts");
40
- const accountRegistry_1 = require("./accountRegistry");
41
5
  const codexProfiles_1 = require("./codexProfiles");
42
- const credentials_1 = require("./credentials");
6
+ const accountSync_1 = require("./accountSync");
43
7
  function logFailure(options, message, error) {
44
8
  try {
45
9
  options?.logger?.(message, error);
@@ -48,65 +12,61 @@ function logFailure(options, message, error) {
48
12
  // Logging must never make account bootstrap fail.
49
13
  }
50
14
  }
51
- async function ensureDefaultClaudeAccount(options) {
52
- try {
53
- if ((0, accountRegistry_1.getActiveSavedAccount)('claude-code'))
54
- return 'skipped';
55
- const active = (0, accounts_1.readActiveClaudeAccount)();
56
- if (!active)
57
- return 'skipped';
58
- const credentials = await (0, credentials_1.readClaudeMaxCredentials)();
59
- if (!credentials)
60
- return 'skipped';
61
- const result = (0, accounts_1.addCurrentAccount)('Default');
62
- if (result.success)
63
- return 'registered';
64
- logFailure(options, 'Claude default account registration failed.', result.error ?? 'unknown error');
15
+ function statusFromReport(report) {
16
+ if (report.registered)
17
+ return 'registered';
18
+ // A keyring-mode Codex login is a steady state sidekick cannot act on, not a failure.
19
+ if (report.skipped === 'keyring')
20
+ return 'skipped';
21
+ if (report.warnings.length > 0)
65
22
  return 'error';
23
+ return 'skipped';
24
+ }
25
+ /**
26
+ * Host startup hook: run the one-time on-disk migrations, drop abandoned
27
+ * isolated logins, then reconcile the live logins with the saved profiles
28
+ * (registering any login sidekick has never seen).
29
+ */
30
+ async function ensureDefaultAccounts(options) {
31
+ try {
32
+ (0, accounts_1.reconcileClaudeAuthState)();
66
33
  }
67
34
  catch (error) {
68
- logFailure(options, 'Claude default account registration failed.', error);
69
- return 'error';
35
+ logFailure(options, 'Claude auth reconciliation failed.', error);
70
36
  }
71
- }
72
- function cleanupPendingCodexProfile(profileId) {
73
- fs.rmSync(path.join((0, codexProfiles_1.getCodexProfilesDir)(), profileId), { recursive: true, force: true });
74
- }
75
- async function ensureDefaultCodexAccount(options) {
76
37
  try {
77
- if ((0, codexProfiles_1.getActiveCodexAccount)())
78
- return 'skipped';
79
- const systemAuthPath = path.join((0, codexProfiles_1.getSystemCodexHome)(), 'auth.json');
80
- if (!fs.existsSync(systemAuthPath))
81
- return 'skipped';
82
- const result = await (0, codexProfiles_1.prepareCodexAccountAsync)('Default');
83
- if (result.success && !result.needsLogin)
84
- return 'registered';
85
- if (result.profileId) {
86
- cleanupPendingCodexProfile(result.profileId);
87
- }
88
- logFailure(options, 'Codex default account registration failed.', result.error ?? 'Codex auth could not be finalized.');
89
- return 'error';
38
+ await (0, codexProfiles_1.reconcileCodexAuthStateAsync)();
90
39
  }
91
40
  catch (error) {
92
- logFailure(options, 'Codex default account registration failed.', error);
93
- return 'error';
41
+ logFailure(options, 'Codex auth reconciliation failed.', error);
94
42
  }
95
- }
96
- async function ensureDefaultAccounts(options) {
97
- const claude = await ensureDefaultClaudeAccount(options);
98
- const codex = await ensureDefaultCodexAccount(options);
99
43
  try {
100
- (0, accounts_1.reconcileClaudeAuthState)();
44
+ (0, accountSync_1.cleanupAbandonedLogins)();
101
45
  }
102
46
  catch (error) {
103
- logFailure(options, 'Claude auth reconciliation failed.', error);
47
+ logFailure(options, 'Abandoned login cleanup failed.', error);
104
48
  }
49
+ let sync;
105
50
  try {
106
- await (0, codexProfiles_1.reconcileCodexAuthStateAsync)();
51
+ sync = await (0, accountSync_1.syncLiveAccountState)({ reason: 'startup' });
107
52
  }
108
53
  catch (error) {
109
- logFailure(options, 'Codex auth reconciliation failed.', error);
54
+ logFailure(options, 'Account sync failed.', error);
55
+ return { claude: 'error', codex: 'error' };
110
56
  }
111
- return { claude, codex };
57
+ for (const [provider, report] of [
58
+ ['Claude', sync.claude],
59
+ ['Codex', sync.codex],
60
+ ]) {
61
+ if (report.skipped === 'keyring')
62
+ continue;
63
+ for (const warning of report.warnings) {
64
+ logFailure(options, `${provider} account sync: ${warning}`, undefined);
65
+ }
66
+ }
67
+ return {
68
+ claude: statusFromReport(sync.claude),
69
+ codex: statusFromReport(sync.codex),
70
+ sync,
71
+ };
112
72
  }
package/dist/index.d.ts CHANGED
@@ -154,27 +154,44 @@ export { calculateCompactionLedger, formatCompactionLedger } from './analytics/c
154
154
  export type { CompactionLedger } from './analytics/compactionLedger';
155
155
  export { generateHtmlReport, parseTranscript, parseTranscriptFromEvents, openInBrowser, } from './report';
156
156
  export type { TranscriptContentBlock, TranscriptEntry, HtmlReportOptions } from './report';
157
- export { readActiveCredentials, writeActiveCredentials } from './credentialIO';
158
- export { readClaudeMaxCredentials, readClaudeMaxAccessTokenSync } from './credentials';
157
+ export { readActiveCredentials, writeActiveCredentials, deleteStoredCredentials, } from './credentialIO';
158
+ export { readClaudeMaxCredentials, readClaudeMaxCredentialsRaw, readClaudeMaxAccessTokenSync, } from './credentials';
159
159
  export type { ClaudeMaxCredentials } from './credentials';
160
+ export { parseClaudeCredentialBlob, claudeCredentialFreshness, isNewerClaudeCredential, resolveClaudeRefreshExpiry, CLAUDE_ACCESS_TOKEN_LIFETIME_MS, CLAUDE_REFRESH_TOKEN_LIFETIME_ESTIMATE_MS, } from './claudeCredentials';
161
+ export type { ClaudeOauthCredentials } from './claudeCredentials';
162
+ export { parseAuthJson as parseCodexAuthJson, readAuthIdentityFromRaw as readCodexAuthIdentity, readLastRefresh as readCodexLastRefresh, readAccessTokenExpiry as readCodexAccessTokenExpiry, identitiesMatch as codexIdentitiesMatch, } from './codexAuth';
163
+ export type { CodexAuthIdentity, CodexAuthJsonFile } from './codexAuth';
160
164
  export { ensureDefaultAccounts } from './ensureDefaultAccounts';
161
165
  export type { EnsureDefaultAccountStatus, EnsureDefaultAccountsOptions, EnsureDefaultAccountsResult, } from './ensureDefaultAccounts';
162
- export { readAccountRegistry, writeAccountRegistry, readActiveClaudeAccount, addCurrentAccount, switchToAccount, resolveActiveClaudeHome, applyActiveClaudeToLiveHome, reconcileClaudeAuthState, removeAccount, listAccounts, getActiveAccount, resolveActiveClaudeAccount, isMultiAccountEnabled, } from './accounts';
166
+ export { readAccountRegistry, writeAccountRegistry, readActiveClaudeAccount, addCurrentAccount, switchToAccount, switchToAccountAsync, syncClaudeLiveState, cleanupAbandonedClaudeLogins, resolveActiveClaudeHome, applyActiveClaudeToLiveHome, reconcileClaudeAuthState, removeAccount, listAccounts, getActiveAccount, resolveActiveClaudeAccount, isMultiAccountEnabled, } from './accounts';
163
167
  export type { AccountEntry, AccountRegistry, ActiveAccountInfo, AccountManagerResult, } from './accounts';
164
- export { beginAccountLogin, getAccountLoginStatus, getAccountLoginStatusAsync, finalizeAccountLogin, finalizeAccountLoginAsync, spawnAccountLogin, switchAccount, switchAccountAsync, listAllAccounts, resolveClaudeLoginCommand, } from './accountManager';
165
- export type { AccountLoginCommand, AccountLoginState, AccountLoginStatus, BeginAccountLoginResult, FinalizeAccountLoginOptions, ListAllAccountsResult, SpawnAccountLoginOptions, } from './accountManager';
168
+ export { beginAccountLogin, getAccountLoginStatus, getAccountLoginStatusAsync, finalizeAccountLogin, finalizeAccountLoginAsync, spawnAccountLogin, switchAccount, switchAccountAsync, undoLastSwitch, getLastSwitch, listAllAccounts, resolveClaudeLoginCommand, } from './accountManager';
169
+ export type { AccountLoginCommand, AccountLoginState, AccountLoginStatus, BeginAccountLoginOptions, BeginAccountLoginResult, BeginAccountLoginSuccess, FinalizeAccountLoginOptions, ListAllAccountsResult, SpawnAccountLoginOptions, } from './accountManager';
170
+ export { readLastSwitch, getLastSwitchPath } from './accountSwitch';
171
+ export type { LastSwitchRecord, SwitchAccountOptions, SwitchAccountResult, SwitchVerification, } from './accountSwitch';
172
+ export { syncLiveAccountState, syncLiveAccountStateSync, cleanupAbandonedLogins, } from './accountSync';
173
+ export type { SyncLiveAccountStateOptions, CleanupAbandonedLoginsResult } from './accountSync';
174
+ export type { ProviderSyncReport, SyncReason, SyncReport } from './accountSyncTypes';
175
+ export { getAccountHealth, listAccountsWithHealth, readHealthSidecar, getHealthSidecarPath, } from './accountHealth';
176
+ export type { AccountHealth, AccountHealthOptions, AccountHealthSidecar, AccountHealthSource, AccountHealthState, AccountView, } from './accountHealth';
177
+ export { getAccountLaunchEnv } from './accountLaunch';
178
+ export type { AccountLaunchEnv, AccountLaunchOptions } from './accountLaunch';
179
+ export { refreshInactiveAccounts, keepAliveCommand } from './keepAlive';
180
+ export type { KeepAliveRunner, RefreshInactiveAccountsOptions, RefreshInactiveAccountsResult, } from './keepAlive';
181
+ export { findRunningProcesses, findRunningProcessesSync, detectRunningAccountConsumers, detectRunningAccountConsumersSync, describeAccountConsumer, ACCOUNT_CONSUMER_REACHABILITY, } from './processDetection';
182
+ export type { AccountConsumerKind, RunningAccountConsumer, RunningProcess, } from './processDetection';
166
183
  export { getAccountsDir, readSavedAccountRegistry, writeSavedAccountRegistry, listSavedAccountProfiles, getActiveSavedAccount, upsertSavedAccountProfile, setActiveSavedAccount, replaceSavedAccountProfiles, removeSavedAccountProfile, } from './accountRegistry';
167
- export type { AccountProviderId, AccountIdentityMetadata, ResolvedActiveAccount, SavedAccountProfile, SavedAccountRegistry, } from './accountRegistry';
184
+ export type { AccountProviderId, AccountIdentityMetadata, AccountProfileOrigin, ResolvedActiveAccount, SavedAccountProfile, SavedAccountRegistry, } from './accountRegistry';
168
185
  export { ACCOUNT_PROVIDER_IDS } from './accountRegistry';
169
186
  export { getActiveAccountStatus } from './accountStatus';
170
187
  export type { ActiveAccountStatus, ActiveAccountStatusOptions, ActiveProviderAccountStatus, } from './accountStatus';
171
188
  export { onAccountsChanged } from './accountChanges';
172
189
  export type { AccountsChangedEvent, OnAccountsChangedOptions } from './accountChanges';
173
- export { getClaudeProfilesDir, getClaudeProfileHome, claudeKeychainSuffix, claudeKeychainService, isClaudeProfileAuthenticated, readClaudeProfileIdentity, } from './claudeProfiles';
190
+ export { getClaudeProfilesDir, getClaudeProfileHome, getLiveClaudeHome, getDefaultClaudeHome, getClaudeConfigPath, claudeKeychainSuffix, claudeKeychainService, claudeKeychainAccountName, buildClaudeChildEnv, CLAUDE_SECURESTORAGE_CONFIG_DIR_ENV, isClaudeProfileAuthenticated, readClaudeProfileIdentity, readLiveClaudeIdentity, } from './claudeProfiles';
174
191
  export type { ClaudeProfileIdentity } from './claudeProfiles';
175
- export { getCodexProfilesDir, getCodexProfileHome, getCodexMonitoringHomes, getSystemCodexHome, listCodexAccounts, getActiveCodexAccount, resolveActiveCodexAccount, resolveSidekickCodexHome, getCodexExecutionEnv, prepareCodexAccount, prepareCodexAccountAsync, finalizeCodexAccount, finalizeCodexAccountAsync, switchToCodexAccount, switchToCodexAccountAsync, removeCodexAccount, } from './codexProfiles';
176
- export type { CodexAccountManagerResult } from './codexProfiles';
177
- export { setTerminalActiveProfile, installShellHook, uninstallShellHook, isShellHookInstalled, writeLauncher, removeLauncher, } from './terminalSync';
192
+ 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';
193
+ export type { CodexAccountManagerResult, CodexCredentialStoreMode } from './codexProfiles';
194
+ export { writeLauncher, removeLauncher } from './terminalSync';
178
195
  export { DEFAULT_AUTO_SWITCH_CONFIG, decideAutoSwitch, AutoSwitchController } from './autoSwitch';
179
196
  export type { AutoSwitchActiveAccount, AutoSwitchCandidate, AutoSwitchConfig, AutoSwitchControllerOptions, AutoSwitchDecision, AutoSwitchTransitionEvent, } from './autoSwitch';
180
197
  export { FIVE_HOUR_WINDOW_MS, QUOTA_PROVIDER_IDS, SEVEN_DAY_WINDOW_MS, fetchQuota, projectQuotaWindow, withQuotaProjections, } from './quota';