sidekick-shared 0.27.2 → 0.27.3
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 +26 -0
- package/README.md +24 -3
- package/dist/aggregation/EventAggregator.d.ts +12 -2
- package/dist/aggregation/EventAggregator.js +49 -19
- package/dist/browser.d.ts +2 -1
- package/dist/browser.js +9 -2
- package/dist/extractors/tokenUsage.js +1 -0
- package/dist/formatters/sessionDump.d.ts +10 -2
- package/dist/formatters/sessionDump.js +45 -23
- package/dist/index.d.ts +7 -3
- package/dist/index.js +31 -10
- package/dist/node.d.ts +2 -0
- package/dist/node.js +8 -2
- package/dist/parsers/codexParser.d.ts +22 -2
- package/dist/parsers/codexParser.js +64 -5
- package/dist/parsers/subagentScanner.d.ts +9 -0
- package/dist/parsers/subagentScanner.js +45 -12
- package/dist/parsers/subagentStatsCache.d.ts +17 -0
- package/dist/parsers/subagentStatsCache.js +82 -0
- package/dist/parsers/subagentTraceParser.js +19 -10
- package/dist/providers/claudeCode.js +8 -41
- package/dist/providers/codex.js +28 -14
- package/dist/providers/codexDatabase.d.ts +16 -1
- package/dist/providers/codexDatabase.js +49 -1
- package/dist/providers/openCode.js +30 -4
- package/dist/report/htmlReportGenerator.js +33 -11
- package/dist/report/sessionReportInputs.d.ts +3 -1
- package/dist/report/sessionReportInputs.js +2 -0
- package/dist/report/types.d.ts +5 -0
- package/dist/schemas/sessionEvent.d.ts +30 -6
- package/dist/schemas/sessionEvent.js +7 -1
- package/dist/schemas/stateFile.d.ts +2 -0
- package/dist/schemas/stateFile.js +1 -0
- package/dist/sessionTokenTotals.d.ts +46 -0
- package/dist/sessionTokenTotals.js +138 -0
- package/dist/stateFile.d.ts +7 -0
- package/dist/tokenSummary.d.ts +27 -1
- package/dist/tokenSummary.js +50 -3
- package/dist/types/codex.d.ts +4 -0
- package/dist/types/sessionEvent.d.ts +22 -0
- package/dist/usage/claudeUsageDedupe.d.ts +53 -0
- package/dist/usage/claudeUsageDedupe.js +195 -0
- package/dist/usage/subagentUsage.d.ts +13 -0
- package/dist/usage/subagentUsage.js +21 -0
- package/dist/usage/usageEvents.d.ts +11 -2
- package/dist/usage/usageEvents.js +79 -8
- package/dist/watchers/eventBridge.js +5 -0
- package/dist/watchers/jsonlWatcher.d.ts +5 -0
- package/dist/watchers/jsonlWatcher.js +40 -5
- package/dist/watchers/types.d.ts +5 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3,24 +3,29 @@
|
|
|
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.
|
|
13
|
-
exports.
|
|
14
|
-
exports.
|
|
15
|
-
exports.
|
|
6
|
+
exports.importSessionHistory = exports.ACTIVE_SESSION_MTIME_THRESHOLD_MS = exports.sessionSummaryFromStats = exports.removeSessionSummary = exports.markFileImported = exports.isFileImported = exports.applySessionSummary = exports.pruneUsageCache = exports.getUsageCacheDir = exports.collectUsageEvents = exports.USAGE_CACHE_VERSION = exports.MAX_USAGE_CACHE_FILES = exports.findActiveBillingBlock = exports.computeBillingBlocks = exports.BILLING_BLOCK_DURATION_MS = exports.writeStateFile = exports.readStateFile = exports.quotaToStateFile = exports.getStateFilePath = exports.billingBlockToStateFile = exports.STATE_FILE_SCHEMA_VERSION = exports.STATE_FILE_NAME = exports.sessionFingerprintParts = exports.fingerprintString = exports.readSessionReportInputs = exports.readSessionFileStats = exports.providerContextSizeFn = exports.firstUserPrompt = exports.computeSessionFileStats = exports.isHumanPrompt = exports.humanPromptText = exports.HUMAN_CODEX_SOURCES = exports.HUMAN_CLAUDE_ENTRYPOINTS = exports.collectPromptHistory = exports.readSessionTranscript = exports.listRecentSessions = exports.projectSessionTranscript = exports.estimateSerializedTokens = exports.estimateTextTokens = exports.TOKEN_TOTAL_LABEL = exports.TOKEN_SUBAGENTS_LABEL = exports.TOKEN_SESSION_TOTAL_LABEL = exports.TOKEN_MAIN_THREAD_LABEL = exports.TOKEN_CONTEXT_LABEL = exports.sumTokenTotals = exports.summarizeTokens = exports.formatTokenBreakdown = exports.calculateNormalizedUsageCost = exports.extractNormalizedUsage = exports.normalizeProviderUsage = void 0;
|
|
7
|
+
exports.updateJsonStoreAtomicSync = exports.updateJsonStoreAtomic = exports.atomicWriteFileSync = 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.splitWatchedPath = exports.DirectoryListingCache = exports.fileFingerprintParts = exports.fileFingerprint = exports.observedSessionSourceFromProvider = exports.ObservedSessionCollector = exports.weekKey = exports.usageBucketKey = exports.summarizeUsageRows = exports.bucketUsage = void 0;
|
|
8
|
+
exports.detectSessionActivity = exports.classifySessionActivity = exports.subagentTokenTotals = exports.scanSessionSubagents = exports.readMainThreadTokenTotals = exports.combineSessionTokenTotals = exports.collectSessionTokenTotals = exports.addUsageToSubagent = exports.normalizeClaudeUsage = exports.dedupedRawClaudeUsage = exports.SYNTHETIC_MODEL = exports.ClaudeUsageDeduper = exports.readAgentMeta = exports.extractTaskInfo = exports.scanSubagentDir = exports.resolveCodexCallUsage = 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.walkRolloutFilesAsync = exports.walkRolloutFiles = exports.findCodexRolloutFile = exports.CodexProvider = exports.getOpenCodeDataDir = exports.OpenCodeProvider = exports.ClaudeCodeProvider = exports.getAllDetectedProviders = exports.detectProvider = exports._resetProviderDetectionCache = exports.getObservedActivityReason = exports.derivePendingUserRequestV1 = exports.createProviderSessionAdapterV1 = exports.createSessionProviders = exports.SESSION_PROVIDER_IDS = exports.renderHandoffUrlTemplate = exports.addNote = exports.decisionFingerprint = exports.addDecision = exports.completeTask = exports.addTask = exports.withFileLockSync = void 0;
|
|
9
|
+
exports.createJsonlTail = exports.toFollowEvents = exports.resolveSessionPath = exports.createWatcher = exports.parseChangelog = exports.extractProposedPlanShared = exports.parsePlanMarkdownShared = exports.PlanExtractor = exports.segmentAssistantTurn = exports.reasoningSummary = exports.isAssistantTurnSubagentTool = exports.extractTurnSubagents = exports.assistantTurnEventsFromSessionEvents = exports.readSessionContextSnapshot = exports.createSessionContextProjector = exports.calculateSessionContextPressure = exports.buildSessionContextSnapshot = exports.composeContext = exports.FilterEngine = exports.searchSessions = exports.CodexDatabase = exports.OpenCodeDatabase = exports.discoverDebugLogs = exports.collapseDuplicates = exports.filterByLevel = exports.parseDebugLog = exports.readSessionPreviewAsync = exports.readSessionPreview = exports.listSessionPreviewsAsync = exports.listSessionPreviews = exports.readCodexHistory = exports.parseMcpToolName = exports.scanSubagentTraces = exports.findAllSessionsWithWorktrees = exports.discoverWorktreeSiblings = exports.resolveWorktreeMainRepo = exports.getAllClaudeProjectFolders = exports.decodeEncodedPath = exports.getMostRecentlyActiveSessionDir = exports.findSubdirectorySessionDirs = exports.findSessionFilesWithStats = exports.findSessionsInDirectory = exports.findAllClaudeSessions = exports.findActiveClaudeSession = exports.discoverSessionDirectory = exports.getClaudeSessionDirectory = exports.encodeClaudeWorkspacePath = exports.SESSION_ACTIVITY_STALENESS_MS = exports.SESSION_ACTIVITY_GRACE_PERIOD_MS = exports.refreshSessionActivityState = void 0;
|
|
10
|
+
exports.parseTranscriptFromEvents = exports.parseTranscript = exports.generateHtmlReport = exports.formatCompactionLedger = exports.calculateCompactionLedger = exports.describeCostProvenance = exports.classifyCostProvenance = exports.calculateCodeImpact = 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.MAX_SNAPSHOT_FILES = exports.pruneSnapshots = 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.parseLocalDateKey = exports.formatTokenCount = exports.formatLocalDateKey = exports.formatDurationMs = exports.addLocalDays = void 0;
|
|
11
|
+
exports.syncLiveAccountState = exports.getLastSwitchPath = exports.readLastSwitch = exports.resolveClaudeLoginCommand = exports.listAllAccounts = exports.getLastSwitch = exports.undoLastSwitch = exports.switchAccountAsync = exports.switchAccount = exports.spawnAccountLogin = exports.finalizeAccountLoginAsync = exports.finalizeAccountLogin = exports.getAccountLoginStatusAsync = exports.getAccountLoginStatus = exports.beginAccountLogin = exports.isMultiAccountEnabled = exports.resolveActiveClaudeAccount = exports.getActiveAccount = exports.listAccounts = exports.removeAccount = exports.reconcileClaudeAuthState = exports.applyActiveClaudeToLiveHome = exports.resolveActiveClaudeHome = exports.cleanupAbandonedClaudeLogins = exports.syncClaudeLiveState = exports.switchToAccountAsync = exports.switchToAccount = exports.addCurrentAccount = exports.readActiveClaudeAccount = exports.writeAccountRegistry = exports.readAccountRegistry = exports.ensureDefaultAccounts = exports.codexIdentitiesMatch = exports.readCodexAccessTokenExpiry = exports.readCodexLastRefresh = exports.readCodexAuthIdentity = exports.parseCodexAuthJson = exports.CLAUDE_REFRESH_TOKEN_LIFETIME_ESTIMATE_MS = exports.CLAUDE_ACCESS_TOKEN_LIFETIME_MS = exports.resolveClaudeRefreshExpiry = exports.isNewerClaudeCredential = exports.claudeCredentialFreshness = exports.parseClaudeCredentialBlob = exports.readClaudeMaxAccessTokenSync = exports.readClaudeMaxCredentialsRaw = exports.readClaudeMaxCredentials = exports.deleteStoredCredentials = exports.writeActiveCredentials = exports.readActiveCredentials = exports.openInBrowser = void 0;
|
|
12
|
+
exports.prepareCodexAccount = exports.getCodexExecutionEnv = exports.resolveSidekickCodexHome = exports.resolveActiveCodexAccount = exports.getActiveCodexAccount = exports.listCodexAccounts = exports.getSystemCodexHome = exports.getCodexMonitoringHomes = exports.getCodexProfileHome = exports.getCodexProfilesDir = exports.readLiveClaudeIdentity = exports.readClaudeProfileIdentity = exports.isClaudeProfileAuthenticated = exports.CLAUDE_SECURESTORAGE_CONFIG_DIR_ENV = exports.buildClaudeChildEnv = exports.claudeKeychainAccountName = exports.claudeKeychainService = exports.claudeKeychainSuffix = exports.getClaudeConfigPath = exports.getDefaultClaudeHome = exports.getLiveClaudeHome = exports.getClaudeProfileHome = exports.getClaudeProfilesDir = exports.onAccountsChanged = exports.getActiveAccountStatus = exports.ACCOUNT_PROVIDER_IDS = exports.removeSavedAccountProfile = exports.replaceSavedAccountProfiles = exports.setActiveSavedAccount = exports.upsertSavedAccountProfile = exports.getActiveSavedAccount = exports.listSavedAccountProfiles = exports.writeSavedAccountRegistry = exports.readSavedAccountRegistry = exports.getAccountsDir = exports.ACCOUNT_CONSUMER_REACHABILITY = exports.describeAccountConsumer = exports.detectRunningAccountConsumersSync = exports.detectRunningAccountConsumers = exports.findRunningProcessesSync = exports.findRunningProcesses = exports.keepAliveCommand = exports.refreshInactiveAccounts = exports.getAccountLaunchEnv = exports.getHealthSidecarPath = exports.readHealthSidecar = exports.listAccountsWithHealth = exports.getAccountHealth = exports.cleanupAbandonedLogins = exports.syncLiveAccountStateSync = void 0;
|
|
13
|
+
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.quotaFromStatuslinePayload = exports.parseClaudeStatuslinePayload = exports.evaluateQuotaThresholds = exports.describeQuotaThresholdAlert = exports.DEFAULT_QUOTA_THRESHOLDS = exports.QUOTA_FRESH_MAX_AGE_MS = exports.QUOTA_AGING_MAX_AGE_MS = exports.formatQuotaAge = exports.classifyQuotaFreshness = exports.resolveQuota = exports.writeQuotaSnapshot = exports.readQuotaSnapshot = exports.QuotaPoller = exports.describeQuotaFailure = exports.withQuotaProjections = exports.projectQuotaWindow = exports.fetchQuota = exports.SEVEN_DAY_WINDOW_MS = exports.QUOTA_PROVIDER_IDS = exports.FIVE_HOUR_WINDOW_MS = exports.AutoSwitchController = exports.decideAutoSwitch = exports.DEFAULT_AUTO_SWITCH_CONFIG = exports.removeLauncher = exports.writeLauncher = exports.CODEX_KEYRING_FIX_HINT = exports.getCodexCredentialStoreMode = exports.cleanupAbandonedCodexLogins = exports.syncCodexLiveState = exports.removeCodexAccount = exports.switchToCodexAccountAsync = exports.switchToCodexAccount = exports.finalizeCodexAccountAsync = exports.finalizeCodexAccount = exports.prepareCodexAccountAsync = void 0;
|
|
14
|
+
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.RESOLVED_MODEL_CATALOG_SCHEMA_VERSION = exports.resolveModelAlias = exports.registerModelAlias = exports.importResolvedModelCatalog = exports.exportResolvedModelCatalog = exports.MODEL_PROVIDER_IDS = 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.DEFAULT_CONTEXT_WINDOW = exports.resolveModelContextWindow = exports.getModelContextWindowSize = exports.selectStatuslineAccount = exports.formatStatusline = exports.estimateTimeToQuota = exports.BurnRateCalculator = exports.RUNTIME_QUOTA_PROVIDER_IDS = exports.MultiProviderQuotaService = exports.resolveZaiQuota = void 0;
|
|
15
|
+
exports.runDoctor = exports.getSessionDiagnostics = exports.formatHealthReport = exports.toLegacyProviderStatus = 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 = exports.codexResetCreditSchema = exports.quotaSourceSchema = exports.quotaProviderIdSchema = exports.quotaFailureKindSchema = exports.quotaStateSchema = exports.quotaWindowSchema = exports.extractSessionEvents = exports.permissionModeSchema = exports.sessionEventSchema = exports.sessionMessageSchema = exports.messageUsageSchema = void 0;
|
|
16
|
+
exports.fetchProviderServiceStatus = exports.diagnoseProviderFailure = exports.mergeFailingToolWindows = exports.failingToolTrend = exports.FAILING_TOOL_TREND_ARROWS = exports.scopePeakHoursToSessionProvider = exports.PEAK_HOURS_DESCRIPTION = exports.PEAK_HOURS_CACHE_MS = exports.isClaudeCodeSessionProvider = exports.getScheduledPeakHoursState = exports.fetchPeakHoursStatus = exports.DEFAULT_PEAK_HOURS_TIMEOUT_MS = exports.createPeakHoursNotApplicableState = exports._resetPeakHoursCache = void 0;
|
|
16
17
|
var usageNormalization_1 = require("./usageNormalization");
|
|
17
18
|
Object.defineProperty(exports, "normalizeProviderUsage", { enumerable: true, get: function () { return usageNormalization_1.normalizeProviderUsage; } });
|
|
18
19
|
Object.defineProperty(exports, "extractNormalizedUsage", { enumerable: true, get: function () { return usageNormalization_1.extractNormalizedUsage; } });
|
|
19
20
|
Object.defineProperty(exports, "calculateNormalizedUsageCost", { enumerable: true, get: function () { return usageNormalization_1.calculateNormalizedUsageCost; } });
|
|
20
21
|
var tokenSummary_1 = require("./tokenSummary");
|
|
22
|
+
Object.defineProperty(exports, "formatTokenBreakdown", { enumerable: true, get: function () { return tokenSummary_1.formatTokenBreakdown; } });
|
|
21
23
|
Object.defineProperty(exports, "summarizeTokens", { enumerable: true, get: function () { return tokenSummary_1.summarizeTokens; } });
|
|
22
24
|
Object.defineProperty(exports, "sumTokenTotals", { enumerable: true, get: function () { return tokenSummary_1.sumTokenTotals; } });
|
|
23
25
|
Object.defineProperty(exports, "TOKEN_CONTEXT_LABEL", { enumerable: true, get: function () { return tokenSummary_1.TOKEN_CONTEXT_LABEL; } });
|
|
26
|
+
Object.defineProperty(exports, "TOKEN_MAIN_THREAD_LABEL", { enumerable: true, get: function () { return tokenSummary_1.TOKEN_MAIN_THREAD_LABEL; } });
|
|
27
|
+
Object.defineProperty(exports, "TOKEN_SESSION_TOTAL_LABEL", { enumerable: true, get: function () { return tokenSummary_1.TOKEN_SESSION_TOTAL_LABEL; } });
|
|
28
|
+
Object.defineProperty(exports, "TOKEN_SUBAGENTS_LABEL", { enumerable: true, get: function () { return tokenSummary_1.TOKEN_SUBAGENTS_LABEL; } });
|
|
24
29
|
Object.defineProperty(exports, "TOKEN_TOTAL_LABEL", { enumerable: true, get: function () { return tokenSummary_1.TOKEN_TOTAL_LABEL; } });
|
|
25
30
|
var tokenEstimation_1 = require("./tokenEstimation");
|
|
26
31
|
Object.defineProperty(exports, "estimateTextTokens", { enumerable: true, get: function () { return tokenEstimation_1.estimateTextTokens; } });
|
|
@@ -197,10 +202,26 @@ Object.defineProperty(exports, "CodexRolloutParser", { enumerable: true, get: fu
|
|
|
197
202
|
Object.defineProperty(exports, "extractPatchFilePaths", { enumerable: true, get: function () { return codexParser_1.extractPatchFilePaths; } });
|
|
198
203
|
Object.defineProperty(exports, "normalizeCodexToolName", { enumerable: true, get: function () { return codexParser_1.normalizeCodexToolName; } });
|
|
199
204
|
Object.defineProperty(exports, "normalizeCodexToolInput", { enumerable: true, get: function () { return codexParser_1.normalizeCodexToolInput; } });
|
|
205
|
+
Object.defineProperty(exports, "resolveCodexCallUsage", { enumerable: true, get: function () { return codexParser_1.resolveCodexCallUsage; } });
|
|
200
206
|
// Parsers — Subagent scanning
|
|
201
207
|
var subagentScanner_1 = require("./parsers/subagentScanner");
|
|
202
208
|
Object.defineProperty(exports, "scanSubagentDir", { enumerable: true, get: function () { return subagentScanner_1.scanSubagentDir; } });
|
|
203
209
|
Object.defineProperty(exports, "extractTaskInfo", { enumerable: true, get: function () { return subagentScanner_1.extractTaskInfo; } });
|
|
210
|
+
Object.defineProperty(exports, "readAgentMeta", { enumerable: true, get: function () { return subagentScanner_1.readAgentMeta; } });
|
|
211
|
+
// Usage — split-line dedupe, subagent tokens, session totals
|
|
212
|
+
var claudeUsageDedupe_1 = require("./usage/claudeUsageDedupe");
|
|
213
|
+
Object.defineProperty(exports, "ClaudeUsageDeduper", { enumerable: true, get: function () { return claudeUsageDedupe_1.ClaudeUsageDeduper; } });
|
|
214
|
+
Object.defineProperty(exports, "SYNTHETIC_MODEL", { enumerable: true, get: function () { return claudeUsageDedupe_1.SYNTHETIC_MODEL; } });
|
|
215
|
+
Object.defineProperty(exports, "dedupedRawClaudeUsage", { enumerable: true, get: function () { return claudeUsageDedupe_1.dedupedRawClaudeUsage; } });
|
|
216
|
+
Object.defineProperty(exports, "normalizeClaudeUsage", { enumerable: true, get: function () { return claudeUsageDedupe_1.normalizeClaudeUsage; } });
|
|
217
|
+
var subagentUsage_1 = require("./usage/subagentUsage");
|
|
218
|
+
Object.defineProperty(exports, "addUsageToSubagent", { enumerable: true, get: function () { return subagentUsage_1.addUsageToSubagent; } });
|
|
219
|
+
var sessionTokenTotals_1 = require("./sessionTokenTotals");
|
|
220
|
+
Object.defineProperty(exports, "collectSessionTokenTotals", { enumerable: true, get: function () { return sessionTokenTotals_1.collectSessionTokenTotals; } });
|
|
221
|
+
Object.defineProperty(exports, "combineSessionTokenTotals", { enumerable: true, get: function () { return sessionTokenTotals_1.combineSessionTokenTotals; } });
|
|
222
|
+
Object.defineProperty(exports, "readMainThreadTokenTotals", { enumerable: true, get: function () { return sessionTokenTotals_1.readMainThreadTokenTotals; } });
|
|
223
|
+
Object.defineProperty(exports, "scanSessionSubagents", { enumerable: true, get: function () { return sessionTokenTotals_1.scanSessionSubagents; } });
|
|
224
|
+
Object.defineProperty(exports, "subagentTokenTotals", { enumerable: true, get: function () { return sessionTokenTotals_1.subagentTokenTotals; } });
|
|
204
225
|
// Parsers — Session activity detection
|
|
205
226
|
var sessionActivityDetector_1 = require("./parsers/sessionActivityDetector");
|
|
206
227
|
Object.defineProperty(exports, "classifySessionActivity", { enumerable: true, get: function () { return sessionActivityDetector_1.classifySessionActivity; } });
|
package/dist/node.d.ts
CHANGED
|
@@ -25,6 +25,8 @@ export { BILLING_BLOCK_DURATION_MS, computeBillingBlocks, findActiveBillingBlock
|
|
|
25
25
|
export type { BillingBlock, BillingBlockInput, BillingBlockModelUsage, BillingBlockTokens, ComputeBillingBlocksOptions, } from './usage/billingBlocks';
|
|
26
26
|
export { MAX_USAGE_CACHE_FILES, USAGE_CACHE_VERSION, collectUsageEvents, getUsageCacheDir, pruneUsageCache, } from './usage/usageEvents';
|
|
27
27
|
export type { CollectUsageEventsOptions, CollectUsageEventsResult, UsageEventRecord, UsageSessionRecord, } from './usage/usageEvents';
|
|
28
|
+
export { collectSessionTokenTotals, combineSessionTokenTotals, readMainThreadTokenTotals, scanSessionSubagents, subagentTokenTotals, } from './sessionTokenTotals';
|
|
29
|
+
export type { SessionTokenTotals, SubagentTokenSummary } from './sessionTokenTotals';
|
|
28
30
|
export { applySessionSummary, isFileImported, markFileImported, removeSessionSummary, sessionSummaryFromStats, } from './historicalStore';
|
|
29
31
|
export type { ApplySessionSummaryOptions, SessionSummaryFromStatsOptions } from './historicalStore';
|
|
30
32
|
export { ACTIVE_SESSION_MTIME_THRESHOLD_MS, importSessionHistory, } from './usage/importSessionHistory';
|
package/dist/node.js
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* for browser bundles — use `sidekick-shared/browser` there.
|
|
8
8
|
*/
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
exports.
|
|
11
|
-
exports.fetchProviderServiceStatus = exports.splitWatchedPath = exports.DirectoryListingCache = exports.fileFingerprintParts = exports.fileFingerprint = exports.observedSessionSourceFromProvider = exports.ObservedSessionCollector = exports.readSessionPreviewAsync = exports.readSessionPreview = exports.listSessionPreviewsAsync = exports.listSessionPreviews = exports.readCodexHistory = void 0;
|
|
10
|
+
exports.summarizeUsageRows = exports.bucketUsage = exports.importSessionHistory = exports.ACTIVE_SESSION_MTIME_THRESHOLD_MS = exports.sessionSummaryFromStats = exports.removeSessionSummary = exports.markFileImported = exports.isFileImported = exports.applySessionSummary = exports.subagentTokenTotals = exports.scanSessionSubagents = exports.readMainThreadTokenTotals = exports.combineSessionTokenTotals = exports.collectSessionTokenTotals = exports.pruneUsageCache = exports.getUsageCacheDir = exports.collectUsageEvents = exports.USAGE_CACHE_VERSION = exports.MAX_USAGE_CACHE_FILES = exports.findActiveBillingBlock = exports.computeBillingBlocks = exports.BILLING_BLOCK_DURATION_MS = exports.writeStateFile = exports.readStateFile = exports.quotaToStateFile = exports.getStateFilePath = exports.billingBlockToStateFile = exports.STATE_FILE_SCHEMA_VERSION = exports.STATE_FILE_NAME = exports.sessionFingerprintParts = exports.fingerprintString = exports.readSessionReportInputs = exports.readSessionFileStats = exports.providerContextSizeFn = exports.firstUserPrompt = exports.computeSessionFileStats = exports.isHumanPrompt = exports.humanPromptText = exports.HUMAN_CODEX_SOURCES = exports.HUMAN_CLAUDE_ENTRYPOINTS = exports.collectPromptHistory = exports.readSessionTranscript = exports.listRecentSessions = exports.getObservedContextWindowPath = exports.recordObservedContextWindow = exports.loadObservedContextWindows = exports.LITELLM_CATALOG_URL = exports.normalizeLiteLlmContextWindows = exports.normalizeLiteLlmCatalog = exports.hydratePricingCatalog = void 0;
|
|
11
|
+
exports.fetchProviderServiceStatus = exports.splitWatchedPath = exports.DirectoryListingCache = exports.fileFingerprintParts = exports.fileFingerprint = exports.observedSessionSourceFromProvider = exports.ObservedSessionCollector = exports.readSessionPreviewAsync = exports.readSessionPreview = exports.listSessionPreviewsAsync = exports.listSessionPreviews = exports.readCodexHistory = exports.walkRolloutFilesAsync = exports.walkRolloutFiles = exports.findCodexRolloutFile = exports.weekKey = exports.usageBucketKey = void 0;
|
|
12
12
|
var pricingCatalog_1 = require("./pricingCatalog");
|
|
13
13
|
Object.defineProperty(exports, "hydratePricingCatalog", { enumerable: true, get: function () { return pricingCatalog_1.hydratePricingCatalog; } });
|
|
14
14
|
Object.defineProperty(exports, "normalizeLiteLlmCatalog", { enumerable: true, get: function () { return pricingCatalog_1.normalizeLiteLlmCatalog; } });
|
|
@@ -56,6 +56,12 @@ Object.defineProperty(exports, "USAGE_CACHE_VERSION", { enumerable: true, get: f
|
|
|
56
56
|
Object.defineProperty(exports, "collectUsageEvents", { enumerable: true, get: function () { return usageEvents_1.collectUsageEvents; } });
|
|
57
57
|
Object.defineProperty(exports, "getUsageCacheDir", { enumerable: true, get: function () { return usageEvents_1.getUsageCacheDir; } });
|
|
58
58
|
Object.defineProperty(exports, "pruneUsageCache", { enumerable: true, get: function () { return usageEvents_1.pruneUsageCache; } });
|
|
59
|
+
var sessionTokenTotals_1 = require("./sessionTokenTotals");
|
|
60
|
+
Object.defineProperty(exports, "collectSessionTokenTotals", { enumerable: true, get: function () { return sessionTokenTotals_1.collectSessionTokenTotals; } });
|
|
61
|
+
Object.defineProperty(exports, "combineSessionTokenTotals", { enumerable: true, get: function () { return sessionTokenTotals_1.combineSessionTokenTotals; } });
|
|
62
|
+
Object.defineProperty(exports, "readMainThreadTokenTotals", { enumerable: true, get: function () { return sessionTokenTotals_1.readMainThreadTokenTotals; } });
|
|
63
|
+
Object.defineProperty(exports, "scanSessionSubagents", { enumerable: true, get: function () { return sessionTokenTotals_1.scanSessionSubagents; } });
|
|
64
|
+
Object.defineProperty(exports, "subagentTokenTotals", { enumerable: true, get: function () { return sessionTokenTotals_1.subagentTokenTotals; } });
|
|
59
65
|
var historicalStore_1 = require("./historicalStore");
|
|
60
66
|
Object.defineProperty(exports, "applySessionSummary", { enumerable: true, get: function () { return historicalStore_1.applySessionSummary; } });
|
|
61
67
|
Object.defineProperty(exports, "isFileImported", { enumerable: true, get: function () { return historicalStore_1.isFileImported; } });
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* Unlike OpenCode's stateless converter, this is stateful because:
|
|
5
5
|
* - exec_command_begin/end and mcp_tool_call_begin/end need pairing by call_id
|
|
6
6
|
* - turn_context sets the current model for subsequent events
|
|
7
|
-
* - token_count
|
|
7
|
+
* - token_count repeats its cumulative total on duplicate events, so each
|
|
8
|
+
* call is counted only when `total_token_usage` changes
|
|
8
9
|
*
|
|
9
10
|
* Moved from sidekick-vscode to sidekick-shared for reuse across packages.
|
|
10
11
|
*
|
|
@@ -12,6 +13,23 @@
|
|
|
12
13
|
*/
|
|
13
14
|
import type { SessionEvent } from '../types/sessionEvent';
|
|
14
15
|
import type { CodexRolloutLine, CodexSessionMeta, CodexTokenUsage, CodexRateLimits } from '../types/codex';
|
|
16
|
+
/**
|
|
17
|
+
* Resolve the usage of the single call a Codex `token_count` event reports.
|
|
18
|
+
*
|
|
19
|
+
* Codex emits `token_count` repeatedly — rate-limit refreshes and resumes
|
|
20
|
+
* resend the same `info` — so summing `last_token_usage` per event counts
|
|
21
|
+
* those calls again. `total_token_usage` is cumulative, which makes an
|
|
22
|
+
* unchanged total the reliable duplicate signal. When `last_token_usage` is
|
|
23
|
+
* missing, the call is the growth of the cumulative total (never the total
|
|
24
|
+
* itself). A total that drops means the counter restarted; re-baseline on it.
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolveCodexCallUsage(info: {
|
|
27
|
+
last_token_usage?: CodexTokenUsage | null;
|
|
28
|
+
total_token_usage?: CodexTokenUsage | null;
|
|
29
|
+
} | null | undefined, previousTotal: CodexTokenUsage | null): {
|
|
30
|
+
usage: CodexTokenUsage | null;
|
|
31
|
+
total: CodexTokenUsage | null;
|
|
32
|
+
};
|
|
15
33
|
/**
|
|
16
34
|
* Codex-specific tool name normalization.
|
|
17
35
|
* Extends the shared normalizeToolName with Codex-specific mappings.
|
|
@@ -33,7 +51,7 @@ export declare function extractPatchFilePaths(input: string): string[];
|
|
|
33
51
|
* - Session metadata (from session_meta)
|
|
34
52
|
* - Current model (from turn_context)
|
|
35
53
|
* - Pending exec commands and MCP tool calls (begin/end pairing)
|
|
36
|
-
* - Previous token
|
|
54
|
+
* - Previous cumulative token total (to skip duplicate token_count events)
|
|
37
55
|
*/
|
|
38
56
|
export declare class CodexRolloutParser {
|
|
39
57
|
private sessionMeta;
|
|
@@ -41,6 +59,8 @@ export declare class CodexRolloutParser {
|
|
|
41
59
|
private pendingExecCommands;
|
|
42
60
|
private pendingMcpToolCalls;
|
|
43
61
|
private lastTokenUsage;
|
|
62
|
+
/** Cumulative `total_token_usage` from the previous token_count event. */
|
|
63
|
+
private prevTotalUsage;
|
|
44
64
|
private modelContextWindow;
|
|
45
65
|
private lastRateLimits;
|
|
46
66
|
private hasAggregateRateLimits;
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
* Unlike OpenCode's stateless converter, this is stateful because:
|
|
6
6
|
* - exec_command_begin/end and mcp_tool_call_begin/end need pairing by call_id
|
|
7
7
|
* - turn_context sets the current model for subsequent events
|
|
8
|
-
* - token_count
|
|
8
|
+
* - token_count repeats its cumulative total on duplicate events, so each
|
|
9
|
+
* call is counted only when `total_token_usage` changes
|
|
9
10
|
*
|
|
10
11
|
* Moved from sidekick-vscode to sidekick-shared for reuse across packages.
|
|
11
12
|
*
|
|
@@ -13,6 +14,7 @@
|
|
|
13
14
|
*/
|
|
14
15
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
16
|
exports.CodexRolloutParser = void 0;
|
|
17
|
+
exports.resolveCodexCallUsage = resolveCodexCallUsage;
|
|
16
18
|
exports.normalizeCodexToolName = normalizeCodexToolName;
|
|
17
19
|
exports.normalizeCodexToolInput = normalizeCodexToolInput;
|
|
18
20
|
exports.extractPatchFilePaths = extractPatchFilePaths;
|
|
@@ -50,6 +52,58 @@ function normalizeRateLimits(rateLimits) {
|
|
|
50
52
|
: undefined,
|
|
51
53
|
};
|
|
52
54
|
}
|
|
55
|
+
const CODEX_USAGE_FIELDS = [
|
|
56
|
+
'input_tokens',
|
|
57
|
+
'cached_input_tokens',
|
|
58
|
+
'output_tokens',
|
|
59
|
+
'reasoning_output_tokens',
|
|
60
|
+
'total_tokens',
|
|
61
|
+
];
|
|
62
|
+
function usageField(usage, field) {
|
|
63
|
+
const value = usage[field];
|
|
64
|
+
return typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : 0;
|
|
65
|
+
}
|
|
66
|
+
function codexTotalOf(usage) {
|
|
67
|
+
return (usageField(usage, 'total_tokens') ||
|
|
68
|
+
usageField(usage, 'input_tokens') + usageField(usage, 'output_tokens'));
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Resolve the usage of the single call a Codex `token_count` event reports.
|
|
72
|
+
*
|
|
73
|
+
* Codex emits `token_count` repeatedly — rate-limit refreshes and resumes
|
|
74
|
+
* resend the same `info` — so summing `last_token_usage` per event counts
|
|
75
|
+
* those calls again. `total_token_usage` is cumulative, which makes an
|
|
76
|
+
* unchanged total the reliable duplicate signal. When `last_token_usage` is
|
|
77
|
+
* missing, the call is the growth of the cumulative total (never the total
|
|
78
|
+
* itself). A total that drops means the counter restarted; re-baseline on it.
|
|
79
|
+
*/
|
|
80
|
+
function resolveCodexCallUsage(info, previousTotal) {
|
|
81
|
+
if (!info)
|
|
82
|
+
return { usage: null, total: previousTotal };
|
|
83
|
+
const last = info.last_token_usage ?? null;
|
|
84
|
+
const total = info.total_token_usage ?? null;
|
|
85
|
+
if (total && previousTotal) {
|
|
86
|
+
const unchanged = CODEX_USAGE_FIELDS.every((field) => usageField(total, field) === usageField(previousTotal, field));
|
|
87
|
+
if (unchanged)
|
|
88
|
+
return { usage: null, total };
|
|
89
|
+
if (codexTotalOf(total) < codexTotalOf(previousTotal)) {
|
|
90
|
+
return { usage: last ?? total, total };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (last)
|
|
94
|
+
return { usage: last, total: total ?? previousTotal };
|
|
95
|
+
if (!total)
|
|
96
|
+
return { usage: null, total: previousTotal };
|
|
97
|
+
const delta = {};
|
|
98
|
+
let any = false;
|
|
99
|
+
for (const field of CODEX_USAGE_FIELDS) {
|
|
100
|
+
const value = Math.max(0, usageField(total, field) - (previousTotal ? usageField(previousTotal, field) : 0));
|
|
101
|
+
delta[field] = value;
|
|
102
|
+
if (value > 0)
|
|
103
|
+
any = true;
|
|
104
|
+
}
|
|
105
|
+
return { usage: any ? delta : null, total };
|
|
106
|
+
}
|
|
53
107
|
/**
|
|
54
108
|
* Codex-specific tool name normalization.
|
|
55
109
|
* Extends the shared normalizeToolName with Codex-specific mappings.
|
|
@@ -129,7 +183,7 @@ function extractPatchFilePaths(input) {
|
|
|
129
183
|
* - Session metadata (from session_meta)
|
|
130
184
|
* - Current model (from turn_context)
|
|
131
185
|
* - Pending exec commands and MCP tool calls (begin/end pairing)
|
|
132
|
-
* - Previous token
|
|
186
|
+
* - Previous cumulative token total (to skip duplicate token_count events)
|
|
133
187
|
*/
|
|
134
188
|
class CodexRolloutParser {
|
|
135
189
|
sessionMeta = null;
|
|
@@ -137,6 +191,8 @@ class CodexRolloutParser {
|
|
|
137
191
|
pendingExecCommands = new Map();
|
|
138
192
|
pendingMcpToolCalls = new Map();
|
|
139
193
|
lastTokenUsage = null;
|
|
194
|
+
/** Cumulative `total_token_usage` from the previous token_count event. */
|
|
195
|
+
prevTotalUsage = null;
|
|
140
196
|
modelContextWindow = null;
|
|
141
197
|
lastRateLimits = null;
|
|
142
198
|
hasAggregateRateLimits = false;
|
|
@@ -189,6 +245,7 @@ class CodexRolloutParser {
|
|
|
189
245
|
this.pendingExecCommands.clear();
|
|
190
246
|
this.pendingMcpToolCalls.clear();
|
|
191
247
|
this.lastTokenUsage = null;
|
|
248
|
+
this.prevTotalUsage = null;
|
|
192
249
|
this.modelContextWindow = null;
|
|
193
250
|
this.lastRateLimits = null;
|
|
194
251
|
this.hasAggregateRateLimits = false;
|
|
@@ -526,9 +583,11 @@ class CodexRolloutParser {
|
|
|
526
583
|
this.lastRateLimits = e.rate_limits;
|
|
527
584
|
}
|
|
528
585
|
}
|
|
529
|
-
// Usage data is nested under info
|
|
530
|
-
|
|
531
|
-
|
|
586
|
+
// Usage data is nested under info (info can be null). Codex repeats an
|
|
587
|
+
// unchanged cumulative total on duplicate events; count each call once.
|
|
588
|
+
const resolved = resolveCodexCallUsage(e.info, this.prevTotalUsage);
|
|
589
|
+
this.prevTotalUsage = resolved.total;
|
|
590
|
+
return this.handleTokenCount(timestamp, resolved.usage, e.rate_limits);
|
|
532
591
|
}
|
|
533
592
|
// agent_message and user_message are suppressed — they duplicate
|
|
534
593
|
// response_item/message events which carry richer metadata (id, content parts, role).
|
|
@@ -8,6 +8,15 @@
|
|
|
8
8
|
* @module parsers/subagentScanner
|
|
9
9
|
*/
|
|
10
10
|
import type { SubagentStats, TaskState } from '../types/sessionEvent';
|
|
11
|
+
/**
|
|
12
|
+
* Reads `agent-<id>.meta.json` (written by Claude Code next to the transcript)
|
|
13
|
+
* for the spawn's agent type and description. Missing or malformed files
|
|
14
|
+
* yield an empty object.
|
|
15
|
+
*/
|
|
16
|
+
export declare function readAgentMeta(agentFilePath: string): {
|
|
17
|
+
agentType?: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
};
|
|
11
20
|
/**
|
|
12
21
|
* Scans subagent directory for agent JSONL files and extracts tool calls.
|
|
13
22
|
*
|
|
@@ -42,16 +42,42 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
42
42
|
};
|
|
43
43
|
})();
|
|
44
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.readAgentMeta = readAgentMeta;
|
|
45
46
|
exports.scanSubagentDir = scanSubagentDir;
|
|
46
47
|
exports.handleTaskUpdate = handleTaskUpdate;
|
|
47
48
|
exports.extractTaskInfo = extractTaskInfo;
|
|
48
49
|
const fs = __importStar(require("fs"));
|
|
49
50
|
const path = __importStar(require("path"));
|
|
51
|
+
const claudeUsageDedupe_1 = require("../usage/claudeUsageDedupe");
|
|
52
|
+
const subagentUsage_1 = require("../usage/subagentUsage");
|
|
53
|
+
const subagentStatsCache_1 = require("./subagentStatsCache");
|
|
50
54
|
/**
|
|
51
55
|
* Pattern for matching subagent JSONL files.
|
|
52
56
|
* Files are named like: agent-<hash>.jsonl
|
|
53
57
|
*/
|
|
54
58
|
const AGENT_FILE_PATTERN = /^agent-(.+)\.jsonl$/;
|
|
59
|
+
/**
|
|
60
|
+
* Reads `agent-<id>.meta.json` (written by Claude Code next to the transcript)
|
|
61
|
+
* for the spawn's agent type and description. Missing or malformed files
|
|
62
|
+
* yield an empty object.
|
|
63
|
+
*/
|
|
64
|
+
function readAgentMeta(agentFilePath) {
|
|
65
|
+
try {
|
|
66
|
+
const metaPath = agentFilePath.replace(/\.jsonl$/, '.meta.json');
|
|
67
|
+
const parsed = JSON.parse(fs.readFileSync(metaPath, 'utf-8'));
|
|
68
|
+
return {
|
|
69
|
+
...(typeof parsed.agentType === 'string' && parsed.agentType
|
|
70
|
+
? { agentType: parsed.agentType }
|
|
71
|
+
: {}),
|
|
72
|
+
...(typeof parsed.description === 'string' && parsed.description
|
|
73
|
+
? { description: parsed.description }
|
|
74
|
+
: {}),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return {};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
55
81
|
/** Task-related tool names */
|
|
56
82
|
const TASK_TOOLS = ['TaskCreate', 'TaskUpdate', 'TaskGet', 'TaskList'];
|
|
57
83
|
/**
|
|
@@ -118,7 +144,7 @@ function scanSubagentDir(sessionDir, sessionId, logger, skipFiles = new Set()) {
|
|
|
118
144
|
}
|
|
119
145
|
const agentId = match[1];
|
|
120
146
|
const filePath = path.join(subagentsDir, file);
|
|
121
|
-
const agentStats = parseAgentFile(filePath, agentId, log);
|
|
147
|
+
const agentStats = (0, subagentStatsCache_1.cachedSubagentStats)(filePath, () => parseAgentFile(filePath, agentId, log));
|
|
122
148
|
if (agentStats) {
|
|
123
149
|
log(`[SubagentScanner] Agent ${agentId}: ${agentStats.toolCalls.length} tool calls`);
|
|
124
150
|
results.push(agentStats);
|
|
@@ -150,8 +176,8 @@ function parseAgentFile(filePath, agentId, log) {
|
|
|
150
176
|
const toolCalls = [];
|
|
151
177
|
let agentType;
|
|
152
178
|
let description;
|
|
153
|
-
|
|
154
|
-
|
|
179
|
+
const tokens = { agentId, toolCalls: [], inputTokens: 0, outputTokens: 0 };
|
|
180
|
+
const usageDeduper = new claudeUsageDedupe_1.ClaudeUsageDeduper();
|
|
155
181
|
let startTime;
|
|
156
182
|
let endTime;
|
|
157
183
|
// Task tracking state
|
|
@@ -168,12 +194,11 @@ function parseAgentFile(filePath, agentId, log) {
|
|
|
168
194
|
if (!startTime)
|
|
169
195
|
startTime = eventTimestamp;
|
|
170
196
|
endTime = eventTimestamp;
|
|
171
|
-
// Extract token usage from assistant messages
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
197
|
+
// Extract token usage from assistant messages. Split lines of one
|
|
198
|
+
// response repeat its usage, so count each response once.
|
|
199
|
+
const usage = (0, claudeUsageDedupe_1.dedupedRawClaudeUsage)(event, usageDeduper);
|
|
200
|
+
if (usage)
|
|
201
|
+
(0, subagentUsage_1.addUsageToSubagent)(tokens, usage);
|
|
177
202
|
// Extract agent type and description from Task tool invocation
|
|
178
203
|
// This appears in the parent session, but we can also look for it
|
|
179
204
|
// in the first system message or context
|
|
@@ -269,8 +294,12 @@ function parseAgentFile(filePath, agentId, log) {
|
|
|
269
294
|
// Skip malformed lines
|
|
270
295
|
}
|
|
271
296
|
}
|
|
297
|
+
// Claude Code writes the spawn's type and description beside the transcript.
|
|
298
|
+
const meta = readAgentMeta(filePath);
|
|
299
|
+
agentType = meta.agentType ?? agentType;
|
|
300
|
+
description = meta.description ?? description;
|
|
272
301
|
// If we found any tool calls, return the stats
|
|
273
|
-
if (toolCalls.length > 0 || agentType || description ||
|
|
302
|
+
if (toolCalls.length > 0 || agentType || description || (tokens.totalTokens ?? 0) > 0) {
|
|
274
303
|
const durationMs = startTime && endTime ? endTime.getTime() - startTime.getTime() : undefined;
|
|
275
304
|
return {
|
|
276
305
|
agentId,
|
|
@@ -278,8 +307,12 @@ function parseAgentFile(filePath, agentId, log) {
|
|
|
278
307
|
description,
|
|
279
308
|
toolCalls,
|
|
280
309
|
taskState: taskState.tasks.size > 0 ? taskState : undefined,
|
|
281
|
-
inputTokens,
|
|
282
|
-
outputTokens,
|
|
310
|
+
inputTokens: tokens.inputTokens,
|
|
311
|
+
outputTokens: tokens.outputTokens,
|
|
312
|
+
cacheReadTokens: tokens.cacheReadTokens ?? 0,
|
|
313
|
+
cacheWriteTokens: tokens.cacheWriteTokens ?? 0,
|
|
314
|
+
reasoningTokens: tokens.reasoningTokens ?? 0,
|
|
315
|
+
totalTokens: tokens.totalTokens ?? 0,
|
|
283
316
|
startTime,
|
|
284
317
|
endTime,
|
|
285
318
|
durationMs,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memoizes per-transcript subagent stats by file size and mtime.
|
|
3
|
+
*
|
|
4
|
+
* Dashboards rescan a session's subagents on a timer, and one parent can own
|
|
5
|
+
* a hundred subagent transcripts of several MB each. An unchanged transcript
|
|
6
|
+
* now costs one `stat` instead of a full parse. Callers treat the returned
|
|
7
|
+
* stats as read-only.
|
|
8
|
+
*
|
|
9
|
+
* Node-only: stats files.
|
|
10
|
+
*
|
|
11
|
+
* @module parsers/subagentStatsCache
|
|
12
|
+
*/
|
|
13
|
+
import type { SubagentStats } from '../types/sessionEvent';
|
|
14
|
+
/** Stats for one subagent transcript, parsed again only when the file changed. */
|
|
15
|
+
export declare function cachedSubagentStats(filePath: string, compute: () => SubagentStats | null): SubagentStats | null;
|
|
16
|
+
/** @internal Test hook. */
|
|
17
|
+
export declare function clearSubagentStatsCache(): void;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Memoizes per-transcript subagent stats by file size and mtime.
|
|
4
|
+
*
|
|
5
|
+
* Dashboards rescan a session's subagents on a timer, and one parent can own
|
|
6
|
+
* a hundred subagent transcripts of several MB each. An unchanged transcript
|
|
7
|
+
* now costs one `stat` instead of a full parse. Callers treat the returned
|
|
8
|
+
* stats as read-only.
|
|
9
|
+
*
|
|
10
|
+
* Node-only: stats files.
|
|
11
|
+
*
|
|
12
|
+
* @module parsers/subagentStatsCache
|
|
13
|
+
*/
|
|
14
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
17
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
18
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
19
|
+
}
|
|
20
|
+
Object.defineProperty(o, k2, desc);
|
|
21
|
+
}) : (function(o, m, k, k2) {
|
|
22
|
+
if (k2 === undefined) k2 = k;
|
|
23
|
+
o[k2] = m[k];
|
|
24
|
+
}));
|
|
25
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
26
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
27
|
+
}) : function(o, v) {
|
|
28
|
+
o["default"] = v;
|
|
29
|
+
});
|
|
30
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
31
|
+
var ownKeys = function(o) {
|
|
32
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
33
|
+
var ar = [];
|
|
34
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
35
|
+
return ar;
|
|
36
|
+
};
|
|
37
|
+
return ownKeys(o);
|
|
38
|
+
};
|
|
39
|
+
return function (mod) {
|
|
40
|
+
if (mod && mod.__esModule) return mod;
|
|
41
|
+
var result = {};
|
|
42
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
43
|
+
__setModuleDefault(result, mod);
|
|
44
|
+
return result;
|
|
45
|
+
};
|
|
46
|
+
})();
|
|
47
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
+
exports.cachedSubagentStats = cachedSubagentStats;
|
|
49
|
+
exports.clearSubagentStatsCache = clearSubagentStatsCache;
|
|
50
|
+
const fs = __importStar(require("fs"));
|
|
51
|
+
const MAX_ENTRIES = 1024;
|
|
52
|
+
const cache = new Map();
|
|
53
|
+
/** Stats for one subagent transcript, parsed again only when the file changed. */
|
|
54
|
+
function cachedSubagentStats(filePath, compute) {
|
|
55
|
+
let stat;
|
|
56
|
+
try {
|
|
57
|
+
stat = fs.statSync(filePath);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
cache.delete(filePath);
|
|
61
|
+
return compute();
|
|
62
|
+
}
|
|
63
|
+
const hit = cache.get(filePath);
|
|
64
|
+
if (hit && hit.size === stat.size && hit.mtimeMs === stat.mtimeMs) {
|
|
65
|
+
cache.delete(filePath);
|
|
66
|
+
cache.set(filePath, hit);
|
|
67
|
+
return hit.stats;
|
|
68
|
+
}
|
|
69
|
+
const stats = compute();
|
|
70
|
+
cache.delete(filePath);
|
|
71
|
+
cache.set(filePath, { size: stat.size, mtimeMs: stat.mtimeMs, stats });
|
|
72
|
+
if (cache.size > MAX_ENTRIES) {
|
|
73
|
+
const oldest = cache.keys().next().value;
|
|
74
|
+
if (oldest !== undefined)
|
|
75
|
+
cache.delete(oldest);
|
|
76
|
+
}
|
|
77
|
+
return stats;
|
|
78
|
+
}
|
|
79
|
+
/** @internal Test hook. */
|
|
80
|
+
function clearSubagentStatsCache() {
|
|
81
|
+
cache.clear();
|
|
82
|
+
}
|