sidekick-shared 0.21.4 → 0.21.5

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.
@@ -44,6 +44,7 @@ const codexProfiles_1 = require("./codexProfiles");
44
44
  const quotaSnapshots_1 = require("./quotaSnapshots");
45
45
  const quota_1 = require("./quota");
46
46
  const codex_1 = require("./providers/codex");
47
+ const codex_2 = require("./types/codex");
47
48
  const DEFAULT_TAIL_BYTES = 2 * 1024 * 1024;
48
49
  const DEFAULT_MAX_SESSION_FILES = 50;
49
50
  const CHATGPT_USAGE_URL = 'https://chatgpt.com/backend-api/wham/usage';
@@ -54,11 +55,19 @@ function timestampMs(value, fallbackMs = 0) {
54
55
  return Number.isFinite(ms) ? ms : fallbackMs;
55
56
  }
56
57
  // Codex can report slightly different percentages for the same reset window
57
- // across recent sessions. Prefer newer reset windows, then the highest observed
58
- // same-window utilization so local fallbacks do not under-report quota usage.
58
+ // across recent sessions. Prefer the aggregate plan family ("codex") over
59
+ // model/feature-specific families (which can read 0% while the plan is busy),
60
+ // then newer reset windows, then the highest observed same-window utilization so
61
+ // local fallbacks do not under-report quota usage.
59
62
  function isPreferredQuotaHit(candidate, current) {
60
63
  if (!current)
61
64
  return true;
65
+ // Family rank first: an aggregate hit always outranks a model-specific one, so a
66
+ // freshly-used per-model family (e.g. codex_bengalfox at 0%) can never mask the plan quota.
67
+ const candidateAggregate = (0, codex_2.isAggregateCodexLimit)(candidate.quota.limitId);
68
+ const currentAggregate = (0, codex_2.isAggregateCodexLimit)(current.quota.limitId);
69
+ if (candidateAggregate !== currentAggregate)
70
+ return candidateAggregate;
62
71
  const candidatePrimaryReset = timestampMs(candidate.quota.fiveHour.resetsAt);
63
72
  const currentPrimaryReset = timestampMs(current.quota.fiveHour.resetsAt);
64
73
  if (candidatePrimaryReset !== currentPrimaryReset)
@@ -464,7 +473,11 @@ function readLatestQuotaFromRollout(sessionPath, maxTailBytes, source) {
464
473
  const firstNewline = text.indexOf('\n');
465
474
  text = firstNewline >= 0 ? text.slice(firstNewline + 1) : '';
466
475
  }
476
+ // Scan from the end for the latest aggregate ("codex") rate-limit sample, which
477
+ // is what the plan quota represents. Keep the latest sample of any family as a
478
+ // fallback so a model-only session still surfaces something.
467
479
  const lines = text.split('\n');
480
+ let fallback = null;
468
481
  for (let i = lines.length - 1; i >= 0; i--) {
469
482
  const line = lines[i].trim();
470
483
  if (!line || !line.includes('rate_limits'))
@@ -474,13 +487,20 @@ function readLatestQuotaFromRollout(sessionPath, maxTailBytes, source) {
474
487
  if (parsed.type !== 'event_msg' || parsed.payload?.type !== 'token_count')
475
488
  continue;
476
489
  const quota = quotaFromCodexRateLimits(parsed.payload.rate_limits, source, parsed.timestamp ?? new Date(stat.mtime).toISOString());
477
- if (quota)
478
- return { quota, filePath: sessionPath, mtimeMs: stat.mtime.getTime() };
490
+ if (!quota)
491
+ continue;
492
+ const hit = { quota, filePath: sessionPath, mtimeMs: stat.mtime.getTime() };
493
+ if ((0, codex_2.isAggregateCodexLimit)(quota.limitId))
494
+ return hit;
495
+ if (!fallback)
496
+ fallback = hit;
479
497
  }
480
498
  catch {
481
499
  // Ignore malformed or partial lines.
482
500
  }
483
501
  }
502
+ if (fallback)
503
+ return fallback;
484
504
  }
485
505
  catch {
486
506
  return null;
package/dist/index.d.ts CHANGED
@@ -4,6 +4,7 @@
4
4
  export type { SessionEvent, ClaudeSessionEvent, MessageUsage, SessionMessage, TokenUsage, ToolCall, ToolAnalytics, TimelineEvent, PendingToolCall, TaskStatus as SessionTaskStatus, TrackedTask, TaskState, SubagentStats, PendingUserRequest, ResponseLatency, LatencyStats, PlanStep, PlanState, SessionStats, CompactionEvent, TruncationEvent, ContextAttribution, TurnAttribution, ContextSizePoint, PermissionMode, PermissionModeChange, } from './types/sessionEvent';
5
5
  export type { OpenCodeSession, OpenCodeMessage, OpenCodePart, OpenCodeTextPart, OpenCodeReasoningPart, OpenCodeToolInvocationPart, OpenCodeCompactionPart, OpenCodeDbToolPart, OpenCodeStepStartPart, OpenCodeStepFinishPart, OpenCodePatchPart, OpenCodeSubtaskPart, OpenCodeAgentPart, OpenCodeFilePart, OpenCodeRetryPart, OpenCodeSnapshotPart, OpenCodeProject, DbProject as OpenCodeDbProject, DbSession as OpenCodeDbSession, DbMessage as OpenCodeDbMessage, DbPart as OpenCodeDbPart, } from './types/opencode';
6
6
  export type { CodexRolloutLine, CodexSessionMeta, CodexResponseItem, CodexMessageItem, CodexContentPart, CodexReasoningItem, CodexFunctionCallItem, CodexFunctionCallOutputItem, CodexLocalShellCallItem, CodexWebSearchCallItem, CodexCustomToolCallItem, CodexCustomToolCallOutputItem, CodexCompacted, CodexTurnContext, CodexEventMsg, CodexEvent, CodexTurnStartedEvent, CodexTurnCompleteEvent, CodexTaskStartedEvent, CodexTaskCompleteEvent, CodexTurnAbortedEvent, CodexTokenCountEvent, CodexTokenUsage, CodexRateLimits, CodexAgentMessageEvent, CodexAgentReasoningEvent, CodexUserMessageEvent, CodexExecCommandBeginEvent, CodexExecCommandEndEvent, CodexMcpToolCallBeginEvent, CodexMcpToolCallEndEvent, CodexErrorEvent, CodexContextCompactedEvent, CodexPatchAppliedEvent, CodexBackgroundEvent, CodexGenericEvent, CodexDbThread, CodexReasoningSummary, } from './types/codex';
7
+ export { isAggregateCodexLimit } from './types/codex';
7
8
  export type { PersistedTask, TaskPersistenceStore, TaskStatus } from './types/taskPersistence';
8
9
  export { TASK_PERSISTENCE_SCHEMA_VERSION, normalizeTaskStatus } from './types/taskPersistence';
9
10
  export type { DecisionEntry, DecisionLogStore, DecisionSource } from './types/decisionLog';
package/dist/index.js CHANGED
@@ -3,12 +3,14 @@
3
3
  * Public API for sidekick-shared.
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- 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.getOpenCodeDataDir = 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
- 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.segmentAssistantTurn = exports.reasoningSummary = exports.isAssistantTurnSubagentTool = exports.extractTurnSubagents = exports.assistantTurnEventsFromSessionEvents = 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 = exports.findActiveClaudeSession = void 0;
8
- exports.upsertSavedAccountProfile = exports.getActiveSavedAccount = exports.listSavedAccountProfiles = exports.writeSavedAccountRegistry = exports.readSavedAccountRegistry = exports.getAccountsDir = exports.resolveClaudeLoginCommand = exports.listAllAccounts = exports.switchAccount = exports.spawnAccountLogin = exports.finalizeAccountLogin = exports.getAccountLoginStatus = exports.beginAccountLogin = exports.isMultiAccountEnabled = exports.resolveActiveClaudeAccount = exports.getActiveAccount = exports.listAccounts = exports.removeAccount = exports.reconcileClaudeAuthState = exports.applyActiveClaudeToLiveHome = exports.resolveActiveClaudeHome = 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 = exports.EventAggregator = exports.getRandomPhrase = exports.PHRASE_CATEGORIES = exports.ALL_PHRASES = exports.HIGHLIGHT_CSS = exports.clearHighlightCache = void 0;
9
- 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 = exports.withQuotaProjections = exports.projectQuotaWindow = exports.fetchQuota = exports.SEVEN_DAY_WINDOW_MS = exports.FIVE_HOUR_WINDOW_MS = exports.AutoSwitchController = exports.decideAutoSwitch = exports.DEFAULT_AUTO_SWITCH_CONFIG = exports.removeLauncher = exports.writeLauncher = exports.isShellHookInstalled = exports.uninstallShellHook = exports.installShellHook = exports.setTerminalActiveProfile = exports.removeCodexAccount = exports.switchToCodexAccount = exports.finalizeCodexAccount = exports.prepareCodexAccount = exports.getCodexExecutionEnv = exports.resolveSidekickCodexHome = exports.resolveActiveCodexAccount = exports.getActiveCodexAccount = exports.listCodexAccounts = exports.getSystemCodexHome = exports.getCodexMonitoringHomes = exports.getCodexProfileHome = exports.getCodexProfilesDir = exports.readClaudeProfileIdentity = exports.isClaudeProfileAuthenticated = exports.claudeKeychainService = exports.claudeKeychainSuffix = exports.getClaudeProfileHome = exports.getClaudeProfilesDir = exports.getActiveAccountStatus = exports.removeSavedAccountProfile = exports.replaceSavedAccountProfiles = exports.setActiveSavedAccount = void 0;
10
- exports.sessionMessageSchema = exports.messageUsageSchema = exports.gatherAssetsForCwd = exports.codexSessions = exports.readCodexAssets = exports.claudeSessions = exports.readClaudeAssets = exports.extractCommands = exports.extractFilePaths = exports.extractUrls = 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.resolveZaiQuota = exports.readZaiCredentials = exports.quotaStateFromZaiQuotaLimitPayload = exports.fetchZaiQuotaFromApi = exports.ZaiQuotaWatcher = exports.ZAI_TIER_BUDGETS = exports.ZAI_PROVIDER_IDS = exports.ZAI_PROMPT_INVOCATIONS = exports.turnTokenWeight = exports.rowsToZaiTurnsAndErrors = exports.resolveZaiTier = exports.parseZaiQuotaError = exports.makeUnavailableZaiQuotaState = exports.isZaiProviderId = exports.inferZaiQuotaState = exports.extractNextFlushTime = exports.accumulateZaiUsage = exports.CodexQuotaWatcher = exports.resolveCodexQuotaFromLocalSources = void 0;
11
- exports.scopePeakHoursToSessionProvider = exports.isClaudeCodeSessionProvider = exports.fetchPeakHoursStatus = exports.createPeakHoursNotApplicableState = exports.fetchOpenAIStatus = exports.fetchProviderStatus = exports.assistantTurnToolRefSchema = exports.assistantTurnToolGroupStepSchema = exports.assistantTurnTimelineItemSchema = exports.assistantTurnSubagentStatusSchema = exports.assistantTurnSubagentSchema = exports.assistantTurnReasoningTimelineItemSchema = exports.assistantTurnProjectionSchema = exports.assistantTurnProcessStepSchema = exports.assistantTurnProcessSchema = exports.assistantTurnNarrationStepSchema = exports.assistantTurnEventTypeSchema = exports.assistantTurnEventSchema = exports.listAllAccountsResultSchema = exports.savedAccountProfileSchema = exports.accountEntrySchema = exports.accountLoginStatusSchema = exports.beginAccountLoginResultSchema = exports.accountManagerResultSchema = exports.accountProviderIdSchema = exports.activeAccountStatusSchema = exports.activeProviderAccountStatusSchema = exports.quotaHistoryDailyBucketSchema = exports.quotaHistorySampleSchema = exports.quotaHistoryRuntimeProviderSchema = exports.providerQuotaMapSchema = exports.zaiProviderQuotaStateSchema = exports.codexProviderQuotaStateSchema = exports.claudeProviderQuotaStateSchema = exports.providerQuotaStateSchema = exports.runtimeQuotaProviderSchema = exports.quotaFailureDescriptorSchema = exports.peakHoursStateSchema = exports.quotaSourceSchema = exports.quotaProviderIdSchema = exports.quotaFailureKindSchema = exports.quotaStateSchema = exports.quotaWindowSchema = exports.extractSessionEvents = exports.permissionModeSchema = exports.sessionEventSchema = void 0;
6
+ 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.getOpenCodeDataDir = 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 = exports.isAggregateCodexLimit = void 0;
7
+ 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.segmentAssistantTurn = exports.reasoningSummary = exports.isAssistantTurnSubagentTool = exports.extractTurnSubagents = exports.assistantTurnEventsFromSessionEvents = 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 = exports.findActiveClaudeSession = exports.discoverSessionDirectory = void 0;
8
+ exports.getActiveSavedAccount = exports.listSavedAccountProfiles = exports.writeSavedAccountRegistry = exports.readSavedAccountRegistry = exports.getAccountsDir = exports.resolveClaudeLoginCommand = exports.listAllAccounts = exports.switchAccount = exports.spawnAccountLogin = exports.finalizeAccountLogin = exports.getAccountLoginStatus = exports.beginAccountLogin = exports.isMultiAccountEnabled = exports.resolveActiveClaudeAccount = exports.getActiveAccount = exports.listAccounts = exports.removeAccount = exports.reconcileClaudeAuthState = exports.applyActiveClaudeToLiveHome = exports.resolveActiveClaudeHome = 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 = exports.EventAggregator = exports.getRandomPhrase = exports.PHRASE_CATEGORIES = exports.ALL_PHRASES = exports.HIGHLIGHT_CSS = exports.clearHighlightCache = exports.highlightEvent = void 0;
9
+ exports.readLatestCodexQuotaFromRollouts = exports.quotaFromCodexRateLimits = exports.fetchCodexQuotaFromApi = exports.getWorkspaceIdFromPath = exports.pruneQuotaHistory = exports.readQuotaHistoryDailyBuckets = exports.readQuotaHistoryRange = exports.appendQuotaHistorySample = exports.writeQuotaSnapshot = exports.readQuotaSnapshot = exports.QuotaPoller = exports.describeQuotaFailure = exports.withQuotaProjections = exports.projectQuotaWindow = exports.fetchQuota = exports.SEVEN_DAY_WINDOW_MS = exports.FIVE_HOUR_WINDOW_MS = exports.AutoSwitchController = exports.decideAutoSwitch = exports.DEFAULT_AUTO_SWITCH_CONFIG = exports.removeLauncher = exports.writeLauncher = exports.isShellHookInstalled = exports.uninstallShellHook = exports.installShellHook = exports.setTerminalActiveProfile = exports.removeCodexAccount = exports.switchToCodexAccount = exports.finalizeCodexAccount = exports.prepareCodexAccount = exports.getCodexExecutionEnv = exports.resolveSidekickCodexHome = exports.resolveActiveCodexAccount = exports.getActiveCodexAccount = exports.listCodexAccounts = exports.getSystemCodexHome = exports.getCodexMonitoringHomes = exports.getCodexProfileHome = exports.getCodexProfilesDir = exports.readClaudeProfileIdentity = exports.isClaudeProfileAuthenticated = exports.claudeKeychainService = exports.claudeKeychainSuffix = exports.getClaudeProfileHome = exports.getClaudeProfilesDir = exports.getActiveAccountStatus = exports.removeSavedAccountProfile = exports.replaceSavedAccountProfiles = exports.setActiveSavedAccount = exports.upsertSavedAccountProfile = void 0;
10
+ exports.messageUsageSchema = exports.gatherAssetsForCwd = exports.codexSessions = exports.readCodexAssets = exports.claudeSessions = exports.readClaudeAssets = exports.extractCommands = exports.extractFilePaths = exports.extractUrls = 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.resolveZaiQuota = exports.readZaiCredentials = exports.quotaStateFromZaiQuotaLimitPayload = exports.fetchZaiQuotaFromApi = exports.ZaiQuotaWatcher = exports.ZAI_TIER_BUDGETS = exports.ZAI_PROVIDER_IDS = exports.ZAI_PROMPT_INVOCATIONS = exports.turnTokenWeight = exports.rowsToZaiTurnsAndErrors = exports.resolveZaiTier = exports.parseZaiQuotaError = exports.makeUnavailableZaiQuotaState = exports.isZaiProviderId = exports.inferZaiQuotaState = exports.extractNextFlushTime = exports.accumulateZaiUsage = exports.CodexQuotaWatcher = exports.resolveCodexQuotaFromLocalSources = exports.resolveCodexQuota = void 0;
11
+ exports.scopePeakHoursToSessionProvider = exports.isClaudeCodeSessionProvider = exports.fetchPeakHoursStatus = exports.createPeakHoursNotApplicableState = exports.fetchOpenAIStatus = exports.fetchProviderStatus = exports.assistantTurnToolRefSchema = exports.assistantTurnToolGroupStepSchema = exports.assistantTurnTimelineItemSchema = exports.assistantTurnSubagentStatusSchema = exports.assistantTurnSubagentSchema = exports.assistantTurnReasoningTimelineItemSchema = exports.assistantTurnProjectionSchema = exports.assistantTurnProcessStepSchema = exports.assistantTurnProcessSchema = exports.assistantTurnNarrationStepSchema = exports.assistantTurnEventTypeSchema = exports.assistantTurnEventSchema = exports.listAllAccountsResultSchema = exports.savedAccountProfileSchema = exports.accountEntrySchema = exports.accountLoginStatusSchema = exports.beginAccountLoginResultSchema = exports.accountManagerResultSchema = exports.accountProviderIdSchema = exports.activeAccountStatusSchema = exports.activeProviderAccountStatusSchema = exports.quotaHistoryDailyBucketSchema = exports.quotaHistorySampleSchema = exports.quotaHistoryRuntimeProviderSchema = exports.providerQuotaMapSchema = exports.zaiProviderQuotaStateSchema = exports.codexProviderQuotaStateSchema = exports.claudeProviderQuotaStateSchema = 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 = void 0;
12
+ var codex_1 = require("./types/codex");
13
+ Object.defineProperty(exports, "isAggregateCodexLimit", { enumerable: true, get: function () { return codex_1.isAggregateCodexLimit; } });
12
14
  var taskPersistence_1 = require("./types/taskPersistence");
13
15
  Object.defineProperty(exports, "TASK_PERSISTENCE_SCHEMA_VERSION", { enumerable: true, get: function () { return taskPersistence_1.TASK_PERSISTENCE_SCHEMA_VERSION; } });
14
16
  Object.defineProperty(exports, "normalizeTaskStatus", { enumerable: true, get: function () { return taskPersistence_1.normalizeTaskStatus; } });
@@ -57,8 +59,8 @@ Object.defineProperty(exports, "ClaudeCodeProvider", { enumerable: true, get: fu
57
59
  var openCode_1 = require("./providers/openCode");
58
60
  Object.defineProperty(exports, "OpenCodeProvider", { enumerable: true, get: function () { return openCode_1.OpenCodeProvider; } });
59
61
  Object.defineProperty(exports, "getOpenCodeDataDir", { enumerable: true, get: function () { return openCode_1.getOpenCodeDataDir; } });
60
- var codex_1 = require("./providers/codex");
61
- Object.defineProperty(exports, "CodexProvider", { enumerable: true, get: function () { return codex_1.CodexProvider; } });
62
+ var codex_2 = require("./providers/codex");
63
+ Object.defineProperty(exports, "CodexProvider", { enumerable: true, get: function () { return codex_2.CodexProvider; } });
62
64
  // Parsers — JSONL
63
65
  var jsonl_1 = require("./parsers/jsonl");
64
66
  Object.defineProperty(exports, "JsonlParser", { enumerable: true, get: function () { return jsonl_1.JsonlParser; } });
@@ -43,6 +43,7 @@ export declare class CodexRolloutParser {
43
43
  private lastTokenUsage;
44
44
  private modelContextWindow;
45
45
  private lastRateLimits;
46
+ private hasAggregateRateLimits;
46
47
  private inPlanMode;
47
48
  private emittedToolUseIds;
48
49
  private patchExpandedToolUseIds;
@@ -16,6 +16,7 @@ exports.CodexRolloutParser = void 0;
16
16
  exports.normalizeCodexToolName = normalizeCodexToolName;
17
17
  exports.normalizeCodexToolInput = normalizeCodexToolInput;
18
18
  exports.extractPatchFilePaths = extractPatchFilePaths;
19
+ const codex_1 = require("../types/codex");
19
20
  const openCodeParser_1 = require("./openCodeParser");
20
21
  function normalizeRateLimits(rateLimits) {
21
22
  if (!rateLimits?.primary && !rateLimits?.secondary)
@@ -126,6 +127,7 @@ class CodexRolloutParser {
126
127
  lastTokenUsage = null;
127
128
  modelContextWindow = null;
128
129
  lastRateLimits = null;
130
+ hasAggregateRateLimits = false;
129
131
  inPlanMode = false;
130
132
  emittedToolUseIds = new Set();
131
133
  patchExpandedToolUseIds = new Map();
@@ -177,6 +179,7 @@ class CodexRolloutParser {
177
179
  this.lastTokenUsage = null;
178
180
  this.modelContextWindow = null;
179
181
  this.lastRateLimits = null;
182
+ this.hasAggregateRateLimits = false;
180
183
  this.inPlanMode = false;
181
184
  this.emittedToolUseIds.clear();
182
185
  this.patchExpandedToolUseIds.clear();
@@ -493,9 +496,19 @@ class CodexRolloutParser {
493
496
  if (e.info?.model_context_window) {
494
497
  this.modelContextWindow = e.info.model_context_window;
495
498
  }
496
- // Store rate_limits if provided (subscription quota data)
499
+ // Store rate_limits if provided (subscription quota data). Codex interleaves
500
+ // multiple families (aggregate "codex" plus per-model ones like codex_bengalfox);
501
+ // keep the latest aggregate sample so a trailing model-specific event at 0% does
502
+ // not mask the plan quota. Fall back to a non-aggregate sample only until an
503
+ // aggregate one has been seen.
497
504
  if (e.rate_limits) {
498
- this.lastRateLimits = e.rate_limits;
505
+ if ((0, codex_1.isAggregateCodexLimit)(e.rate_limits.limit_id)) {
506
+ this.lastRateLimits = e.rate_limits;
507
+ this.hasAggregateRateLimits = true;
508
+ }
509
+ else if (!this.hasAggregateRateLimits) {
510
+ this.lastRateLimits = e.rate_limits;
511
+ }
499
512
  }
500
513
  // Usage data is nested under info.last_token_usage (info can be null)
501
514
  const usage = e.info?.last_token_usage || e.info?.total_token_usage;
@@ -39,6 +39,7 @@ const crypto = __importStar(require("crypto"));
39
39
  const fs = __importStar(require("fs"));
40
40
  const path = __importStar(require("path"));
41
41
  const paths_1 = require("./paths");
42
+ const codex_1 = require("./types/codex");
42
43
  function getQuotaSnapshotPath() {
43
44
  return path.join((0, paths_1.getConfigDir)(), 'quota-snapshots.json');
44
45
  }
@@ -94,6 +95,15 @@ function windowResetMs(value) {
94
95
  // Preserve the best-known same-window snapshot while still allowing lower
95
96
  // utilization after Codex advances to a newer reset window.
96
97
  function shouldKeepExistingSnapshot(existing, next) {
98
+ // Family rank first (Codex): the aggregate plan-quota family ("codex") must never be
99
+ // replaced or blocked by a model/feature-specific family (e.g. codex_bengalfox), whose
100
+ // later-resetting 0% window would otherwise win the reset-window comparison below. This
101
+ // is a no-op for providers whose limitId is consistent across samples (Claude: absent;
102
+ // z.ai: zai-*), where both sides share the same aggregate-ness.
103
+ const existingAggregate = (0, codex_1.isAggregateCodexLimit)(existing.limitId);
104
+ const nextAggregate = (0, codex_1.isAggregateCodexLimit)(next.limitId);
105
+ if (existingAggregate !== nextAggregate)
106
+ return existingAggregate;
97
107
  const existingPrimaryReset = windowResetMs(existing.fiveHour.resetsAt);
98
108
  const nextPrimaryReset = windowResetMs(next.fiveHour.resetsAt);
99
109
  if (existingPrimaryReset !== nextPrimaryReset)
@@ -8,9 +8,9 @@ import { z } from 'zod';
8
8
  export declare const assistantTurnEventTypeSchema: z.ZodEnum<{
9
9
  status: "status";
10
10
  error: "error";
11
+ text: "text";
11
12
  tool_use: "tool_use";
12
13
  tool_result: "tool_result";
13
- text: "text";
14
14
  progress: "progress";
15
15
  thinking: "thinking";
16
16
  delta: "delta";
@@ -19,9 +19,9 @@ export declare const assistantTurnEventSchema: z.ZodObject<{
19
19
  eventType: z.ZodEnum<{
20
20
  status: "status";
21
21
  error: "error";
22
+ text: "text";
22
23
  tool_use: "tool_use";
23
24
  tool_result: "tool_result";
24
- text: "text";
25
25
  progress: "progress";
26
26
  thinking: "thinking";
27
27
  delta: "delta";
@@ -41,10 +41,10 @@ export declare const sessionEventSchema: z.ZodObject<{
41
41
  type: z.ZodEnum<{
42
42
  user: "user";
43
43
  assistant: "assistant";
44
+ system: "system";
44
45
  tool_use: "tool_use";
45
46
  tool_result: "tool_result";
46
47
  summary: "summary";
47
- system: "system";
48
48
  }>;
49
49
  message: z.ZodObject<{
50
50
  role: z.ZodString;
@@ -192,6 +192,15 @@ export interface CodexRateLimits {
192
192
  plan_type?: string;
193
193
  rate_limit_reached_type?: string;
194
194
  }
195
+ /**
196
+ * Codex reports several rate-limit families per session, keyed by `limit_id`.
197
+ * The aggregate plan quota — what the usage API surfaces — is `limit_id: "codex"`
198
+ * (or absent on older payloads). Model/feature-specific families (e.g.
199
+ * `codex_bengalfox`, `premium`) report their own windows and can read 0% while the
200
+ * plan is heavily used, so they must never mask the aggregate in the standard
201
+ * quota view. Returns true only for the aggregate family.
202
+ */
203
+ export declare function isAggregateCodexLimit(limitId?: string | null): boolean;
195
204
  export interface CodexTokenUsage {
196
205
  input_tokens: number;
197
206
  cached_input_tokens?: number;
@@ -12,3 +12,15 @@
12
12
  * @module types/codex
13
13
  */
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.isAggregateCodexLimit = isAggregateCodexLimit;
16
+ /**
17
+ * Codex reports several rate-limit families per session, keyed by `limit_id`.
18
+ * The aggregate plan quota — what the usage API surfaces — is `limit_id: "codex"`
19
+ * (or absent on older payloads). Model/feature-specific families (e.g.
20
+ * `codex_bengalfox`, `premium`) report their own windows and can read 0% while the
21
+ * plan is heavily used, so they must never mask the aggregate in the standard
22
+ * quota view. Returns true only for the aggregate family.
23
+ */
24
+ function isAggregateCodexLimit(limitId) {
25
+ return !limitId || limitId === 'codex';
26
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sidekick-shared",
3
- "version": "0.21.4",
3
+ "version": "0.21.5",
4
4
  "description": "Shared data access layer for Sidekick — readers, types, providers, credentials, quota",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",