sidekick-shared 0.24.5 → 0.25.0
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 +35 -0
- package/README.md +159 -52
- package/dist/accountChangeSignal.d.ts +3 -0
- package/dist/accountChangeSignal.js +19 -0
- package/dist/accountChanges.d.ts +21 -0
- package/dist/accountChanges.js +151 -0
- package/dist/accountRegistry.d.ts +3 -1
- package/dist/accountRegistry.js +5 -0
- package/dist/browser.d.ts +8 -3
- package/dist/browser.js +15 -1
- package/dist/codexQuotaWatcher.d.ts +6 -0
- package/dist/codexQuotaWatcher.js +101 -47
- package/dist/index.d.ts +23 -13
- package/dist/index.js +34 -10
- package/dist/modelAliases.d.ts +13 -0
- package/dist/modelAliases.js +58 -0
- package/dist/modelCatalog.d.ts +32 -0
- package/dist/modelCatalog.js +145 -0
- package/dist/modelContext.d.ts +36 -3
- package/dist/modelContext.js +109 -34
- package/dist/modelInfo.d.ts +30 -1
- package/dist/modelInfo.js +116 -26
- package/dist/multiProviderQuotaService.d.ts +8 -0
- package/dist/multiProviderQuotaService.js +64 -3
- package/dist/node.d.ts +4 -4
- package/dist/node.js +4 -1
- package/dist/observedSessionCollector.d.ts +75 -4
- package/dist/observedSessionCollector.js +452 -42
- package/dist/parsers/codexHistory.d.ts +4 -2
- package/dist/parsers/codexHistory.js +9 -2
- package/dist/parsers/sessionActivityDetector.d.ts +6 -0
- package/dist/parsers/sessionActivityDetector.js +17 -0
- package/dist/providerIds.d.ts +11 -0
- package/dist/providerIds.js +9 -0
- package/dist/providerQuota.d.ts +3 -1
- package/dist/providerQuota.js +3 -0
- package/dist/providers/claudeCode.d.ts +10 -1
- package/dist/providers/claudeCode.js +204 -39
- package/dist/providers/codex.d.ts +18 -1
- package/dist/providers/codex.js +269 -40
- package/dist/providers/codexDatabase.d.ts +9 -0
- package/dist/providers/codexDatabase.js +107 -2
- package/dist/providers/diagnostics.d.ts +13 -0
- package/dist/providers/diagnostics.js +88 -0
- package/dist/providers/factory.d.ts +14 -0
- package/dist/providers/factory.js +57 -0
- package/dist/providers/openCode.d.ts +20 -1
- package/dist/providers/openCode.js +361 -11
- package/dist/providers/openCodeDatabase.d.ts +10 -0
- package/dist/providers/openCodeDatabase.js +69 -0
- package/dist/providers/types.d.ts +52 -2
- package/dist/providers/types.js +4 -0
- package/dist/quota.d.ts +4 -1
- package/dist/quota.js +3 -7
- package/dist/quotaHistory.d.ts +2 -1
- package/dist/quotaPoller.d.ts +13 -1
- package/dist/quotaPoller.js +65 -3
- package/dist/schemas/accountManager.d.ts +2 -2
- package/dist/schemas/accountManager.js +2 -4
- package/dist/schemas/accountStatus.d.ts +3 -0
- package/dist/schemas/accountStatus.js +1 -0
- package/dist/schemas/index.d.ts +1 -0
- package/dist/schemas/index.js +7 -2
- package/dist/schemas/observedSessionV1.d.ts +27 -26
- package/dist/schemas/observedSessionV1.js +6 -4
- package/dist/schemas/quota.d.ts +2 -2
- package/dist/schemas/quota.js +3 -6
- package/dist/schemas/quotaHistory.d.ts +2 -2
- package/dist/schemas/tokenEstimation.d.ts +1 -1
- package/dist/sessionMonitor.d.ts +15 -0
- package/dist/sessionMonitor.js +142 -0
- package/dist/sessionPreviews.d.ts +26 -1
- package/dist/sessionPreviews.js +319 -4
- package/dist/types/observedSessionV1.d.ts +6 -2
- package/dist/types/observedSessionV1.js +14 -8
- package/package.json +22 -1
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.onAccountsChanged = onAccountsChanged;
|
|
37
|
+
exports._notifyAccountsChanged = _notifyAccountsChanged;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const os = __importStar(require("os"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const accountChangeSignal_1 = require("./accountChangeSignal");
|
|
42
|
+
const accountStatus_1 = require("./accountStatus");
|
|
43
|
+
const accountRegistry_1 = require("./accountRegistry");
|
|
44
|
+
const codexProfiles_1 = require("./codexProfiles");
|
|
45
|
+
const listeners = new Set();
|
|
46
|
+
let watchers = [];
|
|
47
|
+
let pollTimer;
|
|
48
|
+
let stopRawListener;
|
|
49
|
+
let lastFingerprint;
|
|
50
|
+
let debounceTimer;
|
|
51
|
+
let activePollIntervalMs = 30_000;
|
|
52
|
+
/**
|
|
53
|
+
* Observe login, logout, and active-account switches. Local Sidekick mutations
|
|
54
|
+
* signal immediately; filesystem watchers cover external CLIs; a low-frequency
|
|
55
|
+
* catch-up poll protects network mounts and watcher-hostile filesystems.
|
|
56
|
+
*/
|
|
57
|
+
function onAccountsChanged(listener, options = {}) {
|
|
58
|
+
listeners.add(listener);
|
|
59
|
+
activePollIntervalMs = Math.max(1_000, options.pollIntervalMs ?? activePollIntervalMs);
|
|
60
|
+
ensureMonitoring();
|
|
61
|
+
if (options.emitCurrent)
|
|
62
|
+
emitIfChanged('poll', true, listener);
|
|
63
|
+
return {
|
|
64
|
+
dispose: () => {
|
|
65
|
+
listeners.delete(listener);
|
|
66
|
+
if (listeners.size === 0)
|
|
67
|
+
stopMonitoring();
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function ensureMonitoring() {
|
|
72
|
+
if (stopRawListener)
|
|
73
|
+
return;
|
|
74
|
+
lastFingerprint = fingerprint((0, accountStatus_1.getActiveAccountStatus)());
|
|
75
|
+
stopRawListener = (0, accountChangeSignal_1._onRawAccountsChanged)((reason) => scheduleCheck(reason));
|
|
76
|
+
for (const target of watchTargets()) {
|
|
77
|
+
try {
|
|
78
|
+
const watcher = fs.watch(target, { persistent: false }, () => {
|
|
79
|
+
scheduleCheck('filesystem');
|
|
80
|
+
});
|
|
81
|
+
watcher.on('error', () => {
|
|
82
|
+
watchers = watchers.filter((candidate) => candidate !== watcher);
|
|
83
|
+
try {
|
|
84
|
+
watcher.close();
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// The catch-up poll remains active.
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
watchers.push(watcher);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// Missing/unwatchable directories are covered by the catch-up poll.
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
pollTimer = setInterval(() => emitIfChanged('poll'), activePollIntervalMs);
|
|
97
|
+
pollTimer.unref?.();
|
|
98
|
+
}
|
|
99
|
+
function stopMonitoring() {
|
|
100
|
+
stopRawListener?.();
|
|
101
|
+
stopRawListener = undefined;
|
|
102
|
+
for (const watcher of watchers)
|
|
103
|
+
watcher.close();
|
|
104
|
+
watchers = [];
|
|
105
|
+
if (pollTimer)
|
|
106
|
+
clearInterval(pollTimer);
|
|
107
|
+
pollTimer = undefined;
|
|
108
|
+
if (debounceTimer)
|
|
109
|
+
clearTimeout(debounceTimer);
|
|
110
|
+
debounceTimer = undefined;
|
|
111
|
+
lastFingerprint = undefined;
|
|
112
|
+
}
|
|
113
|
+
function watchTargets() {
|
|
114
|
+
return Array.from(new Set([(0, accountRegistry_1.getAccountsDir)(), path.join(os.homedir(), '.claude'), (0, codexProfiles_1.getSystemCodexHome)()]));
|
|
115
|
+
}
|
|
116
|
+
function scheduleCheck(reason) {
|
|
117
|
+
if (debounceTimer)
|
|
118
|
+
clearTimeout(debounceTimer);
|
|
119
|
+
debounceTimer = setTimeout(() => {
|
|
120
|
+
debounceTimer = undefined;
|
|
121
|
+
// Never force: watch targets include ~/.claude and the Codex home, whose
|
|
122
|
+
// history files churn on every prompt. Only a real status change may wake
|
|
123
|
+
// subscribers, or dormant quota pollers would poll on unrelated writes.
|
|
124
|
+
emitIfChanged(reason);
|
|
125
|
+
}, 25);
|
|
126
|
+
debounceTimer.unref?.();
|
|
127
|
+
}
|
|
128
|
+
function emitIfChanged(reason, force = false, singleListener) {
|
|
129
|
+
const status = (0, accountStatus_1.getActiveAccountStatus)();
|
|
130
|
+
const nextFingerprint = fingerprint(status);
|
|
131
|
+
if (!force && nextFingerprint === lastFingerprint)
|
|
132
|
+
return;
|
|
133
|
+
lastFingerprint = nextFingerprint;
|
|
134
|
+
const event = { reason, status };
|
|
135
|
+
const targets = singleListener ? [singleListener] : [...listeners];
|
|
136
|
+
for (const listener of targets) {
|
|
137
|
+
try {
|
|
138
|
+
listener(event);
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
// A host callback cannot stop monitoring.
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function fingerprint(status) {
|
|
146
|
+
return JSON.stringify(status);
|
|
147
|
+
}
|
|
148
|
+
/** Internal bridge for account mutations outside the registry module. */
|
|
149
|
+
function _notifyAccountsChanged() {
|
|
150
|
+
(0, accountChangeSignal_1._emitAccountsChanged)('local');
|
|
151
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import type { AccountProviderId } from './providerIds';
|
|
2
|
+
export { ACCOUNT_PROVIDER_IDS } from './providerIds';
|
|
3
|
+
export type { AccountProviderId } from './providerIds';
|
|
2
4
|
export interface AccountIdentityMetadata {
|
|
3
5
|
email?: string;
|
|
4
6
|
workspaceId?: string;
|
package/dist/accountRegistry.js
CHANGED
|
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ACCOUNT_PROVIDER_IDS = void 0;
|
|
36
37
|
exports.getAccountsDir = getAccountsDir;
|
|
37
38
|
exports.readSavedAccountRegistry = readSavedAccountRegistry;
|
|
38
39
|
exports.writeSavedAccountRegistry = writeSavedAccountRegistry;
|
|
@@ -46,6 +47,9 @@ const fs = __importStar(require("fs"));
|
|
|
46
47
|
const path = __importStar(require("path"));
|
|
47
48
|
const paths_1 = require("./paths");
|
|
48
49
|
const atomic_1 = require("./writers/atomic");
|
|
50
|
+
const accountChangeSignal_1 = require("./accountChangeSignal");
|
|
51
|
+
var providerIds_1 = require("./providerIds");
|
|
52
|
+
Object.defineProperty(exports, "ACCOUNT_PROVIDER_IDS", { enumerable: true, get: function () { return providerIds_1.ACCOUNT_PROVIDER_IDS; } });
|
|
49
53
|
function getAccountsDir() {
|
|
50
54
|
return path.join((0, paths_1.getConfigDir)(), 'accounts');
|
|
51
55
|
}
|
|
@@ -60,6 +64,7 @@ function ensureAccountsDir() {
|
|
|
60
64
|
}
|
|
61
65
|
function writeRegistryUnlocked(registry) {
|
|
62
66
|
(0, atomic_1.atomicWriteJsonSync)(getRegistryPath(), normalizeRegistry(registry));
|
|
67
|
+
(0, accountChangeSignal_1._emitAccountsChanged)('local');
|
|
63
68
|
}
|
|
64
69
|
/**
|
|
65
70
|
* Serializes registry read-modify-write cycles across processes. Without the
|
package/dist/browser.d.ts
CHANGED
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
*
|
|
8
8
|
* For pricing hydration (LiteLLM catalog refresh), use `sidekick-shared/node`.
|
|
9
9
|
*/
|
|
10
|
-
export { getModelContextWindowSize, DEFAULT_CONTEXT_WINDOW } from './modelContext';
|
|
10
|
+
export { getModelContextWindowSize, resolveModelContextWindow, DEFAULT_CONTEXT_WINDOW, } from './modelContext';
|
|
11
|
+
export type { ModelCatalogMatch, ModelContextWindowProvenance, ModelContextWindowSource, ResolvedModelContextWindow, } from './modelContext';
|
|
11
12
|
export { normalizeProviderUsage, extractNormalizedUsage, calculateNormalizedUsageCost, } from './usageNormalization';
|
|
12
13
|
export type { UsageProvider, UsageSemantics, UsageNormalizationProvenance, ProviderUsageInput, AnthropicUsageInput, OpenAIUsageInput, SidekickUsageInput, NormalizedUsage, PricingProvenance, NormalizedUsageCostInput, NormalizedUsageCost, } from './usageNormalization';
|
|
13
14
|
export { estimateTextTokens, estimateSerializedTokens } from './tokenEstimation';
|
|
@@ -19,8 +20,12 @@ export type { FormatDurationMsOptions, FormatTokenCountOptions } from './formatt
|
|
|
19
20
|
export { parseMcpToolName } from './parsers/mcpToolName';
|
|
20
21
|
export type { McpToolNameParts } from './parsers/mcpToolName';
|
|
21
22
|
export { buildSessionContextSnapshot, calculateSessionContextPressure, createSessionContextProjector, } from './context/sessionContext';
|
|
23
|
+
export { ACCOUNT_PROVIDER_IDS, MODEL_PROVIDER_IDS, QUOTA_PROVIDER_IDS, RUNTIME_QUOTA_PROVIDER_IDS, SESSION_PROVIDER_IDS, } from './providerIds';
|
|
24
|
+
export type { AccountProviderId, ModelProviderId, QuotaProviderId, RuntimeQuotaProviderId, SessionProviderId, } from './providerIds';
|
|
22
25
|
export type { BuildSessionContextSnapshotOptions, SessionContextCapabilities, SessionContextLayerBreakdown, SessionContextPressure, SessionContextProjector, SessionContextSnapshot, SessionContextSource, SessionContextSourceType, } from './context/sessionContext';
|
|
23
26
|
export { assistantTurnEventsFromSessionEvents, extractTurnSubagents, isAssistantTurnSubagentTool, reasoningSummary, segmentAssistantTurn, } from './turns/assistantTurn';
|
|
24
27
|
export type { AssistantTurnEvent, AssistantTurnEventType, AssistantTurnProcess, AssistantTurnProcessStep, AssistantTurnProjection, AssistantTurnSubagent, AssistantTurnSubagentStatus, AssistantTurnTimelineItem, AssistantTurnToolRef, ExtractTurnSubagentsOptions, ReasoningSummary, SegmentAssistantTurnOptions, } from './turns/assistantTurn';
|
|
25
|
-
export { parseModelId, getModelPricing, getModelInfo, calculateCost, calculateCostWithPricing, calculateCostWithProvenance, mergeCostSources, shortModelName, getModelDisplayInfo, compareModelIds, sortModelIds, formatCost, } from './modelInfo';
|
|
26
|
-
export type { ModelPricing, CostTokenUsage, CostSource, CostProvenanceInput, CostWithProvenance, ModelProvider, ParsedModelId, ModelInfo, ModelDisplayInfo, } from './modelInfo';
|
|
28
|
+
export { parseModelId, getModelPricing, resolveModelPricing, getModelInfo, calculateCost, calculateCostWithPricing, calculateCostWithProvenance, mergeCostSources, shortModelName, getModelDisplayInfo, compareModelIds, sortModelIds, formatCost, } from './modelInfo';
|
|
29
|
+
export type { ModelPricing, CostTokenUsage, CostSource, CostProvenanceInput, CostWithProvenance, ModelProvider, ParsedModelId, ModelInfo, ModelDisplayInfo, ModelPricingMatch, ModelPricingProvenance, ModelPricingSource, ResolvedModelPricing, } from './modelInfo';
|
|
30
|
+
export { exportResolvedModelCatalog, importResolvedModelCatalog, registerModelAlias, resolveModelAlias, RESOLVED_MODEL_CATALOG_SCHEMA_VERSION, } from './modelCatalog';
|
|
31
|
+
export type { ImportResolvedModelCatalogResult, ResolvedModelCatalogEntry, ResolvedModelCatalogSnapshot, } from './modelCatalog';
|
package/dist/browser.js
CHANGED
|
@@ -9,9 +9,10 @@
|
|
|
9
9
|
* For pricing hydration (LiteLLM catalog refresh), use `sidekick-shared/node`.
|
|
10
10
|
*/
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
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.segmentAssistantTurn = exports.reasoningSummary = exports.isAssistantTurnSubagentTool = exports.extractTurnSubagents = exports.assistantTurnEventsFromSessionEvents = exports.createSessionContextProjector = exports.calculateSessionContextPressure = exports.buildSessionContextSnapshot = exports.parseMcpToolName = exports.formatTokenCount = exports.formatDurationMs = exports.projectSessionTranscript = exports.estimateSerializedTokens = exports.estimateTextTokens = exports.calculateNormalizedUsageCost = exports.extractNormalizedUsage = exports.normalizeProviderUsage = exports.DEFAULT_CONTEXT_WINDOW = exports.getModelContextWindowSize = void 0;
|
|
12
|
+
exports.RESOLVED_MODEL_CATALOG_SCHEMA_VERSION = exports.resolveModelAlias = exports.registerModelAlias = exports.importResolvedModelCatalog = exports.exportResolvedModelCatalog = exports.formatCost = exports.sortModelIds = exports.compareModelIds = exports.getModelDisplayInfo = exports.shortModelName = exports.mergeCostSources = exports.calculateCostWithProvenance = exports.calculateCostWithPricing = exports.calculateCost = exports.getModelInfo = exports.resolveModelPricing = exports.getModelPricing = exports.parseModelId = exports.segmentAssistantTurn = exports.reasoningSummary = exports.isAssistantTurnSubagentTool = exports.extractTurnSubagents = exports.assistantTurnEventsFromSessionEvents = exports.SESSION_PROVIDER_IDS = exports.RUNTIME_QUOTA_PROVIDER_IDS = exports.QUOTA_PROVIDER_IDS = exports.MODEL_PROVIDER_IDS = exports.ACCOUNT_PROVIDER_IDS = exports.createSessionContextProjector = exports.calculateSessionContextPressure = exports.buildSessionContextSnapshot = exports.parseMcpToolName = exports.formatTokenCount = exports.formatDurationMs = exports.projectSessionTranscript = exports.estimateSerializedTokens = exports.estimateTextTokens = exports.calculateNormalizedUsageCost = exports.extractNormalizedUsage = exports.normalizeProviderUsage = exports.DEFAULT_CONTEXT_WINDOW = exports.resolveModelContextWindow = exports.getModelContextWindowSize = void 0;
|
|
13
13
|
var modelContext_1 = require("./modelContext");
|
|
14
14
|
Object.defineProperty(exports, "getModelContextWindowSize", { enumerable: true, get: function () { return modelContext_1.getModelContextWindowSize; } });
|
|
15
|
+
Object.defineProperty(exports, "resolveModelContextWindow", { enumerable: true, get: function () { return modelContext_1.resolveModelContextWindow; } });
|
|
15
16
|
Object.defineProperty(exports, "DEFAULT_CONTEXT_WINDOW", { enumerable: true, get: function () { return modelContext_1.DEFAULT_CONTEXT_WINDOW; } });
|
|
16
17
|
var usageNormalization_1 = require("./usageNormalization");
|
|
17
18
|
Object.defineProperty(exports, "normalizeProviderUsage", { enumerable: true, get: function () { return usageNormalization_1.normalizeProviderUsage; } });
|
|
@@ -31,6 +32,12 @@ var sessionContext_1 = require("./context/sessionContext");
|
|
|
31
32
|
Object.defineProperty(exports, "buildSessionContextSnapshot", { enumerable: true, get: function () { return sessionContext_1.buildSessionContextSnapshot; } });
|
|
32
33
|
Object.defineProperty(exports, "calculateSessionContextPressure", { enumerable: true, get: function () { return sessionContext_1.calculateSessionContextPressure; } });
|
|
33
34
|
Object.defineProperty(exports, "createSessionContextProjector", { enumerable: true, get: function () { return sessionContext_1.createSessionContextProjector; } });
|
|
35
|
+
var providerIds_1 = require("./providerIds");
|
|
36
|
+
Object.defineProperty(exports, "ACCOUNT_PROVIDER_IDS", { enumerable: true, get: function () { return providerIds_1.ACCOUNT_PROVIDER_IDS; } });
|
|
37
|
+
Object.defineProperty(exports, "MODEL_PROVIDER_IDS", { enumerable: true, get: function () { return providerIds_1.MODEL_PROVIDER_IDS; } });
|
|
38
|
+
Object.defineProperty(exports, "QUOTA_PROVIDER_IDS", { enumerable: true, get: function () { return providerIds_1.QUOTA_PROVIDER_IDS; } });
|
|
39
|
+
Object.defineProperty(exports, "RUNTIME_QUOTA_PROVIDER_IDS", { enumerable: true, get: function () { return providerIds_1.RUNTIME_QUOTA_PROVIDER_IDS; } });
|
|
40
|
+
Object.defineProperty(exports, "SESSION_PROVIDER_IDS", { enumerable: true, get: function () { return providerIds_1.SESSION_PROVIDER_IDS; } });
|
|
34
41
|
var assistantTurn_1 = require("./turns/assistantTurn");
|
|
35
42
|
Object.defineProperty(exports, "assistantTurnEventsFromSessionEvents", { enumerable: true, get: function () { return assistantTurn_1.assistantTurnEventsFromSessionEvents; } });
|
|
36
43
|
Object.defineProperty(exports, "extractTurnSubagents", { enumerable: true, get: function () { return assistantTurn_1.extractTurnSubagents; } });
|
|
@@ -40,6 +47,7 @@ Object.defineProperty(exports, "segmentAssistantTurn", { enumerable: true, get:
|
|
|
40
47
|
var modelInfo_1 = require("./modelInfo");
|
|
41
48
|
Object.defineProperty(exports, "parseModelId", { enumerable: true, get: function () { return modelInfo_1.parseModelId; } });
|
|
42
49
|
Object.defineProperty(exports, "getModelPricing", { enumerable: true, get: function () { return modelInfo_1.getModelPricing; } });
|
|
50
|
+
Object.defineProperty(exports, "resolveModelPricing", { enumerable: true, get: function () { return modelInfo_1.resolveModelPricing; } });
|
|
43
51
|
Object.defineProperty(exports, "getModelInfo", { enumerable: true, get: function () { return modelInfo_1.getModelInfo; } });
|
|
44
52
|
Object.defineProperty(exports, "calculateCost", { enumerable: true, get: function () { return modelInfo_1.calculateCost; } });
|
|
45
53
|
Object.defineProperty(exports, "calculateCostWithPricing", { enumerable: true, get: function () { return modelInfo_1.calculateCostWithPricing; } });
|
|
@@ -50,3 +58,9 @@ Object.defineProperty(exports, "getModelDisplayInfo", { enumerable: true, get: f
|
|
|
50
58
|
Object.defineProperty(exports, "compareModelIds", { enumerable: true, get: function () { return modelInfo_1.compareModelIds; } });
|
|
51
59
|
Object.defineProperty(exports, "sortModelIds", { enumerable: true, get: function () { return modelInfo_1.sortModelIds; } });
|
|
52
60
|
Object.defineProperty(exports, "formatCost", { enumerable: true, get: function () { return modelInfo_1.formatCost; } });
|
|
61
|
+
var modelCatalog_1 = require("./modelCatalog");
|
|
62
|
+
Object.defineProperty(exports, "exportResolvedModelCatalog", { enumerable: true, get: function () { return modelCatalog_1.exportResolvedModelCatalog; } });
|
|
63
|
+
Object.defineProperty(exports, "importResolvedModelCatalog", { enumerable: true, get: function () { return modelCatalog_1.importResolvedModelCatalog; } });
|
|
64
|
+
Object.defineProperty(exports, "registerModelAlias", { enumerable: true, get: function () { return modelCatalog_1.registerModelAlias; } });
|
|
65
|
+
Object.defineProperty(exports, "resolveModelAlias", { enumerable: true, get: function () { return modelCatalog_1.resolveModelAlias; } });
|
|
66
|
+
Object.defineProperty(exports, "RESOLVED_MODEL_CATALOG_SCHEMA_VERSION", { enumerable: true, get: function () { return modelCatalog_1.RESOLVED_MODEL_CATALOG_SCHEMA_VERSION; } });
|
|
@@ -6,6 +6,7 @@ import type { SavedAccountProfile } from './accountRegistry';
|
|
|
6
6
|
import type { Disposable } from './quotaPoller';
|
|
7
7
|
import type { QuotaState } from './quota';
|
|
8
8
|
import type { ProviderQuotaState } from './providerQuota';
|
|
9
|
+
import { type AccountsChangedEvent } from './accountChanges';
|
|
9
10
|
type CodexAccountReader = () => SavedAccountProfile | null;
|
|
10
11
|
type SnapshotReader = (providerId: 'codex', accountId: string) => QuotaState | null;
|
|
11
12
|
type SnapshotWriter = (providerId: 'codex', accountId: string, quota: QuotaState) => void;
|
|
@@ -27,6 +28,7 @@ export interface CodexQuotaWatcherOptions {
|
|
|
27
28
|
workspaceId?: string;
|
|
28
29
|
/** Override the history append function (used by tests). Default: `appendQuotaHistorySample`. */
|
|
29
30
|
appendHistorySample?: HistoryAppender;
|
|
31
|
+
subscribeAccountsChanged?: (listener: (event: AccountsChangedEvent) => void) => Disposable;
|
|
30
32
|
}
|
|
31
33
|
/**
|
|
32
34
|
* Watches the active Codex rollout for quota snapshots and falls back to the
|
|
@@ -46,6 +48,7 @@ export declare class CodexQuotaWatcher implements Disposable {
|
|
|
46
48
|
private readonly now;
|
|
47
49
|
private readonly workspaceId;
|
|
48
50
|
private readonly appendHistorySample;
|
|
51
|
+
private readonly subscribeAccountsChanged;
|
|
49
52
|
private readonly listeners;
|
|
50
53
|
private discoveryTimer;
|
|
51
54
|
private provider;
|
|
@@ -56,6 +59,7 @@ export declare class CodexQuotaWatcher implements Disposable {
|
|
|
56
59
|
private lastLocalScanAt;
|
|
57
60
|
private lastLocalScanState;
|
|
58
61
|
private running;
|
|
62
|
+
private accountSubscription;
|
|
59
63
|
constructor(workspacePath: string, options?: CodexQuotaWatcherOptions);
|
|
60
64
|
start(): void;
|
|
61
65
|
stop(): void;
|
|
@@ -63,12 +67,14 @@ export declare class CodexQuotaWatcher implements Disposable {
|
|
|
63
67
|
onUpdate(cb: (state: ProviderQuotaState<'codex'>) => void): Disposable;
|
|
64
68
|
onQuotaUpdate(cb: (state: ProviderQuotaState<'codex'>) => void): Disposable;
|
|
65
69
|
refresh(): void;
|
|
70
|
+
private handleAccountsChanged;
|
|
66
71
|
private refreshActiveSession;
|
|
67
72
|
private attachToSession;
|
|
68
73
|
private ingestSessionUpdate;
|
|
69
74
|
private emitCachedOrUnavailable;
|
|
70
75
|
private emitState;
|
|
71
76
|
private getProvider;
|
|
77
|
+
private safeGetActiveAccount;
|
|
72
78
|
private teardownActiveSession;
|
|
73
79
|
}
|
|
74
80
|
export {};
|
|
@@ -40,6 +40,7 @@ const codexQuota_1 = require("./codexQuota");
|
|
|
40
40
|
const quotaSnapshots_1 = require("./quotaSnapshots");
|
|
41
41
|
const quotaHistory_1 = require("./quotaHistory");
|
|
42
42
|
const codex_1 = require("./providers/codex");
|
|
43
|
+
const accountChanges_1 = require("./accountChanges");
|
|
43
44
|
const DEFAULT_DISCOVERY_POLL_INTERVAL_MS = 30_000;
|
|
44
45
|
const DEFAULT_LOCAL_SCAN_CACHE_MS = 5 * 60_000;
|
|
45
46
|
function accountEmail(account) {
|
|
@@ -86,6 +87,7 @@ class CodexQuotaWatcher {
|
|
|
86
87
|
now;
|
|
87
88
|
workspaceId;
|
|
88
89
|
appendHistorySample;
|
|
90
|
+
subscribeAccountsChanged;
|
|
89
91
|
listeners = [];
|
|
90
92
|
discoveryTimer;
|
|
91
93
|
provider = null;
|
|
@@ -96,6 +98,7 @@ class CodexQuotaWatcher {
|
|
|
96
98
|
lastLocalScanAt = Number.NEGATIVE_INFINITY;
|
|
97
99
|
lastLocalScanState = null;
|
|
98
100
|
running = false;
|
|
101
|
+
accountSubscription = null;
|
|
99
102
|
constructor(workspacePath, options = {}) {
|
|
100
103
|
this.workspacePath = workspacePath;
|
|
101
104
|
this.discoveryPollIntervalMs =
|
|
@@ -119,15 +122,14 @@ class CodexQuotaWatcher {
|
|
|
119
122
|
this.now = options.now ?? Date.now;
|
|
120
123
|
this.workspaceId = options.workspaceId;
|
|
121
124
|
this.appendHistorySample = options.appendHistorySample ?? quotaHistory_1.appendQuotaHistorySample;
|
|
125
|
+
this.subscribeAccountsChanged = options.subscribeAccountsChanged ?? accountChanges_1.onAccountsChanged;
|
|
122
126
|
}
|
|
123
127
|
start() {
|
|
124
128
|
if (this.running)
|
|
125
129
|
return;
|
|
126
130
|
this.running = true;
|
|
127
|
-
this.
|
|
128
|
-
this.
|
|
129
|
-
this.refreshActiveSession();
|
|
130
|
-
}, this.discoveryPollIntervalMs);
|
|
131
|
+
this.accountSubscription ??= this.subscribeAccountsChanged(() => this.handleAccountsChanged());
|
|
132
|
+
this.handleAccountsChanged();
|
|
131
133
|
}
|
|
132
134
|
stop() {
|
|
133
135
|
if (!this.running)
|
|
@@ -137,6 +139,8 @@ class CodexQuotaWatcher {
|
|
|
137
139
|
clearInterval(this.discoveryTimer);
|
|
138
140
|
this.discoveryTimer = undefined;
|
|
139
141
|
}
|
|
142
|
+
this.accountSubscription?.dispose();
|
|
143
|
+
this.accountSubscription = null;
|
|
140
144
|
this.teardownActiveSession();
|
|
141
145
|
}
|
|
142
146
|
dispose() {
|
|
@@ -157,21 +161,46 @@ class CodexQuotaWatcher {
|
|
|
157
161
|
return this.onUpdate(cb);
|
|
158
162
|
}
|
|
159
163
|
refresh() {
|
|
160
|
-
this.
|
|
164
|
+
this.handleAccountsChanged();
|
|
161
165
|
}
|
|
162
|
-
|
|
166
|
+
handleAccountsChanged() {
|
|
167
|
+
if (!this.running)
|
|
168
|
+
return;
|
|
169
|
+
const account = this.safeGetActiveAccount();
|
|
170
|
+
if (!account) {
|
|
171
|
+
if (this.discoveryTimer) {
|
|
172
|
+
clearInterval(this.discoveryTimer);
|
|
173
|
+
this.discoveryTimer = undefined;
|
|
174
|
+
}
|
|
175
|
+
this.teardownActiveSession();
|
|
176
|
+
this.emitState(makeUnavailableState(null, 'No Codex account configured'));
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (!this.discoveryTimer) {
|
|
180
|
+
this.discoveryTimer = setInterval(() => {
|
|
181
|
+
this.refreshActiveSession();
|
|
182
|
+
}, this.discoveryPollIntervalMs);
|
|
183
|
+
this.discoveryTimer.unref?.();
|
|
184
|
+
}
|
|
185
|
+
this.refreshActiveSession(account);
|
|
186
|
+
}
|
|
187
|
+
refreshActiveSession(account = this.safeGetActiveAccount()) {
|
|
188
|
+
if (!account) {
|
|
189
|
+
this.handleAccountsChanged();
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
163
192
|
const provider = this.getProvider();
|
|
164
193
|
const nextSessionPath = provider.findActiveSession(this.workspacePath);
|
|
165
194
|
if (!nextSessionPath) {
|
|
166
195
|
this.teardownActiveSession();
|
|
167
|
-
this.emitCachedOrUnavailable();
|
|
196
|
+
this.emitCachedOrUnavailable(account);
|
|
168
197
|
return;
|
|
169
198
|
}
|
|
170
199
|
if (nextSessionPath !== this.sessionPath || this.reader == null) {
|
|
171
200
|
this.attachToSession(nextSessionPath);
|
|
172
201
|
return;
|
|
173
202
|
}
|
|
174
|
-
this.ingestSessionUpdate('readNew');
|
|
203
|
+
this.ingestSessionUpdate('readNew', account);
|
|
175
204
|
}
|
|
176
205
|
attachToSession(nextSessionPath) {
|
|
177
206
|
this.teardownActiveSession();
|
|
@@ -189,14 +218,30 @@ class CodexQuotaWatcher {
|
|
|
189
218
|
}
|
|
190
219
|
this.refreshActiveSession();
|
|
191
220
|
});
|
|
221
|
+
if (typeof this.fileWatcher.on === 'function') {
|
|
222
|
+
this.fileWatcher.on('error', () => {
|
|
223
|
+
try {
|
|
224
|
+
this.fileWatcher?.close();
|
|
225
|
+
}
|
|
226
|
+
catch {
|
|
227
|
+
// Discovery polling remains active.
|
|
228
|
+
}
|
|
229
|
+
this.fileWatcher = null;
|
|
230
|
+
});
|
|
231
|
+
}
|
|
192
232
|
}
|
|
193
233
|
catch {
|
|
194
234
|
this.emitCachedOrUnavailable();
|
|
195
235
|
}
|
|
196
236
|
}
|
|
197
|
-
ingestSessionUpdate(mode) {
|
|
237
|
+
ingestSessionUpdate(mode, knownAccount) {
|
|
238
|
+
const account = knownAccount ?? this.safeGetActiveAccount();
|
|
239
|
+
if (!account) {
|
|
240
|
+
this.handleAccountsChanged();
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
198
243
|
if (!this.provider || !this.reader) {
|
|
199
|
-
this.emitCachedOrUnavailable();
|
|
244
|
+
this.emitCachedOrUnavailable(account);
|
|
200
245
|
return;
|
|
201
246
|
}
|
|
202
247
|
if (!this.reader.exists()) {
|
|
@@ -211,48 +256,45 @@ class CodexQuotaWatcher {
|
|
|
211
256
|
}
|
|
212
257
|
const liveQuota = (0, codexQuota_1.quotaFromCodexRateLimits)(this.provider.getLastRateLimits(), 'session');
|
|
213
258
|
if (!liveQuota) {
|
|
214
|
-
this.emitCachedOrUnavailable();
|
|
259
|
+
this.emitCachedOrUnavailable(account);
|
|
215
260
|
return;
|
|
216
261
|
}
|
|
217
|
-
const
|
|
218
|
-
const cached = account ? this.readSnapshot('codex', account.id) : null;
|
|
262
|
+
const cached = this.readSnapshot('codex', account.id);
|
|
219
263
|
const liveQuotaWithResetCredits = {
|
|
220
264
|
...liveQuota,
|
|
221
265
|
resetCredits: liveQuota.resetCredits ?? cached?.resetCredits,
|
|
222
266
|
};
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
catch {
|
|
253
|
-
// Synchronous errors swallowed for the same reason.
|
|
267
|
+
this.writeSnapshot('codex', account.id, liveQuotaWithResetCredits);
|
|
268
|
+
if (this.workspaceId) {
|
|
269
|
+
const sample = {
|
|
270
|
+
timestamp: liveQuotaWithResetCredits.capturedAt ?? new Date().toISOString(),
|
|
271
|
+
runtimeProvider: 'codex',
|
|
272
|
+
providerId: account.id,
|
|
273
|
+
workspaceId: this.workspaceId,
|
|
274
|
+
fiveHour: {
|
|
275
|
+
utilization: liveQuotaWithResetCredits.fiveHour.utilization,
|
|
276
|
+
resetsAt: liveQuotaWithResetCredits.fiveHour.resetsAt,
|
|
277
|
+
},
|
|
278
|
+
sevenDay: {
|
|
279
|
+
utilization: liveQuotaWithResetCredits.sevenDay.utilization,
|
|
280
|
+
resetsAt: liveQuotaWithResetCredits.sevenDay.resetsAt,
|
|
281
|
+
},
|
|
282
|
+
available: liveQuotaWithResetCredits.available,
|
|
283
|
+
error: liveQuotaWithResetCredits.error,
|
|
284
|
+
source: liveQuotaWithResetCredits.source,
|
|
285
|
+
stale: liveQuotaWithResetCredits.stale,
|
|
286
|
+
};
|
|
287
|
+
try {
|
|
288
|
+
const result = this.appendHistorySample(sample);
|
|
289
|
+
if (result && typeof result.catch === 'function') {
|
|
290
|
+
result.catch(() => {
|
|
291
|
+
// History append must never break the live emission path.
|
|
292
|
+
});
|
|
254
293
|
}
|
|
255
294
|
}
|
|
295
|
+
catch {
|
|
296
|
+
// Synchronous errors swallowed for the same reason.
|
|
297
|
+
}
|
|
256
298
|
}
|
|
257
299
|
this.emitState(enrichQuotaState({
|
|
258
300
|
...liveQuotaWithResetCredits,
|
|
@@ -260,8 +302,12 @@ class CodexQuotaWatcher {
|
|
|
260
302
|
providerId: 'codex',
|
|
261
303
|
}, account));
|
|
262
304
|
}
|
|
263
|
-
emitCachedOrUnavailable() {
|
|
264
|
-
const account = this.
|
|
305
|
+
emitCachedOrUnavailable(knownAccount) {
|
|
306
|
+
const account = knownAccount ?? this.safeGetActiveAccount();
|
|
307
|
+
if (!account) {
|
|
308
|
+
this.emitState(makeUnavailableState(null, 'No Codex account configured'));
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
265
311
|
const scanNow = this.now();
|
|
266
312
|
if (scanNow - this.lastLocalScanAt < this.localScanCacheMs) {
|
|
267
313
|
if (this.lastLocalScanState) {
|
|
@@ -296,7 +342,7 @@ class CodexQuotaWatcher {
|
|
|
296
342
|
localProvider?.dispose();
|
|
297
343
|
}
|
|
298
344
|
}
|
|
299
|
-
const cached =
|
|
345
|
+
const cached = this.readSnapshot('codex', account.id);
|
|
300
346
|
if (cached) {
|
|
301
347
|
this.emitState(enrichQuotaState({
|
|
302
348
|
...cached,
|
|
@@ -331,6 +377,14 @@ class CodexQuotaWatcher {
|
|
|
331
377
|
}
|
|
332
378
|
return this.provider;
|
|
333
379
|
}
|
|
380
|
+
safeGetActiveAccount() {
|
|
381
|
+
try {
|
|
382
|
+
return this.getActiveAccount();
|
|
383
|
+
}
|
|
384
|
+
catch {
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
334
388
|
teardownActiveSession() {
|
|
335
389
|
if (this.fileWatcher) {
|
|
336
390
|
this.fileWatcher.close();
|