sidekick-shared 0.24.2 → 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/CHANGELOG.md +412 -0
- package/LICENSE +21 -0
- package/README.md +87 -16
- package/dist/index.d.ts +3 -3
- package/dist/index.js +12 -7
- package/dist/modelContext.js +1 -0
- package/dist/modelInfo.js +146 -14
- package/dist/observedContextWindows.d.ts +7 -4
- package/dist/observedContextWindows.js +34 -7
- package/dist/paths.d.ts +36 -1
- package/dist/paths.js +59 -3
- package/dist/peakHours.d.ts +16 -2
- package/dist/peakHours.js +18 -3
- package/dist/pricingCatalog.d.ts +7 -3
- package/dist/pricingCatalog.js +3 -2
- package/dist/zaiQuota.d.ts +87 -0
- package/dist/zaiQuota.js +49 -0
- package/dist/zaiQuotaWatcher.d.ts +7 -0
- package/dist/zaiQuotaWatcher.js +3 -0
- package/package.json +60 -2
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.
|
|
7
|
-
exports.
|
|
8
|
-
exports.
|
|
9
|
-
exports.
|
|
10
|
-
exports.
|
|
11
|
-
exports.
|
|
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/modelContext.js
CHANGED
package/dist/modelInfo.js
CHANGED
|
@@ -78,11 +78,14 @@ const PRICING_TABLE = {
|
|
|
78
78
|
},
|
|
79
79
|
// Sonnet 5 carries the standard rate here. The introductory $2/$10 (through
|
|
80
80
|
// 2026-08-31) arrives via catalog hydration, which supersedes this baseline.
|
|
81
|
+
// Sonnet 5 is $2/$10, not the $3/$15 every earlier Sonnet charged, and it
|
|
82
|
+
// carries no >200K surcharge the way Sonnet 4.5 does. The catalog agrees
|
|
83
|
+
// across all eleven of its Sonnet 5 entries.
|
|
81
84
|
'claude-sonnet-5': {
|
|
82
|
-
inputCostPerMillion:
|
|
83
|
-
outputCostPerMillion:
|
|
84
|
-
cacheWriteCostPerMillion:
|
|
85
|
-
cacheReadCostPerMillion: 0.
|
|
85
|
+
inputCostPerMillion: 2.0,
|
|
86
|
+
outputCostPerMillion: 10.0,
|
|
87
|
+
cacheWriteCostPerMillion: 2.5,
|
|
88
|
+
cacheReadCostPerMillion: 0.2,
|
|
86
89
|
},
|
|
87
90
|
'claude-sonnet-4-6': {
|
|
88
91
|
inputCostPerMillion: 3.0,
|
|
@@ -176,6 +179,21 @@ const PRICING_TABLE = {
|
|
|
176
179
|
cacheReadCostPerMillion: 1.5,
|
|
177
180
|
},
|
|
178
181
|
// ── OpenAI: GPT-4.x family ──
|
|
182
|
+
// The `-tts`, `-transcribe`, and `-realtime-preview` variants also bill above
|
|
183
|
+
// the key they inherit, but no coding agent routes to them, so they are left
|
|
184
|
+
// out rather than carried here. Catalog hydration still prices them correctly.
|
|
185
|
+
'gpt-4.1-mini': {
|
|
186
|
+
inputCostPerMillion: 0.4,
|
|
187
|
+
outputCostPerMillion: 1.6,
|
|
188
|
+
cacheWriteCostPerMillion: 0,
|
|
189
|
+
cacheReadCostPerMillion: 0.1,
|
|
190
|
+
},
|
|
191
|
+
'gpt-4.1-nano': {
|
|
192
|
+
inputCostPerMillion: 0.1,
|
|
193
|
+
outputCostPerMillion: 0.4,
|
|
194
|
+
cacheWriteCostPerMillion: 0,
|
|
195
|
+
cacheReadCostPerMillion: 0.025,
|
|
196
|
+
},
|
|
179
197
|
'gpt-4.1': {
|
|
180
198
|
inputCostPerMillion: 2.0,
|
|
181
199
|
outputCostPerMillion: 8.0,
|
|
@@ -188,6 +206,14 @@ const PRICING_TABLE = {
|
|
|
188
206
|
cacheWriteCostPerMillion: 0,
|
|
189
207
|
cacheReadCostPerMillion: 0.075,
|
|
190
208
|
},
|
|
209
|
+
// The launch snapshot kept its original $5/$15 when gpt-4o was cut to
|
|
210
|
+
// $2.50/$10, so a pinned id must not read the current rate.
|
|
211
|
+
'gpt-4o-2024-05-13': {
|
|
212
|
+
inputCostPerMillion: 5.0,
|
|
213
|
+
outputCostPerMillion: 15.0,
|
|
214
|
+
cacheWriteCostPerMillion: 0,
|
|
215
|
+
cacheReadCostPerMillion: 0,
|
|
216
|
+
},
|
|
191
217
|
'gpt-4o': {
|
|
192
218
|
inputCostPerMillion: 2.5,
|
|
193
219
|
outputCostPerMillion: 10.0,
|
|
@@ -202,8 +228,12 @@ const PRICING_TABLE = {
|
|
|
202
228
|
},
|
|
203
229
|
// ── OpenAI: GPT-5 family ──
|
|
204
230
|
// Published rates, verified against the LiteLLM catalog. Runtime hydration
|
|
205
|
-
// still supersedes these; they are the offline baseline.
|
|
206
|
-
//
|
|
231
|
+
// still supersedes these; they are the offline baseline.
|
|
232
|
+
//
|
|
233
|
+
// Every tier that ships at a rate of its own needs an entry of its own. Keys
|
|
234
|
+
// are matched longest-first, so a `-mini`/`-nano`/`-pro` variant with no entry
|
|
235
|
+
// silently inherits its base model's rate and reports a wrong number rather
|
|
236
|
+
// than none — `gpt-5-nano` read 25x its true cost this way.
|
|
207
237
|
'gpt-5.6-sol': {
|
|
208
238
|
inputCostPerMillion: 5.0,
|
|
209
239
|
outputCostPerMillion: 30.0,
|
|
@@ -216,12 +246,24 @@ const PRICING_TABLE = {
|
|
|
216
246
|
cacheWriteCostPerMillion: 3.13,
|
|
217
247
|
cacheReadCostPerMillion: 0.25,
|
|
218
248
|
},
|
|
249
|
+
'gpt-5.6-luna': {
|
|
250
|
+
inputCostPerMillion: 1.0,
|
|
251
|
+
outputCostPerMillion: 6.0,
|
|
252
|
+
cacheWriteCostPerMillion: 1.25,
|
|
253
|
+
cacheReadCostPerMillion: 0.1,
|
|
254
|
+
},
|
|
219
255
|
'gpt-5.6': {
|
|
220
256
|
inputCostPerMillion: 5.0,
|
|
221
257
|
outputCostPerMillion: 30.0,
|
|
222
258
|
cacheWriteCostPerMillion: 6.25,
|
|
223
259
|
cacheReadCostPerMillion: 0.5,
|
|
224
260
|
},
|
|
261
|
+
'gpt-5.5-pro': {
|
|
262
|
+
inputCostPerMillion: 30.0,
|
|
263
|
+
outputCostPerMillion: 180.0,
|
|
264
|
+
cacheWriteCostPerMillion: 0,
|
|
265
|
+
cacheReadCostPerMillion: 3.0,
|
|
266
|
+
},
|
|
225
267
|
'gpt-5.5': {
|
|
226
268
|
inputCostPerMillion: 5.0,
|
|
227
269
|
outputCostPerMillion: 30.0,
|
|
@@ -234,6 +276,18 @@ const PRICING_TABLE = {
|
|
|
234
276
|
cacheWriteCostPerMillion: 0,
|
|
235
277
|
cacheReadCostPerMillion: 0.07,
|
|
236
278
|
},
|
|
279
|
+
'gpt-5.4-nano': {
|
|
280
|
+
inputCostPerMillion: 0.2,
|
|
281
|
+
outputCostPerMillion: 1.25,
|
|
282
|
+
cacheWriteCostPerMillion: 0,
|
|
283
|
+
cacheReadCostPerMillion: 0.02,
|
|
284
|
+
},
|
|
285
|
+
'gpt-5.4-pro': {
|
|
286
|
+
inputCostPerMillion: 30.0,
|
|
287
|
+
outputCostPerMillion: 180.0,
|
|
288
|
+
cacheWriteCostPerMillion: 0,
|
|
289
|
+
cacheReadCostPerMillion: 3.0,
|
|
290
|
+
},
|
|
237
291
|
'gpt-5.4': {
|
|
238
292
|
inputCostPerMillion: 2.5,
|
|
239
293
|
outputCostPerMillion: 15.0,
|
|
@@ -241,17 +295,63 @@ const PRICING_TABLE = {
|
|
|
241
295
|
cacheReadCostPerMillion: 0.25,
|
|
242
296
|
},
|
|
243
297
|
'gpt-5.3-codex': {
|
|
244
|
-
inputCostPerMillion: 1.
|
|
245
|
-
outputCostPerMillion:
|
|
298
|
+
inputCostPerMillion: 1.75,
|
|
299
|
+
outputCostPerMillion: 14.0,
|
|
246
300
|
cacheWriteCostPerMillion: 0,
|
|
247
|
-
cacheReadCostPerMillion: 0.
|
|
301
|
+
cacheReadCostPerMillion: 0.175,
|
|
302
|
+
},
|
|
303
|
+
'gpt-5.3-chat-latest': {
|
|
304
|
+
inputCostPerMillion: 1.75,
|
|
305
|
+
outputCostPerMillion: 14.0,
|
|
306
|
+
cacheWriteCostPerMillion: 0,
|
|
307
|
+
cacheReadCostPerMillion: 0.175,
|
|
248
308
|
},
|
|
309
|
+
// No bare `gpt-5.3` ships in the catalog; both real variants above are
|
|
310
|
+
// $1.75/$14. This entry stays an estimate and only answers ids that match
|
|
311
|
+
// neither variant.
|
|
249
312
|
'gpt-5.3': {
|
|
250
313
|
inputCostPerMillion: 1.25,
|
|
251
314
|
outputCostPerMillion: 10.0,
|
|
252
315
|
cacheWriteCostPerMillion: 0,
|
|
253
316
|
cacheReadCostPerMillion: 0.125,
|
|
254
317
|
},
|
|
318
|
+
'gpt-5.2-pro': {
|
|
319
|
+
inputCostPerMillion: 21.0,
|
|
320
|
+
outputCostPerMillion: 168.0,
|
|
321
|
+
cacheWriteCostPerMillion: 0,
|
|
322
|
+
cacheReadCostPerMillion: 0,
|
|
323
|
+
},
|
|
324
|
+
// Also answers `gpt-5.2-codex` and `gpt-5.2-chat*`, which bill at this rate.
|
|
325
|
+
'gpt-5.2': {
|
|
326
|
+
inputCostPerMillion: 1.75,
|
|
327
|
+
outputCostPerMillion: 14.0,
|
|
328
|
+
cacheWriteCostPerMillion: 0,
|
|
329
|
+
cacheReadCostPerMillion: 0.175,
|
|
330
|
+
},
|
|
331
|
+
'gpt-5.1-codex-mini': {
|
|
332
|
+
inputCostPerMillion: 0.25,
|
|
333
|
+
outputCostPerMillion: 2.0,
|
|
334
|
+
cacheWriteCostPerMillion: 0,
|
|
335
|
+
cacheReadCostPerMillion: 0.025,
|
|
336
|
+
},
|
|
337
|
+
'gpt-5-pro': {
|
|
338
|
+
inputCostPerMillion: 15.0,
|
|
339
|
+
outputCostPerMillion: 120.0,
|
|
340
|
+
cacheWriteCostPerMillion: 0,
|
|
341
|
+
cacheReadCostPerMillion: 0,
|
|
342
|
+
},
|
|
343
|
+
'gpt-5-mini': {
|
|
344
|
+
inputCostPerMillion: 0.25,
|
|
345
|
+
outputCostPerMillion: 2.0,
|
|
346
|
+
cacheWriteCostPerMillion: 0,
|
|
347
|
+
cacheReadCostPerMillion: 0.025,
|
|
348
|
+
},
|
|
349
|
+
'gpt-5-nano': {
|
|
350
|
+
inputCostPerMillion: 0.05,
|
|
351
|
+
outputCostPerMillion: 0.4,
|
|
352
|
+
cacheWriteCostPerMillion: 0,
|
|
353
|
+
cacheReadCostPerMillion: 0.005,
|
|
354
|
+
},
|
|
255
355
|
'gpt-5': {
|
|
256
356
|
inputCostPerMillion: 1.25,
|
|
257
357
|
outputCostPerMillion: 10.0,
|
|
@@ -259,23 +359,46 @@ const PRICING_TABLE = {
|
|
|
259
359
|
cacheReadCostPerMillion: 0.125,
|
|
260
360
|
},
|
|
261
361
|
// ── OpenAI: o-series (reasoning models) ──
|
|
362
|
+
// The `-pro` and deep-research tiers cost an order of magnitude more than the
|
|
363
|
+
// base model whose key they would otherwise match.
|
|
364
|
+
'o3-deep-research': {
|
|
365
|
+
inputCostPerMillion: 10.0,
|
|
366
|
+
outputCostPerMillion: 40.0,
|
|
367
|
+
cacheWriteCostPerMillion: 0,
|
|
368
|
+
cacheReadCostPerMillion: 2.5,
|
|
369
|
+
},
|
|
262
370
|
'o3-mini': {
|
|
263
371
|
inputCostPerMillion: 1.1,
|
|
264
372
|
outputCostPerMillion: 4.4,
|
|
265
373
|
cacheWriteCostPerMillion: 0,
|
|
266
374
|
cacheReadCostPerMillion: 0.55,
|
|
267
375
|
},
|
|
376
|
+
'o3-pro': {
|
|
377
|
+
inputCostPerMillion: 20.0,
|
|
378
|
+
outputCostPerMillion: 80.0,
|
|
379
|
+
cacheWriteCostPerMillion: 0,
|
|
380
|
+
cacheReadCostPerMillion: 0,
|
|
381
|
+
},
|
|
268
382
|
o3: {
|
|
269
383
|
inputCostPerMillion: 2.0,
|
|
270
384
|
outputCostPerMillion: 8.0,
|
|
271
385
|
cacheWriteCostPerMillion: 0,
|
|
272
386
|
cacheReadCostPerMillion: 0.5,
|
|
273
387
|
},
|
|
388
|
+
// OpenAI cut o1-mini to $1.10/$4.40 after launch; $3/$12 was the launch rate.
|
|
389
|
+
// No bare catalog key settles it — Azure's $1.21/$4.84 is its usual 1.1x
|
|
390
|
+
// uplift on exactly this number, and Replicate's OpenAI passthrough agrees.
|
|
274
391
|
'o1-mini': {
|
|
275
|
-
inputCostPerMillion:
|
|
276
|
-
outputCostPerMillion:
|
|
392
|
+
inputCostPerMillion: 1.1,
|
|
393
|
+
outputCostPerMillion: 4.4,
|
|
277
394
|
cacheWriteCostPerMillion: 0,
|
|
278
|
-
cacheReadCostPerMillion:
|
|
395
|
+
cacheReadCostPerMillion: 0.55,
|
|
396
|
+
},
|
|
397
|
+
'o1-pro': {
|
|
398
|
+
inputCostPerMillion: 150.0,
|
|
399
|
+
outputCostPerMillion: 600.0,
|
|
400
|
+
cacheWriteCostPerMillion: 0,
|
|
401
|
+
cacheReadCostPerMillion: 0,
|
|
279
402
|
},
|
|
280
403
|
o1: {
|
|
281
404
|
inputCostPerMillion: 15.0,
|
|
@@ -309,7 +432,12 @@ function _clearPricingOverrides() {
|
|
|
309
432
|
overrideSortedKeys = [];
|
|
310
433
|
}
|
|
311
434
|
// ── Model ID Parsing ──
|
|
312
|
-
|
|
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;
|
|
313
441
|
const LEGACY_CLAUDE_RE = /^claude-([0-9]+(?:[-.][0-9]+)?)-(haiku|sonnet|opus)(?:-|$)/i;
|
|
314
442
|
const GPT_RE = /^gpt-([0-9][0-9.A-Za-z-]*)/i;
|
|
315
443
|
const O_SERIES_RE = /^o([0-9]+)(-mini|-pro)?/i;
|
|
@@ -332,7 +460,11 @@ function parseModelId(modelId) {
|
|
|
332
460
|
.toLowerCase();
|
|
333
461
|
const claude = normalized.match(CLAUDE_RE);
|
|
334
462
|
if (claude) {
|
|
335
|
-
return {
|
|
463
|
+
return {
|
|
464
|
+
provider: 'anthropic',
|
|
465
|
+
family: claude[1].toLowerCase(),
|
|
466
|
+
version: claude[2].replace('-', '.'),
|
|
467
|
+
};
|
|
336
468
|
}
|
|
337
469
|
const legacyClaude = normalized.match(LEGACY_CLAUDE_RE);
|
|
338
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
|
|
48
|
-
* unconditional write would mean disk I/O many times
|
|
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
|
|
114
|
-
* unconditional write would mean disk I/O many times
|
|
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]
|
|
128
|
-
|
|
129
|
-
|
|
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
|
-
*
|
|
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
|
-
*
|
|
53
|
-
*
|
|
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
|
|
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
|
package/dist/peakHours.d.ts
CHANGED
|
@@ -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
|
}
|