@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.
Files changed (934) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +171 -0
  3. package/bin/xcode +127 -0
  4. package/bin/xcode-test +84 -0
  5. package/bin/xcode.cmd +31 -0
  6. package/constants/apiLimits.ts +94 -0
  7. package/constants/betas.ts +52 -0
  8. package/constants/common.ts +33 -0
  9. package/constants/cyberRiskInstruction.ts +24 -0
  10. package/constants/errorIds.ts +15 -0
  11. package/constants/figures.ts +45 -0
  12. package/constants/files.ts +156 -0
  13. package/constants/github-app.ts +144 -0
  14. package/constants/keys.ts +11 -0
  15. package/constants/messages.ts +1 -0
  16. package/constants/oauth.ts +234 -0
  17. package/constants/outputStyles.ts +216 -0
  18. package/constants/product.ts +76 -0
  19. package/constants/prompts.ts +939 -0
  20. package/constants/spinnerVerbs.ts +204 -0
  21. package/constants/system.ts +95 -0
  22. package/constants/systemPromptSections.ts +68 -0
  23. package/constants/toolLimits.ts +56 -0
  24. package/constants/tools.ts +112 -0
  25. package/constants/turnCompletionVerbs.ts +12 -0
  26. package/constants/xml.ts +86 -0
  27. package/entrypoints/agentSdkTypes.ts +443 -0
  28. package/entrypoints/cli.tsx +307 -0
  29. package/entrypoints/init.ts +340 -0
  30. package/entrypoints/mcp.ts +196 -0
  31. package/entrypoints/sandboxTypes.ts +156 -0
  32. package/entrypoints/sdk/controlSchemas.ts +663 -0
  33. package/entrypoints/sdk/coreSchemas.ts +1889 -0
  34. package/entrypoints/sdk/coreTypes.generated.ts +2 -0
  35. package/entrypoints/sdk/coreTypes.ts +62 -0
  36. package/entrypoints/sdk/runtimeTypes.ts +140 -0
  37. package/entrypoints/sdk/sdkUtilityTypes.ts +3 -0
  38. package/entrypoints/sdk/toolTypes.ts +90 -0
  39. package/main.tsx +4686 -0
  40. package/package.json +120 -0
  41. package/services/AgentSummary/agentSummary.ts +179 -0
  42. package/services/MagicDocs/magicDocs.ts +254 -0
  43. package/services/MagicDocs/prompts.ts +127 -0
  44. package/services/PromptSuggestion/promptSuggestion.ts +523 -0
  45. package/services/PromptSuggestion/speculation.ts +991 -0
  46. package/services/SessionMemory/prompts.ts +324 -0
  47. package/services/SessionMemory/sessionMemory.ts +495 -0
  48. package/services/SessionMemory/sessionMemoryUtils.ts +207 -0
  49. package/services/analytics/config.ts +38 -0
  50. package/services/analytics/datadog.ts +307 -0
  51. package/services/analytics/firstPartyEventLogger.ts +449 -0
  52. package/services/analytics/firstPartyEventLoggingExporter.ts +806 -0
  53. package/services/analytics/growthbook.ts +1155 -0
  54. package/services/analytics/index.ts +173 -0
  55. package/services/analytics/metadata.ts +973 -0
  56. package/services/analytics/sink.ts +114 -0
  57. package/services/analytics/sinkKillswitch.ts +25 -0
  58. package/services/api/adminRequests.ts +119 -0
  59. package/services/api/bootstrap.ts +141 -0
  60. package/services/api/claude.ts +3422 -0
  61. package/services/api/client.ts +406 -0
  62. package/services/api/dumpPrompts.ts +226 -0
  63. package/services/api/emptyUsage.ts +22 -0
  64. package/services/api/errorUtils.ts +260 -0
  65. package/services/api/errors.ts +1207 -0
  66. package/services/api/filesApi.ts +748 -0
  67. package/services/api/firstTokenDate.ts +60 -0
  68. package/services/api/gemini.ts +359 -0
  69. package/services/api/geminiAdapter.ts +123 -0
  70. package/services/api/geminiClient.ts +291 -0
  71. package/services/api/grove.ts +357 -0
  72. package/services/api/logging.ts +788 -0
  73. package/services/api/metricsOptOut.ts +159 -0
  74. package/services/api/openRouterClient.ts +453 -0
  75. package/services/api/overageCreditGrant.ts +137 -0
  76. package/services/api/promptCacheBreakDetection.ts +727 -0
  77. package/services/api/referral.ts +281 -0
  78. package/services/api/sessionIngress.ts +514 -0
  79. package/services/api/ultrareviewQuota.ts +38 -0
  80. package/services/api/usage.ts +63 -0
  81. package/services/api/withRetry.ts +822 -0
  82. package/services/autoDream/autoDream.ts +324 -0
  83. package/services/autoDream/config.ts +21 -0
  84. package/services/autoDream/consolidationLock.ts +140 -0
  85. package/services/autoDream/consolidationPrompt.ts +65 -0
  86. package/services/awaySummary.ts +74 -0
  87. package/services/claudeAiLimits.ts +515 -0
  88. package/services/claudeAiLimitsHook.ts +23 -0
  89. package/services/compact/apiMicrocompact.ts +153 -0
  90. package/services/compact/autoCompact.ts +351 -0
  91. package/services/compact/compact.ts +1705 -0
  92. package/services/compact/compactWarningHook.ts +16 -0
  93. package/services/compact/compactWarningState.ts +18 -0
  94. package/services/compact/grouping.ts +63 -0
  95. package/services/compact/microCompact.ts +530 -0
  96. package/services/compact/postCompactCleanup.ts +77 -0
  97. package/services/compact/prompt.ts +374 -0
  98. package/services/compact/sessionMemoryCompact.ts +630 -0
  99. package/services/compact/timeBasedMCConfig.ts +43 -0
  100. package/services/diagnosticTracking.ts +397 -0
  101. package/services/extractMemories/extractMemories.ts +517 -0
  102. package/services/extractMemories/prompts.ts +154 -0
  103. package/services/internalLogging.ts +90 -0
  104. package/services/lsp/LSPClient.ts +447 -0
  105. package/services/lsp/LSPDiagnosticRegistry.ts +386 -0
  106. package/services/lsp/LSPServerInstance.ts +511 -0
  107. package/services/lsp/LSPServerManager.ts +420 -0
  108. package/services/lsp/config.ts +79 -0
  109. package/services/lsp/manager.ts +289 -0
  110. package/services/lsp/passiveFeedback.ts +328 -0
  111. package/services/mcp/InProcessTransport.ts +63 -0
  112. package/services/mcp/MCPConnectionManager.tsx +73 -0
  113. package/services/mcp/SdkControlTransport.ts +136 -0
  114. package/services/mcp/auth.ts +2465 -0
  115. package/services/mcp/channelAllowlist.ts +76 -0
  116. package/services/mcp/channelNotification.ts +316 -0
  117. package/services/mcp/channelPermissions.ts +240 -0
  118. package/services/mcp/claudeai.ts +164 -0
  119. package/services/mcp/client.ts +3348 -0
  120. package/services/mcp/config.ts +1578 -0
  121. package/services/mcp/elicitationHandler.ts +313 -0
  122. package/services/mcp/envExpansion.ts +38 -0
  123. package/services/mcp/headersHelper.ts +138 -0
  124. package/services/mcp/mcpStringUtils.ts +106 -0
  125. package/services/mcp/normalization.ts +23 -0
  126. package/services/mcp/oauthPort.ts +78 -0
  127. package/services/mcp/officialRegistry.ts +72 -0
  128. package/services/mcp/types.ts +258 -0
  129. package/services/mcp/useManageMCPConnections.ts +1141 -0
  130. package/services/mcp/utils.ts +575 -0
  131. package/services/mcp/vscodeSdkMcp.ts +112 -0
  132. package/services/mcp/xaa.ts +511 -0
  133. package/services/mcp/xaaIdpLogin.ts +487 -0
  134. package/services/mcpServerApproval.tsx +41 -0
  135. package/services/mockRateLimits.ts +882 -0
  136. package/services/notifier.ts +156 -0
  137. package/services/oauth/auth-code-listener.ts +211 -0
  138. package/services/oauth/client.ts +566 -0
  139. package/services/oauth/crypto.ts +23 -0
  140. package/services/oauth/getOauthProfile.ts +53 -0
  141. package/services/oauth/index.ts +198 -0
  142. package/services/plugins/PluginInstallationManager.ts +184 -0
  143. package/services/plugins/pluginCliCommands.ts +344 -0
  144. package/services/plugins/pluginOperations.ts +1088 -0
  145. package/services/policyLimits/index.ts +663 -0
  146. package/services/policyLimits/types.ts +27 -0
  147. package/services/preventSleep.ts +165 -0
  148. package/services/rateLimitMessages.ts +344 -0
  149. package/services/rateLimitMocking.ts +144 -0
  150. package/services/remoteManagedSettings/index.ts +638 -0
  151. package/services/remoteManagedSettings/securityCheck.tsx +74 -0
  152. package/services/remoteManagedSettings/syncCache.ts +112 -0
  153. package/services/remoteManagedSettings/syncCacheState.ts +96 -0
  154. package/services/remoteManagedSettings/types.ts +31 -0
  155. package/services/settingsSync/index.ts +581 -0
  156. package/services/settingsSync/types.ts +67 -0
  157. package/services/teamMemorySync/index.ts +1256 -0
  158. package/services/teamMemorySync/secretScanner.ts +324 -0
  159. package/services/teamMemorySync/teamMemSecretGuard.ts +44 -0
  160. package/services/teamMemorySync/types.ts +156 -0
  161. package/services/teamMemorySync/watcher.ts +387 -0
  162. package/services/tips/tipHistory.ts +17 -0
  163. package/services/tips/tipRegistry.ts +686 -0
  164. package/services/tips/tipScheduler.ts +58 -0
  165. package/services/tokenEstimation.ts +495 -0
  166. package/services/toolUseSummary/toolUseSummaryGenerator.ts +112 -0
  167. package/services/tools/StreamingToolExecutor.ts +530 -0
  168. package/services/tools/toolExecution.ts +1745 -0
  169. package/services/tools/toolHooks.ts +650 -0
  170. package/services/tools/toolOrchestration.ts +188 -0
  171. package/services/vcr.ts +406 -0
  172. package/services/voice.ts +525 -0
  173. package/services/voiceKeyterms.ts +106 -0
  174. package/services/voiceStreamSTT.ts +544 -0
  175. package/tools/AgentTool/AgentTool.tsx +1398 -0
  176. package/tools/AgentTool/UI.tsx +872 -0
  177. package/tools/AgentTool/agentColorManager.ts +66 -0
  178. package/tools/AgentTool/agentDisplay.ts +104 -0
  179. package/tools/AgentTool/agentMemory.ts +177 -0
  180. package/tools/AgentTool/agentMemorySnapshot.ts +197 -0
  181. package/tools/AgentTool/agentToolUtils.ts +686 -0
  182. package/tools/AgentTool/built-in/claudeCodeGuideAgent.ts +205 -0
  183. package/tools/AgentTool/built-in/exploreAgent.ts +83 -0
  184. package/tools/AgentTool/built-in/generalPurposeAgent.ts +34 -0
  185. package/tools/AgentTool/built-in/planAgent.ts +92 -0
  186. package/tools/AgentTool/built-in/statuslineSetup.ts +144 -0
  187. package/tools/AgentTool/built-in/verificationAgent.ts +152 -0
  188. package/tools/AgentTool/builtInAgents.ts +72 -0
  189. package/tools/AgentTool/constants.ts +12 -0
  190. package/tools/AgentTool/forkSubagent.ts +210 -0
  191. package/tools/AgentTool/loadAgentsDir.ts +755 -0
  192. package/tools/AgentTool/prompt.ts +287 -0
  193. package/tools/AgentTool/resumeAgent.ts +265 -0
  194. package/tools/AgentTool/runAgent.ts +973 -0
  195. package/tools/AskUserQuestionTool/AskUserQuestionTool.tsx +266 -0
  196. package/tools/AskUserQuestionTool/prompt.ts +44 -0
  197. package/tools/BashTool/BashTool.tsx +1144 -0
  198. package/tools/BashTool/BashToolResultMessage.tsx +191 -0
  199. package/tools/BashTool/UI.tsx +185 -0
  200. package/tools/BashTool/bashCommandHelpers.ts +265 -0
  201. package/tools/BashTool/bashPermissions.ts +2621 -0
  202. package/tools/BashTool/bashSecurity.ts +2592 -0
  203. package/tools/BashTool/commandSemantics.ts +140 -0
  204. package/tools/BashTool/commentLabel.ts +13 -0
  205. package/tools/BashTool/destructiveCommandWarning.ts +102 -0
  206. package/tools/BashTool/modeValidation.ts +115 -0
  207. package/tools/BashTool/pathValidation.ts +1303 -0
  208. package/tools/BashTool/prompt.ts +369 -0
  209. package/tools/BashTool/readOnlyValidation.ts +1990 -0
  210. package/tools/BashTool/sedEditParser.ts +322 -0
  211. package/tools/BashTool/sedValidation.ts +684 -0
  212. package/tools/BashTool/shouldUseSandbox.ts +153 -0
  213. package/tools/BashTool/toolName.ts +2 -0
  214. package/tools/BashTool/utils.ts +223 -0
  215. package/tools/BriefTool/BriefTool.ts +204 -0
  216. package/tools/BriefTool/UI.tsx +101 -0
  217. package/tools/BriefTool/attachments.ts +110 -0
  218. package/tools/BriefTool/prompt.ts +22 -0
  219. package/tools/BriefTool/upload.ts +174 -0
  220. package/tools/ConfigTool/ConfigTool.ts +467 -0
  221. package/tools/ConfigTool/UI.tsx +38 -0
  222. package/tools/ConfigTool/constants.ts +1 -0
  223. package/tools/ConfigTool/prompt.ts +93 -0
  224. package/tools/ConfigTool/supportedSettings.ts +211 -0
  225. package/tools/EnterPlanModeTool/EnterPlanModeTool.ts +126 -0
  226. package/tools/EnterPlanModeTool/UI.tsx +33 -0
  227. package/tools/EnterPlanModeTool/constants.ts +1 -0
  228. package/tools/EnterPlanModeTool/prompt.ts +170 -0
  229. package/tools/EnterWorktreeTool/EnterWorktreeTool.ts +127 -0
  230. package/tools/EnterWorktreeTool/UI.tsx +20 -0
  231. package/tools/EnterWorktreeTool/constants.ts +1 -0
  232. package/tools/EnterWorktreeTool/prompt.ts +30 -0
  233. package/tools/ExitPlanModeTool/ExitPlanModeV2Tool.ts +493 -0
  234. package/tools/ExitPlanModeTool/UI.tsx +82 -0
  235. package/tools/ExitPlanModeTool/constants.ts +2 -0
  236. package/tools/ExitPlanModeTool/prompt.ts +29 -0
  237. package/tools/ExitWorktreeTool/ExitWorktreeTool.ts +329 -0
  238. package/tools/ExitWorktreeTool/UI.tsx +25 -0
  239. package/tools/ExitWorktreeTool/constants.ts +1 -0
  240. package/tools/ExitWorktreeTool/prompt.ts +32 -0
  241. package/tools/FileEditTool/FileEditTool.ts +625 -0
  242. package/tools/FileEditTool/UI.tsx +289 -0
  243. package/tools/FileEditTool/constants.ts +11 -0
  244. package/tools/FileEditTool/prompt.ts +28 -0
  245. package/tools/FileEditTool/types.ts +85 -0
  246. package/tools/FileEditTool/utils.ts +775 -0
  247. package/tools/FileReadTool/FileReadTool.ts +1183 -0
  248. package/tools/FileReadTool/UI.tsx +185 -0
  249. package/tools/FileReadTool/imageProcessor.ts +94 -0
  250. package/tools/FileReadTool/limits.ts +92 -0
  251. package/tools/FileReadTool/prompt.ts +49 -0
  252. package/tools/FileWriteTool/FileWriteTool.ts +434 -0
  253. package/tools/FileWriteTool/UI.tsx +405 -0
  254. package/tools/FileWriteTool/prompt.ts +18 -0
  255. package/tools/GlobTool/GlobTool.ts +198 -0
  256. package/tools/GlobTool/UI.tsx +63 -0
  257. package/tools/GlobTool/prompt.ts +7 -0
  258. package/tools/GrepTool/GrepTool.ts +577 -0
  259. package/tools/GrepTool/UI.tsx +201 -0
  260. package/tools/GrepTool/prompt.ts +18 -0
  261. package/tools/LSPTool/LSPTool.ts +860 -0
  262. package/tools/LSPTool/UI.tsx +228 -0
  263. package/tools/LSPTool/formatters.ts +592 -0
  264. package/tools/LSPTool/prompt.ts +21 -0
  265. package/tools/LSPTool/schemas.ts +215 -0
  266. package/tools/LSPTool/symbolContext.ts +90 -0
  267. package/tools/ListMcpResourcesTool/ListMcpResourcesTool.ts +123 -0
  268. package/tools/ListMcpResourcesTool/UI.tsx +29 -0
  269. package/tools/ListMcpResourcesTool/prompt.ts +20 -0
  270. package/tools/MCPTool/MCPTool.ts +77 -0
  271. package/tools/MCPTool/UI.tsx +403 -0
  272. package/tools/MCPTool/classifyForCollapse.ts +604 -0
  273. package/tools/MCPTool/prompt.ts +3 -0
  274. package/tools/McpAuthTool/McpAuthTool.ts +215 -0
  275. package/tools/NotebookEditTool/NotebookEditTool.ts +490 -0
  276. package/tools/NotebookEditTool/UI.tsx +93 -0
  277. package/tools/NotebookEditTool/constants.ts +2 -0
  278. package/tools/NotebookEditTool/prompt.ts +3 -0
  279. package/tools/PowerShellTool/PowerShellTool.tsx +1001 -0
  280. package/tools/PowerShellTool/UI.tsx +131 -0
  281. package/tools/PowerShellTool/clmTypes.ts +211 -0
  282. package/tools/PowerShellTool/commandSemantics.ts +142 -0
  283. package/tools/PowerShellTool/commonParameters.ts +30 -0
  284. package/tools/PowerShellTool/destructiveCommandWarning.ts +109 -0
  285. package/tools/PowerShellTool/gitSafety.ts +176 -0
  286. package/tools/PowerShellTool/modeValidation.ts +404 -0
  287. package/tools/PowerShellTool/pathValidation.ts +2049 -0
  288. package/tools/PowerShellTool/powershellPermissions.ts +1648 -0
  289. package/tools/PowerShellTool/powershellSecurity.ts +1090 -0
  290. package/tools/PowerShellTool/prompt.ts +145 -0
  291. package/tools/PowerShellTool/readOnlyValidation.ts +1823 -0
  292. package/tools/PowerShellTool/toolName.ts +2 -0
  293. package/tools/REPLTool/constants.ts +46 -0
  294. package/tools/REPLTool/primitiveTools.ts +39 -0
  295. package/tools/ReadMcpResourceTool/ReadMcpResourceTool.ts +158 -0
  296. package/tools/ReadMcpResourceTool/UI.tsx +37 -0
  297. package/tools/ReadMcpResourceTool/prompt.ts +16 -0
  298. package/tools/RemoteTriggerTool/RemoteTriggerTool.ts +161 -0
  299. package/tools/RemoteTriggerTool/UI.tsx +17 -0
  300. package/tools/RemoteTriggerTool/prompt.ts +15 -0
  301. package/tools/ScheduleCronTool/CronCreateTool.ts +157 -0
  302. package/tools/ScheduleCronTool/CronDeleteTool.ts +95 -0
  303. package/tools/ScheduleCronTool/CronListTool.ts +97 -0
  304. package/tools/ScheduleCronTool/UI.tsx +60 -0
  305. package/tools/ScheduleCronTool/prompt.ts +135 -0
  306. package/tools/SendMessageTool/SendMessageTool.ts +917 -0
  307. package/tools/SendMessageTool/UI.tsx +31 -0
  308. package/tools/SendMessageTool/constants.ts +1 -0
  309. package/tools/SendMessageTool/prompt.ts +49 -0
  310. package/tools/SkillTool/SkillTool.ts +1108 -0
  311. package/tools/SkillTool/UI.tsx +128 -0
  312. package/tools/SkillTool/constants.ts +1 -0
  313. package/tools/SkillTool/prompt.ts +241 -0
  314. package/tools/SleepTool/prompt.ts +17 -0
  315. package/tools/SyntheticOutputTool/SyntheticOutputTool.ts +163 -0
  316. package/tools/TaskCreateTool/TaskCreateTool.ts +138 -0
  317. package/tools/TaskCreateTool/constants.ts +1 -0
  318. package/tools/TaskCreateTool/prompt.ts +56 -0
  319. package/tools/TaskGetTool/TaskGetTool.ts +128 -0
  320. package/tools/TaskGetTool/constants.ts +1 -0
  321. package/tools/TaskGetTool/prompt.ts +24 -0
  322. package/tools/TaskListTool/TaskListTool.ts +116 -0
  323. package/tools/TaskListTool/constants.ts +1 -0
  324. package/tools/TaskListTool/prompt.ts +49 -0
  325. package/tools/TaskOutputTool/TaskOutputTool.tsx +584 -0
  326. package/tools/TaskOutputTool/constants.ts +1 -0
  327. package/tools/TaskStopTool/TaskStopTool.ts +131 -0
  328. package/tools/TaskStopTool/UI.tsx +41 -0
  329. package/tools/TaskStopTool/prompt.ts +8 -0
  330. package/tools/TaskUpdateTool/TaskUpdateTool.ts +406 -0
  331. package/tools/TaskUpdateTool/constants.ts +1 -0
  332. package/tools/TaskUpdateTool/prompt.ts +77 -0
  333. package/tools/TeamCreateTool/TeamCreateTool.ts +240 -0
  334. package/tools/TeamCreateTool/UI.tsx +6 -0
  335. package/tools/TeamCreateTool/constants.ts +1 -0
  336. package/tools/TeamCreateTool/prompt.ts +113 -0
  337. package/tools/TeamDeleteTool/TeamDeleteTool.ts +139 -0
  338. package/tools/TeamDeleteTool/UI.tsx +20 -0
  339. package/tools/TeamDeleteTool/constants.ts +1 -0
  340. package/tools/TeamDeleteTool/prompt.ts +16 -0
  341. package/tools/TodoWriteTool/TodoWriteTool.ts +115 -0
  342. package/tools/TodoWriteTool/constants.ts +1 -0
  343. package/tools/TodoWriteTool/prompt.ts +184 -0
  344. package/tools/ToolSearchTool/ToolSearchTool.ts +471 -0
  345. package/tools/ToolSearchTool/constants.ts +1 -0
  346. package/tools/ToolSearchTool/prompt.ts +121 -0
  347. package/tools/TungstenTool/TungstenTool.ts +4 -0
  348. package/tools/WebFetchTool/UI.tsx +72 -0
  349. package/tools/WebFetchTool/WebFetchTool.ts +318 -0
  350. package/tools/WebFetchTool/preapproved.ts +166 -0
  351. package/tools/WebFetchTool/prompt.ts +46 -0
  352. package/tools/WebFetchTool/utils.ts +530 -0
  353. package/tools/WebSearchTool/UI.tsx +101 -0
  354. package/tools/WebSearchTool/WebSearchTool.ts +435 -0
  355. package/tools/WebSearchTool/prompt.ts +34 -0
  356. package/tools/WorkflowTool/constants.ts +2 -0
  357. package/tools/XMemIngestTool/XMemIngestTool.ts +140 -0
  358. package/tools/XMemIngestTool/prompt.ts +13 -0
  359. package/tools/XMemRetrieveTool/XMemRetrieveTool.ts +177 -0
  360. package/tools/XMemRetrieveTool/prompt.ts +16 -0
  361. package/tools/XMemSearchTool/XMemSearchTool.ts +172 -0
  362. package/tools/XMemSearchTool/prompt.ts +11 -0
  363. package/tools/shared/gitOperationTracking.ts +277 -0
  364. package/tools/shared/spawnMultiAgent.ts +1093 -0
  365. package/tools/testing/TestingPermissionTool.tsx +74 -0
  366. package/tools/utils.ts +40 -0
  367. package/utils/CircularBuffer.ts +84 -0
  368. package/utils/Cursor.ts +1530 -0
  369. package/utils/QueryGuard.ts +121 -0
  370. package/utils/Shell.ts +474 -0
  371. package/utils/ShellCommand.ts +465 -0
  372. package/utils/abortController.ts +99 -0
  373. package/utils/activityManager.ts +164 -0
  374. package/utils/advisor.ts +145 -0
  375. package/utils/agentContext.ts +178 -0
  376. package/utils/agentId.ts +99 -0
  377. package/utils/agentSwarmsEnabled.ts +44 -0
  378. package/utils/agenticSessionSearch.ts +307 -0
  379. package/utils/analyzeContext.ts +1382 -0
  380. package/utils/ansiToPng.ts +334 -0
  381. package/utils/ansiToSvg.ts +272 -0
  382. package/utils/api.ts +718 -0
  383. package/utils/apiPreconnect.ts +71 -0
  384. package/utils/appleTerminalBackup.ts +124 -0
  385. package/utils/argumentSubstitution.ts +145 -0
  386. package/utils/array.ts +13 -0
  387. package/utils/asciicast.ts +239 -0
  388. package/utils/attachments.ts +4091 -0
  389. package/utils/attribution.ts +393 -0
  390. package/utils/auth.ts +2002 -0
  391. package/utils/authFileDescriptor.ts +196 -0
  392. package/utils/authPortable.ts +19 -0
  393. package/utils/autoModeDenials.ts +26 -0
  394. package/utils/autoRunIssue.tsx +122 -0
  395. package/utils/autoUpdater.ts +561 -0
  396. package/utils/aws.ts +74 -0
  397. package/utils/awsAuthStatusManager.ts +81 -0
  398. package/utils/axios.ts +8 -0
  399. package/utils/background/remote/preconditions.ts +235 -0
  400. package/utils/background/remote/remoteSession.ts +98 -0
  401. package/utils/backgroundHousekeeping.ts +94 -0
  402. package/utils/bash/ParsedCommand.ts +318 -0
  403. package/utils/bash/ShellSnapshot.ts +582 -0
  404. package/utils/bash/ast.ts +2679 -0
  405. package/utils/bash/bashParser.ts +4436 -0
  406. package/utils/bash/bashPipeCommand.ts +294 -0
  407. package/utils/bash/commands.ts +1339 -0
  408. package/utils/bash/heredoc.ts +733 -0
  409. package/utils/bash/parser.ts +230 -0
  410. package/utils/bash/prefix.ts +204 -0
  411. package/utils/bash/registry.ts +53 -0
  412. package/utils/bash/shellCompletion.ts +259 -0
  413. package/utils/bash/shellPrefix.ts +28 -0
  414. package/utils/bash/shellQuote.ts +304 -0
  415. package/utils/bash/shellQuoting.ts +128 -0
  416. package/utils/bash/specs/alias.ts +14 -0
  417. package/utils/bash/specs/index.ts +18 -0
  418. package/utils/bash/specs/nohup.ts +13 -0
  419. package/utils/bash/specs/pyright.ts +91 -0
  420. package/utils/bash/specs/sleep.ts +13 -0
  421. package/utils/bash/specs/srun.ts +31 -0
  422. package/utils/bash/specs/time.ts +13 -0
  423. package/utils/bash/specs/timeout.ts +20 -0
  424. package/utils/bash/treeSitterAnalysis.ts +506 -0
  425. package/utils/betas.ts +434 -0
  426. package/utils/billing.ts +78 -0
  427. package/utils/binaryCheck.ts +53 -0
  428. package/utils/browser.ts +68 -0
  429. package/utils/bufferedWriter.ts +100 -0
  430. package/utils/bundledMode.ts +22 -0
  431. package/utils/caCerts.ts +115 -0
  432. package/utils/caCertsConfig.ts +88 -0
  433. package/utils/cachePaths.ts +38 -0
  434. package/utils/classifierApprovals.ts +88 -0
  435. package/utils/classifierApprovalsHook.ts +17 -0
  436. package/utils/claudeCodeHints.ts +193 -0
  437. package/utils/claudeDesktop.ts +152 -0
  438. package/utils/claudeInChrome/chromeNativeHost.ts +527 -0
  439. package/utils/claudeInChrome/common.ts +540 -0
  440. package/utils/claudeInChrome/mcpServer.ts +292 -0
  441. package/utils/claudeInChrome/prompt.ts +83 -0
  442. package/utils/claudeInChrome/setup.ts +400 -0
  443. package/utils/claudeInChrome/setupPortable.ts +233 -0
  444. package/utils/claudeInChrome/toolRendering.tsx +262 -0
  445. package/utils/claudemd.ts +1479 -0
  446. package/utils/cleanup.ts +602 -0
  447. package/utils/cleanupRegistry.ts +25 -0
  448. package/utils/cliArgs.ts +60 -0
  449. package/utils/cliHighlight.ts +54 -0
  450. package/utils/codeIndexing.ts +206 -0
  451. package/utils/collapseBackgroundBashNotifications.ts +84 -0
  452. package/utils/collapseHookSummaries.ts +59 -0
  453. package/utils/collapseReadSearch.ts +1109 -0
  454. package/utils/collapseTeammateShutdowns.ts +55 -0
  455. package/utils/color-diff-mock.ts +27 -0
  456. package/utils/combinedAbortSignal.ts +47 -0
  457. package/utils/commandLifecycle.ts +21 -0
  458. package/utils/commitAttribution.ts +961 -0
  459. package/utils/completionCache.ts +166 -0
  460. package/utils/computerUse/appNames.ts +196 -0
  461. package/utils/computerUse/cleanup.ts +86 -0
  462. package/utils/computerUse/common.ts +61 -0
  463. package/utils/computerUse/computerUseLock.ts +215 -0
  464. package/utils/computerUse/drainRunLoop.ts +79 -0
  465. package/utils/computerUse/escHotkey.ts +54 -0
  466. package/utils/computerUse/executor.ts +658 -0
  467. package/utils/computerUse/gates.ts +72 -0
  468. package/utils/computerUse/hostAdapter.ts +69 -0
  469. package/utils/computerUse/inputLoader.ts +30 -0
  470. package/utils/computerUse/mcpServer.ts +106 -0
  471. package/utils/computerUse/setup.ts +53 -0
  472. package/utils/computerUse/swiftLoader.ts +23 -0
  473. package/utils/computerUse/toolRendering.tsx +125 -0
  474. package/utils/computerUse/wrapper.tsx +336 -0
  475. package/utils/concurrentSessions.ts +204 -0
  476. package/utils/config.ts +1817 -0
  477. package/utils/configConstants.ts +21 -0
  478. package/utils/contentArray.ts +51 -0
  479. package/utils/context.ts +221 -0
  480. package/utils/contextAnalysis.ts +272 -0
  481. package/utils/contextSuggestions.ts +235 -0
  482. package/utils/controlMessageCompat.ts +32 -0
  483. package/utils/conversationRecovery.ts +597 -0
  484. package/utils/cron.ts +308 -0
  485. package/utils/cronJitterConfig.ts +75 -0
  486. package/utils/cronScheduler.ts +565 -0
  487. package/utils/cronTasks.ts +458 -0
  488. package/utils/cronTasksLock.ts +195 -0
  489. package/utils/crossProjectResume.ts +75 -0
  490. package/utils/crypto.ts +13 -0
  491. package/utils/cwd.ts +32 -0
  492. package/utils/debug.ts +268 -0
  493. package/utils/debugFilter.ts +157 -0
  494. package/utils/deepLink/banner.ts +123 -0
  495. package/utils/deepLink/parseDeepLink.ts +170 -0
  496. package/utils/deepLink/protocolHandler.ts +136 -0
  497. package/utils/deepLink/registerProtocol.ts +348 -0
  498. package/utils/deepLink/terminalLauncher.ts +557 -0
  499. package/utils/deepLink/terminalPreference.ts +54 -0
  500. package/utils/desktopDeepLink.ts +236 -0
  501. package/utils/detectRepository.ts +178 -0
  502. package/utils/diagLogs.ts +94 -0
  503. package/utils/diff.ts +177 -0
  504. package/utils/directMemberMessage.ts +69 -0
  505. package/utils/displayTags.ts +51 -0
  506. package/utils/doctorContextWarnings.ts +265 -0
  507. package/utils/doctorDiagnostic.ts +625 -0
  508. package/utils/dxt/helpers.ts +88 -0
  509. package/utils/dxt/zip.ts +226 -0
  510. package/utils/earlyInput.ts +191 -0
  511. package/utils/editor.ts +183 -0
  512. package/utils/effort.ts +329 -0
  513. package/utils/embeddedTools.ts +29 -0
  514. package/utils/env.ts +347 -0
  515. package/utils/envDynamic.ts +151 -0
  516. package/utils/envUtils.ts +183 -0
  517. package/utils/envValidation.ts +38 -0
  518. package/utils/errorLogSink.ts +235 -0
  519. package/utils/errors.ts +238 -0
  520. package/utils/exampleCommands.ts +184 -0
  521. package/utils/execFileNoThrow.ts +150 -0
  522. package/utils/execFileNoThrowPortable.ts +89 -0
  523. package/utils/execSyncWrapper.ts +38 -0
  524. package/utils/exportRenderer.tsx +98 -0
  525. package/utils/extraUsage.ts +23 -0
  526. package/utils/fastMode.ts +532 -0
  527. package/utils/file.ts +584 -0
  528. package/utils/fileHistory.ts +1115 -0
  529. package/utils/fileOperationAnalytics.ts +71 -0
  530. package/utils/filePersistence/filePersistence.ts +287 -0
  531. package/utils/filePersistence/outputsScanner.ts +126 -0
  532. package/utils/fileRead.ts +102 -0
  533. package/utils/fileReadCache.ts +96 -0
  534. package/utils/fileStateCache.ts +142 -0
  535. package/utils/findExecutable.ts +17 -0
  536. package/utils/fingerprint.ts +76 -0
  537. package/utils/forkedAgent.ts +689 -0
  538. package/utils/format.ts +308 -0
  539. package/utils/formatBriefTimestamp.ts +81 -0
  540. package/utils/fpsTracker.ts +47 -0
  541. package/utils/frontmatterParser.ts +370 -0
  542. package/utils/fsOperations.ts +770 -0
  543. package/utils/fullscreen.ts +202 -0
  544. package/utils/generatedFiles.ts +136 -0
  545. package/utils/generators.ts +88 -0
  546. package/utils/genericProcessUtils.ts +184 -0
  547. package/utils/getWorktreePaths.ts +70 -0
  548. package/utils/getWorktreePathsPortable.ts +27 -0
  549. package/utils/ghPrStatus.ts +106 -0
  550. package/utils/git/gitConfigParser.ts +277 -0
  551. package/utils/git/gitFilesystem.ts +699 -0
  552. package/utils/git/gitignore.ts +99 -0
  553. package/utils/git.ts +926 -0
  554. package/utils/gitDiff.ts +532 -0
  555. package/utils/gitSettings.ts +18 -0
  556. package/utils/github/ghAuthStatus.ts +29 -0
  557. package/utils/githubRepoPathMapping.ts +162 -0
  558. package/utils/glob.ts +130 -0
  559. package/utils/gracefulShutdown.ts +529 -0
  560. package/utils/groupToolUses.ts +182 -0
  561. package/utils/handlePromptSubmit.ts +610 -0
  562. package/utils/hash.ts +46 -0
  563. package/utils/headlessProfiler.ts +178 -0
  564. package/utils/heapDumpService.ts +303 -0
  565. package/utils/heatmap.ts +198 -0
  566. package/utils/highlightMatch.tsx +28 -0
  567. package/utils/hooks/AsyncHookRegistry.ts +309 -0
  568. package/utils/hooks/apiQueryHookHelper.ts +141 -0
  569. package/utils/hooks/execAgentHook.ts +339 -0
  570. package/utils/hooks/execHttpHook.ts +242 -0
  571. package/utils/hooks/execPromptHook.ts +211 -0
  572. package/utils/hooks/fileChangedWatcher.ts +191 -0
  573. package/utils/hooks/hookEvents.ts +192 -0
  574. package/utils/hooks/hookHelpers.ts +83 -0
  575. package/utils/hooks/hooksConfigManager.ts +400 -0
  576. package/utils/hooks/hooksConfigSnapshot.ts +133 -0
  577. package/utils/hooks/hooksSettings.ts +271 -0
  578. package/utils/hooks/postSamplingHooks.ts +70 -0
  579. package/utils/hooks/registerFrontmatterHooks.ts +67 -0
  580. package/utils/hooks/registerSkillHooks.ts +64 -0
  581. package/utils/hooks/sessionHooks.ts +447 -0
  582. package/utils/hooks/skillImprovement.ts +267 -0
  583. package/utils/hooks/ssrfGuard.ts +294 -0
  584. package/utils/hooks.ts +5022 -0
  585. package/utils/horizontalScroll.ts +137 -0
  586. package/utils/http.ts +136 -0
  587. package/utils/hyperlink.ts +39 -0
  588. package/utils/iTermBackup.ts +73 -0
  589. package/utils/ide.ts +1494 -0
  590. package/utils/idePathConversion.ts +90 -0
  591. package/utils/idleTimeout.ts +53 -0
  592. package/utils/imagePaste.ts +416 -0
  593. package/utils/imageResizer.ts +880 -0
  594. package/utils/imageStore.ts +167 -0
  595. package/utils/imageValidation.ts +104 -0
  596. package/utils/immediateCommand.ts +15 -0
  597. package/utils/inProcessTeammateHelpers.ts +102 -0
  598. package/utils/ink.ts +26 -0
  599. package/utils/intl.ts +94 -0
  600. package/utils/jetbrains.ts +191 -0
  601. package/utils/json.ts +277 -0
  602. package/utils/jsonRead.ts +16 -0
  603. package/utils/keyboardShortcuts.ts +14 -0
  604. package/utils/lazySchema.ts +8 -0
  605. package/utils/listSessionsImpl.ts +454 -0
  606. package/utils/localInstaller.ts +162 -0
  607. package/utils/lockfile.ts +43 -0
  608. package/utils/log.ts +362 -0
  609. package/utils/logoV2Utils.ts +347 -0
  610. package/utils/mailbox.ts +73 -0
  611. package/utils/managedEnv.ts +199 -0
  612. package/utils/managedEnvConstants.ts +191 -0
  613. package/utils/markdown.ts +381 -0
  614. package/utils/markdownConfigLoader.ts +600 -0
  615. package/utils/mcp/dateTimeParser.ts +121 -0
  616. package/utils/mcp/elicitationValidation.ts +336 -0
  617. package/utils/mcpInstructionsDelta.ts +130 -0
  618. package/utils/mcpOutputStorage.ts +189 -0
  619. package/utils/mcpValidation.ts +208 -0
  620. package/utils/mcpWebSocketTransport.ts +200 -0
  621. package/utils/memoize.ts +269 -0
  622. package/utils/memory/types.ts +12 -0
  623. package/utils/memory/versions.ts +8 -0
  624. package/utils/memoryFileDetection.ts +289 -0
  625. package/utils/messagePredicates.ts +8 -0
  626. package/utils/messageQueueManager.ts +547 -0
  627. package/utils/messages/mappers.ts +290 -0
  628. package/utils/messages/systemInit.ts +96 -0
  629. package/utils/messages.ts +5520 -0
  630. package/utils/model/agent.ts +157 -0
  631. package/utils/model/aliases.ts +35 -0
  632. package/utils/model/antModels.ts +64 -0
  633. package/utils/model/bedrock.ts +265 -0
  634. package/utils/model/check1mAccess.ts +72 -0
  635. package/utils/model/configs.ts +158 -0
  636. package/utils/model/contextWindowUpgradeCheck.ts +47 -0
  637. package/utils/model/deprecation.ts +101 -0
  638. package/utils/model/model.ts +654 -0
  639. package/utils/model/modelAllowlist.ts +170 -0
  640. package/utils/model/modelCapabilities.ts +118 -0
  641. package/utils/model/modelOptions.ts +589 -0
  642. package/utils/model/modelStrings.ts +170 -0
  643. package/utils/model/modelSupportOverrides.ts +50 -0
  644. package/utils/model/providers.ts +42 -0
  645. package/utils/model/validateModel.ts +159 -0
  646. package/utils/modelCost.ts +231 -0
  647. package/utils/modifiers.ts +36 -0
  648. package/utils/mtls.ts +179 -0
  649. package/utils/nativeInstaller/download.ts +523 -0
  650. package/utils/nativeInstaller/index.ts +18 -0
  651. package/utils/nativeInstaller/installer.ts +1708 -0
  652. package/utils/nativeInstaller/packageManagers.ts +336 -0
  653. package/utils/nativeInstaller/pidLock.ts +433 -0
  654. package/utils/notebook.ts +224 -0
  655. package/utils/objectGroupBy.ts +18 -0
  656. package/utils/pasteStore.ts +104 -0
  657. package/utils/path.ts +155 -0
  658. package/utils/pdf.ts +300 -0
  659. package/utils/pdfUtils.ts +70 -0
  660. package/utils/peerAddress.ts +21 -0
  661. package/utils/permissions/PermissionMode.ts +141 -0
  662. package/utils/permissions/PermissionPromptToolResultSchema.ts +127 -0
  663. package/utils/permissions/PermissionResult.ts +35 -0
  664. package/utils/permissions/PermissionRule.ts +40 -0
  665. package/utils/permissions/PermissionUpdate.ts +389 -0
  666. package/utils/permissions/PermissionUpdateSchema.ts +78 -0
  667. package/utils/permissions/autoModeState.ts +39 -0
  668. package/utils/permissions/bashClassifier.ts +61 -0
  669. package/utils/permissions/bypassPermissionsKillswitch.ts +155 -0
  670. package/utils/permissions/classifierDecision.ts +98 -0
  671. package/utils/permissions/classifierShared.ts +39 -0
  672. package/utils/permissions/dangerousPatterns.ts +80 -0
  673. package/utils/permissions/denialTracking.ts +45 -0
  674. package/utils/permissions/filesystem.ts +1777 -0
  675. package/utils/permissions/getNextPermissionMode.ts +101 -0
  676. package/utils/permissions/pathValidation.ts +485 -0
  677. package/utils/permissions/permissionExplainer.ts +250 -0
  678. package/utils/permissions/permissionRuleParser.ts +198 -0
  679. package/utils/permissions/permissionSetup.ts +1532 -0
  680. package/utils/permissions/permissions.ts +1486 -0
  681. package/utils/permissions/permissionsLoader.ts +296 -0
  682. package/utils/permissions/shadowedRuleDetection.ts +234 -0
  683. package/utils/permissions/shellRuleMatching.ts +228 -0
  684. package/utils/permissions/yoloClassifier.ts +1495 -0
  685. package/utils/planModeV2.ts +95 -0
  686. package/utils/plans.ts +397 -0
  687. package/utils/platform.ts +150 -0
  688. package/utils/plugins/addDirPluginSettings.ts +71 -0
  689. package/utils/plugins/cacheUtils.ts +196 -0
  690. package/utils/plugins/dependencyResolver.ts +305 -0
  691. package/utils/plugins/fetchTelemetry.ts +135 -0
  692. package/utils/plugins/gitAvailability.ts +69 -0
  693. package/utils/plugins/headlessPluginInstall.ts +174 -0
  694. package/utils/plugins/hintRecommendation.ts +164 -0
  695. package/utils/plugins/installCounts.ts +292 -0
  696. package/utils/plugins/installedPluginsManager.ts +1268 -0
  697. package/utils/plugins/loadPluginAgents.ts +348 -0
  698. package/utils/plugins/loadPluginCommands.ts +946 -0
  699. package/utils/plugins/loadPluginHooks.ts +287 -0
  700. package/utils/plugins/loadPluginOutputStyles.ts +178 -0
  701. package/utils/plugins/lspPluginIntegration.ts +387 -0
  702. package/utils/plugins/lspRecommendation.ts +374 -0
  703. package/utils/plugins/managedPlugins.ts +27 -0
  704. package/utils/plugins/marketplaceHelpers.ts +592 -0
  705. package/utils/plugins/marketplaceManager.ts +2643 -0
  706. package/utils/plugins/mcpPluginIntegration.ts +634 -0
  707. package/utils/plugins/mcpbHandler.ts +968 -0
  708. package/utils/plugins/officialMarketplace.ts +25 -0
  709. package/utils/plugins/officialMarketplaceGcs.ts +216 -0
  710. package/utils/plugins/officialMarketplaceStartupCheck.ts +439 -0
  711. package/utils/plugins/orphanedPluginFilter.ts +114 -0
  712. package/utils/plugins/parseMarketplaceInput.ts +162 -0
  713. package/utils/plugins/performStartupChecks.tsx +70 -0
  714. package/utils/plugins/pluginAutoupdate.ts +284 -0
  715. package/utils/plugins/pluginBlocklist.ts +127 -0
  716. package/utils/plugins/pluginDirectories.ts +178 -0
  717. package/utils/plugins/pluginFlagging.ts +208 -0
  718. package/utils/plugins/pluginIdentifier.ts +123 -0
  719. package/utils/plugins/pluginInstallationHelpers.ts +595 -0
  720. package/utils/plugins/pluginLoader.ts +3302 -0
  721. package/utils/plugins/pluginOptionsStorage.ts +400 -0
  722. package/utils/plugins/pluginPolicy.ts +20 -0
  723. package/utils/plugins/pluginStartupCheck.ts +341 -0
  724. package/utils/plugins/pluginVersioning.ts +157 -0
  725. package/utils/plugins/reconciler.ts +265 -0
  726. package/utils/plugins/refresh.ts +215 -0
  727. package/utils/plugins/schemas.ts +1681 -0
  728. package/utils/plugins/validatePlugin.ts +903 -0
  729. package/utils/plugins/walkPluginMarkdown.ts +69 -0
  730. package/utils/plugins/zipCache.ts +406 -0
  731. package/utils/plugins/zipCacheAdapters.ts +164 -0
  732. package/utils/powershell/dangerousCmdlets.ts +185 -0
  733. package/utils/powershell/parser.ts +1804 -0
  734. package/utils/powershell/staticPrefix.ts +316 -0
  735. package/utils/preflightChecks.tsx +151 -0
  736. package/utils/privacyLevel.ts +55 -0
  737. package/utils/process.ts +68 -0
  738. package/utils/processUserInput/processBashCommand.tsx +140 -0
  739. package/utils/processUserInput/processSlashCommand.tsx +922 -0
  740. package/utils/processUserInput/processTextPrompt.ts +100 -0
  741. package/utils/processUserInput/processUserInput.ts +605 -0
  742. package/utils/profilerBase.ts +46 -0
  743. package/utils/promptCategory.ts +49 -0
  744. package/utils/promptEditor.ts +188 -0
  745. package/utils/promptShellExecution.ts +183 -0
  746. package/utils/proxy.ts +426 -0
  747. package/utils/queryContext.ts +179 -0
  748. package/utils/queryHelpers.ts +552 -0
  749. package/utils/queryProfiler.ts +301 -0
  750. package/utils/queueProcessor.ts +95 -0
  751. package/utils/readEditContext.ts +227 -0
  752. package/utils/readFileInRange.ts +383 -0
  753. package/utils/releaseNotes.ts +360 -0
  754. package/utils/renderOptions.ts +113 -0
  755. package/utils/ripgrep.ts +679 -0
  756. package/utils/sandbox/sandbox-adapter.ts +985 -0
  757. package/utils/sandbox/sandbox-ui-utils.ts +12 -0
  758. package/utils/sanitization.ts +91 -0
  759. package/utils/screenshotClipboard.ts +121 -0
  760. package/utils/sdkEventQueue.ts +134 -0
  761. package/utils/secureStorage/fallbackStorage.ts +70 -0
  762. package/utils/secureStorage/index.ts +17 -0
  763. package/utils/secureStorage/keychainPrefetch.ts +116 -0
  764. package/utils/secureStorage/macOsKeychainHelpers.ts +111 -0
  765. package/utils/secureStorage/macOsKeychainStorage.ts +231 -0
  766. package/utils/secureStorage/plainTextStorage.ts +84 -0
  767. package/utils/semanticBoolean.ts +29 -0
  768. package/utils/semanticNumber.ts +36 -0
  769. package/utils/semver.ts +59 -0
  770. package/utils/sequential.ts +56 -0
  771. package/utils/sessionActivity.ts +133 -0
  772. package/utils/sessionEnvVars.ts +22 -0
  773. package/utils/sessionEnvironment.ts +166 -0
  774. package/utils/sessionFileAccessHooks.ts +250 -0
  775. package/utils/sessionIngressAuth.ts +140 -0
  776. package/utils/sessionRestore.ts +551 -0
  777. package/utils/sessionStart.ts +232 -0
  778. package/utils/sessionState.ts +150 -0
  779. package/utils/sessionStorage.ts +5105 -0
  780. package/utils/sessionStoragePortable.ts +793 -0
  781. package/utils/sessionTitle.ts +129 -0
  782. package/utils/sessionUrl.ts +64 -0
  783. package/utils/set.ts +53 -0
  784. package/utils/settings/allErrors.ts +32 -0
  785. package/utils/settings/applySettingsChange.ts +92 -0
  786. package/utils/settings/changeDetector.ts +488 -0
  787. package/utils/settings/constants.ts +202 -0
  788. package/utils/settings/internalWrites.ts +37 -0
  789. package/utils/settings/managedPath.ts +34 -0
  790. package/utils/settings/mdm/constants.ts +81 -0
  791. package/utils/settings/mdm/rawRead.ts +130 -0
  792. package/utils/settings/mdm/settings.ts +316 -0
  793. package/utils/settings/permissionValidation.ts +262 -0
  794. package/utils/settings/pluginOnlyPolicy.ts +60 -0
  795. package/utils/settings/schemaOutput.ts +8 -0
  796. package/utils/settings/settings.ts +1015 -0
  797. package/utils/settings/settingsCache.ts +80 -0
  798. package/utils/settings/toolValidationConfig.ts +103 -0
  799. package/utils/settings/types.ts +1149 -0
  800. package/utils/settings/validateEditTool.ts +45 -0
  801. package/utils/settings/validation.ts +265 -0
  802. package/utils/settings/validationTips.ts +164 -0
  803. package/utils/shell/bashProvider.ts +255 -0
  804. package/utils/shell/outputLimits.ts +14 -0
  805. package/utils/shell/powershellDetection.ts +107 -0
  806. package/utils/shell/powershellProvider.ts +123 -0
  807. package/utils/shell/prefix.ts +367 -0
  808. package/utils/shell/readOnlyCommandValidation.ts +1893 -0
  809. package/utils/shell/resolveDefaultShell.ts +14 -0
  810. package/utils/shell/shellProvider.ts +33 -0
  811. package/utils/shell/shellToolUtils.ts +22 -0
  812. package/utils/shell/specPrefix.ts +241 -0
  813. package/utils/shellConfig.ts +167 -0
  814. package/utils/sideQuery.ts +222 -0
  815. package/utils/sideQuestion.ts +155 -0
  816. package/utils/signal.ts +43 -0
  817. package/utils/sinks.ts +16 -0
  818. package/utils/skills/skillChangeDetector.ts +311 -0
  819. package/utils/slashCommandParsing.ts +60 -0
  820. package/utils/sleep.ts +84 -0
  821. package/utils/sliceAnsi.ts +91 -0
  822. package/utils/slowOperations.ts +286 -0
  823. package/utils/standaloneAgent.ts +23 -0
  824. package/utils/startupProfiler.ts +194 -0
  825. package/utils/staticRender.tsx +116 -0
  826. package/utils/stats.ts +1061 -0
  827. package/utils/statsCache.ts +434 -0
  828. package/utils/status.tsx +362 -0
  829. package/utils/statusNoticeDefinitions.tsx +198 -0
  830. package/utils/statusNoticeHelpers.ts +20 -0
  831. package/utils/stream.ts +76 -0
  832. package/utils/streamJsonStdoutGuard.ts +123 -0
  833. package/utils/streamlinedTransform.ts +201 -0
  834. package/utils/stringUtils.ts +235 -0
  835. package/utils/subprocessEnv.ts +99 -0
  836. package/utils/suggestions/commandSuggestions.ts +567 -0
  837. package/utils/suggestions/directoryCompletion.ts +263 -0
  838. package/utils/suggestions/shellHistoryCompletion.ts +119 -0
  839. package/utils/suggestions/skillUsageTracking.ts +55 -0
  840. package/utils/suggestions/slackChannelSuggestions.ts +209 -0
  841. package/utils/swarm/It2SetupPrompt.tsx +380 -0
  842. package/utils/swarm/backends/ITermBackend.ts +370 -0
  843. package/utils/swarm/backends/InProcessBackend.ts +339 -0
  844. package/utils/swarm/backends/PaneBackendExecutor.ts +354 -0
  845. package/utils/swarm/backends/TmuxBackend.ts +764 -0
  846. package/utils/swarm/backends/detection.ts +128 -0
  847. package/utils/swarm/backends/it2Setup.ts +245 -0
  848. package/utils/swarm/backends/registry.ts +464 -0
  849. package/utils/swarm/backends/teammateModeSnapshot.ts +87 -0
  850. package/utils/swarm/backends/types.ts +311 -0
  851. package/utils/swarm/constants.ts +33 -0
  852. package/utils/swarm/inProcessRunner.ts +1552 -0
  853. package/utils/swarm/leaderPermissionBridge.ts +54 -0
  854. package/utils/swarm/permissionSync.ts +928 -0
  855. package/utils/swarm/reconnection.ts +119 -0
  856. package/utils/swarm/spawnInProcess.ts +328 -0
  857. package/utils/swarm/spawnUtils.ts +146 -0
  858. package/utils/swarm/teamHelpers.ts +683 -0
  859. package/utils/swarm/teammateInit.ts +129 -0
  860. package/utils/swarm/teammateLayoutManager.ts +107 -0
  861. package/utils/swarm/teammateModel.ts +10 -0
  862. package/utils/swarm/teammatePromptAddendum.ts +18 -0
  863. package/utils/systemDirectories.ts +74 -0
  864. package/utils/systemPrompt.ts +123 -0
  865. package/utils/systemPromptType.ts +14 -0
  866. package/utils/systemTheme.ts +119 -0
  867. package/utils/taggedId.ts +54 -0
  868. package/utils/task/TaskOutput.ts +390 -0
  869. package/utils/task/diskOutput.ts +451 -0
  870. package/utils/task/framework.ts +308 -0
  871. package/utils/task/outputFormatting.ts +38 -0
  872. package/utils/task/sdkProgress.ts +36 -0
  873. package/utils/tasks.ts +862 -0
  874. package/utils/teamDiscovery.ts +81 -0
  875. package/utils/teamMemoryOps.ts +88 -0
  876. package/utils/teammate.ts +292 -0
  877. package/utils/teammateContext.ts +96 -0
  878. package/utils/teammateMailbox.ts +1183 -0
  879. package/utils/telemetry/betaSessionTracing.ts +491 -0
  880. package/utils/telemetry/bigqueryExporter.ts +252 -0
  881. package/utils/telemetry/events.ts +75 -0
  882. package/utils/telemetry/instrumentation.ts +825 -0
  883. package/utils/telemetry/logger.ts +26 -0
  884. package/utils/telemetry/perfettoTracing.ts +1120 -0
  885. package/utils/telemetry/pluginTelemetry.ts +289 -0
  886. package/utils/telemetry/sessionTracing.ts +927 -0
  887. package/utils/telemetry/skillLoadedEvent.ts +39 -0
  888. package/utils/telemetryAttributes.ts +71 -0
  889. package/utils/teleport/api.ts +466 -0
  890. package/utils/teleport/environmentSelection.ts +77 -0
  891. package/utils/teleport/environments.ts +120 -0
  892. package/utils/teleport/gitBundle.ts +292 -0
  893. package/utils/teleport.tsx +1226 -0
  894. package/utils/tempfile.ts +31 -0
  895. package/utils/terminal.ts +131 -0
  896. package/utils/terminalPanel.ts +191 -0
  897. package/utils/textHighlighting.ts +166 -0
  898. package/utils/theme.ts +639 -0
  899. package/utils/thinking.ts +162 -0
  900. package/utils/timeouts.ts +39 -0
  901. package/utils/tmuxSocket.ts +427 -0
  902. package/utils/todo/types.ts +18 -0
  903. package/utils/tokenBudget.ts +73 -0
  904. package/utils/tokens.ts +261 -0
  905. package/utils/toolErrors.ts +132 -0
  906. package/utils/toolPool.ts +79 -0
  907. package/utils/toolResultStorage.ts +1040 -0
  908. package/utils/toolSchemaCache.ts +26 -0
  909. package/utils/toolSearch.ts +756 -0
  910. package/utils/transcriptSearch.ts +202 -0
  911. package/utils/treeify.ts +170 -0
  912. package/utils/truncate.ts +179 -0
  913. package/utils/ultraplan/ccrSession.ts +349 -0
  914. package/utils/ultraplan/keyword.ts +127 -0
  915. package/utils/ultraplan/prompt.txt +1 -0
  916. package/utils/unaryLogging.ts +39 -0
  917. package/utils/undercover.ts +89 -0
  918. package/utils/user.ts +194 -0
  919. package/utils/userAgent.ts +10 -0
  920. package/utils/userPromptKeywords.ts +27 -0
  921. package/utils/uuid.ts +27 -0
  922. package/utils/warningHandler.ts +121 -0
  923. package/utils/which.ts +82 -0
  924. package/utils/windowsPaths.ts +173 -0
  925. package/utils/withResolvers.ts +13 -0
  926. package/utils/words.ts +800 -0
  927. package/utils/workloadContext.ts +57 -0
  928. package/utils/worktree.ts +1519 -0
  929. package/utils/worktreeModeEnabled.ts +11 -0
  930. package/utils/xdg.ts +65 -0
  931. package/utils/xmem.ts +6 -0
  932. package/utils/xml.ts +16 -0
  933. package/utils/yaml.ts +15 -0
  934. 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
+ }