@xortex/xcode 3.0.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/LICENSE +21 -0
- package/README.md +171 -0
- package/bin/xcode +127 -0
- package/bin/xcode-test +84 -0
- package/bin/xcode.cmd +31 -0
- package/constants/apiLimits.ts +94 -0
- package/constants/betas.ts +52 -0
- package/constants/common.ts +33 -0
- package/constants/cyberRiskInstruction.ts +24 -0
- package/constants/errorIds.ts +15 -0
- package/constants/figures.ts +45 -0
- package/constants/files.ts +156 -0
- package/constants/github-app.ts +144 -0
- package/constants/keys.ts +11 -0
- package/constants/messages.ts +1 -0
- package/constants/oauth.ts +234 -0
- package/constants/outputStyles.ts +216 -0
- package/constants/product.ts +76 -0
- package/constants/prompts.ts +939 -0
- package/constants/spinnerVerbs.ts +204 -0
- package/constants/system.ts +95 -0
- package/constants/systemPromptSections.ts +68 -0
- package/constants/toolLimits.ts +56 -0
- package/constants/tools.ts +112 -0
- package/constants/turnCompletionVerbs.ts +12 -0
- package/constants/xml.ts +86 -0
- package/entrypoints/agentSdkTypes.ts +443 -0
- package/entrypoints/cli.tsx +307 -0
- package/entrypoints/init.ts +340 -0
- package/entrypoints/mcp.ts +196 -0
- package/entrypoints/sandboxTypes.ts +156 -0
- package/entrypoints/sdk/controlSchemas.ts +663 -0
- package/entrypoints/sdk/coreSchemas.ts +1889 -0
- package/entrypoints/sdk/coreTypes.generated.ts +2 -0
- package/entrypoints/sdk/coreTypes.ts +62 -0
- package/entrypoints/sdk/runtimeTypes.ts +140 -0
- package/entrypoints/sdk/sdkUtilityTypes.ts +3 -0
- package/entrypoints/sdk/toolTypes.ts +90 -0
- package/main.tsx +4686 -0
- package/package.json +120 -0
- package/services/AgentSummary/agentSummary.ts +179 -0
- package/services/MagicDocs/magicDocs.ts +254 -0
- package/services/MagicDocs/prompts.ts +127 -0
- package/services/PromptSuggestion/promptSuggestion.ts +523 -0
- package/services/PromptSuggestion/speculation.ts +991 -0
- package/services/SessionMemory/prompts.ts +324 -0
- package/services/SessionMemory/sessionMemory.ts +495 -0
- package/services/SessionMemory/sessionMemoryUtils.ts +207 -0
- package/services/analytics/config.ts +38 -0
- package/services/analytics/datadog.ts +307 -0
- package/services/analytics/firstPartyEventLogger.ts +449 -0
- package/services/analytics/firstPartyEventLoggingExporter.ts +806 -0
- package/services/analytics/growthbook.ts +1155 -0
- package/services/analytics/index.ts +173 -0
- package/services/analytics/metadata.ts +973 -0
- package/services/analytics/sink.ts +114 -0
- package/services/analytics/sinkKillswitch.ts +25 -0
- package/services/api/adminRequests.ts +119 -0
- package/services/api/bootstrap.ts +141 -0
- package/services/api/claude.ts +3422 -0
- package/services/api/client.ts +406 -0
- package/services/api/dumpPrompts.ts +226 -0
- package/services/api/emptyUsage.ts +22 -0
- package/services/api/errorUtils.ts +260 -0
- package/services/api/errors.ts +1207 -0
- package/services/api/filesApi.ts +748 -0
- package/services/api/firstTokenDate.ts +60 -0
- package/services/api/gemini.ts +359 -0
- package/services/api/geminiAdapter.ts +123 -0
- package/services/api/geminiClient.ts +291 -0
- package/services/api/grove.ts +357 -0
- package/services/api/logging.ts +788 -0
- package/services/api/metricsOptOut.ts +159 -0
- package/services/api/openRouterClient.ts +453 -0
- package/services/api/overageCreditGrant.ts +137 -0
- package/services/api/promptCacheBreakDetection.ts +727 -0
- package/services/api/referral.ts +281 -0
- package/services/api/sessionIngress.ts +514 -0
- package/services/api/ultrareviewQuota.ts +38 -0
- package/services/api/usage.ts +63 -0
- package/services/api/withRetry.ts +822 -0
- package/services/autoDream/autoDream.ts +324 -0
- package/services/autoDream/config.ts +21 -0
- package/services/autoDream/consolidationLock.ts +140 -0
- package/services/autoDream/consolidationPrompt.ts +65 -0
- package/services/awaySummary.ts +74 -0
- package/services/claudeAiLimits.ts +515 -0
- package/services/claudeAiLimitsHook.ts +23 -0
- package/services/compact/apiMicrocompact.ts +153 -0
- package/services/compact/autoCompact.ts +351 -0
- package/services/compact/compact.ts +1705 -0
- package/services/compact/compactWarningHook.ts +16 -0
- package/services/compact/compactWarningState.ts +18 -0
- package/services/compact/grouping.ts +63 -0
- package/services/compact/microCompact.ts +530 -0
- package/services/compact/postCompactCleanup.ts +77 -0
- package/services/compact/prompt.ts +374 -0
- package/services/compact/sessionMemoryCompact.ts +630 -0
- package/services/compact/timeBasedMCConfig.ts +43 -0
- package/services/diagnosticTracking.ts +397 -0
- package/services/extractMemories/extractMemories.ts +517 -0
- package/services/extractMemories/prompts.ts +154 -0
- package/services/internalLogging.ts +90 -0
- package/services/lsp/LSPClient.ts +447 -0
- package/services/lsp/LSPDiagnosticRegistry.ts +386 -0
- package/services/lsp/LSPServerInstance.ts +511 -0
- package/services/lsp/LSPServerManager.ts +420 -0
- package/services/lsp/config.ts +79 -0
- package/services/lsp/manager.ts +289 -0
- package/services/lsp/passiveFeedback.ts +328 -0
- package/services/mcp/InProcessTransport.ts +63 -0
- package/services/mcp/MCPConnectionManager.tsx +73 -0
- package/services/mcp/SdkControlTransport.ts +136 -0
- package/services/mcp/auth.ts +2465 -0
- package/services/mcp/channelAllowlist.ts +76 -0
- package/services/mcp/channelNotification.ts +316 -0
- package/services/mcp/channelPermissions.ts +240 -0
- package/services/mcp/claudeai.ts +164 -0
- package/services/mcp/client.ts +3348 -0
- package/services/mcp/config.ts +1578 -0
- package/services/mcp/elicitationHandler.ts +313 -0
- package/services/mcp/envExpansion.ts +38 -0
- package/services/mcp/headersHelper.ts +138 -0
- package/services/mcp/mcpStringUtils.ts +106 -0
- package/services/mcp/normalization.ts +23 -0
- package/services/mcp/oauthPort.ts +78 -0
- package/services/mcp/officialRegistry.ts +72 -0
- package/services/mcp/types.ts +258 -0
- package/services/mcp/useManageMCPConnections.ts +1141 -0
- package/services/mcp/utils.ts +575 -0
- package/services/mcp/vscodeSdkMcp.ts +112 -0
- package/services/mcp/xaa.ts +511 -0
- package/services/mcp/xaaIdpLogin.ts +487 -0
- package/services/mcpServerApproval.tsx +41 -0
- package/services/mockRateLimits.ts +882 -0
- package/services/notifier.ts +156 -0
- package/services/oauth/auth-code-listener.ts +211 -0
- package/services/oauth/client.ts +566 -0
- package/services/oauth/crypto.ts +23 -0
- package/services/oauth/getOauthProfile.ts +53 -0
- package/services/oauth/index.ts +198 -0
- package/services/plugins/PluginInstallationManager.ts +184 -0
- package/services/plugins/pluginCliCommands.ts +344 -0
- package/services/plugins/pluginOperations.ts +1088 -0
- package/services/policyLimits/index.ts +663 -0
- package/services/policyLimits/types.ts +27 -0
- package/services/preventSleep.ts +165 -0
- package/services/rateLimitMessages.ts +344 -0
- package/services/rateLimitMocking.ts +144 -0
- package/services/remoteManagedSettings/index.ts +638 -0
- package/services/remoteManagedSettings/securityCheck.tsx +74 -0
- package/services/remoteManagedSettings/syncCache.ts +112 -0
- package/services/remoteManagedSettings/syncCacheState.ts +96 -0
- package/services/remoteManagedSettings/types.ts +31 -0
- package/services/settingsSync/index.ts +581 -0
- package/services/settingsSync/types.ts +67 -0
- package/services/teamMemorySync/index.ts +1256 -0
- package/services/teamMemorySync/secretScanner.ts +324 -0
- package/services/teamMemorySync/teamMemSecretGuard.ts +44 -0
- package/services/teamMemorySync/types.ts +156 -0
- package/services/teamMemorySync/watcher.ts +387 -0
- package/services/tips/tipHistory.ts +17 -0
- package/services/tips/tipRegistry.ts +686 -0
- package/services/tips/tipScheduler.ts +58 -0
- package/services/tokenEstimation.ts +495 -0
- package/services/toolUseSummary/toolUseSummaryGenerator.ts +112 -0
- package/services/tools/StreamingToolExecutor.ts +530 -0
- package/services/tools/toolExecution.ts +1745 -0
- package/services/tools/toolHooks.ts +650 -0
- package/services/tools/toolOrchestration.ts +188 -0
- package/services/vcr.ts +406 -0
- package/services/voice.ts +525 -0
- package/services/voiceKeyterms.ts +106 -0
- package/services/voiceStreamSTT.ts +544 -0
- package/tools/AgentTool/AgentTool.tsx +1398 -0
- package/tools/AgentTool/UI.tsx +872 -0
- package/tools/AgentTool/agentColorManager.ts +66 -0
- package/tools/AgentTool/agentDisplay.ts +104 -0
- package/tools/AgentTool/agentMemory.ts +177 -0
- package/tools/AgentTool/agentMemorySnapshot.ts +197 -0
- package/tools/AgentTool/agentToolUtils.ts +686 -0
- package/tools/AgentTool/built-in/claudeCodeGuideAgent.ts +205 -0
- package/tools/AgentTool/built-in/exploreAgent.ts +83 -0
- package/tools/AgentTool/built-in/generalPurposeAgent.ts +34 -0
- package/tools/AgentTool/built-in/planAgent.ts +92 -0
- package/tools/AgentTool/built-in/statuslineSetup.ts +144 -0
- package/tools/AgentTool/built-in/verificationAgent.ts +152 -0
- package/tools/AgentTool/builtInAgents.ts +72 -0
- package/tools/AgentTool/constants.ts +12 -0
- package/tools/AgentTool/forkSubagent.ts +210 -0
- package/tools/AgentTool/loadAgentsDir.ts +755 -0
- package/tools/AgentTool/prompt.ts +287 -0
- package/tools/AgentTool/resumeAgent.ts +265 -0
- package/tools/AgentTool/runAgent.ts +973 -0
- package/tools/AskUserQuestionTool/AskUserQuestionTool.tsx +266 -0
- package/tools/AskUserQuestionTool/prompt.ts +44 -0
- package/tools/BashTool/BashTool.tsx +1144 -0
- package/tools/BashTool/BashToolResultMessage.tsx +191 -0
- package/tools/BashTool/UI.tsx +185 -0
- package/tools/BashTool/bashCommandHelpers.ts +265 -0
- package/tools/BashTool/bashPermissions.ts +2621 -0
- package/tools/BashTool/bashSecurity.ts +2592 -0
- package/tools/BashTool/commandSemantics.ts +140 -0
- package/tools/BashTool/commentLabel.ts +13 -0
- package/tools/BashTool/destructiveCommandWarning.ts +102 -0
- package/tools/BashTool/modeValidation.ts +115 -0
- package/tools/BashTool/pathValidation.ts +1303 -0
- package/tools/BashTool/prompt.ts +369 -0
- package/tools/BashTool/readOnlyValidation.ts +1990 -0
- package/tools/BashTool/sedEditParser.ts +322 -0
- package/tools/BashTool/sedValidation.ts +684 -0
- package/tools/BashTool/shouldUseSandbox.ts +153 -0
- package/tools/BashTool/toolName.ts +2 -0
- package/tools/BashTool/utils.ts +223 -0
- package/tools/BriefTool/BriefTool.ts +204 -0
- package/tools/BriefTool/UI.tsx +101 -0
- package/tools/BriefTool/attachments.ts +110 -0
- package/tools/BriefTool/prompt.ts +22 -0
- package/tools/BriefTool/upload.ts +174 -0
- package/tools/ConfigTool/ConfigTool.ts +467 -0
- package/tools/ConfigTool/UI.tsx +38 -0
- package/tools/ConfigTool/constants.ts +1 -0
- package/tools/ConfigTool/prompt.ts +93 -0
- package/tools/ConfigTool/supportedSettings.ts +211 -0
- package/tools/EnterPlanModeTool/EnterPlanModeTool.ts +126 -0
- package/tools/EnterPlanModeTool/UI.tsx +33 -0
- package/tools/EnterPlanModeTool/constants.ts +1 -0
- package/tools/EnterPlanModeTool/prompt.ts +170 -0
- package/tools/EnterWorktreeTool/EnterWorktreeTool.ts +127 -0
- package/tools/EnterWorktreeTool/UI.tsx +20 -0
- package/tools/EnterWorktreeTool/constants.ts +1 -0
- package/tools/EnterWorktreeTool/prompt.ts +30 -0
- package/tools/ExitPlanModeTool/ExitPlanModeV2Tool.ts +493 -0
- package/tools/ExitPlanModeTool/UI.tsx +82 -0
- package/tools/ExitPlanModeTool/constants.ts +2 -0
- package/tools/ExitPlanModeTool/prompt.ts +29 -0
- package/tools/ExitWorktreeTool/ExitWorktreeTool.ts +329 -0
- package/tools/ExitWorktreeTool/UI.tsx +25 -0
- package/tools/ExitWorktreeTool/constants.ts +1 -0
- package/tools/ExitWorktreeTool/prompt.ts +32 -0
- package/tools/FileEditTool/FileEditTool.ts +625 -0
- package/tools/FileEditTool/UI.tsx +289 -0
- package/tools/FileEditTool/constants.ts +11 -0
- package/tools/FileEditTool/prompt.ts +28 -0
- package/tools/FileEditTool/types.ts +85 -0
- package/tools/FileEditTool/utils.ts +775 -0
- package/tools/FileReadTool/FileReadTool.ts +1183 -0
- package/tools/FileReadTool/UI.tsx +185 -0
- package/tools/FileReadTool/imageProcessor.ts +94 -0
- package/tools/FileReadTool/limits.ts +92 -0
- package/tools/FileReadTool/prompt.ts +49 -0
- package/tools/FileWriteTool/FileWriteTool.ts +434 -0
- package/tools/FileWriteTool/UI.tsx +405 -0
- package/tools/FileWriteTool/prompt.ts +18 -0
- package/tools/GlobTool/GlobTool.ts +198 -0
- package/tools/GlobTool/UI.tsx +63 -0
- package/tools/GlobTool/prompt.ts +7 -0
- package/tools/GrepTool/GrepTool.ts +577 -0
- package/tools/GrepTool/UI.tsx +201 -0
- package/tools/GrepTool/prompt.ts +18 -0
- package/tools/LSPTool/LSPTool.ts +860 -0
- package/tools/LSPTool/UI.tsx +228 -0
- package/tools/LSPTool/formatters.ts +592 -0
- package/tools/LSPTool/prompt.ts +21 -0
- package/tools/LSPTool/schemas.ts +215 -0
- package/tools/LSPTool/symbolContext.ts +90 -0
- package/tools/ListMcpResourcesTool/ListMcpResourcesTool.ts +123 -0
- package/tools/ListMcpResourcesTool/UI.tsx +29 -0
- package/tools/ListMcpResourcesTool/prompt.ts +20 -0
- package/tools/MCPTool/MCPTool.ts +77 -0
- package/tools/MCPTool/UI.tsx +403 -0
- package/tools/MCPTool/classifyForCollapse.ts +604 -0
- package/tools/MCPTool/prompt.ts +3 -0
- package/tools/McpAuthTool/McpAuthTool.ts +215 -0
- package/tools/NotebookEditTool/NotebookEditTool.ts +490 -0
- package/tools/NotebookEditTool/UI.tsx +93 -0
- package/tools/NotebookEditTool/constants.ts +2 -0
- package/tools/NotebookEditTool/prompt.ts +3 -0
- package/tools/PowerShellTool/PowerShellTool.tsx +1001 -0
- package/tools/PowerShellTool/UI.tsx +131 -0
- package/tools/PowerShellTool/clmTypes.ts +211 -0
- package/tools/PowerShellTool/commandSemantics.ts +142 -0
- package/tools/PowerShellTool/commonParameters.ts +30 -0
- package/tools/PowerShellTool/destructiveCommandWarning.ts +109 -0
- package/tools/PowerShellTool/gitSafety.ts +176 -0
- package/tools/PowerShellTool/modeValidation.ts +404 -0
- package/tools/PowerShellTool/pathValidation.ts +2049 -0
- package/tools/PowerShellTool/powershellPermissions.ts +1648 -0
- package/tools/PowerShellTool/powershellSecurity.ts +1090 -0
- package/tools/PowerShellTool/prompt.ts +145 -0
- package/tools/PowerShellTool/readOnlyValidation.ts +1823 -0
- package/tools/PowerShellTool/toolName.ts +2 -0
- package/tools/REPLTool/constants.ts +46 -0
- package/tools/REPLTool/primitiveTools.ts +39 -0
- package/tools/ReadMcpResourceTool/ReadMcpResourceTool.ts +158 -0
- package/tools/ReadMcpResourceTool/UI.tsx +37 -0
- package/tools/ReadMcpResourceTool/prompt.ts +16 -0
- package/tools/RemoteTriggerTool/RemoteTriggerTool.ts +161 -0
- package/tools/RemoteTriggerTool/UI.tsx +17 -0
- package/tools/RemoteTriggerTool/prompt.ts +15 -0
- package/tools/ScheduleCronTool/CronCreateTool.ts +157 -0
- package/tools/ScheduleCronTool/CronDeleteTool.ts +95 -0
- package/tools/ScheduleCronTool/CronListTool.ts +97 -0
- package/tools/ScheduleCronTool/UI.tsx +60 -0
- package/tools/ScheduleCronTool/prompt.ts +135 -0
- package/tools/SendMessageTool/SendMessageTool.ts +917 -0
- package/tools/SendMessageTool/UI.tsx +31 -0
- package/tools/SendMessageTool/constants.ts +1 -0
- package/tools/SendMessageTool/prompt.ts +49 -0
- package/tools/SkillTool/SkillTool.ts +1108 -0
- package/tools/SkillTool/UI.tsx +128 -0
- package/tools/SkillTool/constants.ts +1 -0
- package/tools/SkillTool/prompt.ts +241 -0
- package/tools/SleepTool/prompt.ts +17 -0
- package/tools/SyntheticOutputTool/SyntheticOutputTool.ts +163 -0
- package/tools/TaskCreateTool/TaskCreateTool.ts +138 -0
- package/tools/TaskCreateTool/constants.ts +1 -0
- package/tools/TaskCreateTool/prompt.ts +56 -0
- package/tools/TaskGetTool/TaskGetTool.ts +128 -0
- package/tools/TaskGetTool/constants.ts +1 -0
- package/tools/TaskGetTool/prompt.ts +24 -0
- package/tools/TaskListTool/TaskListTool.ts +116 -0
- package/tools/TaskListTool/constants.ts +1 -0
- package/tools/TaskListTool/prompt.ts +49 -0
- package/tools/TaskOutputTool/TaskOutputTool.tsx +584 -0
- package/tools/TaskOutputTool/constants.ts +1 -0
- package/tools/TaskStopTool/TaskStopTool.ts +131 -0
- package/tools/TaskStopTool/UI.tsx +41 -0
- package/tools/TaskStopTool/prompt.ts +8 -0
- package/tools/TaskUpdateTool/TaskUpdateTool.ts +406 -0
- package/tools/TaskUpdateTool/constants.ts +1 -0
- package/tools/TaskUpdateTool/prompt.ts +77 -0
- package/tools/TeamCreateTool/TeamCreateTool.ts +240 -0
- package/tools/TeamCreateTool/UI.tsx +6 -0
- package/tools/TeamCreateTool/constants.ts +1 -0
- package/tools/TeamCreateTool/prompt.ts +113 -0
- package/tools/TeamDeleteTool/TeamDeleteTool.ts +139 -0
- package/tools/TeamDeleteTool/UI.tsx +20 -0
- package/tools/TeamDeleteTool/constants.ts +1 -0
- package/tools/TeamDeleteTool/prompt.ts +16 -0
- package/tools/TodoWriteTool/TodoWriteTool.ts +115 -0
- package/tools/TodoWriteTool/constants.ts +1 -0
- package/tools/TodoWriteTool/prompt.ts +184 -0
- package/tools/ToolSearchTool/ToolSearchTool.ts +471 -0
- package/tools/ToolSearchTool/constants.ts +1 -0
- package/tools/ToolSearchTool/prompt.ts +121 -0
- package/tools/TungstenTool/TungstenTool.ts +4 -0
- package/tools/WebFetchTool/UI.tsx +72 -0
- package/tools/WebFetchTool/WebFetchTool.ts +318 -0
- package/tools/WebFetchTool/preapproved.ts +166 -0
- package/tools/WebFetchTool/prompt.ts +46 -0
- package/tools/WebFetchTool/utils.ts +530 -0
- package/tools/WebSearchTool/UI.tsx +101 -0
- package/tools/WebSearchTool/WebSearchTool.ts +435 -0
- package/tools/WebSearchTool/prompt.ts +34 -0
- package/tools/WorkflowTool/constants.ts +2 -0
- package/tools/XMemIngestTool/XMemIngestTool.ts +140 -0
- package/tools/XMemIngestTool/prompt.ts +13 -0
- package/tools/XMemRetrieveTool/XMemRetrieveTool.ts +177 -0
- package/tools/XMemRetrieveTool/prompt.ts +16 -0
- package/tools/XMemSearchTool/XMemSearchTool.ts +172 -0
- package/tools/XMemSearchTool/prompt.ts +11 -0
- package/tools/shared/gitOperationTracking.ts +277 -0
- package/tools/shared/spawnMultiAgent.ts +1093 -0
- package/tools/testing/TestingPermissionTool.tsx +74 -0
- package/tools/utils.ts +40 -0
- package/utils/CircularBuffer.ts +84 -0
- package/utils/Cursor.ts +1530 -0
- package/utils/QueryGuard.ts +121 -0
- package/utils/Shell.ts +474 -0
- package/utils/ShellCommand.ts +465 -0
- package/utils/abortController.ts +99 -0
- package/utils/activityManager.ts +164 -0
- package/utils/advisor.ts +145 -0
- package/utils/agentContext.ts +178 -0
- package/utils/agentId.ts +99 -0
- package/utils/agentSwarmsEnabled.ts +44 -0
- package/utils/agenticSessionSearch.ts +307 -0
- package/utils/analyzeContext.ts +1382 -0
- package/utils/ansiToPng.ts +334 -0
- package/utils/ansiToSvg.ts +272 -0
- package/utils/api.ts +718 -0
- package/utils/apiPreconnect.ts +71 -0
- package/utils/appleTerminalBackup.ts +124 -0
- package/utils/argumentSubstitution.ts +145 -0
- package/utils/array.ts +13 -0
- package/utils/asciicast.ts +239 -0
- package/utils/attachments.ts +4091 -0
- package/utils/attribution.ts +393 -0
- package/utils/auth.ts +2002 -0
- package/utils/authFileDescriptor.ts +196 -0
- package/utils/authPortable.ts +19 -0
- package/utils/autoModeDenials.ts +26 -0
- package/utils/autoRunIssue.tsx +122 -0
- package/utils/autoUpdater.ts +561 -0
- package/utils/aws.ts +74 -0
- package/utils/awsAuthStatusManager.ts +81 -0
- package/utils/axios.ts +8 -0
- package/utils/background/remote/preconditions.ts +235 -0
- package/utils/background/remote/remoteSession.ts +98 -0
- package/utils/backgroundHousekeeping.ts +94 -0
- package/utils/bash/ParsedCommand.ts +318 -0
- package/utils/bash/ShellSnapshot.ts +582 -0
- package/utils/bash/ast.ts +2679 -0
- package/utils/bash/bashParser.ts +4436 -0
- package/utils/bash/bashPipeCommand.ts +294 -0
- package/utils/bash/commands.ts +1339 -0
- package/utils/bash/heredoc.ts +733 -0
- package/utils/bash/parser.ts +230 -0
- package/utils/bash/prefix.ts +204 -0
- package/utils/bash/registry.ts +53 -0
- package/utils/bash/shellCompletion.ts +259 -0
- package/utils/bash/shellPrefix.ts +28 -0
- package/utils/bash/shellQuote.ts +304 -0
- package/utils/bash/shellQuoting.ts +128 -0
- package/utils/bash/specs/alias.ts +14 -0
- package/utils/bash/specs/index.ts +18 -0
- package/utils/bash/specs/nohup.ts +13 -0
- package/utils/bash/specs/pyright.ts +91 -0
- package/utils/bash/specs/sleep.ts +13 -0
- package/utils/bash/specs/srun.ts +31 -0
- package/utils/bash/specs/time.ts +13 -0
- package/utils/bash/specs/timeout.ts +20 -0
- package/utils/bash/treeSitterAnalysis.ts +506 -0
- package/utils/betas.ts +434 -0
- package/utils/billing.ts +78 -0
- package/utils/binaryCheck.ts +53 -0
- package/utils/browser.ts +68 -0
- package/utils/bufferedWriter.ts +100 -0
- package/utils/bundledMode.ts +22 -0
- package/utils/caCerts.ts +115 -0
- package/utils/caCertsConfig.ts +88 -0
- package/utils/cachePaths.ts +38 -0
- package/utils/classifierApprovals.ts +88 -0
- package/utils/classifierApprovalsHook.ts +17 -0
- package/utils/claudeCodeHints.ts +193 -0
- package/utils/claudeDesktop.ts +152 -0
- package/utils/claudeInChrome/chromeNativeHost.ts +527 -0
- package/utils/claudeInChrome/common.ts +540 -0
- package/utils/claudeInChrome/mcpServer.ts +292 -0
- package/utils/claudeInChrome/prompt.ts +83 -0
- package/utils/claudeInChrome/setup.ts +400 -0
- package/utils/claudeInChrome/setupPortable.ts +233 -0
- package/utils/claudeInChrome/toolRendering.tsx +262 -0
- package/utils/claudemd.ts +1479 -0
- package/utils/cleanup.ts +602 -0
- package/utils/cleanupRegistry.ts +25 -0
- package/utils/cliArgs.ts +60 -0
- package/utils/cliHighlight.ts +54 -0
- package/utils/codeIndexing.ts +206 -0
- package/utils/collapseBackgroundBashNotifications.ts +84 -0
- package/utils/collapseHookSummaries.ts +59 -0
- package/utils/collapseReadSearch.ts +1109 -0
- package/utils/collapseTeammateShutdowns.ts +55 -0
- package/utils/color-diff-mock.ts +27 -0
- package/utils/combinedAbortSignal.ts +47 -0
- package/utils/commandLifecycle.ts +21 -0
- package/utils/commitAttribution.ts +961 -0
- package/utils/completionCache.ts +166 -0
- package/utils/computerUse/appNames.ts +196 -0
- package/utils/computerUse/cleanup.ts +86 -0
- package/utils/computerUse/common.ts +61 -0
- package/utils/computerUse/computerUseLock.ts +215 -0
- package/utils/computerUse/drainRunLoop.ts +79 -0
- package/utils/computerUse/escHotkey.ts +54 -0
- package/utils/computerUse/executor.ts +658 -0
- package/utils/computerUse/gates.ts +72 -0
- package/utils/computerUse/hostAdapter.ts +69 -0
- package/utils/computerUse/inputLoader.ts +30 -0
- package/utils/computerUse/mcpServer.ts +106 -0
- package/utils/computerUse/setup.ts +53 -0
- package/utils/computerUse/swiftLoader.ts +23 -0
- package/utils/computerUse/toolRendering.tsx +125 -0
- package/utils/computerUse/wrapper.tsx +336 -0
- package/utils/concurrentSessions.ts +204 -0
- package/utils/config.ts +1817 -0
- package/utils/configConstants.ts +21 -0
- package/utils/contentArray.ts +51 -0
- package/utils/context.ts +221 -0
- package/utils/contextAnalysis.ts +272 -0
- package/utils/contextSuggestions.ts +235 -0
- package/utils/controlMessageCompat.ts +32 -0
- package/utils/conversationRecovery.ts +597 -0
- package/utils/cron.ts +308 -0
- package/utils/cronJitterConfig.ts +75 -0
- package/utils/cronScheduler.ts +565 -0
- package/utils/cronTasks.ts +458 -0
- package/utils/cronTasksLock.ts +195 -0
- package/utils/crossProjectResume.ts +75 -0
- package/utils/crypto.ts +13 -0
- package/utils/cwd.ts +32 -0
- package/utils/debug.ts +268 -0
- package/utils/debugFilter.ts +157 -0
- package/utils/deepLink/banner.ts +123 -0
- package/utils/deepLink/parseDeepLink.ts +170 -0
- package/utils/deepLink/protocolHandler.ts +136 -0
- package/utils/deepLink/registerProtocol.ts +348 -0
- package/utils/deepLink/terminalLauncher.ts +557 -0
- package/utils/deepLink/terminalPreference.ts +54 -0
- package/utils/desktopDeepLink.ts +236 -0
- package/utils/detectRepository.ts +178 -0
- package/utils/diagLogs.ts +94 -0
- package/utils/diff.ts +177 -0
- package/utils/directMemberMessage.ts +69 -0
- package/utils/displayTags.ts +51 -0
- package/utils/doctorContextWarnings.ts +265 -0
- package/utils/doctorDiagnostic.ts +625 -0
- package/utils/dxt/helpers.ts +88 -0
- package/utils/dxt/zip.ts +226 -0
- package/utils/earlyInput.ts +191 -0
- package/utils/editor.ts +183 -0
- package/utils/effort.ts +329 -0
- package/utils/embeddedTools.ts +29 -0
- package/utils/env.ts +347 -0
- package/utils/envDynamic.ts +151 -0
- package/utils/envUtils.ts +183 -0
- package/utils/envValidation.ts +38 -0
- package/utils/errorLogSink.ts +235 -0
- package/utils/errors.ts +238 -0
- package/utils/exampleCommands.ts +184 -0
- package/utils/execFileNoThrow.ts +150 -0
- package/utils/execFileNoThrowPortable.ts +89 -0
- package/utils/execSyncWrapper.ts +38 -0
- package/utils/exportRenderer.tsx +98 -0
- package/utils/extraUsage.ts +23 -0
- package/utils/fastMode.ts +532 -0
- package/utils/file.ts +584 -0
- package/utils/fileHistory.ts +1115 -0
- package/utils/fileOperationAnalytics.ts +71 -0
- package/utils/filePersistence/filePersistence.ts +287 -0
- package/utils/filePersistence/outputsScanner.ts +126 -0
- package/utils/fileRead.ts +102 -0
- package/utils/fileReadCache.ts +96 -0
- package/utils/fileStateCache.ts +142 -0
- package/utils/findExecutable.ts +17 -0
- package/utils/fingerprint.ts +76 -0
- package/utils/forkedAgent.ts +689 -0
- package/utils/format.ts +308 -0
- package/utils/formatBriefTimestamp.ts +81 -0
- package/utils/fpsTracker.ts +47 -0
- package/utils/frontmatterParser.ts +370 -0
- package/utils/fsOperations.ts +770 -0
- package/utils/fullscreen.ts +202 -0
- package/utils/generatedFiles.ts +136 -0
- package/utils/generators.ts +88 -0
- package/utils/genericProcessUtils.ts +184 -0
- package/utils/getWorktreePaths.ts +70 -0
- package/utils/getWorktreePathsPortable.ts +27 -0
- package/utils/ghPrStatus.ts +106 -0
- package/utils/git/gitConfigParser.ts +277 -0
- package/utils/git/gitFilesystem.ts +699 -0
- package/utils/git/gitignore.ts +99 -0
- package/utils/git.ts +926 -0
- package/utils/gitDiff.ts +532 -0
- package/utils/gitSettings.ts +18 -0
- package/utils/github/ghAuthStatus.ts +29 -0
- package/utils/githubRepoPathMapping.ts +162 -0
- package/utils/glob.ts +130 -0
- package/utils/gracefulShutdown.ts +529 -0
- package/utils/groupToolUses.ts +182 -0
- package/utils/handlePromptSubmit.ts +610 -0
- package/utils/hash.ts +46 -0
- package/utils/headlessProfiler.ts +178 -0
- package/utils/heapDumpService.ts +303 -0
- package/utils/heatmap.ts +198 -0
- package/utils/highlightMatch.tsx +28 -0
- package/utils/hooks/AsyncHookRegistry.ts +309 -0
- package/utils/hooks/apiQueryHookHelper.ts +141 -0
- package/utils/hooks/execAgentHook.ts +339 -0
- package/utils/hooks/execHttpHook.ts +242 -0
- package/utils/hooks/execPromptHook.ts +211 -0
- package/utils/hooks/fileChangedWatcher.ts +191 -0
- package/utils/hooks/hookEvents.ts +192 -0
- package/utils/hooks/hookHelpers.ts +83 -0
- package/utils/hooks/hooksConfigManager.ts +400 -0
- package/utils/hooks/hooksConfigSnapshot.ts +133 -0
- package/utils/hooks/hooksSettings.ts +271 -0
- package/utils/hooks/postSamplingHooks.ts +70 -0
- package/utils/hooks/registerFrontmatterHooks.ts +67 -0
- package/utils/hooks/registerSkillHooks.ts +64 -0
- package/utils/hooks/sessionHooks.ts +447 -0
- package/utils/hooks/skillImprovement.ts +267 -0
- package/utils/hooks/ssrfGuard.ts +294 -0
- package/utils/hooks.ts +5022 -0
- package/utils/horizontalScroll.ts +137 -0
- package/utils/http.ts +136 -0
- package/utils/hyperlink.ts +39 -0
- package/utils/iTermBackup.ts +73 -0
- package/utils/ide.ts +1494 -0
- package/utils/idePathConversion.ts +90 -0
- package/utils/idleTimeout.ts +53 -0
- package/utils/imagePaste.ts +416 -0
- package/utils/imageResizer.ts +880 -0
- package/utils/imageStore.ts +167 -0
- package/utils/imageValidation.ts +104 -0
- package/utils/immediateCommand.ts +15 -0
- package/utils/inProcessTeammateHelpers.ts +102 -0
- package/utils/ink.ts +26 -0
- package/utils/intl.ts +94 -0
- package/utils/jetbrains.ts +191 -0
- package/utils/json.ts +277 -0
- package/utils/jsonRead.ts +16 -0
- package/utils/keyboardShortcuts.ts +14 -0
- package/utils/lazySchema.ts +8 -0
- package/utils/listSessionsImpl.ts +454 -0
- package/utils/localInstaller.ts +162 -0
- package/utils/lockfile.ts +43 -0
- package/utils/log.ts +362 -0
- package/utils/logoV2Utils.ts +347 -0
- package/utils/mailbox.ts +73 -0
- package/utils/managedEnv.ts +199 -0
- package/utils/managedEnvConstants.ts +191 -0
- package/utils/markdown.ts +381 -0
- package/utils/markdownConfigLoader.ts +600 -0
- package/utils/mcp/dateTimeParser.ts +121 -0
- package/utils/mcp/elicitationValidation.ts +336 -0
- package/utils/mcpInstructionsDelta.ts +130 -0
- package/utils/mcpOutputStorage.ts +189 -0
- package/utils/mcpValidation.ts +208 -0
- package/utils/mcpWebSocketTransport.ts +200 -0
- package/utils/memoize.ts +269 -0
- package/utils/memory/types.ts +12 -0
- package/utils/memory/versions.ts +8 -0
- package/utils/memoryFileDetection.ts +289 -0
- package/utils/messagePredicates.ts +8 -0
- package/utils/messageQueueManager.ts +547 -0
- package/utils/messages/mappers.ts +290 -0
- package/utils/messages/systemInit.ts +96 -0
- package/utils/messages.ts +5520 -0
- package/utils/model/agent.ts +157 -0
- package/utils/model/aliases.ts +35 -0
- package/utils/model/antModels.ts +64 -0
- package/utils/model/bedrock.ts +265 -0
- package/utils/model/check1mAccess.ts +72 -0
- package/utils/model/configs.ts +158 -0
- package/utils/model/contextWindowUpgradeCheck.ts +47 -0
- package/utils/model/deprecation.ts +101 -0
- package/utils/model/model.ts +654 -0
- package/utils/model/modelAllowlist.ts +170 -0
- package/utils/model/modelCapabilities.ts +118 -0
- package/utils/model/modelOptions.ts +589 -0
- package/utils/model/modelStrings.ts +170 -0
- package/utils/model/modelSupportOverrides.ts +50 -0
- package/utils/model/providers.ts +42 -0
- package/utils/model/validateModel.ts +159 -0
- package/utils/modelCost.ts +231 -0
- package/utils/modifiers.ts +36 -0
- package/utils/mtls.ts +179 -0
- package/utils/nativeInstaller/download.ts +523 -0
- package/utils/nativeInstaller/index.ts +18 -0
- package/utils/nativeInstaller/installer.ts +1708 -0
- package/utils/nativeInstaller/packageManagers.ts +336 -0
- package/utils/nativeInstaller/pidLock.ts +433 -0
- package/utils/notebook.ts +224 -0
- package/utils/objectGroupBy.ts +18 -0
- package/utils/pasteStore.ts +104 -0
- package/utils/path.ts +155 -0
- package/utils/pdf.ts +300 -0
- package/utils/pdfUtils.ts +70 -0
- package/utils/peerAddress.ts +21 -0
- package/utils/permissions/PermissionMode.ts +141 -0
- package/utils/permissions/PermissionPromptToolResultSchema.ts +127 -0
- package/utils/permissions/PermissionResult.ts +35 -0
- package/utils/permissions/PermissionRule.ts +40 -0
- package/utils/permissions/PermissionUpdate.ts +389 -0
- package/utils/permissions/PermissionUpdateSchema.ts +78 -0
- package/utils/permissions/autoModeState.ts +39 -0
- package/utils/permissions/bashClassifier.ts +61 -0
- package/utils/permissions/bypassPermissionsKillswitch.ts +155 -0
- package/utils/permissions/classifierDecision.ts +98 -0
- package/utils/permissions/classifierShared.ts +39 -0
- package/utils/permissions/dangerousPatterns.ts +80 -0
- package/utils/permissions/denialTracking.ts +45 -0
- package/utils/permissions/filesystem.ts +1777 -0
- package/utils/permissions/getNextPermissionMode.ts +101 -0
- package/utils/permissions/pathValidation.ts +485 -0
- package/utils/permissions/permissionExplainer.ts +250 -0
- package/utils/permissions/permissionRuleParser.ts +198 -0
- package/utils/permissions/permissionSetup.ts +1532 -0
- package/utils/permissions/permissions.ts +1486 -0
- package/utils/permissions/permissionsLoader.ts +296 -0
- package/utils/permissions/shadowedRuleDetection.ts +234 -0
- package/utils/permissions/shellRuleMatching.ts +228 -0
- package/utils/permissions/yoloClassifier.ts +1495 -0
- package/utils/planModeV2.ts +95 -0
- package/utils/plans.ts +397 -0
- package/utils/platform.ts +150 -0
- package/utils/plugins/addDirPluginSettings.ts +71 -0
- package/utils/plugins/cacheUtils.ts +196 -0
- package/utils/plugins/dependencyResolver.ts +305 -0
- package/utils/plugins/fetchTelemetry.ts +135 -0
- package/utils/plugins/gitAvailability.ts +69 -0
- package/utils/plugins/headlessPluginInstall.ts +174 -0
- package/utils/plugins/hintRecommendation.ts +164 -0
- package/utils/plugins/installCounts.ts +292 -0
- package/utils/plugins/installedPluginsManager.ts +1268 -0
- package/utils/plugins/loadPluginAgents.ts +348 -0
- package/utils/plugins/loadPluginCommands.ts +946 -0
- package/utils/plugins/loadPluginHooks.ts +287 -0
- package/utils/plugins/loadPluginOutputStyles.ts +178 -0
- package/utils/plugins/lspPluginIntegration.ts +387 -0
- package/utils/plugins/lspRecommendation.ts +374 -0
- package/utils/plugins/managedPlugins.ts +27 -0
- package/utils/plugins/marketplaceHelpers.ts +592 -0
- package/utils/plugins/marketplaceManager.ts +2643 -0
- package/utils/plugins/mcpPluginIntegration.ts +634 -0
- package/utils/plugins/mcpbHandler.ts +968 -0
- package/utils/plugins/officialMarketplace.ts +25 -0
- package/utils/plugins/officialMarketplaceGcs.ts +216 -0
- package/utils/plugins/officialMarketplaceStartupCheck.ts +439 -0
- package/utils/plugins/orphanedPluginFilter.ts +114 -0
- package/utils/plugins/parseMarketplaceInput.ts +162 -0
- package/utils/plugins/performStartupChecks.tsx +70 -0
- package/utils/plugins/pluginAutoupdate.ts +284 -0
- package/utils/plugins/pluginBlocklist.ts +127 -0
- package/utils/plugins/pluginDirectories.ts +178 -0
- package/utils/plugins/pluginFlagging.ts +208 -0
- package/utils/plugins/pluginIdentifier.ts +123 -0
- package/utils/plugins/pluginInstallationHelpers.ts +595 -0
- package/utils/plugins/pluginLoader.ts +3302 -0
- package/utils/plugins/pluginOptionsStorage.ts +400 -0
- package/utils/plugins/pluginPolicy.ts +20 -0
- package/utils/plugins/pluginStartupCheck.ts +341 -0
- package/utils/plugins/pluginVersioning.ts +157 -0
- package/utils/plugins/reconciler.ts +265 -0
- package/utils/plugins/refresh.ts +215 -0
- package/utils/plugins/schemas.ts +1681 -0
- package/utils/plugins/validatePlugin.ts +903 -0
- package/utils/plugins/walkPluginMarkdown.ts +69 -0
- package/utils/plugins/zipCache.ts +406 -0
- package/utils/plugins/zipCacheAdapters.ts +164 -0
- package/utils/powershell/dangerousCmdlets.ts +185 -0
- package/utils/powershell/parser.ts +1804 -0
- package/utils/powershell/staticPrefix.ts +316 -0
- package/utils/preflightChecks.tsx +151 -0
- package/utils/privacyLevel.ts +55 -0
- package/utils/process.ts +68 -0
- package/utils/processUserInput/processBashCommand.tsx +140 -0
- package/utils/processUserInput/processSlashCommand.tsx +922 -0
- package/utils/processUserInput/processTextPrompt.ts +100 -0
- package/utils/processUserInput/processUserInput.ts +605 -0
- package/utils/profilerBase.ts +46 -0
- package/utils/promptCategory.ts +49 -0
- package/utils/promptEditor.ts +188 -0
- package/utils/promptShellExecution.ts +183 -0
- package/utils/proxy.ts +426 -0
- package/utils/queryContext.ts +179 -0
- package/utils/queryHelpers.ts +552 -0
- package/utils/queryProfiler.ts +301 -0
- package/utils/queueProcessor.ts +95 -0
- package/utils/readEditContext.ts +227 -0
- package/utils/readFileInRange.ts +383 -0
- package/utils/releaseNotes.ts +360 -0
- package/utils/renderOptions.ts +113 -0
- package/utils/ripgrep.ts +679 -0
- package/utils/sandbox/sandbox-adapter.ts +985 -0
- package/utils/sandbox/sandbox-ui-utils.ts +12 -0
- package/utils/sanitization.ts +91 -0
- package/utils/screenshotClipboard.ts +121 -0
- package/utils/sdkEventQueue.ts +134 -0
- package/utils/secureStorage/fallbackStorage.ts +70 -0
- package/utils/secureStorage/index.ts +17 -0
- package/utils/secureStorage/keychainPrefetch.ts +116 -0
- package/utils/secureStorage/macOsKeychainHelpers.ts +111 -0
- package/utils/secureStorage/macOsKeychainStorage.ts +231 -0
- package/utils/secureStorage/plainTextStorage.ts +84 -0
- package/utils/semanticBoolean.ts +29 -0
- package/utils/semanticNumber.ts +36 -0
- package/utils/semver.ts +59 -0
- package/utils/sequential.ts +56 -0
- package/utils/sessionActivity.ts +133 -0
- package/utils/sessionEnvVars.ts +22 -0
- package/utils/sessionEnvironment.ts +166 -0
- package/utils/sessionFileAccessHooks.ts +250 -0
- package/utils/sessionIngressAuth.ts +140 -0
- package/utils/sessionRestore.ts +551 -0
- package/utils/sessionStart.ts +232 -0
- package/utils/sessionState.ts +150 -0
- package/utils/sessionStorage.ts +5105 -0
- package/utils/sessionStoragePortable.ts +793 -0
- package/utils/sessionTitle.ts +129 -0
- package/utils/sessionUrl.ts +64 -0
- package/utils/set.ts +53 -0
- package/utils/settings/allErrors.ts +32 -0
- package/utils/settings/applySettingsChange.ts +92 -0
- package/utils/settings/changeDetector.ts +488 -0
- package/utils/settings/constants.ts +202 -0
- package/utils/settings/internalWrites.ts +37 -0
- package/utils/settings/managedPath.ts +34 -0
- package/utils/settings/mdm/constants.ts +81 -0
- package/utils/settings/mdm/rawRead.ts +130 -0
- package/utils/settings/mdm/settings.ts +316 -0
- package/utils/settings/permissionValidation.ts +262 -0
- package/utils/settings/pluginOnlyPolicy.ts +60 -0
- package/utils/settings/schemaOutput.ts +8 -0
- package/utils/settings/settings.ts +1015 -0
- package/utils/settings/settingsCache.ts +80 -0
- package/utils/settings/toolValidationConfig.ts +103 -0
- package/utils/settings/types.ts +1149 -0
- package/utils/settings/validateEditTool.ts +45 -0
- package/utils/settings/validation.ts +265 -0
- package/utils/settings/validationTips.ts +164 -0
- package/utils/shell/bashProvider.ts +255 -0
- package/utils/shell/outputLimits.ts +14 -0
- package/utils/shell/powershellDetection.ts +107 -0
- package/utils/shell/powershellProvider.ts +123 -0
- package/utils/shell/prefix.ts +367 -0
- package/utils/shell/readOnlyCommandValidation.ts +1893 -0
- package/utils/shell/resolveDefaultShell.ts +14 -0
- package/utils/shell/shellProvider.ts +33 -0
- package/utils/shell/shellToolUtils.ts +22 -0
- package/utils/shell/specPrefix.ts +241 -0
- package/utils/shellConfig.ts +167 -0
- package/utils/sideQuery.ts +222 -0
- package/utils/sideQuestion.ts +155 -0
- package/utils/signal.ts +43 -0
- package/utils/sinks.ts +16 -0
- package/utils/skills/skillChangeDetector.ts +311 -0
- package/utils/slashCommandParsing.ts +60 -0
- package/utils/sleep.ts +84 -0
- package/utils/sliceAnsi.ts +91 -0
- package/utils/slowOperations.ts +286 -0
- package/utils/standaloneAgent.ts +23 -0
- package/utils/startupProfiler.ts +194 -0
- package/utils/staticRender.tsx +116 -0
- package/utils/stats.ts +1061 -0
- package/utils/statsCache.ts +434 -0
- package/utils/status.tsx +362 -0
- package/utils/statusNoticeDefinitions.tsx +198 -0
- package/utils/statusNoticeHelpers.ts +20 -0
- package/utils/stream.ts +76 -0
- package/utils/streamJsonStdoutGuard.ts +123 -0
- package/utils/streamlinedTransform.ts +201 -0
- package/utils/stringUtils.ts +235 -0
- package/utils/subprocessEnv.ts +99 -0
- package/utils/suggestions/commandSuggestions.ts +567 -0
- package/utils/suggestions/directoryCompletion.ts +263 -0
- package/utils/suggestions/shellHistoryCompletion.ts +119 -0
- package/utils/suggestions/skillUsageTracking.ts +55 -0
- package/utils/suggestions/slackChannelSuggestions.ts +209 -0
- package/utils/swarm/It2SetupPrompt.tsx +380 -0
- package/utils/swarm/backends/ITermBackend.ts +370 -0
- package/utils/swarm/backends/InProcessBackend.ts +339 -0
- package/utils/swarm/backends/PaneBackendExecutor.ts +354 -0
- package/utils/swarm/backends/TmuxBackend.ts +764 -0
- package/utils/swarm/backends/detection.ts +128 -0
- package/utils/swarm/backends/it2Setup.ts +245 -0
- package/utils/swarm/backends/registry.ts +464 -0
- package/utils/swarm/backends/teammateModeSnapshot.ts +87 -0
- package/utils/swarm/backends/types.ts +311 -0
- package/utils/swarm/constants.ts +33 -0
- package/utils/swarm/inProcessRunner.ts +1552 -0
- package/utils/swarm/leaderPermissionBridge.ts +54 -0
- package/utils/swarm/permissionSync.ts +928 -0
- package/utils/swarm/reconnection.ts +119 -0
- package/utils/swarm/spawnInProcess.ts +328 -0
- package/utils/swarm/spawnUtils.ts +146 -0
- package/utils/swarm/teamHelpers.ts +683 -0
- package/utils/swarm/teammateInit.ts +129 -0
- package/utils/swarm/teammateLayoutManager.ts +107 -0
- package/utils/swarm/teammateModel.ts +10 -0
- package/utils/swarm/teammatePromptAddendum.ts +18 -0
- package/utils/systemDirectories.ts +74 -0
- package/utils/systemPrompt.ts +123 -0
- package/utils/systemPromptType.ts +14 -0
- package/utils/systemTheme.ts +119 -0
- package/utils/taggedId.ts +54 -0
- package/utils/task/TaskOutput.ts +390 -0
- package/utils/task/diskOutput.ts +451 -0
- package/utils/task/framework.ts +308 -0
- package/utils/task/outputFormatting.ts +38 -0
- package/utils/task/sdkProgress.ts +36 -0
- package/utils/tasks.ts +862 -0
- package/utils/teamDiscovery.ts +81 -0
- package/utils/teamMemoryOps.ts +88 -0
- package/utils/teammate.ts +292 -0
- package/utils/teammateContext.ts +96 -0
- package/utils/teammateMailbox.ts +1183 -0
- package/utils/telemetry/betaSessionTracing.ts +491 -0
- package/utils/telemetry/bigqueryExporter.ts +252 -0
- package/utils/telemetry/events.ts +75 -0
- package/utils/telemetry/instrumentation.ts +825 -0
- package/utils/telemetry/logger.ts +26 -0
- package/utils/telemetry/perfettoTracing.ts +1120 -0
- package/utils/telemetry/pluginTelemetry.ts +289 -0
- package/utils/telemetry/sessionTracing.ts +927 -0
- package/utils/telemetry/skillLoadedEvent.ts +39 -0
- package/utils/telemetryAttributes.ts +71 -0
- package/utils/teleport/api.ts +466 -0
- package/utils/teleport/environmentSelection.ts +77 -0
- package/utils/teleport/environments.ts +120 -0
- package/utils/teleport/gitBundle.ts +292 -0
- package/utils/teleport.tsx +1226 -0
- package/utils/tempfile.ts +31 -0
- package/utils/terminal.ts +131 -0
- package/utils/terminalPanel.ts +191 -0
- package/utils/textHighlighting.ts +166 -0
- package/utils/theme.ts +639 -0
- package/utils/thinking.ts +162 -0
- package/utils/timeouts.ts +39 -0
- package/utils/tmuxSocket.ts +427 -0
- package/utils/todo/types.ts +18 -0
- package/utils/tokenBudget.ts +73 -0
- package/utils/tokens.ts +261 -0
- package/utils/toolErrors.ts +132 -0
- package/utils/toolPool.ts +79 -0
- package/utils/toolResultStorage.ts +1040 -0
- package/utils/toolSchemaCache.ts +26 -0
- package/utils/toolSearch.ts +756 -0
- package/utils/transcriptSearch.ts +202 -0
- package/utils/treeify.ts +170 -0
- package/utils/truncate.ts +179 -0
- package/utils/ultraplan/ccrSession.ts +349 -0
- package/utils/ultraplan/keyword.ts +127 -0
- package/utils/ultraplan/prompt.txt +1 -0
- package/utils/unaryLogging.ts +39 -0
- package/utils/undercover.ts +89 -0
- package/utils/user.ts +194 -0
- package/utils/userAgent.ts +10 -0
- package/utils/userPromptKeywords.ts +27 -0
- package/utils/uuid.ts +27 -0
- package/utils/warningHandler.ts +121 -0
- package/utils/which.ts +82 -0
- package/utils/windowsPaths.ts +173 -0
- package/utils/withResolvers.ts +13 -0
- package/utils/words.ts +800 -0
- package/utils/workloadContext.ts +57 -0
- package/utils/worktree.ts +1519 -0
- package/utils/worktreeModeEnabled.ts +11 -0
- package/utils/xdg.ts +65 -0
- package/utils/xmem.ts +6 -0
- package/utils/xml.ts +16 -0
- package/utils/yaml.ts +15 -0
- package/utils/zodToJsonSchema.ts +23 -0
package/utils/stats.ts
ADDED
|
@@ -0,0 +1,1061 @@
|
|
|
1
|
+
import { feature } from 'bun:bundle'
|
|
2
|
+
import { open } from 'fs/promises'
|
|
3
|
+
import { basename, dirname, join, sep } from 'path'
|
|
4
|
+
import type { ModelUsage } from 'src/entrypoints/agentSdkTypes.js'
|
|
5
|
+
import type { Entry, TranscriptMessage } from '../types/logs.js'
|
|
6
|
+
import { logForDebugging } from './debug.js'
|
|
7
|
+
import { errorMessage, isENOENT } from './errors.js'
|
|
8
|
+
import { getFsImplementation } from './fsOperations.js'
|
|
9
|
+
import { readJSONLFile } from './json.js'
|
|
10
|
+
import { SYNTHETIC_MODEL } from './messages.js'
|
|
11
|
+
import { getProjectsDir, isTranscriptMessage } from './sessionStorage.js'
|
|
12
|
+
import { SHELL_TOOL_NAMES } from './shell/shellToolUtils.js'
|
|
13
|
+
import { jsonParse } from './slowOperations.js'
|
|
14
|
+
import {
|
|
15
|
+
getTodayDateString,
|
|
16
|
+
getYesterdayDateString,
|
|
17
|
+
isDateBefore,
|
|
18
|
+
loadStatsCache,
|
|
19
|
+
mergeCacheWithNewStats,
|
|
20
|
+
type PersistedStatsCache,
|
|
21
|
+
saveStatsCache,
|
|
22
|
+
toDateString,
|
|
23
|
+
withStatsCacheLock,
|
|
24
|
+
} from './statsCache.js'
|
|
25
|
+
|
|
26
|
+
export type DailyActivity = {
|
|
27
|
+
date: string // YYYY-MM-DD format
|
|
28
|
+
messageCount: number
|
|
29
|
+
sessionCount: number
|
|
30
|
+
toolCallCount: number
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type DailyModelTokens = {
|
|
34
|
+
date: string // YYYY-MM-DD format
|
|
35
|
+
tokensByModel: { [modelName: string]: number } // total tokens (input + output) per model
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export type StreakInfo = {
|
|
39
|
+
currentStreak: number
|
|
40
|
+
longestStreak: number
|
|
41
|
+
currentStreakStart: string | null
|
|
42
|
+
longestStreakStart: string | null
|
|
43
|
+
longestStreakEnd: string | null
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type SessionStats = {
|
|
47
|
+
sessionId: string
|
|
48
|
+
duration: number // in milliseconds
|
|
49
|
+
messageCount: number
|
|
50
|
+
timestamp: string
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export type ClaudeCodeStats = {
|
|
54
|
+
// Activity overview
|
|
55
|
+
totalSessions: number
|
|
56
|
+
totalMessages: number
|
|
57
|
+
totalDays: number
|
|
58
|
+
activeDays: number
|
|
59
|
+
|
|
60
|
+
// Streaks
|
|
61
|
+
streaks: StreakInfo
|
|
62
|
+
|
|
63
|
+
// Daily activity for heatmap
|
|
64
|
+
dailyActivity: DailyActivity[]
|
|
65
|
+
|
|
66
|
+
// Daily token usage per model for charts
|
|
67
|
+
dailyModelTokens: DailyModelTokens[]
|
|
68
|
+
|
|
69
|
+
// Session info
|
|
70
|
+
longestSession: SessionStats | null
|
|
71
|
+
|
|
72
|
+
// Model usage aggregated
|
|
73
|
+
modelUsage: { [modelName: string]: ModelUsage }
|
|
74
|
+
|
|
75
|
+
// Time stats
|
|
76
|
+
firstSessionDate: string | null
|
|
77
|
+
lastSessionDate: string | null
|
|
78
|
+
peakActivityDay: string | null
|
|
79
|
+
peakActivityHour: number | null
|
|
80
|
+
|
|
81
|
+
// Speculation time saved
|
|
82
|
+
totalSpeculationTimeSavedMs: number
|
|
83
|
+
|
|
84
|
+
// Shot stats (ant-only, gated by SHOT_STATS feature flag)
|
|
85
|
+
shotDistribution?: { [shotCount: number]: number }
|
|
86
|
+
oneShotRate?: number
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Result of processing session files - intermediate stats that can be merged.
|
|
91
|
+
*/
|
|
92
|
+
type ProcessedStats = {
|
|
93
|
+
dailyActivity: DailyActivity[]
|
|
94
|
+
dailyModelTokens: DailyModelTokens[]
|
|
95
|
+
modelUsage: { [modelName: string]: ModelUsage }
|
|
96
|
+
sessionStats: SessionStats[]
|
|
97
|
+
hourCounts: { [hour: number]: number }
|
|
98
|
+
totalMessages: number
|
|
99
|
+
totalSpeculationTimeSavedMs: number
|
|
100
|
+
shotDistribution?: { [shotCount: number]: number }
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Options for processing session files.
|
|
105
|
+
*/
|
|
106
|
+
type ProcessOptions = {
|
|
107
|
+
// Only include data from dates >= this date (YYYY-MM-DD format)
|
|
108
|
+
fromDate?: string
|
|
109
|
+
// Only include data from dates <= this date (YYYY-MM-DD format)
|
|
110
|
+
toDate?: string
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Process session files and extract stats.
|
|
115
|
+
* Can filter by date range.
|
|
116
|
+
*/
|
|
117
|
+
async function processSessionFiles(
|
|
118
|
+
sessionFiles: string[],
|
|
119
|
+
options: ProcessOptions = {},
|
|
120
|
+
): Promise<ProcessedStats> {
|
|
121
|
+
const { fromDate, toDate } = options
|
|
122
|
+
const fs = getFsImplementation()
|
|
123
|
+
|
|
124
|
+
const dailyActivityMap = new Map<string, DailyActivity>()
|
|
125
|
+
const dailyModelTokensMap = new Map<string, { [modelName: string]: number }>()
|
|
126
|
+
const sessions: SessionStats[] = []
|
|
127
|
+
const hourCounts = new Map<number, number>()
|
|
128
|
+
let totalMessages = 0
|
|
129
|
+
let totalSpeculationTimeSavedMs = 0
|
|
130
|
+
const modelUsageAgg: { [modelName: string]: ModelUsage } = {}
|
|
131
|
+
const shotDistributionMap = feature('SHOT_STATS')
|
|
132
|
+
? new Map<number, number>()
|
|
133
|
+
: undefined
|
|
134
|
+
// Track parent sessions that already recorded a shot count (dedup across subagents)
|
|
135
|
+
const sessionsWithShotCount = new Set<string>()
|
|
136
|
+
|
|
137
|
+
// Process session files in parallel batches for better performance
|
|
138
|
+
const BATCH_SIZE = 20
|
|
139
|
+
for (let i = 0; i < sessionFiles.length; i += BATCH_SIZE) {
|
|
140
|
+
const batch = sessionFiles.slice(i, i + BATCH_SIZE)
|
|
141
|
+
const results = await Promise.all(
|
|
142
|
+
batch.map(async sessionFile => {
|
|
143
|
+
try {
|
|
144
|
+
// If we have a fromDate filter, skip files that haven't been modified since then
|
|
145
|
+
if (fromDate) {
|
|
146
|
+
let fileSize = 0
|
|
147
|
+
try {
|
|
148
|
+
const fileStat = await fs.stat(sessionFile)
|
|
149
|
+
const fileModifiedDate = toDateString(fileStat.mtime)
|
|
150
|
+
if (isDateBefore(fileModifiedDate, fromDate)) {
|
|
151
|
+
return {
|
|
152
|
+
sessionFile,
|
|
153
|
+
entries: null,
|
|
154
|
+
error: null,
|
|
155
|
+
skipped: true,
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
fileSize = fileStat.size
|
|
159
|
+
} catch {
|
|
160
|
+
// If we can't stat the file, try to read it anyway
|
|
161
|
+
}
|
|
162
|
+
// For large files, peek at the session start date before reading everything.
|
|
163
|
+
// Sessions that pass the mtime filter but started before fromDate are skipped
|
|
164
|
+
// (e.g. a month-old session resumed today gets a new mtime write but old start date).
|
|
165
|
+
if (fileSize > 65536) {
|
|
166
|
+
const startDate = await readSessionStartDate(sessionFile)
|
|
167
|
+
if (startDate && isDateBefore(startDate, fromDate)) {
|
|
168
|
+
return {
|
|
169
|
+
sessionFile,
|
|
170
|
+
entries: null,
|
|
171
|
+
error: null,
|
|
172
|
+
skipped: true,
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const entries = await readJSONLFile<Entry>(sessionFile)
|
|
178
|
+
return { sessionFile, entries, error: null, skipped: false }
|
|
179
|
+
} catch (error) {
|
|
180
|
+
return { sessionFile, entries: null, error, skipped: false }
|
|
181
|
+
}
|
|
182
|
+
}),
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
for (const { sessionFile, entries, error, skipped } of results) {
|
|
186
|
+
if (skipped) continue
|
|
187
|
+
if (error || !entries) {
|
|
188
|
+
logForDebugging(
|
|
189
|
+
`Failed to read session file ${sessionFile}: ${errorMessage(error)}`,
|
|
190
|
+
)
|
|
191
|
+
continue
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const sessionId = basename(sessionFile, '.jsonl')
|
|
195
|
+
const messages: TranscriptMessage[] = []
|
|
196
|
+
|
|
197
|
+
for (const entry of entries) {
|
|
198
|
+
if (isTranscriptMessage(entry)) {
|
|
199
|
+
messages.push(entry)
|
|
200
|
+
} else if (entry.type === 'speculation-accept') {
|
|
201
|
+
totalSpeculationTimeSavedMs += entry.timeSavedMs
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (messages.length === 0) continue
|
|
206
|
+
|
|
207
|
+
// Subagent transcripts mark all messages as sidechain. We still want
|
|
208
|
+
// their token usage counted, but not as separate sessions.
|
|
209
|
+
const isSubagentFile = sessionFile.includes(`${sep}subagents${sep}`)
|
|
210
|
+
|
|
211
|
+
// Extract shot count from PR attribution in gh pr create calls (ant-only)
|
|
212
|
+
// This must run before the sidechain filter since subagent transcripts
|
|
213
|
+
// mark all messages as sidechain
|
|
214
|
+
if (feature('SHOT_STATS') && shotDistributionMap) {
|
|
215
|
+
const parentSessionId = isSubagentFile
|
|
216
|
+
? basename(dirname(dirname(sessionFile)))
|
|
217
|
+
: sessionId
|
|
218
|
+
|
|
219
|
+
if (!sessionsWithShotCount.has(parentSessionId)) {
|
|
220
|
+
const shotCount = extractShotCountFromMessages(messages)
|
|
221
|
+
if (shotCount !== null) {
|
|
222
|
+
sessionsWithShotCount.add(parentSessionId)
|
|
223
|
+
shotDistributionMap.set(
|
|
224
|
+
shotCount,
|
|
225
|
+
(shotDistributionMap.get(shotCount) || 0) + 1,
|
|
226
|
+
)
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Filter out sidechain messages for session metadata (duration, counts).
|
|
232
|
+
// For subagent files, use all messages since they're all sidechain.
|
|
233
|
+
const mainMessages = isSubagentFile
|
|
234
|
+
? messages
|
|
235
|
+
: messages.filter(m => !m.isSidechain)
|
|
236
|
+
if (mainMessages.length === 0) continue
|
|
237
|
+
|
|
238
|
+
const firstMessage = mainMessages[0]!
|
|
239
|
+
const lastMessage = mainMessages.at(-1)!
|
|
240
|
+
|
|
241
|
+
const firstTimestamp = new Date(firstMessage.timestamp)
|
|
242
|
+
const lastTimestamp = new Date(lastMessage.timestamp)
|
|
243
|
+
|
|
244
|
+
// Skip sessions with malformed timestamps — some transcripts on disk
|
|
245
|
+
// have entries missing the timestamp field (e.g. partial/remote writes).
|
|
246
|
+
// new Date(undefined) produces an Invalid Date, and toDateString() would
|
|
247
|
+
// throw RangeError: Invalid Date on .toISOString().
|
|
248
|
+
if (isNaN(firstTimestamp.getTime()) || isNaN(lastTimestamp.getTime())) {
|
|
249
|
+
logForDebugging(
|
|
250
|
+
`Skipping session with invalid timestamp: ${sessionFile}`,
|
|
251
|
+
)
|
|
252
|
+
continue
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const dateKey = toDateString(firstTimestamp)
|
|
256
|
+
|
|
257
|
+
// Apply date filters
|
|
258
|
+
if (fromDate && isDateBefore(dateKey, fromDate)) continue
|
|
259
|
+
if (toDate && isDateBefore(toDate, dateKey)) continue
|
|
260
|
+
|
|
261
|
+
// Track daily activity (use first message date as session date)
|
|
262
|
+
const existing = dailyActivityMap.get(dateKey) || {
|
|
263
|
+
date: dateKey,
|
|
264
|
+
messageCount: 0,
|
|
265
|
+
sessionCount: 0,
|
|
266
|
+
toolCallCount: 0,
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Subagent files contribute tokens and tool calls, but aren't sessions.
|
|
270
|
+
if (!isSubagentFile) {
|
|
271
|
+
const duration = lastTimestamp.getTime() - firstTimestamp.getTime()
|
|
272
|
+
|
|
273
|
+
sessions.push({
|
|
274
|
+
sessionId,
|
|
275
|
+
duration,
|
|
276
|
+
messageCount: mainMessages.length,
|
|
277
|
+
timestamp: firstMessage.timestamp,
|
|
278
|
+
})
|
|
279
|
+
|
|
280
|
+
totalMessages += mainMessages.length
|
|
281
|
+
|
|
282
|
+
existing.sessionCount++
|
|
283
|
+
existing.messageCount += mainMessages.length
|
|
284
|
+
|
|
285
|
+
const hour = firstTimestamp.getHours()
|
|
286
|
+
hourCounts.set(hour, (hourCounts.get(hour) || 0) + 1)
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (!isSubagentFile || dailyActivityMap.has(dateKey)) {
|
|
290
|
+
dailyActivityMap.set(dateKey, existing)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Process messages for tool usage and model stats
|
|
294
|
+
for (const message of mainMessages) {
|
|
295
|
+
if (message.type === 'assistant') {
|
|
296
|
+
const content = message.message?.content
|
|
297
|
+
if (Array.isArray(content)) {
|
|
298
|
+
for (const block of content) {
|
|
299
|
+
if (block.type === 'tool_use') {
|
|
300
|
+
const activity = dailyActivityMap.get(dateKey)
|
|
301
|
+
if (activity) {
|
|
302
|
+
activity.toolCallCount++
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Track model usage if available (skip synthetic messages)
|
|
309
|
+
if (message.message?.usage) {
|
|
310
|
+
const usage = message.message.usage
|
|
311
|
+
const model = message.message.model || 'unknown'
|
|
312
|
+
|
|
313
|
+
// Skip synthetic messages - they are internal and shouldn't appear in stats
|
|
314
|
+
if (model === SYNTHETIC_MODEL) {
|
|
315
|
+
continue
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (!modelUsageAgg[model]) {
|
|
319
|
+
modelUsageAgg[model] = {
|
|
320
|
+
inputTokens: 0,
|
|
321
|
+
outputTokens: 0,
|
|
322
|
+
cacheReadInputTokens: 0,
|
|
323
|
+
cacheCreationInputTokens: 0,
|
|
324
|
+
webSearchRequests: 0,
|
|
325
|
+
costUSD: 0,
|
|
326
|
+
contextWindow: 0,
|
|
327
|
+
maxOutputTokens: 0,
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
modelUsageAgg[model]!.inputTokens += usage.input_tokens || 0
|
|
332
|
+
modelUsageAgg[model]!.outputTokens += usage.output_tokens || 0
|
|
333
|
+
modelUsageAgg[model]!.cacheReadInputTokens +=
|
|
334
|
+
usage.cache_read_input_tokens || 0
|
|
335
|
+
modelUsageAgg[model]!.cacheCreationInputTokens +=
|
|
336
|
+
usage.cache_creation_input_tokens || 0
|
|
337
|
+
|
|
338
|
+
// Track daily tokens per model
|
|
339
|
+
const totalTokens =
|
|
340
|
+
(usage.input_tokens || 0) + (usage.output_tokens || 0)
|
|
341
|
+
if (totalTokens > 0) {
|
|
342
|
+
const dayTokens = dailyModelTokensMap.get(dateKey) || {}
|
|
343
|
+
dayTokens[model] = (dayTokens[model] || 0) + totalTokens
|
|
344
|
+
dailyModelTokensMap.set(dateKey, dayTokens)
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return {
|
|
353
|
+
dailyActivity: Array.from(dailyActivityMap.values()).sort((a, b) =>
|
|
354
|
+
a.date.localeCompare(b.date),
|
|
355
|
+
),
|
|
356
|
+
dailyModelTokens: Array.from(dailyModelTokensMap.entries())
|
|
357
|
+
.map(([date, tokensByModel]) => ({ date, tokensByModel }))
|
|
358
|
+
.sort((a, b) => a.date.localeCompare(b.date)),
|
|
359
|
+
modelUsage: modelUsageAgg,
|
|
360
|
+
sessionStats: sessions,
|
|
361
|
+
hourCounts: Object.fromEntries(hourCounts),
|
|
362
|
+
totalMessages,
|
|
363
|
+
totalSpeculationTimeSavedMs,
|
|
364
|
+
...(feature('SHOT_STATS') && shotDistributionMap
|
|
365
|
+
? { shotDistribution: Object.fromEntries(shotDistributionMap) }
|
|
366
|
+
: {}),
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Get all session files from all project directories.
|
|
372
|
+
* Includes both main session files and subagent transcript files.
|
|
373
|
+
*/
|
|
374
|
+
async function getAllSessionFiles(): Promise<string[]> {
|
|
375
|
+
const projectsDir = getProjectsDir()
|
|
376
|
+
const fs = getFsImplementation()
|
|
377
|
+
|
|
378
|
+
// Get all project directories
|
|
379
|
+
let allEntries
|
|
380
|
+
try {
|
|
381
|
+
allEntries = await fs.readdir(projectsDir)
|
|
382
|
+
} catch (e) {
|
|
383
|
+
if (isENOENT(e)) return []
|
|
384
|
+
throw e
|
|
385
|
+
}
|
|
386
|
+
const projectDirs = allEntries
|
|
387
|
+
.filter(dirent => dirent.isDirectory())
|
|
388
|
+
.map(dirent => join(projectsDir, dirent.name))
|
|
389
|
+
|
|
390
|
+
// Collect all session files from all projects in parallel
|
|
391
|
+
const projectResults = await Promise.all(
|
|
392
|
+
projectDirs.map(async projectDir => {
|
|
393
|
+
try {
|
|
394
|
+
const entries = await fs.readdir(projectDir)
|
|
395
|
+
|
|
396
|
+
// Collect main session files (*.jsonl directly in project dir)
|
|
397
|
+
const mainFiles = entries
|
|
398
|
+
.filter(dirent => dirent.isFile() && dirent.name.endsWith('.jsonl'))
|
|
399
|
+
.map(dirent => join(projectDir, dirent.name))
|
|
400
|
+
|
|
401
|
+
// Collect subagent files from session subdirectories in parallel
|
|
402
|
+
// Structure: {projectDir}/{sessionId}/subagents/agent-{agentId}.jsonl
|
|
403
|
+
const sessionDirs = entries.filter(dirent => dirent.isDirectory())
|
|
404
|
+
const subagentResults = await Promise.all(
|
|
405
|
+
sessionDirs.map(async sessionDir => {
|
|
406
|
+
const subagentsDir = join(projectDir, sessionDir.name, 'subagents')
|
|
407
|
+
try {
|
|
408
|
+
const subagentEntries = await fs.readdir(subagentsDir)
|
|
409
|
+
return subagentEntries
|
|
410
|
+
.filter(
|
|
411
|
+
dirent =>
|
|
412
|
+
dirent.isFile() &&
|
|
413
|
+
dirent.name.endsWith('.jsonl') &&
|
|
414
|
+
dirent.name.startsWith('agent-'),
|
|
415
|
+
)
|
|
416
|
+
.map(dirent => join(subagentsDir, dirent.name))
|
|
417
|
+
} catch {
|
|
418
|
+
// subagents directory doesn't exist for this session, skip
|
|
419
|
+
return []
|
|
420
|
+
}
|
|
421
|
+
}),
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
return [...mainFiles, ...subagentResults.flat()]
|
|
425
|
+
} catch (error) {
|
|
426
|
+
logForDebugging(
|
|
427
|
+
`Failed to read project directory ${projectDir}: ${errorMessage(error)}`,
|
|
428
|
+
)
|
|
429
|
+
return []
|
|
430
|
+
}
|
|
431
|
+
}),
|
|
432
|
+
)
|
|
433
|
+
|
|
434
|
+
return projectResults.flat()
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Convert a PersistedStatsCache to ClaudeCodeStats by computing derived fields.
|
|
439
|
+
*/
|
|
440
|
+
function cacheToStats(
|
|
441
|
+
cache: PersistedStatsCache,
|
|
442
|
+
todayStats: ProcessedStats | null,
|
|
443
|
+
): ClaudeCodeStats {
|
|
444
|
+
// Merge cache with today's stats
|
|
445
|
+
const dailyActivityMap = new Map<string, DailyActivity>()
|
|
446
|
+
for (const day of cache.dailyActivity) {
|
|
447
|
+
dailyActivityMap.set(day.date, { ...day })
|
|
448
|
+
}
|
|
449
|
+
if (todayStats) {
|
|
450
|
+
for (const day of todayStats.dailyActivity) {
|
|
451
|
+
const existing = dailyActivityMap.get(day.date)
|
|
452
|
+
if (existing) {
|
|
453
|
+
existing.messageCount += day.messageCount
|
|
454
|
+
existing.sessionCount += day.sessionCount
|
|
455
|
+
existing.toolCallCount += day.toolCallCount
|
|
456
|
+
} else {
|
|
457
|
+
dailyActivityMap.set(day.date, { ...day })
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const dailyModelTokensMap = new Map<string, { [model: string]: number }>()
|
|
463
|
+
for (const day of cache.dailyModelTokens) {
|
|
464
|
+
dailyModelTokensMap.set(day.date, { ...day.tokensByModel })
|
|
465
|
+
}
|
|
466
|
+
if (todayStats) {
|
|
467
|
+
for (const day of todayStats.dailyModelTokens) {
|
|
468
|
+
const existing = dailyModelTokensMap.get(day.date)
|
|
469
|
+
if (existing) {
|
|
470
|
+
for (const [model, tokens] of Object.entries(day.tokensByModel)) {
|
|
471
|
+
existing[model] = (existing[model] || 0) + tokens
|
|
472
|
+
}
|
|
473
|
+
} else {
|
|
474
|
+
dailyModelTokensMap.set(day.date, { ...day.tokensByModel })
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// Merge model usage
|
|
480
|
+
const modelUsage = { ...cache.modelUsage }
|
|
481
|
+
if (todayStats) {
|
|
482
|
+
for (const [model, usage] of Object.entries(todayStats.modelUsage)) {
|
|
483
|
+
if (modelUsage[model]) {
|
|
484
|
+
modelUsage[model] = {
|
|
485
|
+
inputTokens: modelUsage[model]!.inputTokens + usage.inputTokens,
|
|
486
|
+
outputTokens: modelUsage[model]!.outputTokens + usage.outputTokens,
|
|
487
|
+
cacheReadInputTokens:
|
|
488
|
+
modelUsage[model]!.cacheReadInputTokens +
|
|
489
|
+
usage.cacheReadInputTokens,
|
|
490
|
+
cacheCreationInputTokens:
|
|
491
|
+
modelUsage[model]!.cacheCreationInputTokens +
|
|
492
|
+
usage.cacheCreationInputTokens,
|
|
493
|
+
webSearchRequests:
|
|
494
|
+
modelUsage[model]!.webSearchRequests + usage.webSearchRequests,
|
|
495
|
+
costUSD: modelUsage[model]!.costUSD + usage.costUSD,
|
|
496
|
+
contextWindow: Math.max(
|
|
497
|
+
modelUsage[model]!.contextWindow,
|
|
498
|
+
usage.contextWindow,
|
|
499
|
+
),
|
|
500
|
+
maxOutputTokens: Math.max(
|
|
501
|
+
modelUsage[model]!.maxOutputTokens,
|
|
502
|
+
usage.maxOutputTokens,
|
|
503
|
+
),
|
|
504
|
+
}
|
|
505
|
+
} else {
|
|
506
|
+
modelUsage[model] = { ...usage }
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// Merge hour counts
|
|
512
|
+
const hourCountsMap = new Map<number, number>()
|
|
513
|
+
for (const [hour, count] of Object.entries(cache.hourCounts)) {
|
|
514
|
+
hourCountsMap.set(parseInt(hour, 10), count)
|
|
515
|
+
}
|
|
516
|
+
if (todayStats) {
|
|
517
|
+
for (const [hour, count] of Object.entries(todayStats.hourCounts)) {
|
|
518
|
+
const hourNum = parseInt(hour, 10)
|
|
519
|
+
hourCountsMap.set(hourNum, (hourCountsMap.get(hourNum) || 0) + count)
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// Calculate derived stats
|
|
524
|
+
const dailyActivityArray = Array.from(dailyActivityMap.values()).sort(
|
|
525
|
+
(a, b) => a.date.localeCompare(b.date),
|
|
526
|
+
)
|
|
527
|
+
const streaks = calculateStreaks(dailyActivityArray)
|
|
528
|
+
|
|
529
|
+
const dailyModelTokens = Array.from(dailyModelTokensMap.entries())
|
|
530
|
+
.map(([date, tokensByModel]) => ({ date, tokensByModel }))
|
|
531
|
+
.sort((a, b) => a.date.localeCompare(b.date))
|
|
532
|
+
|
|
533
|
+
// Compute session aggregates: combine cache aggregates with today's stats
|
|
534
|
+
const totalSessions =
|
|
535
|
+
cache.totalSessions + (todayStats?.sessionStats.length || 0)
|
|
536
|
+
const totalMessages = cache.totalMessages + (todayStats?.totalMessages || 0)
|
|
537
|
+
|
|
538
|
+
// Find longest session (compare cache's longest with today's sessions)
|
|
539
|
+
let longestSession = cache.longestSession
|
|
540
|
+
if (todayStats) {
|
|
541
|
+
for (const session of todayStats.sessionStats) {
|
|
542
|
+
if (!longestSession || session.duration > longestSession.duration) {
|
|
543
|
+
longestSession = session
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// Find first/last session dates
|
|
549
|
+
let firstSessionDate = cache.firstSessionDate
|
|
550
|
+
let lastSessionDate: string | null = null
|
|
551
|
+
if (todayStats) {
|
|
552
|
+
for (const session of todayStats.sessionStats) {
|
|
553
|
+
if (!firstSessionDate || session.timestamp < firstSessionDate) {
|
|
554
|
+
firstSessionDate = session.timestamp
|
|
555
|
+
}
|
|
556
|
+
if (!lastSessionDate || session.timestamp > lastSessionDate) {
|
|
557
|
+
lastSessionDate = session.timestamp
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
// If no today sessions, derive lastSessionDate from dailyActivity
|
|
562
|
+
if (!lastSessionDate && dailyActivityArray.length > 0) {
|
|
563
|
+
lastSessionDate = dailyActivityArray.at(-1)!.date
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
const peakActivityDay =
|
|
567
|
+
dailyActivityArray.length > 0
|
|
568
|
+
? dailyActivityArray.reduce((max, d) =>
|
|
569
|
+
d.messageCount > max.messageCount ? d : max,
|
|
570
|
+
).date
|
|
571
|
+
: null
|
|
572
|
+
|
|
573
|
+
const peakActivityHour =
|
|
574
|
+
hourCountsMap.size > 0
|
|
575
|
+
? Array.from(hourCountsMap.entries()).reduce((max, [hour, count]) =>
|
|
576
|
+
count > max[1] ? [hour, count] : max,
|
|
577
|
+
)[0]
|
|
578
|
+
: null
|
|
579
|
+
|
|
580
|
+
const totalDays =
|
|
581
|
+
firstSessionDate && lastSessionDate
|
|
582
|
+
? Math.ceil(
|
|
583
|
+
(new Date(lastSessionDate).getTime() -
|
|
584
|
+
new Date(firstSessionDate).getTime()) /
|
|
585
|
+
(1000 * 60 * 60 * 24),
|
|
586
|
+
) + 1
|
|
587
|
+
: 0
|
|
588
|
+
|
|
589
|
+
const totalSpeculationTimeSavedMs =
|
|
590
|
+
cache.totalSpeculationTimeSavedMs +
|
|
591
|
+
(todayStats?.totalSpeculationTimeSavedMs || 0)
|
|
592
|
+
|
|
593
|
+
const result: ClaudeCodeStats = {
|
|
594
|
+
totalSessions,
|
|
595
|
+
totalMessages,
|
|
596
|
+
totalDays,
|
|
597
|
+
activeDays: dailyActivityMap.size,
|
|
598
|
+
streaks,
|
|
599
|
+
dailyActivity: dailyActivityArray,
|
|
600
|
+
dailyModelTokens,
|
|
601
|
+
longestSession,
|
|
602
|
+
modelUsage,
|
|
603
|
+
firstSessionDate,
|
|
604
|
+
lastSessionDate,
|
|
605
|
+
peakActivityDay,
|
|
606
|
+
peakActivityHour,
|
|
607
|
+
totalSpeculationTimeSavedMs,
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
if (feature('SHOT_STATS')) {
|
|
611
|
+
const shotDistribution: { [shotCount: number]: number } = {
|
|
612
|
+
...(cache.shotDistribution || {}),
|
|
613
|
+
}
|
|
614
|
+
if (todayStats?.shotDistribution) {
|
|
615
|
+
for (const [count, sessions] of Object.entries(
|
|
616
|
+
todayStats.shotDistribution,
|
|
617
|
+
)) {
|
|
618
|
+
const key = parseInt(count, 10)
|
|
619
|
+
shotDistribution[key] = (shotDistribution[key] || 0) + sessions
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
result.shotDistribution = shotDistribution
|
|
623
|
+
const totalWithShots = Object.values(shotDistribution).reduce(
|
|
624
|
+
(sum, n) => sum + n,
|
|
625
|
+
0,
|
|
626
|
+
)
|
|
627
|
+
result.oneShotRate =
|
|
628
|
+
totalWithShots > 0
|
|
629
|
+
? Math.round(((shotDistribution[1] || 0) / totalWithShots) * 100)
|
|
630
|
+
: 0
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
return result
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* Aggregates stats from all Claude Code sessions across all projects.
|
|
638
|
+
* Uses a disk cache to avoid reprocessing historical data.
|
|
639
|
+
*/
|
|
640
|
+
export async function aggregateClaudeCodeStats(): Promise<ClaudeCodeStats> {
|
|
641
|
+
const allSessionFiles = await getAllSessionFiles()
|
|
642
|
+
|
|
643
|
+
if (allSessionFiles.length === 0) {
|
|
644
|
+
return getEmptyStats()
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
// Use lock to prevent race conditions with background cache updates
|
|
648
|
+
const updatedCache = await withStatsCacheLock(async () => {
|
|
649
|
+
// Load the cache
|
|
650
|
+
const cache = await loadStatsCache()
|
|
651
|
+
const yesterday = getYesterdayDateString()
|
|
652
|
+
|
|
653
|
+
// Determine what needs to be processed
|
|
654
|
+
// - If no cache: process everything up to yesterday, then today separately
|
|
655
|
+
// - If cache exists: process from day after lastComputedDate to yesterday, then today
|
|
656
|
+
let result = cache
|
|
657
|
+
|
|
658
|
+
if (!cache.lastComputedDate) {
|
|
659
|
+
// No cache - process all historical data (everything before today)
|
|
660
|
+
logForDebugging('Stats cache empty, processing all historical data')
|
|
661
|
+
const historicalStats = await processSessionFiles(allSessionFiles, {
|
|
662
|
+
toDate: yesterday,
|
|
663
|
+
})
|
|
664
|
+
|
|
665
|
+
if (
|
|
666
|
+
historicalStats.sessionStats.length > 0 ||
|
|
667
|
+
historicalStats.dailyActivity.length > 0
|
|
668
|
+
) {
|
|
669
|
+
result = mergeCacheWithNewStats(cache, historicalStats, yesterday)
|
|
670
|
+
await saveStatsCache(result)
|
|
671
|
+
}
|
|
672
|
+
} else if (isDateBefore(cache.lastComputedDate, yesterday)) {
|
|
673
|
+
// Cache is stale - process new days
|
|
674
|
+
// Process from day after lastComputedDate to yesterday
|
|
675
|
+
const nextDay = getNextDay(cache.lastComputedDate)
|
|
676
|
+
logForDebugging(
|
|
677
|
+
`Stats cache stale (${cache.lastComputedDate}), processing ${nextDay} to ${yesterday}`,
|
|
678
|
+
)
|
|
679
|
+
const newStats = await processSessionFiles(allSessionFiles, {
|
|
680
|
+
fromDate: nextDay,
|
|
681
|
+
toDate: yesterday,
|
|
682
|
+
})
|
|
683
|
+
|
|
684
|
+
if (
|
|
685
|
+
newStats.sessionStats.length > 0 ||
|
|
686
|
+
newStats.dailyActivity.length > 0
|
|
687
|
+
) {
|
|
688
|
+
result = mergeCacheWithNewStats(cache, newStats, yesterday)
|
|
689
|
+
await saveStatsCache(result)
|
|
690
|
+
} else {
|
|
691
|
+
// No new data, but update lastComputedDate
|
|
692
|
+
result = { ...cache, lastComputedDate: yesterday }
|
|
693
|
+
await saveStatsCache(result)
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
return result
|
|
698
|
+
})
|
|
699
|
+
|
|
700
|
+
// Always process today's data live (it's incomplete)
|
|
701
|
+
// This doesn't need to be in the lock since it doesn't modify the cache
|
|
702
|
+
const today = getTodayDateString()
|
|
703
|
+
const todayStats = await processSessionFiles(allSessionFiles, {
|
|
704
|
+
fromDate: today,
|
|
705
|
+
toDate: today,
|
|
706
|
+
})
|
|
707
|
+
|
|
708
|
+
// Combine cache with today's stats
|
|
709
|
+
return cacheToStats(updatedCache, todayStats)
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
export type StatsDateRange = '7d' | '30d' | 'all'
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* Aggregates stats for a specific date range.
|
|
716
|
+
* For 'all', uses the cached aggregation. For other ranges, processes files directly.
|
|
717
|
+
*/
|
|
718
|
+
export async function aggregateClaudeCodeStatsForRange(
|
|
719
|
+
range: StatsDateRange,
|
|
720
|
+
): Promise<ClaudeCodeStats> {
|
|
721
|
+
if (range === 'all') {
|
|
722
|
+
return aggregateClaudeCodeStats()
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
const allSessionFiles = await getAllSessionFiles()
|
|
726
|
+
if (allSessionFiles.length === 0) {
|
|
727
|
+
return getEmptyStats()
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
// Calculate fromDate based on range
|
|
731
|
+
const today = new Date()
|
|
732
|
+
const daysBack = range === '7d' ? 7 : 30
|
|
733
|
+
const fromDate = new Date(today)
|
|
734
|
+
fromDate.setDate(today.getDate() - daysBack + 1) // +1 to include today
|
|
735
|
+
const fromDateStr = toDateString(fromDate)
|
|
736
|
+
|
|
737
|
+
// Process session files for the date range
|
|
738
|
+
const stats = await processSessionFiles(allSessionFiles, {
|
|
739
|
+
fromDate: fromDateStr,
|
|
740
|
+
})
|
|
741
|
+
|
|
742
|
+
return processedStatsToClaudeCodeStats(stats)
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
/**
|
|
746
|
+
* Convert ProcessedStats to ClaudeCodeStats.
|
|
747
|
+
* Used for filtered date ranges that bypass the cache.
|
|
748
|
+
*/
|
|
749
|
+
function processedStatsToClaudeCodeStats(
|
|
750
|
+
stats: ProcessedStats,
|
|
751
|
+
): ClaudeCodeStats {
|
|
752
|
+
const dailyActivitySorted = stats.dailyActivity
|
|
753
|
+
.slice()
|
|
754
|
+
.sort((a, b) => a.date.localeCompare(b.date))
|
|
755
|
+
const dailyModelTokensSorted = stats.dailyModelTokens
|
|
756
|
+
.slice()
|
|
757
|
+
.sort((a, b) => a.date.localeCompare(b.date))
|
|
758
|
+
|
|
759
|
+
// Calculate streaks from daily activity
|
|
760
|
+
const streaks = calculateStreaks(dailyActivitySorted)
|
|
761
|
+
|
|
762
|
+
// Find longest session
|
|
763
|
+
let longestSession: SessionStats | null = null
|
|
764
|
+
for (const session of stats.sessionStats) {
|
|
765
|
+
if (!longestSession || session.duration > longestSession.duration) {
|
|
766
|
+
longestSession = session
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
// Find first/last session dates
|
|
771
|
+
let firstSessionDate: string | null = null
|
|
772
|
+
let lastSessionDate: string | null = null
|
|
773
|
+
for (const session of stats.sessionStats) {
|
|
774
|
+
if (!firstSessionDate || session.timestamp < firstSessionDate) {
|
|
775
|
+
firstSessionDate = session.timestamp
|
|
776
|
+
}
|
|
777
|
+
if (!lastSessionDate || session.timestamp > lastSessionDate) {
|
|
778
|
+
lastSessionDate = session.timestamp
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
// Peak activity day
|
|
783
|
+
const peakActivityDay =
|
|
784
|
+
dailyActivitySorted.length > 0
|
|
785
|
+
? dailyActivitySorted.reduce((max, d) =>
|
|
786
|
+
d.messageCount > max.messageCount ? d : max,
|
|
787
|
+
).date
|
|
788
|
+
: null
|
|
789
|
+
|
|
790
|
+
// Peak activity hour
|
|
791
|
+
const hourEntries = Object.entries(stats.hourCounts)
|
|
792
|
+
const peakActivityHour =
|
|
793
|
+
hourEntries.length > 0
|
|
794
|
+
? parseInt(
|
|
795
|
+
hourEntries.reduce((max, [hour, count]) =>
|
|
796
|
+
count > parseInt(max[1].toString()) ? [hour, count] : max,
|
|
797
|
+
)[0],
|
|
798
|
+
10,
|
|
799
|
+
)
|
|
800
|
+
: null
|
|
801
|
+
|
|
802
|
+
// Total days in range
|
|
803
|
+
const totalDays =
|
|
804
|
+
firstSessionDate && lastSessionDate
|
|
805
|
+
? Math.ceil(
|
|
806
|
+
(new Date(lastSessionDate).getTime() -
|
|
807
|
+
new Date(firstSessionDate).getTime()) /
|
|
808
|
+
(1000 * 60 * 60 * 24),
|
|
809
|
+
) + 1
|
|
810
|
+
: 0
|
|
811
|
+
|
|
812
|
+
const result: ClaudeCodeStats = {
|
|
813
|
+
totalSessions: stats.sessionStats.length,
|
|
814
|
+
totalMessages: stats.totalMessages,
|
|
815
|
+
totalDays,
|
|
816
|
+
activeDays: stats.dailyActivity.length,
|
|
817
|
+
streaks,
|
|
818
|
+
dailyActivity: dailyActivitySorted,
|
|
819
|
+
dailyModelTokens: dailyModelTokensSorted,
|
|
820
|
+
longestSession,
|
|
821
|
+
modelUsage: stats.modelUsage,
|
|
822
|
+
firstSessionDate,
|
|
823
|
+
lastSessionDate,
|
|
824
|
+
peakActivityDay,
|
|
825
|
+
peakActivityHour,
|
|
826
|
+
totalSpeculationTimeSavedMs: stats.totalSpeculationTimeSavedMs,
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
if (feature('SHOT_STATS') && stats.shotDistribution) {
|
|
830
|
+
result.shotDistribution = stats.shotDistribution
|
|
831
|
+
const totalWithShots = Object.values(stats.shotDistribution).reduce(
|
|
832
|
+
(sum, n) => sum + n,
|
|
833
|
+
0,
|
|
834
|
+
)
|
|
835
|
+
result.oneShotRate =
|
|
836
|
+
totalWithShots > 0
|
|
837
|
+
? Math.round(((stats.shotDistribution[1] || 0) / totalWithShots) * 100)
|
|
838
|
+
: 0
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
return result
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
/**
|
|
845
|
+
* Get the next day after a given date string (YYYY-MM-DD format).
|
|
846
|
+
*/
|
|
847
|
+
function getNextDay(dateStr: string): string {
|
|
848
|
+
const date = new Date(dateStr)
|
|
849
|
+
date.setDate(date.getDate() + 1)
|
|
850
|
+
return toDateString(date)
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
function calculateStreaks(dailyActivity: DailyActivity[]): StreakInfo {
|
|
854
|
+
if (dailyActivity.length === 0) {
|
|
855
|
+
return {
|
|
856
|
+
currentStreak: 0,
|
|
857
|
+
longestStreak: 0,
|
|
858
|
+
currentStreakStart: null,
|
|
859
|
+
longestStreakStart: null,
|
|
860
|
+
longestStreakEnd: null,
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
const today = new Date()
|
|
865
|
+
today.setHours(0, 0, 0, 0)
|
|
866
|
+
|
|
867
|
+
// Calculate current streak (working backwards from today)
|
|
868
|
+
let currentStreak = 0
|
|
869
|
+
let currentStreakStart: string | null = null
|
|
870
|
+
const checkDate = new Date(today)
|
|
871
|
+
|
|
872
|
+
// Build a set of active dates for quick lookup
|
|
873
|
+
const activeDates = new Set(dailyActivity.map(d => d.date))
|
|
874
|
+
|
|
875
|
+
while (true) {
|
|
876
|
+
const dateStr = toDateString(checkDate)
|
|
877
|
+
if (!activeDates.has(dateStr)) {
|
|
878
|
+
break
|
|
879
|
+
}
|
|
880
|
+
currentStreak++
|
|
881
|
+
currentStreakStart = dateStr
|
|
882
|
+
checkDate.setDate(checkDate.getDate() - 1)
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
// Calculate longest streak
|
|
886
|
+
let longestStreak = 0
|
|
887
|
+
let longestStreakStart: string | null = null
|
|
888
|
+
let longestStreakEnd: string | null = null
|
|
889
|
+
|
|
890
|
+
if (dailyActivity.length > 0) {
|
|
891
|
+
const sortedDates = Array.from(activeDates).sort()
|
|
892
|
+
let tempStreak = 1
|
|
893
|
+
let tempStart = sortedDates[0]!
|
|
894
|
+
|
|
895
|
+
for (let i = 1; i < sortedDates.length; i++) {
|
|
896
|
+
const prevDate = new Date(sortedDates[i - 1]!)
|
|
897
|
+
const currDate = new Date(sortedDates[i]!)
|
|
898
|
+
|
|
899
|
+
const dayDiff = Math.round(
|
|
900
|
+
(currDate.getTime() - prevDate.getTime()) / (1000 * 60 * 60 * 24),
|
|
901
|
+
)
|
|
902
|
+
|
|
903
|
+
if (dayDiff === 1) {
|
|
904
|
+
tempStreak++
|
|
905
|
+
} else {
|
|
906
|
+
if (tempStreak > longestStreak) {
|
|
907
|
+
longestStreak = tempStreak
|
|
908
|
+
longestStreakStart = tempStart
|
|
909
|
+
longestStreakEnd = sortedDates[i - 1]!
|
|
910
|
+
}
|
|
911
|
+
tempStreak = 1
|
|
912
|
+
tempStart = sortedDates[i]!
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
// Check final streak
|
|
917
|
+
if (tempStreak > longestStreak) {
|
|
918
|
+
longestStreak = tempStreak
|
|
919
|
+
longestStreakStart = tempStart
|
|
920
|
+
longestStreakEnd = sortedDates.at(-1)!
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
return {
|
|
925
|
+
currentStreak,
|
|
926
|
+
longestStreak,
|
|
927
|
+
currentStreakStart,
|
|
928
|
+
longestStreakStart,
|
|
929
|
+
longestStreakEnd,
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
const SHOT_COUNT_REGEX = /(\d+)-shotted by/
|
|
934
|
+
|
|
935
|
+
/**
|
|
936
|
+
* Extract the shot count from PR attribution text in a `gh pr create` Bash call.
|
|
937
|
+
* The attribution format is: "N-shotted by model-name"
|
|
938
|
+
* Returns the shot count, or null if not found.
|
|
939
|
+
*/
|
|
940
|
+
function extractShotCountFromMessages(
|
|
941
|
+
messages: TranscriptMessage[],
|
|
942
|
+
): number | null {
|
|
943
|
+
for (const m of messages) {
|
|
944
|
+
if (m.type !== 'assistant') continue
|
|
945
|
+
const content = m.message?.content
|
|
946
|
+
if (!Array.isArray(content)) continue
|
|
947
|
+
for (const block of content) {
|
|
948
|
+
if (
|
|
949
|
+
block.type !== 'tool_use' ||
|
|
950
|
+
!SHELL_TOOL_NAMES.includes(block.name) ||
|
|
951
|
+
typeof block.input !== 'object' ||
|
|
952
|
+
block.input === null ||
|
|
953
|
+
!('command' in block.input) ||
|
|
954
|
+
typeof block.input.command !== 'string'
|
|
955
|
+
) {
|
|
956
|
+
continue
|
|
957
|
+
}
|
|
958
|
+
const match = SHOT_COUNT_REGEX.exec(block.input.command)
|
|
959
|
+
if (match) {
|
|
960
|
+
return parseInt(match[1]!, 10)
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
return null
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
// Transcript message types — must match isTranscriptMessage() in sessionStorage.ts.
|
|
968
|
+
// The canonical dateKey (see processSessionFiles) reads mainMessages[0].timestamp,
|
|
969
|
+
// where mainMessages = entries.filter(isTranscriptMessage).filter(!isSidechain).
|
|
970
|
+
// This peek must extract the same value to be a safe skip optimization.
|
|
971
|
+
const TRANSCRIPT_MESSAGE_TYPES = new Set([
|
|
972
|
+
'user',
|
|
973
|
+
'assistant',
|
|
974
|
+
'attachment',
|
|
975
|
+
'system',
|
|
976
|
+
'progress',
|
|
977
|
+
])
|
|
978
|
+
|
|
979
|
+
/**
|
|
980
|
+
* Peeks at the head of a session file to get the session start date.
|
|
981
|
+
* Uses a small 4 KB read to avoid loading the full file.
|
|
982
|
+
*
|
|
983
|
+
* Session files typically begin with non-transcript entries (`mode`,
|
|
984
|
+
* `file-history-snapshot`, `attribution-snapshot`) before the first transcript
|
|
985
|
+
* message, so we scan lines until we hit one. Each complete line is JSON-parsed
|
|
986
|
+
* — naive string search is unsafe here because `file-history-snapshot` entries
|
|
987
|
+
* embed a nested `snapshot.timestamp` carrying the *previous* session's date
|
|
988
|
+
* (written by copyFileHistoryForResume), which would cause resumed sessions to
|
|
989
|
+
* be miscategorised as old and silently dropped from stats.
|
|
990
|
+
*
|
|
991
|
+
* Returns a YYYY-MM-DD string, or null if no transcript message fits in the
|
|
992
|
+
* head (caller falls through to the full read — safe default).
|
|
993
|
+
*/
|
|
994
|
+
export async function readSessionStartDate(
|
|
995
|
+
filePath: string,
|
|
996
|
+
): Promise<string | null> {
|
|
997
|
+
try {
|
|
998
|
+
const fd = await open(filePath, 'r')
|
|
999
|
+
try {
|
|
1000
|
+
const buf = Buffer.allocUnsafe(4096)
|
|
1001
|
+
const { bytesRead } = await fd.read(buf, 0, buf.length, 0)
|
|
1002
|
+
if (bytesRead === 0) return null
|
|
1003
|
+
const head = buf.toString('utf8', 0, bytesRead)
|
|
1004
|
+
|
|
1005
|
+
// Only trust complete lines — the 4KB boundary may bisect a JSON entry.
|
|
1006
|
+
const lastNewline = head.lastIndexOf('\n')
|
|
1007
|
+
if (lastNewline < 0) return null
|
|
1008
|
+
|
|
1009
|
+
for (const line of head.slice(0, lastNewline).split('\n')) {
|
|
1010
|
+
if (!line) continue
|
|
1011
|
+
let entry: {
|
|
1012
|
+
type?: unknown
|
|
1013
|
+
timestamp?: unknown
|
|
1014
|
+
isSidechain?: unknown
|
|
1015
|
+
}
|
|
1016
|
+
try {
|
|
1017
|
+
entry = jsonParse(line)
|
|
1018
|
+
} catch {
|
|
1019
|
+
continue
|
|
1020
|
+
}
|
|
1021
|
+
if (typeof entry.type !== 'string') continue
|
|
1022
|
+
if (!TRANSCRIPT_MESSAGE_TYPES.has(entry.type)) continue
|
|
1023
|
+
if (entry.isSidechain === true) continue
|
|
1024
|
+
if (typeof entry.timestamp !== 'string') return null
|
|
1025
|
+
const date = new Date(entry.timestamp)
|
|
1026
|
+
if (Number.isNaN(date.getTime())) return null
|
|
1027
|
+
return toDateString(date)
|
|
1028
|
+
}
|
|
1029
|
+
return null
|
|
1030
|
+
} finally {
|
|
1031
|
+
await fd.close()
|
|
1032
|
+
}
|
|
1033
|
+
} catch {
|
|
1034
|
+
return null
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
function getEmptyStats(): ClaudeCodeStats {
|
|
1039
|
+
return {
|
|
1040
|
+
totalSessions: 0,
|
|
1041
|
+
totalMessages: 0,
|
|
1042
|
+
totalDays: 0,
|
|
1043
|
+
activeDays: 0,
|
|
1044
|
+
streaks: {
|
|
1045
|
+
currentStreak: 0,
|
|
1046
|
+
longestStreak: 0,
|
|
1047
|
+
currentStreakStart: null,
|
|
1048
|
+
longestStreakStart: null,
|
|
1049
|
+
longestStreakEnd: null,
|
|
1050
|
+
},
|
|
1051
|
+
dailyActivity: [],
|
|
1052
|
+
dailyModelTokens: [],
|
|
1053
|
+
longestSession: null,
|
|
1054
|
+
modelUsage: {},
|
|
1055
|
+
firstSessionDate: null,
|
|
1056
|
+
lastSessionDate: null,
|
|
1057
|
+
peakActivityDay: null,
|
|
1058
|
+
peakActivityHour: null,
|
|
1059
|
+
totalSpeculationTimeSavedMs: 0,
|
|
1060
|
+
}
|
|
1061
|
+
}
|