sidekick-shared 0.24.3 → 0.24.4

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/dist/index.js CHANGED
@@ -3,13 +3,13 @@
3
3
  * Public API for sidekick-shared.
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.addNote = exports.decisionFingerprint = exports.addDecision = exports.completeTask = exports.addTask = exports.updateJsonStoreAtomic = exports.atomicWriteJsonSync = exports.atomicWriteJson = exports.readClaudeCodePlanFiles = exports.getPlanAnalytics = exports.writePlans = exports.getLatestPlan = exports.readPlans = exports.readLatestHandoff = exports.readHistory = exports.readNotes = exports.readDecisions = exports.readTasks = exports.migrateLegacyProjectStores = exports.resolveProjectIdentity = exports.getProjectSlugRaw = exports.getProjectSlug = exports.encodeWorkspacePath = exports.getGlobalDataPath = exports.getProjectDataPath = exports.getConfigDir = exports.MAX_PLANS_PER_PROJECT = exports.PLAN_SCHEMA_VERSION = exports.createEmptyDataStore = exports.createEmptyTokenTotals = exports.HISTORICAL_SESSION_RETENTION_LIMIT = 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 = exports.fileFingerprint = exports.observedSessionSourceFromProvider = exports.ObservedSessionCollector = exports.readSessionTranscript = exports.listRecentSessions = exports.projectSessionTranscript = exports.estimateSerializedTokens = exports.estimateTextTokens = exports.calculateNormalizedUsageCost = exports.extractNormalizedUsage = exports.normalizeProviderUsage = void 0;
7
- 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 = 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.derivePendingUserRequestV1 = exports.createProviderSessionAdapterV1 = exports.renderHandoffUrlTemplate = void 0;
8
- exports.scoreSessionQuality = exports.calculateQualityTrend = exports.PatternExtractor = exports.HeatmapTracker = exports.FrequencyTracker = exports.readErrorHistory = exports.getTopFailingTools = exports.appendErrorHistory = exports.MAX_ERROR_HISTORY_SESSIONS = exports.ERROR_HISTORY_SCHEMA_VERSION = exports.getSnapshotPath = exports.isSnapshotValid = exports.deleteSnapshot = exports.loadSnapshot = exports.saveSnapshot = exports.SessionMonitor = exports.parseTodoDependencies = 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.segmentAssistantTurn = exports.reasoningSummary = exports.isAssistantTurnSubagentTool = exports.extractTurnSubagents = exports.assistantTurnEventsFromSessionEvents = exports.readSessionContextSnapshot = void 0;
9
- 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 = 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.formatCompactionLedger = exports.calculateCompactionLedger = exports.calculateCodeImpact = void 0;
10
- exports.selectStatuslineAccount = exports.formatStatusline = exports.estimateTimeToQuota = exports.BurnRateCalculator = exports.MultiProviderQuotaService = exports.resolveZaiQuota = exports.readZaiCredentials = exports.quotaStateFromZaiQuotaLimitPayload = exports.fetchZaiQuotaFromApi = exports.CodexQuotaWatcher = exports.resolveCodexQuotaFromLocalSources = exports.resolveCodexQuota = exports.readLatestCodexQuotaFromRollouts = exports.quotaFromCodexRateLimits = exports.fetchCodexQuotaFromApi = exports.fetchCodexResetCreditsFromApi = 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 = void 0;
11
- exports.runtimeQuotaProviderSchema = exports.quotaFailureDescriptorSchema = exports.peakHoursStateSchema = exports.codexResetCreditsSnapshotSchema = exports.codexResetCreditSchema = exports.quotaSourceSchema = exports.quotaProviderIdSchema = exports.quotaFailureKindSchema = exports.quotaStateSchema = exports.quotaWindowSchema = exports.extractSessionEvents = exports.permissionModeSchema = exports.sessionEventSchema = exports.sessionMessageSchema = exports.messageUsageSchema = exports.ToolCallTracker = exports.extractToolCalls = exports.extractToolCall = exports.extractErrorMessage = exports.categorizeError = exports.gatherAssetsForCwd = exports.codexSessions = exports.readCodexAssets = exports.claudeSessions = exports.readClaudeAssets = exports.extractCommands = exports.extractFilePaths = exports.extractUrls = exports.extractTokenUsage = exports.getObservedContextWindowPath = exports.recordObservedContextWindow = exports.loadObservedContextWindows = exports.LITELLM_CATALOG_URL = exports.normalizeLiteLlmContextWindows = 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 = void 0;
12
- exports.scopePeakHoursToSessionProvider = exports.isClaudeCodeSessionProvider = exports.fetchPeakHoursStatus = exports.createPeakHoursNotApplicableState = exports.runDoctor = exports.getSessionDiagnostics = exports.formatHealthReport = 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 = void 0;
6
+ exports.addTask = exports.updateJsonStoreAtomic = exports.atomicWriteJsonSync = exports.atomicWriteJson = exports.readClaudeCodePlanFiles = exports.getPlanAnalytics = exports.writePlans = exports.getLatestPlan = exports.readPlans = exports.readLatestHandoff = exports.readHistory = exports.readNotes = exports.readDecisions = exports.readTasks = exports.migrateLegacyProjectStores = exports.resolveProjectIdentity = exports.getProjectSlugRaw = exports.getProjectSlug = exports.encodeWorkspacePath = exports.getGlobalDataPath = exports.getProjectDataPath = exports.setConfigDir = exports.getDefaultConfigDir = exports.getConfigDirOverride = exports.getConfigDir = exports.CONFIG_DIR_ENV_VAR = exports.MAX_PLANS_PER_PROJECT = exports.PLAN_SCHEMA_VERSION = exports.createEmptyDataStore = exports.createEmptyTokenTotals = exports.HISTORICAL_SESSION_RETENTION_LIMIT = 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 = exports.fileFingerprint = exports.observedSessionSourceFromProvider = exports.ObservedSessionCollector = exports.readSessionTranscript = exports.listRecentSessions = exports.projectSessionTranscript = exports.estimateSerializedTokens = exports.estimateTextTokens = exports.calculateNormalizedUsageCost = exports.extractNormalizedUsage = exports.normalizeProviderUsage = void 0;
7
+ 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 = 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.derivePendingUserRequestV1 = exports.createProviderSessionAdapterV1 = exports.renderHandoffUrlTemplate = exports.addNote = exports.decisionFingerprint = exports.addDecision = exports.completeTask = void 0;
8
+ exports.FrequencyTracker = exports.readErrorHistory = exports.getTopFailingTools = exports.appendErrorHistory = exports.MAX_ERROR_HISTORY_SESSIONS = exports.ERROR_HISTORY_SCHEMA_VERSION = exports.getSnapshotPath = exports.isSnapshotValid = exports.deleteSnapshot = exports.loadSnapshot = exports.saveSnapshot = exports.SessionMonitor = exports.parseTodoDependencies = 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.segmentAssistantTurn = exports.reasoningSummary = exports.isAssistantTurnSubagentTool = exports.extractTurnSubagents = exports.assistantTurnEventsFromSessionEvents = exports.readSessionContextSnapshot = exports.createSessionContextProjector = exports.calculateSessionContextPressure = exports.buildSessionContextSnapshot = exports.composeContext = void 0;
9
+ exports.claudeKeychainService = exports.claudeKeychainSuffix = exports.getClaudeProfileHome = exports.getClaudeProfilesDir = exports.getActiveAccountStatus = exports.removeSavedAccountProfile = exports.replaceSavedAccountProfiles = exports.setActiveSavedAccount = 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.formatCompactionLedger = exports.calculateCompactionLedger = exports.calculateCodeImpact = exports.scoreSessionQuality = exports.calculateQualityTrend = exports.PatternExtractor = exports.HeatmapTracker = void 0;
10
+ exports.MultiProviderQuotaService = exports.resolveZaiQuota = exports.readZaiCredentials = exports.quotaStateFromZaiQuotaLimitPayload = exports.fetchZaiQuotaFromApi = exports.CodexQuotaWatcher = exports.resolveCodexQuotaFromLocalSources = exports.resolveCodexQuota = exports.readLatestCodexQuotaFromRollouts = exports.quotaFromCodexRateLimits = exports.fetchCodexQuotaFromApi = exports.fetchCodexResetCreditsFromApi = 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 = void 0;
11
+ exports.codexResetCreditSchema = exports.quotaSourceSchema = exports.quotaProviderIdSchema = exports.quotaFailureKindSchema = exports.quotaStateSchema = exports.quotaWindowSchema = exports.extractSessionEvents = exports.permissionModeSchema = exports.sessionEventSchema = exports.sessionMessageSchema = exports.messageUsageSchema = exports.ToolCallTracker = exports.extractToolCalls = exports.extractToolCall = exports.extractErrorMessage = exports.categorizeError = exports.gatherAssetsForCwd = exports.codexSessions = exports.readCodexAssets = exports.claudeSessions = exports.readClaudeAssets = exports.extractCommands = exports.extractFilePaths = exports.extractUrls = exports.extractTokenUsage = exports.getObservedContextWindowPath = exports.recordObservedContextWindow = exports.loadObservedContextWindows = exports.LITELLM_CATALOG_URL = exports.normalizeLiteLlmContextWindows = 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.selectStatuslineAccount = exports.formatStatusline = exports.estimateTimeToQuota = exports.BurnRateCalculator = void 0;
12
+ exports.scopePeakHoursToSessionProvider = exports.isClaudeCodeSessionProvider = exports.fetchPeakHoursStatus = exports.DEFAULT_PEAK_HOURS_TIMEOUT_MS = exports.createPeakHoursNotApplicableState = exports.runDoctor = exports.getSessionDiagnostics = exports.formatHealthReport = 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.codexResetCreditsSnapshotSchema = void 0;
13
13
  var usageNormalization_1 = require("./usageNormalization");
14
14
  Object.defineProperty(exports, "normalizeProviderUsage", { enumerable: true, get: function () { return usageNormalization_1.normalizeProviderUsage; } });
15
15
  Object.defineProperty(exports, "extractNormalizedUsage", { enumerable: true, get: function () { return usageNormalization_1.extractNormalizedUsage; } });
@@ -47,7 +47,11 @@ Object.defineProperty(exports, "PLAN_SCHEMA_VERSION", { enumerable: true, get: f
47
47
  Object.defineProperty(exports, "MAX_PLANS_PER_PROJECT", { enumerable: true, get: function () { return plan_1.MAX_PLANS_PER_PROJECT; } });
48
48
  // Paths
49
49
  var paths_1 = require("./paths");
50
+ Object.defineProperty(exports, "CONFIG_DIR_ENV_VAR", { enumerable: true, get: function () { return paths_1.CONFIG_DIR_ENV_VAR; } });
50
51
  Object.defineProperty(exports, "getConfigDir", { enumerable: true, get: function () { return paths_1.getConfigDir; } });
52
+ Object.defineProperty(exports, "getConfigDirOverride", { enumerable: true, get: function () { return paths_1.getConfigDirOverride; } });
53
+ Object.defineProperty(exports, "getDefaultConfigDir", { enumerable: true, get: function () { return paths_1.getDefaultConfigDir; } });
54
+ Object.defineProperty(exports, "setConfigDir", { enumerable: true, get: function () { return paths_1.setConfigDir; } });
51
55
  Object.defineProperty(exports, "getProjectDataPath", { enumerable: true, get: function () { return paths_1.getProjectDataPath; } });
52
56
  Object.defineProperty(exports, "getGlobalDataPath", { enumerable: true, get: function () { return paths_1.getGlobalDataPath; } });
53
57
  Object.defineProperty(exports, "encodeWorkspacePath", { enumerable: true, get: function () { return paths_1.encodeWorkspacePath; } });
@@ -494,6 +498,7 @@ Object.defineProperty(exports, "runDoctor", { enumerable: true, get: function ()
494
498
  // Peak Hours (PromoClock — third-party)
495
499
  var peakHours_1 = require("./peakHours");
496
500
  Object.defineProperty(exports, "createPeakHoursNotApplicableState", { enumerable: true, get: function () { return peakHours_1.createPeakHoursNotApplicableState; } });
501
+ Object.defineProperty(exports, "DEFAULT_PEAK_HOURS_TIMEOUT_MS", { enumerable: true, get: function () { return peakHours_1.DEFAULT_PEAK_HOURS_TIMEOUT_MS; } });
497
502
  Object.defineProperty(exports, "fetchPeakHoursStatus", { enumerable: true, get: function () { return peakHours_1.fetchPeakHoursStatus; } });
498
503
  Object.defineProperty(exports, "isClaudeCodeSessionProvider", { enumerable: true, get: function () { return peakHours_1.isClaudeCodeSessionProvider; } });
499
504
  Object.defineProperty(exports, "scopePeakHoursToSessionProvider", { enumerable: true, get: function () { return peakHours_1.scopePeakHoursToSessionProvider; } });
package/dist/modelInfo.js CHANGED
@@ -432,7 +432,12 @@ function _clearPricingOverrides() {
432
432
  overrideSortedKeys = [];
433
433
  }
434
434
  // ── Model ID Parsing ──
435
- const CLAUDE_RE = /^claude-(haiku|sonnet|opus|fable)-([0-9.]+)/i;
435
+ // Anthropic writes the minor version with a hyphen in modern IDs
436
+ // (`claude-sonnet-4-6-20260321`) and a dot in older ones
437
+ // (`claude-sonnet-4.5-20241022`). Accept both, then normalize to a dot.
438
+ // The `{1,2}` bound plus the trailing `(?![0-9])` keep the 8-digit release
439
+ // date from being mistaken for a minor version in `claude-opus-4-20250514`.
440
+ const CLAUDE_RE = /^claude-(haiku|sonnet|opus|fable)-([0-9]+(?:[-.][0-9]{1,2})?)(?![0-9])/i;
436
441
  const LEGACY_CLAUDE_RE = /^claude-([0-9]+(?:[-.][0-9]+)?)-(haiku|sonnet|opus)(?:-|$)/i;
437
442
  const GPT_RE = /^gpt-([0-9][0-9.A-Za-z-]*)/i;
438
443
  const O_SERIES_RE = /^o([0-9]+)(-mini|-pro)?/i;
@@ -455,7 +460,11 @@ function parseModelId(modelId) {
455
460
  .toLowerCase();
456
461
  const claude = normalized.match(CLAUDE_RE);
457
462
  if (claude) {
458
- return { provider: 'anthropic', family: claude[1].toLowerCase(), version: claude[2] };
463
+ return {
464
+ provider: 'anthropic',
465
+ family: claude[1].toLowerCase(),
466
+ version: claude[2].replace('-', '.'),
467
+ };
459
468
  }
460
469
  const legacyClaude = normalized.match(LEGACY_CLAUDE_RE);
461
470
  if (legacyClaude) {
@@ -33,6 +33,8 @@ export interface ObservedContextWindowStore {
33
33
  }
34
34
  /** Resolve the on-disk store path. */
35
35
  export declare function getObservedContextWindowPath(cacheDir?: string): string;
36
+ /** Reset the per-store write dedupe. Test-only; not part of the public API. */
37
+ export declare function _clearObservedContextWindowWriteCache(): void;
36
38
  /**
37
39
  * Load persisted observations and apply them as context-window overrides.
38
40
  *
@@ -44,11 +46,12 @@ export declare function loadObservedContextWindows(options?: ObservedContextWind
44
46
  * Record a provider-reported context window for a model.
45
47
  *
46
48
  * Applies in memory immediately, then persists — but only when the value
47
- * actually changed. Codex reports a window on every `token_count` event, so an
48
- * unconditional write would mean disk I/O many times per session for a value
49
- * that almost never moves.
49
+ * actually changed *for that store*. Codex reports a window on every
50
+ * `token_count` event, so an unconditional write would mean disk I/O many times
51
+ * per session for a value that almost never moves.
50
52
  *
51
53
  * Always resolves — never throws. Persistence failures are logged and dropped;
52
- * the in-memory override still stands for this process.
54
+ * the in-memory override still stands for this process, and the next call
55
+ * retries the write.
53
56
  */
54
57
  export declare function recordObservedContextWindow(modelId: string, contextWindow: number, options?: ObservedContextWindowOptions): Promise<void>;
@@ -52,6 +52,7 @@ var __importStar = (this && this.__importStar) || (function () {
52
52
  })();
53
53
  Object.defineProperty(exports, "__esModule", { value: true });
54
54
  exports.getObservedContextWindowPath = getObservedContextWindowPath;
55
+ exports._clearObservedContextWindowWriteCache = _clearObservedContextWindowWriteCache;
55
56
  exports.loadObservedContextWindows = loadObservedContextWindows;
56
57
  exports.recordObservedContextWindow = recordObservedContextWindow;
57
58
  const node_fs_1 = require("node:fs");
@@ -69,6 +70,21 @@ function getObservedContextWindowPath(cacheDir) {
69
70
  function emptyStore() {
70
71
  return { version: STORE_VERSION, models: {} };
71
72
  }
73
+ /**
74
+ * Last value successfully persisted, per resolved store path.
75
+ *
76
+ * The in-memory override table in `modelContext` is process-global by design —
77
+ * a lookup should answer the same way everywhere. That makes it unusable as the
78
+ * write dedupe: with two `cacheDir`s in one process (two temp dirs in a test
79
+ * suite, a multi-tenant host, a CLI and extension host sharing a process), the
80
+ * global would already hold the value from the first store and the second store
81
+ * would never be written at all.
82
+ */
83
+ const lastPersistedByStore = new Map();
84
+ /** Reset the per-store write dedupe. Test-only; not part of the public API. */
85
+ function _clearObservedContextWindowWriteCache() {
86
+ lastPersistedByStore.clear();
87
+ }
72
88
  /** Keep only well-formed entries; a hand-edited or partly-corrupt file shouldn't poison lookups. */
73
89
  function toOverrideMap(store) {
74
90
  const out = {};
@@ -110,12 +126,13 @@ async function loadObservedContextWindows(options = {}) {
110
126
  * Record a provider-reported context window for a model.
111
127
  *
112
128
  * Applies in memory immediately, then persists — but only when the value
113
- * actually changed. Codex reports a window on every `token_count` event, so an
114
- * unconditional write would mean disk I/O many times per session for a value
115
- * that almost never moves.
129
+ * actually changed *for that store*. Codex reports a window on every
130
+ * `token_count` event, so an unconditional write would mean disk I/O many times
131
+ * per session for a value that almost never moves.
116
132
  *
117
133
  * Always resolves — never throws. Persistence failures are logged and dropped;
118
- * the in-memory override still stands for this process.
134
+ * the in-memory override still stands for this process, and the next call
135
+ * retries the write.
119
136
  */
120
137
  async function recordObservedContextWindow(modelId, contextWindow, options = {}) {
121
138
  const normalizedId = modelId?.trim().toLowerCase();
@@ -124,10 +141,13 @@ async function recordObservedContextWindow(modelId, contextWindow, options = {})
124
141
  if (!Number.isFinite(contextWindow) || contextWindow <= 0)
125
142
  return;
126
143
  const current = (0, modelContext_1._getObservedContextWindows)();
127
- if (current[normalizedId] === contextWindow)
128
- return;
129
- (0, modelContext_1._setObservedContextWindows)({ ...current, [normalizedId]: contextWindow });
144
+ if (current[normalizedId] !== contextWindow) {
145
+ (0, modelContext_1._setObservedContextWindows)({ ...current, [normalizedId]: contextWindow });
146
+ }
130
147
  const storePath = getObservedContextWindowPath(options.cacheDir);
148
+ const persisted = lastPersistedByStore.get(storePath);
149
+ if (persisted?.get(normalizedId) === contextWindow)
150
+ return;
131
151
  try {
132
152
  // Lock-guarded read-modify-write: the CLI and the extension host can both
133
153
  // be observing sessions at once, and each should merge rather than clobber.
@@ -143,6 +163,13 @@ async function recordObservedContextWindow(modelId, contextWindow, options = {})
143
163
  },
144
164
  };
145
165
  });
166
+ // Recorded only on success, so a transient EACCES retries next time.
167
+ let store = lastPersistedByStore.get(storePath);
168
+ if (!store) {
169
+ store = new Map();
170
+ lastPersistedByStore.set(storePath, store);
171
+ }
172
+ store.set(normalizedId, contextWindow);
146
173
  }
147
174
  catch (err) {
148
175
  options.logger?.(`observedContextWindows: failed to persist ${storePath}: ${String(err)}`);
package/dist/paths.d.ts CHANGED
@@ -3,9 +3,44 @@
3
3
  * Mirrors patterns from sidekick-vscode/src/services/SessionPathResolver.ts
4
4
  * and TaskPersistenceService.ts
5
5
  */
6
+ /** Environment variable that redirects the Sidekick config root. */
7
+ export declare const CONFIG_DIR_ENV_VAR = "SIDEKICK_CONFIG_DIR";
8
+ /**
9
+ * The platform default config directory, ignoring both {@link setConfigDir}
10
+ * and `SIDEKICK_CONFIG_DIR`.
11
+ *
12
+ * `~/.config/sidekick` on Unix, `%APPDATA%/sidekick` on Windows.
13
+ */
14
+ export declare function getDefaultConfigDir(): string;
15
+ /**
16
+ * Redirect the Sidekick config root for this process.
17
+ *
18
+ * Takes precedence over `SIDEKICK_CONFIG_DIR`. Pass `null` (or an empty
19
+ * string) to clear it. Every reader and writer in the package resolves the
20
+ * root lazily through {@link getConfigDir}, so this takes effect immediately
21
+ * for all of them — including transitive callers of `getProjectDataPath`,
22
+ * `getGlobalDataPath`, and the account registry.
23
+ *
24
+ * Prefer `SIDEKICK_CONFIG_DIR` when the value is known before the process
25
+ * starts: it is read fresh on every call, so it stays correct even if a
26
+ * bundler ends up with more than one copy of this module.
27
+ *
28
+ * @example
29
+ * setConfigDir(path.join(os.tmpdir(), 'sidekick-fixture'));
30
+ * try {
31
+ * await addTask(project, { subject: 'isolated' });
32
+ * } finally {
33
+ * setConfigDir(null);
34
+ * }
35
+ */
36
+ export declare function setConfigDir(dir: string | null | undefined): void;
37
+ /** The active {@link setConfigDir} override, or `null` when unset. */
38
+ export declare function getConfigDirOverride(): string | null;
6
39
  /**
7
40
  * Gets the Sidekick config directory.
8
- * ~/.config/sidekick on Unix, %APPDATA%/sidekick on Windows.
41
+ *
42
+ * Resolution order: {@link setConfigDir} override → `SIDEKICK_CONFIG_DIR`
43
+ * → {@link getDefaultConfigDir}.
9
44
  */
10
45
  export declare function getConfigDir(): string;
11
46
  /**
package/dist/paths.js CHANGED
@@ -38,6 +38,10 @@ var __importStar = (this && this.__importStar) || (function () {
38
38
  };
39
39
  })();
40
40
  Object.defineProperty(exports, "__esModule", { value: true });
41
+ exports.CONFIG_DIR_ENV_VAR = void 0;
42
+ exports.getDefaultConfigDir = getDefaultConfigDir;
43
+ exports.setConfigDir = setConfigDir;
44
+ exports.getConfigDirOverride = getConfigDirOverride;
41
45
  exports.getConfigDir = getConfigDir;
42
46
  exports.getProjectDataPath = getProjectDataPath;
43
47
  exports.getGlobalDataPath = getGlobalDataPath;
@@ -48,16 +52,68 @@ exports.getProjectSlugRaw = getProjectSlugRaw;
48
52
  const fs = __importStar(require("fs"));
49
53
  const path = __importStar(require("path"));
50
54
  const os = __importStar(require("os"));
55
+ /** Environment variable that redirects the Sidekick config root. */
56
+ exports.CONFIG_DIR_ENV_VAR = 'SIDEKICK_CONFIG_DIR';
57
+ let configDirOverride = null;
51
58
  /**
52
- * Gets the Sidekick config directory.
53
- * ~/.config/sidekick on Unix, %APPDATA%/sidekick on Windows.
59
+ * The platform default config directory, ignoring both {@link setConfigDir}
60
+ * and `SIDEKICK_CONFIG_DIR`.
61
+ *
62
+ * `~/.config/sidekick` on Unix, `%APPDATA%/sidekick` on Windows.
54
63
  */
55
- function getConfigDir() {
64
+ function getDefaultConfigDir() {
56
65
  if (process.platform === 'win32') {
57
66
  return path.join(process.env.APPDATA || os.homedir(), 'sidekick');
58
67
  }
59
68
  return path.join(os.homedir(), '.config', 'sidekick');
60
69
  }
70
+ /**
71
+ * Redirect the Sidekick config root for this process.
72
+ *
73
+ * Takes precedence over `SIDEKICK_CONFIG_DIR`. Pass `null` (or an empty
74
+ * string) to clear it. Every reader and writer in the package resolves the
75
+ * root lazily through {@link getConfigDir}, so this takes effect immediately
76
+ * for all of them — including transitive callers of `getProjectDataPath`,
77
+ * `getGlobalDataPath`, and the account registry.
78
+ *
79
+ * Prefer `SIDEKICK_CONFIG_DIR` when the value is known before the process
80
+ * starts: it is read fresh on every call, so it stays correct even if a
81
+ * bundler ends up with more than one copy of this module.
82
+ *
83
+ * @example
84
+ * setConfigDir(path.join(os.tmpdir(), 'sidekick-fixture'));
85
+ * try {
86
+ * await addTask(project, { subject: 'isolated' });
87
+ * } finally {
88
+ * setConfigDir(null);
89
+ * }
90
+ */
91
+ function setConfigDir(dir) {
92
+ // Resolve the trimmed value, not the original: `path.resolve(' /tmp/x ')`
93
+ // treats the leading spaces as a relative segment and lands under cwd. The
94
+ // `SIDEKICK_CONFIG_DIR` branch in getConfigDir() already trims, and the two
95
+ // routes are documented as interchangeable.
96
+ const trimmed = dir?.trim();
97
+ configDirOverride = trimmed ? path.resolve(trimmed) : null;
98
+ }
99
+ /** The active {@link setConfigDir} override, or `null` when unset. */
100
+ function getConfigDirOverride() {
101
+ return configDirOverride;
102
+ }
103
+ /**
104
+ * Gets the Sidekick config directory.
105
+ *
106
+ * Resolution order: {@link setConfigDir} override → `SIDEKICK_CONFIG_DIR`
107
+ * → {@link getDefaultConfigDir}.
108
+ */
109
+ function getConfigDir() {
110
+ if (configDirOverride)
111
+ return configDirOverride;
112
+ const fromEnv = process.env[exports.CONFIG_DIR_ENV_VAR]?.trim();
113
+ if (fromEnv)
114
+ return path.resolve(fromEnv);
115
+ return getDefaultConfigDir();
116
+ }
61
117
  /**
62
118
  * Gets the path to a project-specific data file.
63
119
  * e.g., ~/.config/sidekick/tasks/my-project.json
@@ -23,6 +23,16 @@ export interface PeakHoursState {
23
23
  unavailable: boolean;
24
24
  notApplicable?: boolean;
25
25
  }
26
+ /** Default budget for the promoclock.co request, in milliseconds. */
27
+ export declare const DEFAULT_PEAK_HOURS_TIMEOUT_MS = 10000;
28
+ /** Options for {@link fetchPeakHoursStatus}. */
29
+ export interface FetchPeakHoursOptions {
30
+ /**
31
+ * Abort the request after this many milliseconds.
32
+ * Defaults to {@link DEFAULT_PEAK_HOURS_TIMEOUT_MS}.
33
+ */
34
+ timeoutMs?: number;
35
+ }
26
36
  export declare function isClaudeCodeSessionProvider(providerId: ProviderId): boolean;
27
37
  export declare function createPeakHoursNotApplicableState(providerId: ProviderId): PeakHoursState;
28
38
  export declare function scopePeakHoursToSessionProvider(providerId: ProviderId, status: PeakHoursState | null | undefined): PeakHoursState | null;
@@ -30,6 +40,10 @@ export declare function scopePeakHoursToSessionProvider(providerId: ProviderId,
30
40
  * Fetch current Claude peak-hours state from promoclock.co.
31
41
  *
32
42
  * Single-shot — caller wraps in polling loop, EventEmitter, or interval.
33
- * Returns `unavailable: true` on any network or parse error.
43
+ * Returns `unavailable: true` on any network, timeout, or parse error.
44
+ *
45
+ * promoclock.co is a third-party host, so the request is always bounded by
46
+ * an abort timeout. Without one a hung host would stall the caller — and
47
+ * this is polled, so the stall would repeat.
34
48
  */
35
- export declare function fetchPeakHoursStatus(): Promise<PeakHoursState>;
49
+ export declare function fetchPeakHoursStatus(options?: FetchPeakHoursOptions): Promise<PeakHoursState>;
package/dist/peakHours.js CHANGED
@@ -11,11 +11,14 @@
11
11
  * Polling / eventing is the caller's responsibility.
12
12
  */
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.DEFAULT_PEAK_HOURS_TIMEOUT_MS = void 0;
14
15
  exports.isClaudeCodeSessionProvider = isClaudeCodeSessionProvider;
15
16
  exports.createPeakHoursNotApplicableState = createPeakHoursNotApplicableState;
16
17
  exports.scopePeakHoursToSessionProvider = scopePeakHoursToSessionProvider;
17
18
  exports.fetchPeakHoursStatus = fetchPeakHoursStatus;
18
19
  const PROMOCLOCK_ENDPOINT = 'https://promoclock.co/api/status';
20
+ /** Default budget for the promoclock.co request, in milliseconds. */
21
+ exports.DEFAULT_PEAK_HOURS_TIMEOUT_MS = 10_000;
19
22
  function unavailableState() {
20
23
  return {
21
24
  status: 'unknown',
@@ -73,11 +76,19 @@ function normalizeSpeed(raw) {
73
76
  * Fetch current Claude peak-hours state from promoclock.co.
74
77
  *
75
78
  * Single-shot — caller wraps in polling loop, EventEmitter, or interval.
76
- * Returns `unavailable: true` on any network or parse error.
79
+ * Returns `unavailable: true` on any network, timeout, or parse error.
80
+ *
81
+ * promoclock.co is a third-party host, so the request is always bounded by
82
+ * an abort timeout. Without one a hung host would stall the caller — and
83
+ * this is polled, so the stall would repeat.
77
84
  */
78
- async function fetchPeakHoursStatus() {
85
+ async function fetchPeakHoursStatus(options = {}) {
86
+ const timeoutMs = options.timeoutMs ?? exports.DEFAULT_PEAK_HOURS_TIMEOUT_MS;
87
+ const controller = new AbortController();
88
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
89
+ timeout.unref();
79
90
  try {
80
- const res = await fetch(PROMOCLOCK_ENDPOINT);
91
+ const res = await fetch(PROMOCLOCK_ENDPOINT, { signal: controller.signal });
81
92
  if (!res.ok)
82
93
  return unavailableState();
83
94
  const data = await res.json();
@@ -98,6 +109,10 @@ async function fetchPeakHoursStatus() {
98
109
  };
99
110
  }
100
111
  catch {
112
+ // Covers AbortError from the timeout above alongside network/parse failures.
101
113
  return unavailableState();
102
114
  }
115
+ finally {
116
+ clearTimeout(timeout);
117
+ }
103
118
  }
@@ -18,8 +18,12 @@
18
18
  */
19
19
  import { type ModelPricing } from './modelInfo';
20
20
  export interface HydrateOptions {
21
- /** Directory for the on-disk cache (e.g. ~/.config/sidekick). */
22
- cacheDir: string;
21
+ /**
22
+ * Directory for the on-disk cache. Defaults to the Sidekick config dir,
23
+ * which honors `SIDEKICK_CONFIG_DIR` and `setConfigDir()` — pass this only
24
+ * to place the cache somewhere outside the config root.
25
+ */
26
+ cacheDir?: string;
23
27
  /** Inject a fetch implementation (tests, custom agents). Defaults to `globalThis.fetch`. */
24
28
  fetchImpl?: typeof fetch;
25
29
  /** Cache TTL in ms. Default 24h. */
@@ -52,7 +56,7 @@ export declare const LITELLM_CATALOG_URL = "https://raw.githubusercontent.com/Be
52
56
  *
53
57
  * Always resolves — never throws. Offline-safe.
54
58
  */
55
- export declare function hydratePricingCatalog(options: HydrateOptions): Promise<HydrateResult>;
59
+ export declare function hydratePricingCatalog(options?: HydrateOptions): Promise<HydrateResult>;
56
60
  /**
57
61
  * Convert a LiteLLM catalog payload to our `ModelPricing` override map.
58
62
  * Exported for tests; rarely called directly.
@@ -59,6 +59,7 @@ const node_fs_1 = require("node:fs");
59
59
  const path = __importStar(require("node:path"));
60
60
  const modelContext_1 = require("./modelContext");
61
61
  const modelInfo_1 = require("./modelInfo");
62
+ const paths_1 = require("./paths");
62
63
  // ── Constants ──
63
64
  exports.LITELLM_CATALOG_URL = 'https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json';
64
65
  const CACHE_FILE_NAME = 'pricing-catalog.json';
@@ -75,8 +76,8 @@ const DEFAULT_TIMEOUT_MS = 3_000;
75
76
  *
76
77
  * Always resolves — never throws. Offline-safe.
77
78
  */
78
- async function hydratePricingCatalog(options) {
79
- const { cacheDir, fetchImpl = globalThis.fetch, ttlMs = DEFAULT_TTL_MS, timeoutMs = DEFAULT_TIMEOUT_MS, url = exports.LITELLM_CATALOG_URL, logger, } = options;
79
+ async function hydratePricingCatalog(options = {}) {
80
+ const { cacheDir = (0, paths_1.getConfigDir)(), fetchImpl = globalThis.fetch, ttlMs = DEFAULT_TTL_MS, timeoutMs = DEFAULT_TIMEOUT_MS, url = exports.LITELLM_CATALOG_URL, logger, } = options;
80
81
  const cachePath = path.join(cacheDir, CACHE_FILE_NAME);
81
82
  const now = Date.now();
82
83
  // 1. Fresh cache?