sidekick-shared 0.18.5 → 0.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -3
- package/dist/accounts.d.ts +1 -0
- package/dist/codexProfiles.d.ts +3 -2
- package/dist/codexProfiles.js +382 -52
- package/dist/ensureDefaultAccounts.js +6 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +26 -1
- package/dist/modelContext.d.ts +3 -0
- package/dist/modelContext.js +8 -2
- package/dist/modelInfo.d.ts +8 -0
- package/dist/modelInfo.js +98 -25
- package/dist/schemas/accountStatus.d.ts +30 -0
- package/dist/schemas/accountStatus.js +27 -0
- package/dist/schemas/index.d.ts +22 -0
- package/dist/schemas/index.js +40 -0
- package/dist/schemas/quota.d.ts +499 -0
- package/dist/schemas/quota.js +109 -0
- package/dist/schemas/quotaHistory.d.ts +49 -0
- package/dist/schemas/quotaHistory.js +42 -0
- package/dist/schemas/sessionEvent.d.ts +11 -0
- package/dist/schemas/sessionEvent.js +30 -0
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -31,13 +31,13 @@ npm install sidekick-shared
|
|
|
31
31
|
| **Credentials** | Claude Max OAuth credential reading from `~/.claude/.credentials.json` |
|
|
32
32
|
| **Quota** | Claude Max subscription quota fetching (5-hour and 7-day windows) and Codex rate-limit extraction from event streams |
|
|
33
33
|
| **Provider Status** | API health checking via status.claude.com and status.openai.com (indicator, components, incidents) |
|
|
34
|
-
| **Schemas** | Zod schemas for runtime JSONL
|
|
34
|
+
| **Schemas** | Zod schemas for runtime validation of data crossing process/IPC boundaries — JSONL session events (`sessionEventSchema`, `messageUsageSchema`, `sessionMessageSchema`), quota, account status, and quota history — plus `extractSessionEvents()` to unwrap `progress`-wrapped events. Also published fs-free via the [`sidekick-shared/schemas`](#supported-import-paths) subpath |
|
|
35
35
|
| **Extractors** | Pure functions for single-event processing: `extractTokenUsage()`, `extractToolCall()` (top-level `tool_use`), `extractToolCalls()` (assistant content blocks) |
|
|
36
|
-
| **Model Info & Pricing** | Model family parsing (Anthropic / OpenAI / Google, including legacy `claude-3-opus-…` and `claude-3-5-sonnet-…` IDs), context-window lookup (including Opus 4.7 / Sonnet 4.7 1M and GPT-5.x variants), pricing tables with optional LiteLLM hydration, null-aware cost (`calculateCost()`), provenance-preserving cost (`calculateCostWithProvenance()`, `mergeCostSources()`), and display helpers (`shortModelName()`, `getModelDisplayInfo()`, `compareModelIds()`, `sortModelIds()`, `formatCost()`) |
|
|
36
|
+
| **Model Info & Pricing** | Model family parsing (Anthropic / OpenAI / Google, including legacy `claude-3-opus-…` and `claude-3-5-sonnet-…` IDs), context-window lookup (including Fable 5 / Opus 4.8 / Opus 4.7 / Sonnet 4.7 1M and GPT-5.x variants), pricing tables with optional LiteLLM hydration, null-aware cost (`calculateCost()`), provenance-preserving cost (`calculateCostWithProvenance()`, `mergeCostSources()`), and display helpers (`shortModelName()`, `getModelDisplayInfo()`, `compareModelIds()`, `sortModelIds()`, `formatCost()`) |
|
|
37
37
|
| **Quota Polling** | `QuotaPoller` class with exponential backoff, active/idle intervals, and cached fallback |
|
|
38
38
|
| **Multi-Provider Quota** | `MultiProviderQuotaService` orchestrates Claude polling + peak-hours + account labels + Codex quota updates behind one typed `{ claude?, codex? }` event stream. `CodexQuotaWatcher` watches the active Codex rollout for live rate limits with snapshot fallback |
|
|
39
39
|
| **Accounts** | Multi-provider account registry (v2) with per-provider active account, save/switch/remove, v1 migration, `ensureDefaultAccounts()` for first-run bootstrap of the active system Claude/Codex credentials as a "Default" saved account, and `getActiveAccountStatus()` for a single-pass active-account read across providers |
|
|
40
|
-
| **Codex Profiles** | Codex account lifecycle — prepare, finalize, switch, remove — with
|
|
40
|
+
| **Codex Profiles** | Codex account lifecycle — prepare, finalize, switch, remove — switching atomically swaps the profile's backed-up credentials into the system `~/.codex/auth.json`, with rotated-token staleness protection, one-time dual-home migration, and legacy multi-home session monitoring |
|
|
41
41
|
| **Quota Snapshots** | Persistent quota caching per provider/account for offline fallback |
|
|
42
42
|
| **Phrases** | Curated humorous phrases for loading/idle states, available as a flat `ALL_PHRASES` array or grouped via `PHRASE_CATEGORIES` for category-aware UI |
|
|
43
43
|
|
|
@@ -54,6 +54,7 @@ npm install sidekick-shared
|
|
|
54
54
|
| `sidekick-shared/modelContext` | Any runtime | Direct access to the context-window module. |
|
|
55
55
|
| `sidekick-shared/modelInfo` | Any runtime | Direct access to model parsing and cost math. |
|
|
56
56
|
| `sidekick-shared/formatting` | Any runtime | Direct access to pure token and duration display helpers. |
|
|
57
|
+
| `sidekick-shared/schemas` | Any runtime | Pure Zod boundary schemas (session events, quota, account status, quota history) — fs-free, no Node builtins. |
|
|
57
58
|
|
|
58
59
|
### Browser / webview runtimes
|
|
59
60
|
|
|
@@ -223,6 +224,8 @@ const parser = new JsonlParser(
|
|
|
223
224
|
parser.processChunk(rawData);
|
|
224
225
|
```
|
|
225
226
|
|
|
227
|
+
The boundary schemas — `sessionEventSchema` plus the quota, account-status, and quota-history schemas — are also importable fs-free from `sidekick-shared/schemas`, which keeps Zod out of bundles that only need the pure math/formatting helpers. `extractSessionEvents()` from the same subpath unwraps Claude Code `progress`-wrapped events into canonical `SessionEvent[]`.
|
|
228
|
+
|
|
226
229
|
### Tail raw JSONL events incrementally
|
|
227
230
|
|
|
228
231
|
Use `createJsonlTail()` when a consumer needs raw parsed events and owns its own aggregation lifecycle. `onBatchComplete` fires once after each drained byte chunk, which lets callers defer expensive UI or metrics updates until parsing for that chunk is complete.
|
package/dist/accounts.d.ts
CHANGED
package/dist/codexProfiles.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export declare function getActiveCodexAccount(): SavedAccountProfile | null;
|
|
|
14
14
|
export declare function resolveSidekickCodexHome(): string;
|
|
15
15
|
export declare function getCodexExecutionEnv(baseEnv?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
16
16
|
export declare function prepareCodexAccount(label: string): CodexAccountManagerResult;
|
|
17
|
-
export declare function finalizeCodexAccount(profileId: string):
|
|
18
|
-
export declare function switchToCodexAccount(profileId: string):
|
|
17
|
+
export declare function finalizeCodexAccount(profileId: string): CodexAccountManagerResult;
|
|
18
|
+
export declare function switchToCodexAccount(profileId: string): CodexAccountManagerResult;
|
|
19
|
+
export declare function reconcileCodexAuthState(): void;
|
|
19
20
|
export declare function removeCodexAccount(profileId: string): AccountManagerResult;
|
package/dist/codexProfiles.js
CHANGED
|
@@ -44,6 +44,7 @@ exports.getCodexExecutionEnv = getCodexExecutionEnv;
|
|
|
44
44
|
exports.prepareCodexAccount = prepareCodexAccount;
|
|
45
45
|
exports.finalizeCodexAccount = finalizeCodexAccount;
|
|
46
46
|
exports.switchToCodexAccount = switchToCodexAccount;
|
|
47
|
+
exports.reconcileCodexAuthState = reconcileCodexAuthState;
|
|
47
48
|
exports.removeCodexAccount = removeCodexAccount;
|
|
48
49
|
const fs = __importStar(require("fs"));
|
|
49
50
|
const os = __importStar(require("os"));
|
|
@@ -51,6 +52,9 @@ const path = __importStar(require("path"));
|
|
|
51
52
|
const child_process_1 = require("child_process");
|
|
52
53
|
const crypto_1 = require("crypto");
|
|
53
54
|
const accountRegistry_1 = require("./accountRegistry");
|
|
55
|
+
// Codex refreshes OAuth tokens at most every 8 days; a stored refresh token
|
|
56
|
+
// older than that may already be rejected by the auth server.
|
|
57
|
+
const STALE_AUTH_THRESHOLD_MS = 8 * 24 * 60 * 60 * 1000;
|
|
54
58
|
function getDefaultSystemCodexHome() {
|
|
55
59
|
return path.join(os.homedir(), '.codex');
|
|
56
60
|
}
|
|
@@ -77,12 +81,15 @@ function getCodexMonitoringHomes() {
|
|
|
77
81
|
const explicitHome = getExplicitCodexHome();
|
|
78
82
|
if (explicitHome)
|
|
79
83
|
return [explicitHome];
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
+
// The system home is the single live home; profile homes only matter for
|
|
85
|
+
// sessions recorded back when they doubled as live CODEX_HOMEs.
|
|
86
|
+
const homes = [getDefaultSystemCodexHome()];
|
|
87
|
+
for (const profile of listCodexAccounts()) {
|
|
88
|
+
const profileHome = getCodexProfileHome(profile.id);
|
|
89
|
+
if (fs.existsSync(path.join(profileHome, 'sessions'))) {
|
|
90
|
+
homes.push(profileHome);
|
|
91
|
+
}
|
|
84
92
|
}
|
|
85
|
-
homes.push(getDefaultSystemCodexHome());
|
|
86
93
|
return dedupePaths(homes);
|
|
87
94
|
}
|
|
88
95
|
function getCodexProfilesDir() {
|
|
@@ -104,8 +111,43 @@ function atomicWriteJson(filePath, data, mode = 0o600) {
|
|
|
104
111
|
const tmp = filePath + '.tmp';
|
|
105
112
|
const json = JSON.stringify(data, null, 2);
|
|
106
113
|
JSON.parse(json);
|
|
107
|
-
|
|
108
|
-
|
|
114
|
+
try {
|
|
115
|
+
fs.writeFileSync(tmp, json, { encoding: 'utf8', mode });
|
|
116
|
+
fs.renameSync(tmp, filePath);
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
try {
|
|
120
|
+
fs.unlinkSync(tmp);
|
|
121
|
+
}
|
|
122
|
+
catch { /* nothing to clean up */ }
|
|
123
|
+
throw err;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// auth.json must be copied byte-for-byte: re-serializing would drop fields
|
|
127
|
+
// added by newer codex versions, and the rotated refresh token inside is
|
|
128
|
+
// only valid in its freshest form.
|
|
129
|
+
function atomicWriteFile(filePath, content, mode = 0o600) {
|
|
130
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true, mode: 0o700 });
|
|
131
|
+
const tmp = filePath + '.tmp';
|
|
132
|
+
try {
|
|
133
|
+
fs.writeFileSync(tmp, content, { encoding: 'utf8', mode });
|
|
134
|
+
fs.renameSync(tmp, filePath);
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
try {
|
|
138
|
+
fs.unlinkSync(tmp);
|
|
139
|
+
}
|
|
140
|
+
catch { /* nothing to clean up */ }
|
|
141
|
+
throw err;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function readFileOrNull(filePath) {
|
|
145
|
+
try {
|
|
146
|
+
return fs.readFileSync(filePath, 'utf8');
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
109
151
|
}
|
|
110
152
|
function readPendingProfile(profileId) {
|
|
111
153
|
try {
|
|
@@ -146,40 +188,65 @@ function parseJwtPayload(jwt) {
|
|
|
146
188
|
return null;
|
|
147
189
|
}
|
|
148
190
|
}
|
|
149
|
-
function
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
return {};
|
|
191
|
+
function parseAuthJson(raw) {
|
|
192
|
+
if (!raw)
|
|
193
|
+
return null;
|
|
153
194
|
try {
|
|
154
|
-
|
|
155
|
-
const idToken = parsed.tokens?.id_token;
|
|
156
|
-
const claims = idToken ? parseJwtPayload(idToken) : null;
|
|
157
|
-
const profileClaims = claims?.['https://api.openai.com/profile'];
|
|
158
|
-
const authClaims = claims?.['https://api.openai.com/auth'];
|
|
159
|
-
const email = typeof claims?.email === 'string'
|
|
160
|
-
? claims.email
|
|
161
|
-
: typeof profileClaims?.email === 'string'
|
|
162
|
-
? profileClaims.email
|
|
163
|
-
: undefined;
|
|
164
|
-
const workspaceId = typeof authClaims?.chatgpt_account_id === 'string'
|
|
165
|
-
? authClaims.chatgpt_account_id
|
|
166
|
-
: parsed.tokens?.account_id;
|
|
167
|
-
const planType = typeof authClaims?.chatgpt_plan_type === 'string'
|
|
168
|
-
? authClaims.chatgpt_plan_type
|
|
169
|
-
: undefined;
|
|
170
|
-
const authMode = parsed.OPENAI_API_KEY || parsed.auth_mode === 'api_key'
|
|
171
|
-
? 'api-key'
|
|
172
|
-
: 'chatgpt';
|
|
173
|
-
return {
|
|
174
|
-
email,
|
|
175
|
-
workspaceId,
|
|
176
|
-
planType,
|
|
177
|
-
authMode,
|
|
178
|
-
};
|
|
195
|
+
return JSON.parse(raw);
|
|
179
196
|
}
|
|
180
197
|
catch {
|
|
181
|
-
return
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
function readAuthIdentityFromRaw(raw) {
|
|
202
|
+
const parsed = parseAuthJson(raw);
|
|
203
|
+
if (!parsed)
|
|
204
|
+
return null;
|
|
205
|
+
const idToken = parsed.tokens?.id_token;
|
|
206
|
+
const claims = idToken ? parseJwtPayload(idToken) : null;
|
|
207
|
+
const profileClaims = claims?.['https://api.openai.com/profile'];
|
|
208
|
+
const authClaims = claims?.['https://api.openai.com/auth'];
|
|
209
|
+
const email = typeof claims?.email === 'string'
|
|
210
|
+
? claims.email
|
|
211
|
+
: typeof profileClaims?.email === 'string'
|
|
212
|
+
? profileClaims.email
|
|
213
|
+
: undefined;
|
|
214
|
+
const workspaceId = typeof authClaims?.chatgpt_account_id === 'string'
|
|
215
|
+
? authClaims.chatgpt_account_id
|
|
216
|
+
: parsed.tokens?.account_id;
|
|
217
|
+
const planType = typeof authClaims?.chatgpt_plan_type === 'string'
|
|
218
|
+
? authClaims.chatgpt_plan_type
|
|
219
|
+
: undefined;
|
|
220
|
+
const authMode = parsed.OPENAI_API_KEY || parsed.auth_mode === 'api_key'
|
|
221
|
+
? 'api-key'
|
|
222
|
+
: 'chatgpt';
|
|
223
|
+
return { email, workspaceId, planType, authMode };
|
|
224
|
+
}
|
|
225
|
+
function readLastRefresh(raw, fallbackPath) {
|
|
226
|
+
const parsed = parseAuthJson(raw);
|
|
227
|
+
if (parsed?.last_refresh) {
|
|
228
|
+
const ts = Date.parse(parsed.last_refresh);
|
|
229
|
+
if (!Number.isNaN(ts))
|
|
230
|
+
return ts;
|
|
182
231
|
}
|
|
232
|
+
if (fallbackPath) {
|
|
233
|
+
try {
|
|
234
|
+
return fs.statSync(fallbackPath).mtimeMs;
|
|
235
|
+
}
|
|
236
|
+
catch { /* fall through */ }
|
|
237
|
+
}
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
function readMetadataFromAuthJson(codexHome) {
|
|
241
|
+
const identity = readAuthIdentityFromRaw(readFileOrNull(path.join(codexHome, 'auth.json')));
|
|
242
|
+
if (!identity)
|
|
243
|
+
return {};
|
|
244
|
+
return {
|
|
245
|
+
email: identity.email,
|
|
246
|
+
workspaceId: identity.workspaceId,
|
|
247
|
+
planType: identity.planType,
|
|
248
|
+
authMode: identity.authMode,
|
|
249
|
+
};
|
|
183
250
|
}
|
|
184
251
|
function readMetadataFromLegacyCredentials(codexHome) {
|
|
185
252
|
const legacyPath = path.join(codexHome, '.credentials.json');
|
|
@@ -219,6 +286,16 @@ function getCodexLoginStatus(codexHome) {
|
|
|
219
286
|
}
|
|
220
287
|
return { loggedIn: false };
|
|
221
288
|
}
|
|
289
|
+
function detectRunningCodexProcess() {
|
|
290
|
+
if (process.platform === 'win32')
|
|
291
|
+
return false;
|
|
292
|
+
try {
|
|
293
|
+
return (0, child_process_1.spawnSync)('pgrep', ['-x', 'codex'], { encoding: 'utf8' }).status === 0;
|
|
294
|
+
}
|
|
295
|
+
catch {
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
222
299
|
function readCodexAccountMetadata(codexHome) {
|
|
223
300
|
const fromAuth = readMetadataFromAuthJson(codexHome);
|
|
224
301
|
if (fromAuth.email || fromAuth.workspaceId || fromAuth.planType || fromAuth.authMode) {
|
|
@@ -256,15 +333,8 @@ function getActiveCodexAccount() {
|
|
|
256
333
|
return (0, accountRegistry_1.getActiveSavedAccount)('codex');
|
|
257
334
|
}
|
|
258
335
|
function resolveSidekickCodexHome() {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
return explicitHome;
|
|
262
|
-
const active = getActiveCodexAccount();
|
|
263
|
-
if (active) {
|
|
264
|
-
const managedHome = getCodexProfileHome(active.id);
|
|
265
|
-
if (fs.existsSync(managedHome))
|
|
266
|
-
return managedHome;
|
|
267
|
-
}
|
|
336
|
+
// Account switching swaps auth.json inside the system home, so the system
|
|
337
|
+
// home (or an explicit CODEX_HOME) is always the single live home.
|
|
268
338
|
return getSystemCodexHome();
|
|
269
339
|
}
|
|
270
340
|
function getCodexExecutionEnv(baseEnv = process.env) {
|
|
@@ -318,24 +388,284 @@ function finalizeCodexAccount(profileId) {
|
|
|
318
388
|
return { success: false, error: 'Codex profile is not authenticated yet.' };
|
|
319
389
|
}
|
|
320
390
|
const metadata = readCodexAccountMetadata(codexHome);
|
|
321
|
-
|
|
391
|
+
const profile = {
|
|
322
392
|
id: profileId,
|
|
323
393
|
providerId: 'codex',
|
|
324
394
|
label: pending.label,
|
|
325
395
|
email: metadata.email,
|
|
326
396
|
addedAt: pending.addedAt,
|
|
327
397
|
metadata,
|
|
328
|
-
}
|
|
329
|
-
(0, accountRegistry_1.
|
|
330
|
-
|
|
398
|
+
};
|
|
399
|
+
(0, accountRegistry_1.upsertSavedAccountProfile)(profile);
|
|
400
|
+
const hasCredentialFiles = fs.existsSync(path.join(codexHome, 'auth.json')) ||
|
|
401
|
+
fs.existsSync(path.join(codexHome, '.credentials.json'));
|
|
402
|
+
if (!hasCredentialFiles) {
|
|
403
|
+
// Authenticated via the OS keyring — there are no credential files to
|
|
404
|
+
// swap, so the registry pointer is all we can update.
|
|
405
|
+
(0, accountRegistry_1.setActiveSavedAccount)('codex', profileId);
|
|
406
|
+
return {
|
|
407
|
+
success: true,
|
|
408
|
+
warning: 'Codex stores credentials in the OS keyring; sidekick cannot swap them per account, so `codex` keeps using the keyring credentials.',
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
return performCodexAuthSwap(profile);
|
|
412
|
+
}
|
|
413
|
+
function getCodexStashDir() {
|
|
414
|
+
return path.join((0, accountRegistry_1.getAccountsDir)(), 'codex', 'stash');
|
|
415
|
+
}
|
|
416
|
+
function stashLiveCodexAuth(liveAuthRaw, liveLegacyRaw) {
|
|
417
|
+
try {
|
|
418
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
419
|
+
let stashPath = null;
|
|
420
|
+
if (liveAuthRaw) {
|
|
421
|
+
stashPath = path.join(getCodexStashDir(), `auth-${stamp}.json`);
|
|
422
|
+
atomicWriteFile(stashPath, liveAuthRaw);
|
|
423
|
+
}
|
|
424
|
+
if (liveLegacyRaw) {
|
|
425
|
+
const legacyStashPath = path.join(getCodexStashDir(), `credentials-${stamp}.json`);
|
|
426
|
+
atomicWriteFile(legacyStashPath, liveLegacyRaw);
|
|
427
|
+
stashPath = stashPath ?? legacyStashPath;
|
|
428
|
+
}
|
|
429
|
+
return stashPath;
|
|
430
|
+
}
|
|
431
|
+
catch {
|
|
432
|
+
return null;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
function findProfileForIdentity(identity) {
|
|
436
|
+
const profiles = listCodexAccounts();
|
|
437
|
+
if (identity?.workspaceId) {
|
|
438
|
+
const byWorkspace = profiles.find(profile => profile.metadata?.workspaceId === identity.workspaceId);
|
|
439
|
+
if (byWorkspace)
|
|
440
|
+
return byWorkspace;
|
|
441
|
+
}
|
|
442
|
+
if (identity?.email) {
|
|
443
|
+
const byEmail = profiles.find(profile => (profile.email ?? profile.metadata?.email) === identity.email);
|
|
444
|
+
if (byEmail)
|
|
445
|
+
return byEmail;
|
|
446
|
+
}
|
|
447
|
+
if (!identity?.workspaceId && !identity?.email) {
|
|
448
|
+
// API-key auth or unparseable tokens carry no identity; assume the live
|
|
449
|
+
// file belongs to whichever account the registry says is active.
|
|
450
|
+
return getActiveCodexAccount();
|
|
451
|
+
}
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
// Codex rotates the refresh token whenever it refreshes auth.json, so the
|
|
455
|
+
// live file is always the freshest copy of its account. Before replacing it,
|
|
456
|
+
// preserve it in the matching profile's backup — or stash it if it belongs to
|
|
457
|
+
// no saved account. Best-effort: never throws.
|
|
458
|
+
function syncBackLiveCodexAuth(liveAuthRaw, liveLegacyRaw) {
|
|
459
|
+
if (!liveAuthRaw && !liveLegacyRaw)
|
|
460
|
+
return {};
|
|
461
|
+
try {
|
|
462
|
+
const identity = readAuthIdentityFromRaw(liveAuthRaw);
|
|
463
|
+
const profile = findProfileForIdentity(identity);
|
|
464
|
+
if (!profile) {
|
|
465
|
+
const stashPath = stashLiveCodexAuth(liveAuthRaw, liveLegacyRaw);
|
|
466
|
+
return {
|
|
467
|
+
stashPath: stashPath ?? undefined,
|
|
468
|
+
warning: stashPath
|
|
469
|
+
? `Live Codex credentials did not match any saved account; stashed at ${stashPath}.`
|
|
470
|
+
: 'Live Codex credentials did not match any saved account and could not be stashed.',
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
const profileHome = getCodexProfileHome(profile.id);
|
|
474
|
+
if (liveAuthRaw)
|
|
475
|
+
atomicWriteFile(path.join(profileHome, 'auth.json'), liveAuthRaw);
|
|
476
|
+
if (liveLegacyRaw)
|
|
477
|
+
atomicWriteFile(path.join(profileHome, '.credentials.json'), liveLegacyRaw);
|
|
478
|
+
try {
|
|
479
|
+
const metadata = readCodexAccountMetadata(profileHome);
|
|
480
|
+
(0, accountRegistry_1.upsertSavedAccountProfile)({
|
|
481
|
+
...profile,
|
|
482
|
+
email: metadata.email ?? profile.email,
|
|
483
|
+
metadata: { ...profile.metadata, ...metadata },
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
catch { /* metadata refresh is best-effort */ }
|
|
487
|
+
return { syncedProfileId: profile.id };
|
|
488
|
+
}
|
|
489
|
+
catch (err) {
|
|
490
|
+
return { warning: `Could not back up live Codex credentials: ${err}` };
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
function performCodexAuthSwap(target) {
|
|
494
|
+
const systemHome = getSystemCodexHome();
|
|
495
|
+
const liveAuthPath = path.join(systemHome, 'auth.json');
|
|
496
|
+
const liveLegacyPath = path.join(systemHome, '.credentials.json');
|
|
497
|
+
const liveAuthRaw = readFileOrNull(liveAuthPath);
|
|
498
|
+
const liveLegacyRaw = readFileOrNull(liveLegacyPath);
|
|
499
|
+
if (!liveAuthRaw && !liveLegacyRaw && getCodexLoginStatus(systemHome).loggedIn) {
|
|
500
|
+
return {
|
|
501
|
+
success: false,
|
|
502
|
+
error: 'Codex stores credentials in the OS keyring; file-based account switching is not supported. Set `cli_auth_credentials_store = "file"` in ~/.codex/config.toml and run `codex login` again.',
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
const profileHome = getCodexProfileHome(target.id);
|
|
506
|
+
const targetAuthPath = path.join(profileHome, 'auth.json');
|
|
507
|
+
const targetAuthRaw = readFileOrNull(targetAuthPath);
|
|
508
|
+
const targetLegacyRaw = readFileOrNull(path.join(profileHome, '.credentials.json'));
|
|
509
|
+
const targetName = target.label ?? target.email ?? target.id;
|
|
510
|
+
if (!targetAuthRaw && !targetLegacyRaw) {
|
|
511
|
+
return { success: false, error: `No stored credentials for "${targetName}". Remove and re-add this account.` };
|
|
512
|
+
}
|
|
513
|
+
if (targetAuthRaw && !parseAuthJson(targetAuthRaw)) {
|
|
514
|
+
return { success: false, error: `Stored credentials for "${targetName}" are corrupted. Remove and re-add this account.` };
|
|
515
|
+
}
|
|
516
|
+
const warnings = [];
|
|
517
|
+
if (detectRunningCodexProcess()) {
|
|
518
|
+
warnings.push('A codex process appears to be running; restart codex sessions so they pick up the switched account.');
|
|
519
|
+
}
|
|
520
|
+
// If the live file already belongs to the target account it is the freshest
|
|
521
|
+
// copy (rotated refresh token included) — never replace it with a staler
|
|
522
|
+
// backup, which would permanently invalidate the login. Just refresh the
|
|
523
|
+
// backup and the registry pointer.
|
|
524
|
+
const liveIdentity = readAuthIdentityFromRaw(liveAuthRaw);
|
|
525
|
+
const targetIdentity = readAuthIdentityFromRaw(targetAuthRaw);
|
|
526
|
+
const targetWorkspaceId = target.metadata?.workspaceId ?? targetIdentity?.workspaceId;
|
|
527
|
+
const targetEmail = target.email ?? target.metadata?.email ?? targetIdentity?.email;
|
|
528
|
+
const liveMatchesTarget = Boolean((liveIdentity?.workspaceId && targetWorkspaceId && liveIdentity.workspaceId === targetWorkspaceId) ||
|
|
529
|
+
(liveIdentity?.email && targetEmail && liveIdentity.email === targetEmail) ||
|
|
530
|
+
(liveAuthRaw !== null && liveAuthRaw === targetAuthRaw) ||
|
|
531
|
+
(!liveAuthRaw && !targetAuthRaw && liveLegacyRaw !== null && liveLegacyRaw === targetLegacyRaw));
|
|
532
|
+
if (liveMatchesTarget) {
|
|
533
|
+
try {
|
|
534
|
+
if (liveAuthRaw)
|
|
535
|
+
atomicWriteFile(targetAuthPath, liveAuthRaw);
|
|
536
|
+
if (liveLegacyRaw)
|
|
537
|
+
atomicWriteFile(path.join(profileHome, '.credentials.json'), liveLegacyRaw);
|
|
538
|
+
const metadata = readCodexAccountMetadata(profileHome);
|
|
539
|
+
(0, accountRegistry_1.upsertSavedAccountProfile)({
|
|
540
|
+
...target,
|
|
541
|
+
email: metadata.email ?? target.email,
|
|
542
|
+
metadata: { ...target.metadata, ...metadata },
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
catch { /* backup refresh is best-effort */ }
|
|
546
|
+
(0, accountRegistry_1.setActiveSavedAccount)('codex', target.id);
|
|
547
|
+
return { success: true, warning: warnings.length ? warnings.join(' ') : undefined };
|
|
548
|
+
}
|
|
549
|
+
const targetLastRefresh = readLastRefresh(targetAuthRaw, targetAuthPath);
|
|
550
|
+
if (targetLastRefresh !== null && Date.now() - targetLastRefresh > STALE_AUTH_THRESHOLD_MS) {
|
|
551
|
+
warnings.push(`Stored credentials for "${targetName}" have not been refreshed in over 8 days; codex may ask you to log in again.`);
|
|
552
|
+
}
|
|
553
|
+
const syncBack = syncBackLiveCodexAuth(liveAuthRaw, liveLegacyRaw);
|
|
554
|
+
if (syncBack.warning)
|
|
555
|
+
warnings.push(syncBack.warning);
|
|
556
|
+
const restoreLiveFiles = () => {
|
|
557
|
+
try {
|
|
558
|
+
if (liveAuthRaw)
|
|
559
|
+
atomicWriteFile(liveAuthPath, liveAuthRaw);
|
|
560
|
+
else
|
|
561
|
+
fs.rmSync(liveAuthPath, { force: true });
|
|
562
|
+
if (liveLegacyRaw)
|
|
563
|
+
atomicWriteFile(liveLegacyPath, liveLegacyRaw);
|
|
564
|
+
else
|
|
565
|
+
fs.rmSync(liveLegacyPath, { force: true });
|
|
566
|
+
}
|
|
567
|
+
catch { /* rollback is best-effort */ }
|
|
568
|
+
};
|
|
569
|
+
try {
|
|
570
|
+
if (targetAuthRaw) {
|
|
571
|
+
atomicWriteFile(liveAuthPath, targetAuthRaw);
|
|
572
|
+
if (targetLegacyRaw)
|
|
573
|
+
atomicWriteFile(liveLegacyPath, targetLegacyRaw);
|
|
574
|
+
else if (liveLegacyRaw)
|
|
575
|
+
fs.rmSync(liveLegacyPath, { force: true });
|
|
576
|
+
}
|
|
577
|
+
else {
|
|
578
|
+
atomicWriteFile(liveLegacyPath, targetLegacyRaw);
|
|
579
|
+
if (liveAuthRaw)
|
|
580
|
+
fs.rmSync(liveAuthPath, { force: true });
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
catch (err) {
|
|
584
|
+
restoreLiveFiles();
|
|
585
|
+
return { success: false, error: `Failed to write Codex credentials: ${err}` };
|
|
586
|
+
}
|
|
587
|
+
try {
|
|
588
|
+
(0, accountRegistry_1.setActiveSavedAccount)('codex', target.id);
|
|
589
|
+
}
|
|
590
|
+
catch (err) {
|
|
591
|
+
restoreLiveFiles();
|
|
592
|
+
return { success: false, error: `Failed to update account registry: ${err}` };
|
|
593
|
+
}
|
|
594
|
+
return { success: true, warning: warnings.length ? warnings.join(' ') : undefined };
|
|
331
595
|
}
|
|
332
596
|
function switchToCodexAccount(profileId) {
|
|
333
597
|
const target = listCodexAccounts().find(account => account.id === profileId);
|
|
334
598
|
if (!target) {
|
|
335
599
|
return { success: false, error: `Codex account ${profileId} not found.` };
|
|
336
600
|
}
|
|
337
|
-
|
|
338
|
-
|
|
601
|
+
return performCodexAuthSwap(target);
|
|
602
|
+
}
|
|
603
|
+
// One-time migration for installs created when profile homes doubled as live
|
|
604
|
+
// CODEX_HOMEs: the active profile's auth.json may hold a fresher rotated
|
|
605
|
+
// refresh token than the system home. Best-effort: never throws.
|
|
606
|
+
function reconcileCodexAuthState() {
|
|
607
|
+
try {
|
|
608
|
+
const markerPath = path.join((0, accountRegistry_1.getAccountsDir)(), 'codex', '.live-auth-migrated-v1');
|
|
609
|
+
if (fs.existsSync(markerPath))
|
|
610
|
+
return;
|
|
611
|
+
const writeMarker = () => atomicWriteFile(markerPath, new Date().toISOString() + '\n');
|
|
612
|
+
const active = getActiveCodexAccount();
|
|
613
|
+
if (!active) {
|
|
614
|
+
writeMarker();
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
const profileHome = getCodexProfileHome(active.id);
|
|
618
|
+
const profileAuthPath = path.join(profileHome, 'auth.json');
|
|
619
|
+
const profileAuthRaw = readFileOrNull(profileAuthPath);
|
|
620
|
+
if (!profileAuthRaw) {
|
|
621
|
+
writeMarker();
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
const systemHome = getSystemCodexHome();
|
|
625
|
+
const liveAuthPath = path.join(systemHome, 'auth.json');
|
|
626
|
+
const liveAuthRaw = readFileOrNull(liveAuthPath);
|
|
627
|
+
if (!liveAuthRaw) {
|
|
628
|
+
// No live credentials (account was added via isolated login and never
|
|
629
|
+
// promoted). Promote the active profile's copy unless codex is logged
|
|
630
|
+
// in through the OS keyring.
|
|
631
|
+
if (!getCodexLoginStatus(systemHome).loggedIn) {
|
|
632
|
+
atomicWriteFile(liveAuthPath, profileAuthRaw);
|
|
633
|
+
}
|
|
634
|
+
writeMarker();
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
const liveIdentity = readAuthIdentityFromRaw(liveAuthRaw);
|
|
638
|
+
const profileIdentity = readAuthIdentityFromRaw(profileAuthRaw);
|
|
639
|
+
const sameIdentity = Boolean((liveIdentity?.workspaceId && profileIdentity?.workspaceId && liveIdentity.workspaceId === profileIdentity.workspaceId) ||
|
|
640
|
+
(liveIdentity?.email && liveIdentity.email === profileIdentity?.email));
|
|
641
|
+
if (sameIdentity) {
|
|
642
|
+
const liveRefresh = readLastRefresh(liveAuthRaw, liveAuthPath);
|
|
643
|
+
const profileRefresh = readLastRefresh(profileAuthRaw, profileAuthPath);
|
|
644
|
+
if (profileRefresh !== null && (liveRefresh === null || profileRefresh > liveRefresh)) {
|
|
645
|
+
// The profile copy was the live home under the old model and holds
|
|
646
|
+
// the valid rotated refresh token — promote it.
|
|
647
|
+
stashLiveCodexAuth(liveAuthRaw, null);
|
|
648
|
+
atomicWriteFile(liveAuthPath, profileAuthRaw);
|
|
649
|
+
}
|
|
650
|
+
else {
|
|
651
|
+
atomicWriteFile(profileAuthPath, liveAuthRaw);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
else {
|
|
655
|
+
// The live credentials belong to a different account; the live state
|
|
656
|
+
// wins — point the registry at the matching saved profile if there is
|
|
657
|
+
// one, and refresh its backup.
|
|
658
|
+
const matching = findProfileForIdentity(liveIdentity);
|
|
659
|
+
if (matching && matching.id !== active.id) {
|
|
660
|
+
atomicWriteFile(path.join(getCodexProfileHome(matching.id), 'auth.json'), liveAuthRaw);
|
|
661
|
+
(0, accountRegistry_1.setActiveSavedAccount)('codex', matching.id);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
writeMarker();
|
|
665
|
+
}
|
|
666
|
+
catch {
|
|
667
|
+
// Reconciliation must never break startup.
|
|
668
|
+
}
|
|
339
669
|
}
|
|
340
670
|
function removeCodexAccount(profileId) {
|
|
341
671
|
const removed = (0, accountRegistry_1.removeSavedAccountProfile)('codex', profileId);
|
|
@@ -96,5 +96,11 @@ function ensureDefaultCodexAccount(options) {
|
|
|
96
96
|
async function ensureDefaultAccounts(options) {
|
|
97
97
|
const claude = await ensureDefaultClaudeAccount(options);
|
|
98
98
|
const codex = ensureDefaultCodexAccount(options);
|
|
99
|
+
try {
|
|
100
|
+
(0, codexProfiles_1.reconcileCodexAuthState)();
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
logFailure(options, 'Codex auth reconciliation failed.', error);
|
|
104
|
+
}
|
|
99
105
|
return { claude, codex };
|
|
100
106
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -122,7 +122,10 @@ export { hydratePricingCatalog, normalizeLiteLlmCatalog, LITELLM_CATALOG_URL } f
|
|
|
122
122
|
export type { HydrateOptions, HydrateResult } from './pricingCatalog';
|
|
123
123
|
export { extractTokenUsage } from './extractors/tokenUsage';
|
|
124
124
|
export { extractToolCall, extractToolCalls } from './extractors/toolCall';
|
|
125
|
-
export { messageUsageSchema, sessionMessageSchema, sessionEventSchema, permissionModeSchema, } from './schemas/sessionEvent';
|
|
125
|
+
export { messageUsageSchema, sessionMessageSchema, sessionEventSchema, permissionModeSchema, extractSessionEvents, } from './schemas/sessionEvent';
|
|
126
|
+
export { quotaWindowSchema, quotaStateSchema, quotaFailureKindSchema, quotaProviderIdSchema, quotaSourceSchema, peakHoursStateSchema, quotaFailureDescriptorSchema, runtimeQuotaProviderSchema, providerQuotaStateSchema, claudeProviderQuotaStateSchema, codexProviderQuotaStateSchema, providerQuotaMapSchema, } from './schemas/quota';
|
|
127
|
+
export { quotaHistoryRuntimeProviderSchema, quotaHistorySampleSchema, quotaHistoryDailyBucketSchema, } from './schemas/quotaHistory';
|
|
128
|
+
export { activeProviderAccountStatusSchema, activeAccountStatusSchema, } from './schemas/accountStatus';
|
|
126
129
|
export { fetchProviderStatus, fetchOpenAIStatus } from './providerStatus';
|
|
127
130
|
export type { ProviderStatusState } from './providerStatus';
|
|
128
131
|
export { createPeakHoursNotApplicableState, fetchPeakHoursStatus, isClaudeCodeSessionProvider, scopePeakHoursToSessionProvider, } from './peakHours';
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.findActiveClaudeSession = exports.discoverSessionDirectory = exports.getClaudeSessionDirectory = exports.encodeClaudeWorkspacePath = exports.detectSessionActivity = exports.extractTaskInfo = exports.scanSubagentDir = exports.normalizeCodexToolInput = exports.normalizeCodexToolName = exports.extractPatchFilePaths = exports.CodexRolloutParser = exports.parseDbPartData = exports.parseDbMessageData = exports.convertOpenCodeMessage = exports.detectPlanModeFromText = exports.normalizeToolInput = exports.normalizeToolName = exports.TRUNCATION_PATTERNS = exports.JsonlParser = exports.CodexProvider = exports.OpenCodeProvider = exports.ClaudeCodeProvider = exports.getAllDetectedProviders = exports.detectProvider = exports.readClaudeCodePlanFiles = exports.getPlanAnalytics = exports.writePlans = exports.getLatestPlan = exports.readPlans = exports.readLatestHandoff = exports.readHistory = exports.readNotes = exports.readDecisions = exports.readTasks = exports.getProjectSlugRaw = exports.getProjectSlug = exports.encodeWorkspacePath = exports.getGlobalDataPath = exports.getProjectDataPath = exports.getConfigDir = exports.MAX_PLANS_PER_PROJECT = exports.PLAN_SCHEMA_VERSION = exports.createEmptyTokenTotals = exports.HISTORICAL_DATA_SCHEMA_VERSION = exports.STALENESS_THRESHOLDS = exports.IMPORTANCE_DECAY_FACTORS = exports.KNOWLEDGE_NOTE_SCHEMA_VERSION = exports.DECISION_LOG_SCHEMA_VERSION = exports.normalizeTaskStatus = exports.TASK_PERSISTENCE_SCHEMA_VERSION = void 0;
|
|
7
7
|
exports.EventAggregator = exports.getRandomPhrase = exports.PHRASE_CATEGORIES = exports.ALL_PHRASES = exports.HIGHLIGHT_CSS = exports.clearHighlightCache = exports.highlightEvent = exports.formatSessionJson = exports.formatSessionMarkdown = exports.formatSessionText = exports.classifyNoise = exports.shouldMergeWithPrevious = exports.classifyFollowEvent = exports.classifyMessage = exports.getSoftNoiseReason = exports.isHardNoiseFollowEvent = exports.isHardNoise = exports.formatToolSummary = exports.formatTokenCount = exports.formatDurationMs = exports.createJsonlTail = exports.toFollowEvents = exports.createWatcher = exports.parseChangelog = exports.extractProposedPlanShared = exports.parsePlanMarkdownShared = exports.PlanExtractor = exports.readSessionContextSnapshot = exports.createSessionContextProjector = exports.calculateSessionContextPressure = exports.buildSessionContextSnapshot = exports.composeContext = exports.FilterEngine = exports.searchSessions = exports.CodexDatabase = exports.OpenCodeDatabase = exports.discoverDebugLogs = exports.collapseDuplicates = exports.filterByLevel = exports.parseDebugLog = exports.scanSubagentTraces = exports.findAllSessionsWithWorktrees = exports.discoverWorktreeSiblings = exports.resolveWorktreeMainRepo = exports.getAllClaudeProjectFolders = exports.decodeEncodedPath = exports.getMostRecentlyActiveSessionDir = exports.findSubdirectorySessionDirs = exports.findSessionsInDirectory = exports.findAllClaudeSessions = void 0;
|
|
8
8
|
exports.fetchQuota = exports.removeCodexAccount = exports.switchToCodexAccount = exports.finalizeCodexAccount = exports.prepareCodexAccount = exports.getCodexExecutionEnv = exports.resolveSidekickCodexHome = exports.getActiveCodexAccount = exports.listCodexAccounts = exports.getSystemCodexHome = exports.getCodexMonitoringHomes = exports.getCodexProfileHome = exports.getCodexProfilesDir = exports.getActiveAccountStatus = exports.removeSavedAccountProfile = exports.replaceSavedAccountProfiles = exports.setActiveSavedAccount = exports.upsertSavedAccountProfile = exports.getActiveSavedAccount = exports.listSavedAccountProfiles = exports.writeSavedAccountRegistry = exports.readSavedAccountRegistry = exports.getAccountsDir = exports.isMultiAccountEnabled = exports.getActiveAccount = exports.listAccounts = exports.removeAccount = exports.switchToAccount = exports.addCurrentAccount = exports.readActiveClaudeAccount = exports.writeAccountRegistry = exports.readAccountRegistry = exports.ensureDefaultAccounts = exports.readClaudeMaxAccessTokenSync = exports.readClaudeMaxCredentials = exports.writeActiveCredentials = exports.readActiveCredentials = exports.openInBrowser = exports.parseTranscriptFromEvents = exports.parseTranscript = exports.generateHtmlReport = exports.PatternExtractor = exports.HeatmapTracker = exports.FrequencyTracker = exports.getSnapshotPath = exports.isSnapshotValid = exports.deleteSnapshot = exports.loadSnapshot = exports.saveSnapshot = exports.parseTodoDependencies = void 0;
|
|
9
|
-
exports.
|
|
9
|
+
exports.providerQuotaStateSchema = exports.runtimeQuotaProviderSchema = exports.quotaFailureDescriptorSchema = exports.peakHoursStateSchema = exports.quotaSourceSchema = exports.quotaProviderIdSchema = exports.quotaFailureKindSchema = exports.quotaStateSchema = exports.quotaWindowSchema = exports.extractSessionEvents = exports.permissionModeSchema = exports.sessionEventSchema = exports.sessionMessageSchema = exports.messageUsageSchema = exports.extractToolCalls = exports.extractToolCall = exports.extractTokenUsage = exports.LITELLM_CATALOG_URL = exports.normalizeLiteLlmCatalog = exports.hydratePricingCatalog = exports.formatCost = exports.sortModelIds = exports.compareModelIds = exports.getModelDisplayInfo = exports.shortModelName = exports.mergeCostSources = exports.calculateCostWithProvenance = exports.calculateCostWithPricing = exports.calculateCost = exports.getModelInfo = exports.getModelPricing = exports.parseModelId = exports.DEFAULT_CONTEXT_WINDOW = exports.getModelContextWindowSize = exports.MultiProviderQuotaService = exports.CodexQuotaWatcher = exports.resolveCodexQuotaFromLocalSources = exports.resolveCodexQuota = exports.readLatestCodexQuotaFromRollouts = exports.quotaFromCodexRateLimits = exports.fetchCodexQuotaFromApi = exports.getWorkspaceIdFromPath = exports.pruneQuotaHistory = exports.readQuotaHistoryDailyBuckets = exports.readQuotaHistoryRange = exports.appendQuotaHistorySample = exports.writeQuotaSnapshot = exports.readQuotaSnapshot = exports.QuotaPoller = exports.describeQuotaFailure = void 0;
|
|
10
|
+
exports.scopePeakHoursToSessionProvider = exports.isClaudeCodeSessionProvider = exports.fetchPeakHoursStatus = exports.createPeakHoursNotApplicableState = exports.fetchOpenAIStatus = exports.fetchProviderStatus = exports.activeAccountStatusSchema = exports.activeProviderAccountStatusSchema = exports.quotaHistoryDailyBucketSchema = exports.quotaHistorySampleSchema = exports.quotaHistoryRuntimeProviderSchema = exports.providerQuotaMapSchema = exports.codexProviderQuotaStateSchema = exports.claudeProviderQuotaStateSchema = void 0;
|
|
10
11
|
var taskPersistence_1 = require("./types/taskPersistence");
|
|
11
12
|
Object.defineProperty(exports, "TASK_PERSISTENCE_SCHEMA_VERSION", { enumerable: true, get: function () { return taskPersistence_1.TASK_PERSISTENCE_SCHEMA_VERSION; } });
|
|
12
13
|
Object.defineProperty(exports, "normalizeTaskStatus", { enumerable: true, get: function () { return taskPersistence_1.normalizeTaskStatus; } });
|
|
@@ -295,6 +296,30 @@ Object.defineProperty(exports, "messageUsageSchema", { enumerable: true, get: fu
|
|
|
295
296
|
Object.defineProperty(exports, "sessionMessageSchema", { enumerable: true, get: function () { return sessionEvent_1.sessionMessageSchema; } });
|
|
296
297
|
Object.defineProperty(exports, "sessionEventSchema", { enumerable: true, get: function () { return sessionEvent_1.sessionEventSchema; } });
|
|
297
298
|
Object.defineProperty(exports, "permissionModeSchema", { enumerable: true, get: function () { return sessionEvent_1.permissionModeSchema; } });
|
|
299
|
+
Object.defineProperty(exports, "extractSessionEvents", { enumerable: true, get: function () { return sessionEvent_1.extractSessionEvents; } });
|
|
300
|
+
// Schemas — Zod runtime validation for quota / provider quota / peak hours
|
|
301
|
+
var quota_2 = require("./schemas/quota");
|
|
302
|
+
Object.defineProperty(exports, "quotaWindowSchema", { enumerable: true, get: function () { return quota_2.quotaWindowSchema; } });
|
|
303
|
+
Object.defineProperty(exports, "quotaStateSchema", { enumerable: true, get: function () { return quota_2.quotaStateSchema; } });
|
|
304
|
+
Object.defineProperty(exports, "quotaFailureKindSchema", { enumerable: true, get: function () { return quota_2.quotaFailureKindSchema; } });
|
|
305
|
+
Object.defineProperty(exports, "quotaProviderIdSchema", { enumerable: true, get: function () { return quota_2.quotaProviderIdSchema; } });
|
|
306
|
+
Object.defineProperty(exports, "quotaSourceSchema", { enumerable: true, get: function () { return quota_2.quotaSourceSchema; } });
|
|
307
|
+
Object.defineProperty(exports, "peakHoursStateSchema", { enumerable: true, get: function () { return quota_2.peakHoursStateSchema; } });
|
|
308
|
+
Object.defineProperty(exports, "quotaFailureDescriptorSchema", { enumerable: true, get: function () { return quota_2.quotaFailureDescriptorSchema; } });
|
|
309
|
+
Object.defineProperty(exports, "runtimeQuotaProviderSchema", { enumerable: true, get: function () { return quota_2.runtimeQuotaProviderSchema; } });
|
|
310
|
+
Object.defineProperty(exports, "providerQuotaStateSchema", { enumerable: true, get: function () { return quota_2.providerQuotaStateSchema; } });
|
|
311
|
+
Object.defineProperty(exports, "claudeProviderQuotaStateSchema", { enumerable: true, get: function () { return quota_2.claudeProviderQuotaStateSchema; } });
|
|
312
|
+
Object.defineProperty(exports, "codexProviderQuotaStateSchema", { enumerable: true, get: function () { return quota_2.codexProviderQuotaStateSchema; } });
|
|
313
|
+
Object.defineProperty(exports, "providerQuotaMapSchema", { enumerable: true, get: function () { return quota_2.providerQuotaMapSchema; } });
|
|
314
|
+
// Schemas — Zod runtime validation for quota history
|
|
315
|
+
var quotaHistory_2 = require("./schemas/quotaHistory");
|
|
316
|
+
Object.defineProperty(exports, "quotaHistoryRuntimeProviderSchema", { enumerable: true, get: function () { return quotaHistory_2.quotaHistoryRuntimeProviderSchema; } });
|
|
317
|
+
Object.defineProperty(exports, "quotaHistorySampleSchema", { enumerable: true, get: function () { return quotaHistory_2.quotaHistorySampleSchema; } });
|
|
318
|
+
Object.defineProperty(exports, "quotaHistoryDailyBucketSchema", { enumerable: true, get: function () { return quotaHistory_2.quotaHistoryDailyBucketSchema; } });
|
|
319
|
+
// Schemas — Zod runtime validation for account status
|
|
320
|
+
var accountStatus_2 = require("./schemas/accountStatus");
|
|
321
|
+
Object.defineProperty(exports, "activeProviderAccountStatusSchema", { enumerable: true, get: function () { return accountStatus_2.activeProviderAccountStatusSchema; } });
|
|
322
|
+
Object.defineProperty(exports, "activeAccountStatusSchema", { enumerable: true, get: function () { return accountStatus_2.activeAccountStatusSchema; } });
|
|
298
323
|
// Provider Status
|
|
299
324
|
var providerStatus_1 = require("./providerStatus");
|
|
300
325
|
Object.defineProperty(exports, "fetchProviderStatus", { enumerable: true, get: function () { return providerStatus_1.fetchProviderStatus; } });
|
package/dist/modelContext.d.ts
CHANGED
|
@@ -7,6 +7,9 @@ export declare const DEFAULT_CONTEXT_WINDOW = 200000;
|
|
|
7
7
|
/**
|
|
8
8
|
* Returns the context window size for a model ID.
|
|
9
9
|
*
|
|
10
|
+
* Input is trimmed and lowercased before lookup, so padded or mixed-case
|
|
11
|
+
* IDs (e.g. "Claude-Opus-4-8 ") resolve without caller-side normalization.
|
|
12
|
+
*
|
|
10
13
|
* Lookup order:
|
|
11
14
|
* 1. Explicit "[1m]" suffix (Claude Code's 1M-variant marker) → 1_000_000
|
|
12
15
|
* 2. Exact match against MODEL_CONTEXT_SIZES
|