yepanywhere 0.5.2 → 0.6.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 (858) hide show
  1. package/README.md +21 -5
  2. package/bundled/@yep-anywhere/shared/dist/agent-context.d.ts +9 -0
  3. package/bundled/@yep-anywhere/shared/dist/agent-context.d.ts.map +1 -0
  4. package/bundled/@yep-anywhere/shared/dist/agent-context.js +18 -0
  5. package/bundled/@yep-anywhere/shared/dist/agent-context.js.map +1 -0
  6. package/bundled/@yep-anywhere/shared/dist/app-types.d.ts +104 -1
  7. package/bundled/@yep-anywhere/shared/dist/app-types.d.ts.map +1 -1
  8. package/bundled/@yep-anywhere/shared/dist/app-types.js +4 -0
  9. package/bundled/@yep-anywhere/shared/dist/app-types.js.map +1 -1
  10. package/bundled/@yep-anywhere/shared/dist/binary-framing.d.ts +4 -1
  11. package/bundled/@yep-anywhere/shared/dist/binary-framing.d.ts.map +1 -1
  12. package/bundled/@yep-anywhere/shared/dist/binary-framing.js +8 -3
  13. package/bundled/@yep-anywhere/shared/dist/binary-framing.js.map +1 -1
  14. package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/AssistantEntrySchema.d.ts +4 -0
  15. package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/AssistantEntrySchema.d.ts.map +1 -1
  16. package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/BaseEntrySchema.d.ts +4 -0
  17. package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/BaseEntrySchema.d.ts.map +1 -1
  18. package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/BaseEntrySchema.js +7 -0
  19. package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/BaseEntrySchema.js.map +1 -1
  20. package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/ProgressEntrySchema.d.ts +4 -0
  21. package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/ProgressEntrySchema.d.ts.map +1 -1
  22. package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/SystemEntrySchema.d.ts +64 -1
  23. package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/SystemEntrySchema.d.ts.map +1 -1
  24. package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/SystemEntrySchema.js +9 -0
  25. package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/SystemEntrySchema.js.map +1 -1
  26. package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/UserEntrySchema.d.ts +4 -0
  27. package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/UserEntrySchema.d.ts.map +1 -1
  28. package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/guards.d.ts.map +1 -1
  29. package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/guards.js +45 -1
  30. package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/guards.js.map +1 -1
  31. package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/index.d.ts +144 -2
  32. package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/index.d.ts.map +1 -1
  33. package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/tool/ToolResultSchemas.d.ts +6 -4
  34. package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/tool/ToolResultSchemas.d.ts.map +1 -1
  35. package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/tool/ToolResultSchemas.js +8 -1
  36. package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/tool/ToolResultSchemas.js.map +1 -1
  37. package/bundled/@yep-anywhere/shared/dist/codex-schema/index.d.ts +3 -2
  38. package/bundled/@yep-anywhere/shared/dist/codex-schema/index.d.ts.map +1 -1
  39. package/bundled/@yep-anywhere/shared/dist/codex-schema/index.js +3 -2
  40. package/bundled/@yep-anywhere/shared/dist/codex-schema/index.js.map +1 -1
  41. package/bundled/@yep-anywhere/shared/dist/codex-schema/session.d.ts +87 -3
  42. package/bundled/@yep-anywhere/shared/dist/codex-schema/session.d.ts.map +1 -1
  43. package/bundled/@yep-anywhere/shared/dist/codex-schema/session.js +39 -1
  44. package/bundled/@yep-anywhere/shared/dist/codex-schema/session.js.map +1 -1
  45. package/bundled/@yep-anywhere/shared/dist/dag.d.ts +31 -11
  46. package/bundled/@yep-anywhere/shared/dist/dag.d.ts.map +1 -1
  47. package/bundled/@yep-anywhere/shared/dist/dag.js +77 -33
  48. package/bundled/@yep-anywhere/shared/dist/dag.js.map +1 -1
  49. package/bundled/@yep-anywhere/shared/dist/git-status.d.ts +70 -1
  50. package/bundled/@yep-anywhere/shared/dist/git-status.d.ts.map +1 -1
  51. package/bundled/@yep-anywhere/shared/dist/git-status.js +6 -1
  52. package/bundled/@yep-anywhere/shared/dist/git-status.js.map +1 -1
  53. package/bundled/@yep-anywhere/shared/dist/ideMetadata.js +1 -1
  54. package/bundled/@yep-anywhere/shared/dist/ideMetadata.js.map +1 -1
  55. package/bundled/@yep-anywhere/shared/dist/index.d.ts +20 -11
  56. package/bundled/@yep-anywhere/shared/dist/index.d.ts.map +1 -1
  57. package/bundled/@yep-anywhere/shared/dist/index.js +8 -3
  58. package/bundled/@yep-anywhere/shared/dist/index.js.map +1 -1
  59. package/bundled/@yep-anywhere/shared/dist/local-resource.d.ts +1 -0
  60. package/bundled/@yep-anywhere/shared/dist/local-resource.d.ts.map +1 -1
  61. package/bundled/@yep-anywhere/shared/dist/local-resource.js +4 -0
  62. package/bundled/@yep-anywhere/shared/dist/local-resource.js.map +1 -1
  63. package/bundled/@yep-anywhere/shared/dist/opencode-schema/events.d.ts +136 -0
  64. package/bundled/@yep-anywhere/shared/dist/opencode-schema/events.d.ts.map +1 -1
  65. package/bundled/@yep-anywhere/shared/dist/opencode-schema/events.js +65 -3
  66. package/bundled/@yep-anywhere/shared/dist/opencode-schema/events.js.map +1 -1
  67. package/bundled/@yep-anywhere/shared/dist/opencode-schema/types.d.ts +1 -1
  68. package/bundled/@yep-anywhere/shared/dist/opencode-schema/types.d.ts.map +1 -1
  69. package/bundled/@yep-anywhere/shared/dist/project-queue.d.ts +153 -0
  70. package/bundled/@yep-anywhere/shared/dist/project-queue.d.ts.map +1 -0
  71. package/bundled/@yep-anywhere/shared/dist/project-queue.js +8 -0
  72. package/bundled/@yep-anywhere/shared/dist/project-queue.js.map +1 -0
  73. package/bundled/@yep-anywhere/shared/dist/relay-protocol.d.ts +26 -2
  74. package/bundled/@yep-anywhere/shared/dist/relay-protocol.d.ts.map +1 -1
  75. package/bundled/@yep-anywhere/shared/dist/relay-protocol.js +33 -0
  76. package/bundled/@yep-anywhere/shared/dist/relay-protocol.js.map +1 -1
  77. package/bundled/@yep-anywhere/shared/dist/relay.d.ts +45 -5
  78. package/bundled/@yep-anywhere/shared/dist/relay.d.ts.map +1 -1
  79. package/bundled/@yep-anywhere/shared/dist/relay.js.map +1 -1
  80. package/bundled/@yep-anywhere/shared/dist/safe-restart.d.ts +25 -0
  81. package/bundled/@yep-anywhere/shared/dist/safe-restart.d.ts.map +1 -0
  82. package/bundled/@yep-anywhere/shared/dist/safe-restart.js +2 -0
  83. package/bundled/@yep-anywhere/shared/dist/safe-restart.js.map +1 -0
  84. package/bundled/@yep-anywhere/shared/dist/session/SessionView.d.ts +2 -2
  85. package/bundled/@yep-anywhere/shared/dist/session/SessionView.js +3 -3
  86. package/bundled/@yep-anywhere/shared/dist/session/SessionView.js.map +1 -1
  87. package/bundled/@yep-anywhere/shared/dist/session/UnifiedSession.d.ts +10 -0
  88. package/bundled/@yep-anywhere/shared/dist/session/UnifiedSession.d.ts.map +1 -1
  89. package/bundled/@yep-anywhere/shared/dist/session-liveness.d.ts +18 -0
  90. package/bundled/@yep-anywhere/shared/dist/session-liveness.d.ts.map +1 -1
  91. package/bundled/@yep-anywhere/shared/dist/types.d.ts +253 -8
  92. package/bundled/@yep-anywhere/shared/dist/types.d.ts.map +1 -1
  93. package/bundled/@yep-anywhere/shared/dist/types.js +48 -5
  94. package/bundled/@yep-anywhere/shared/dist/types.js.map +1 -1
  95. package/bundled/@yep-anywhere/shared/dist/upload.d.ts +34 -2
  96. package/bundled/@yep-anywhere/shared/dist/upload.d.ts.map +1 -1
  97. package/bundled/@yep-anywhere/shared/dist/user-message-metadata.d.ts +47 -0
  98. package/bundled/@yep-anywhere/shared/dist/user-message-metadata.d.ts.map +1 -1
  99. package/bundled/@yep-anywhere/shared/dist/user-message-metadata.js +59 -1
  100. package/bundled/@yep-anywhere/shared/dist/user-message-metadata.js.map +1 -1
  101. package/bundled/@yep-anywhere/shared/dist/workstreams.d.ts +54 -0
  102. package/bundled/@yep-anywhere/shared/dist/workstreams.d.ts.map +1 -0
  103. package/bundled/@yep-anywhere/shared/dist/workstreams.js +8 -0
  104. package/bundled/@yep-anywhere/shared/dist/workstreams.js.map +1 -0
  105. package/bundled/@yep-anywhere/shared/package.json +1 -1
  106. package/client-dist/assets/alegreya-sans-latin-400-italic-BQIUBrX-.woff2 +0 -0
  107. package/client-dist/assets/alegreya-sans-latin-400-normal-BxeZdXas.woff2 +0 -0
  108. package/client-dist/assets/alegreya-sans-latin-500-normal-uodOEoAl.woff2 +0 -0
  109. package/client-dist/assets/alegreya-sans-latin-700-normal-DFYOGfC8.woff2 +0 -0
  110. package/client-dist/assets/de-CHMDbVD5.js +6 -0
  111. package/client-dist/assets/es-CK8MPF_C.js +6 -0
  112. package/client-dist/assets/fira-mono-latin-400-normal-DVTTRLHv.woff2 +0 -0
  113. package/client-dist/assets/fira-mono-latin-ext-400-normal-B2gPvaNr.woff2 +0 -0
  114. package/client-dist/assets/fira-mono-symbols2-400-normal-C6JptOil.woff2 +0 -0
  115. package/client-dist/assets/fr-49PXQiUL.js +6 -0
  116. package/client-dist/assets/index-B-09fVut.js +557 -0
  117. package/client-dist/assets/index-uJnfvD1f.css +1 -0
  118. package/client-dist/assets/inter-latin-400-italic-D1l0FflY.woff2 +0 -0
  119. package/client-dist/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
  120. package/client-dist/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
  121. package/client-dist/assets/inter-latin-700-normal-Yt3aPRUw.woff2 +0 -0
  122. package/client-dist/assets/ja-CrCGPmoH.js +6 -0
  123. package/client-dist/assets/zh-CN-AFJxv5ke.js +6 -0
  124. package/client-dist/index.html +3 -3
  125. package/client-dist/sw.js +96 -9
  126. package/dist/app.d.ts +25 -0
  127. package/dist/app.d.ts.map +1 -1
  128. package/dist/app.js +350 -35
  129. package/dist/app.js.map +1 -1
  130. package/dist/augments/augment-generator.d.ts +1 -1
  131. package/dist/augments/augment-generator.d.ts.map +1 -1
  132. package/dist/augments/augment-generator.js +2 -2
  133. package/dist/augments/augment-generator.js.map +1 -1
  134. package/dist/augments/markdown-augments.d.ts +1 -1
  135. package/dist/augments/markdown-augments.d.ts.map +1 -1
  136. package/dist/augments/markdown-augments.js +5 -5
  137. package/dist/augments/markdown-augments.js.map +1 -1
  138. package/dist/augments/safe-markdown.d.ts +10 -0
  139. package/dist/augments/safe-markdown.d.ts.map +1 -1
  140. package/dist/augments/safe-markdown.js +146 -3
  141. package/dist/augments/safe-markdown.js.map +1 -1
  142. package/dist/augments/stream-augmenter.d.ts +3 -0
  143. package/dist/augments/stream-augmenter.d.ts.map +1 -1
  144. package/dist/augments/stream-augmenter.js +6 -3
  145. package/dist/augments/stream-augmenter.js.map +1 -1
  146. package/dist/augments/stream-coordinator.d.ts +5 -1
  147. package/dist/augments/stream-coordinator.d.ts.map +1 -1
  148. package/dist/augments/stream-coordinator.js +6 -4
  149. package/dist/augments/stream-coordinator.js.map +1 -1
  150. package/dist/augments/task-list-augments.d.ts +27 -0
  151. package/dist/augments/task-list-augments.d.ts.map +1 -0
  152. package/dist/augments/task-list-augments.js +360 -0
  153. package/dist/augments/task-list-augments.js.map +1 -0
  154. package/dist/cli.d.ts +1 -17
  155. package/dist/cli.d.ts.map +1 -1
  156. package/dist/cli.js +22 -8
  157. package/dist/cli.js.map +1 -1
  158. package/dist/codex/correlationDebugLogger.d.ts.map +1 -1
  159. package/dist/codex/correlationDebugLogger.js +36 -8
  160. package/dist/codex/correlationDebugLogger.js.map +1 -1
  161. package/dist/codex/normalization.d.ts +1 -0
  162. package/dist/codex/normalization.d.ts.map +1 -1
  163. package/dist/codex/normalization.js +262 -7
  164. package/dist/codex/normalization.js.map +1 -1
  165. package/dist/config.d.ts +49 -6
  166. package/dist/config.d.ts.map +1 -1
  167. package/dist/config.js +55 -14
  168. package/dist/config.js.map +1 -1
  169. package/dist/defaults.d.ts +3 -0
  170. package/dist/defaults.d.ts.map +1 -0
  171. package/dist/defaults.js +3 -0
  172. package/dist/defaults.js.map +1 -0
  173. package/dist/device/DeviceBridgeService.js +1 -1
  174. package/dist/device/DeviceBridgeService.js.map +1 -1
  175. package/dist/envSettings.d.ts +64 -0
  176. package/dist/envSettings.d.ts.map +1 -0
  177. package/dist/envSettings.js +553 -0
  178. package/dist/envSettings.js.map +1 -0
  179. package/dist/frontend/static.d.ts.map +1 -1
  180. package/dist/frontend/static.js +3 -1
  181. package/dist/frontend/static.js.map +1 -1
  182. package/dist/index.d.ts +1 -1
  183. package/dist/index.d.ts.map +1 -1
  184. package/dist/index.js +190 -14
  185. package/dist/index.js.map +1 -1
  186. package/dist/indexes/SessionDiscoveryIndex.d.ts +78 -0
  187. package/dist/indexes/SessionDiscoveryIndex.d.ts.map +1 -0
  188. package/dist/indexes/SessionDiscoveryIndex.js +223 -0
  189. package/dist/indexes/SessionDiscoveryIndex.js.map +1 -0
  190. package/dist/indexes/SessionIndexService.d.ts +114 -1
  191. package/dist/indexes/SessionIndexService.d.ts.map +1 -1
  192. package/dist/indexes/SessionIndexService.js +875 -105
  193. package/dist/indexes/SessionIndexService.js.map +1 -1
  194. package/dist/indexes/index.d.ts +2 -1
  195. package/dist/indexes/index.d.ts.map +1 -1
  196. package/dist/indexes/index.js +1 -0
  197. package/dist/indexes/index.js.map +1 -1
  198. package/dist/indexes/types.d.ts +26 -0
  199. package/dist/indexes/types.d.ts.map +1 -1
  200. package/dist/logging/logger.d.ts.map +1 -1
  201. package/dist/logging/logger.js +2 -3
  202. package/dist/logging/logger.js.map +1 -1
  203. package/dist/maintenance/server.d.ts.map +1 -1
  204. package/dist/maintenance/server.js +8 -11
  205. package/dist/maintenance/server.js.map +1 -1
  206. package/dist/metadata/ProjectMetadataService.d.ts +7 -0
  207. package/dist/metadata/ProjectMetadataService.d.ts.map +1 -1
  208. package/dist/metadata/ProjectMetadataService.js +63 -19
  209. package/dist/metadata/ProjectMetadataService.js.map +1 -1
  210. package/dist/metadata/SessionMetadataService.d.ts +82 -3
  211. package/dist/metadata/SessionMetadataService.d.ts.map +1 -1
  212. package/dist/metadata/SessionMetadataService.js +233 -17
  213. package/dist/metadata/SessionMetadataService.js.map +1 -1
  214. package/dist/middleware/file-access.d.ts +66 -0
  215. package/dist/middleware/file-access.d.ts.map +1 -0
  216. package/dist/middleware/file-access.js +112 -0
  217. package/dist/middleware/file-access.js.map +1 -0
  218. package/dist/projects/codex-scanner.d.ts +28 -1
  219. package/dist/projects/codex-scanner.d.ts.map +1 -1
  220. package/dist/projects/codex-scanner.js +149 -39
  221. package/dist/projects/codex-scanner.js.map +1 -1
  222. package/dist/projects/gemini-scanner.d.ts.map +1 -1
  223. package/dist/projects/gemini-scanner.js +59 -6
  224. package/dist/projects/gemini-scanner.js.map +1 -1
  225. package/dist/projects/paths.d.ts +15 -1
  226. package/dist/projects/paths.d.ts.map +1 -1
  227. package/dist/projects/paths.js +69 -23
  228. package/dist/projects/paths.js.map +1 -1
  229. package/dist/projects/scanner.d.ts +5 -0
  230. package/dist/projects/scanner.d.ts.map +1 -1
  231. package/dist/projects/scanner.js +136 -28
  232. package/dist/projects/scanner.js.map +1 -1
  233. package/dist/push/InactivityPushNotifier.d.ts +61 -0
  234. package/dist/push/InactivityPushNotifier.d.ts.map +1 -0
  235. package/dist/push/InactivityPushNotifier.js +305 -0
  236. package/dist/push/InactivityPushNotifier.js.map +1 -0
  237. package/dist/push/PushNotifier.d.ts.map +1 -1
  238. package/dist/push/PushNotifier.js.map +1 -1
  239. package/dist/push/PushService.d.ts +7 -4
  240. package/dist/push/PushService.d.ts.map +1 -1
  241. package/dist/push/PushService.js +27 -7
  242. package/dist/push/PushService.js.map +1 -1
  243. package/dist/push/index.d.ts +2 -1
  244. package/dist/push/index.d.ts.map +1 -1
  245. package/dist/push/index.js +1 -0
  246. package/dist/push/index.js.map +1 -1
  247. package/dist/push/routes.d.ts.map +1 -1
  248. package/dist/push/routes.js +28 -1
  249. package/dist/push/routes.js.map +1 -1
  250. package/dist/push/types.d.ts +21 -3
  251. package/dist/push/types.d.ts.map +1 -1
  252. package/dist/push/types.js +2 -0
  253. package/dist/push/types.js.map +1 -1
  254. package/dist/routes/dev.d.ts +2 -0
  255. package/dist/routes/dev.d.ts.map +1 -1
  256. package/dist/routes/dev.js +25 -0
  257. package/dist/routes/dev.js.map +1 -1
  258. package/dist/routes/env-settings.d.ts +20 -0
  259. package/dist/routes/env-settings.d.ts.map +1 -0
  260. package/dist/routes/env-settings.js +25 -0
  261. package/dist/routes/env-settings.js.map +1 -0
  262. package/dist/routes/files.d.ts +9 -0
  263. package/dist/routes/files.d.ts.map +1 -1
  264. package/dist/routes/files.js +98 -10
  265. package/dist/routes/files.js.map +1 -1
  266. package/dist/routes/git-status.d.ts.map +1 -1
  267. package/dist/routes/git-status.js +621 -23
  268. package/dist/routes/git-status.js.map +1 -1
  269. package/dist/routes/global-sessions.d.ts +11 -1
  270. package/dist/routes/global-sessions.d.ts.map +1 -1
  271. package/dist/routes/global-sessions.js +53 -33
  272. package/dist/routes/global-sessions.js.map +1 -1
  273. package/dist/routes/inbox.d.ts +10 -1
  274. package/dist/routes/inbox.d.ts.map +1 -1
  275. package/dist/routes/inbox.js +30 -3
  276. package/dist/routes/inbox.js.map +1 -1
  277. package/dist/routes/local-file.d.ts +6 -2
  278. package/dist/routes/local-file.d.ts.map +1 -1
  279. package/dist/routes/local-file.js +13 -4
  280. package/dist/routes/local-file.js.map +1 -1
  281. package/dist/routes/local-image.d.ts +2 -1
  282. package/dist/routes/local-image.d.ts.map +1 -1
  283. package/dist/routes/local-image.js.map +1 -1
  284. package/dist/routes/local-resource-policy.d.ts +7 -1
  285. package/dist/routes/local-resource-policy.d.ts.map +1 -1
  286. package/dist/routes/local-resource-policy.js +0 -0
  287. package/dist/routes/local-resource-policy.js.map +1 -1
  288. package/dist/routes/processes.d.ts.map +1 -1
  289. package/dist/routes/processes.js +49 -11
  290. package/dist/routes/processes.js.map +1 -1
  291. package/dist/routes/project-queue-response.d.ts +26 -0
  292. package/dist/routes/project-queue-response.d.ts.map +1 -0
  293. package/dist/routes/project-queue-response.js +188 -0
  294. package/dist/routes/project-queue-response.js.map +1 -0
  295. package/dist/routes/project-queue.d.ts +5 -0
  296. package/dist/routes/project-queue.d.ts.map +1 -0
  297. package/dist/routes/project-queue.js +219 -0
  298. package/dist/routes/project-queue.js.map +1 -0
  299. package/dist/routes/projects.d.ts +6 -0
  300. package/dist/routes/projects.d.ts.map +1 -1
  301. package/dist/routes/projects.js +116 -28
  302. package/dist/routes/projects.js.map +1 -1
  303. package/dist/routes/providers.d.ts +5 -0
  304. package/dist/routes/providers.d.ts.map +1 -1
  305. package/dist/routes/providers.js +52 -33
  306. package/dist/routes/providers.js.map +1 -1
  307. package/dist/routes/public-shares.d.ts.map +1 -1
  308. package/dist/routes/public-shares.js +46 -17
  309. package/dist/routes/public-shares.js.map +1 -1
  310. package/dist/routes/recents.d.ts +3 -0
  311. package/dist/routes/recents.d.ts.map +1 -1
  312. package/dist/routes/recents.js +3 -1
  313. package/dist/routes/recents.js.map +1 -1
  314. package/dist/routes/server-admin.d.ts +9 -0
  315. package/dist/routes/server-admin.d.ts.map +1 -1
  316. package/dist/routes/server-admin.js +45 -7
  317. package/dist/routes/server-admin.js.map +1 -1
  318. package/dist/routes/session-claude-resume-guard.d.ts +16 -0
  319. package/dist/routes/session-claude-resume-guard.d.ts.map +1 -0
  320. package/dist/routes/session-claude-resume-guard.js +50 -0
  321. package/dist/routes/session-claude-resume-guard.js.map +1 -0
  322. package/dist/routes/session-compact-thresholds.d.ts +22 -0
  323. package/dist/routes/session-compact-thresholds.d.ts.map +1 -0
  324. package/dist/routes/session-compact-thresholds.js +35 -0
  325. package/dist/routes/session-compact-thresholds.js.map +1 -0
  326. package/dist/routes/session-index.d.ts +7 -0
  327. package/dist/routes/session-index.d.ts.map +1 -0
  328. package/dist/routes/session-index.js +9 -0
  329. package/dist/routes/session-index.js.map +1 -0
  330. package/dist/routes/session-list-options.d.ts +1 -1
  331. package/dist/routes/session-list-options.d.ts.map +1 -1
  332. package/dist/routes/session-list-options.js +1 -1
  333. package/dist/routes/session-list-options.js.map +1 -1
  334. package/dist/routes/session-request-helpers.d.ts +31 -0
  335. package/dist/routes/session-request-helpers.d.ts.map +1 -0
  336. package/dist/routes/session-request-helpers.js +212 -0
  337. package/dist/routes/session-request-helpers.js.map +1 -0
  338. package/dist/routes/sessions.d.ts +14 -1
  339. package/dist/routes/sessions.d.ts.map +1 -1
  340. package/dist/routes/sessions.js +2141 -551
  341. package/dist/routes/sessions.js.map +1 -1
  342. package/dist/routes/settings.d.ts +7 -1
  343. package/dist/routes/settings.d.ts.map +1 -1
  344. package/dist/routes/settings.js +771 -25
  345. package/dist/routes/settings.js.map +1 -1
  346. package/dist/routes/speech.d.ts +24 -2
  347. package/dist/routes/speech.d.ts.map +1 -1
  348. package/dist/routes/speech.js +539 -10
  349. package/dist/routes/speech.js.map +1 -1
  350. package/dist/routes/supervisor-queue.d.ts +6 -0
  351. package/dist/routes/supervisor-queue.d.ts.map +1 -0
  352. package/dist/routes/supervisor-queue.js +35 -0
  353. package/dist/routes/supervisor-queue.js.map +1 -0
  354. package/dist/routes/upload.d.ts +2 -0
  355. package/dist/routes/upload.d.ts.map +1 -1
  356. package/dist/routes/upload.js +190 -38
  357. package/dist/routes/upload.js.map +1 -1
  358. package/dist/routes/version.d.ts +18 -1
  359. package/dist/routes/version.d.ts.map +1 -1
  360. package/dist/routes/version.js +22 -1
  361. package/dist/routes/version.js.map +1 -1
  362. package/dist/routes/workstreams.d.ts +11 -0
  363. package/dist/routes/workstreams.d.ts.map +1 -0
  364. package/dist/routes/workstreams.js +144 -0
  365. package/dist/routes/workstreams.js.map +1 -0
  366. package/dist/routes/ws-message-router.d.ts +10 -1
  367. package/dist/routes/ws-message-router.d.ts.map +1 -1
  368. package/dist/routes/ws-message-router.js +43 -4
  369. package/dist/routes/ws-message-router.js.map +1 -1
  370. package/dist/routes/ws-relay-handlers.d.ts +27 -5
  371. package/dist/routes/ws-relay-handlers.d.ts.map +1 -1
  372. package/dist/routes/ws-relay-handlers.js +177 -19
  373. package/dist/routes/ws-relay-handlers.js.map +1 -1
  374. package/dist/routes/ws-relay.d.ts +19 -0
  375. package/dist/routes/ws-relay.d.ts.map +1 -1
  376. package/dist/routes/ws-relay.js +21 -7
  377. package/dist/routes/ws-relay.js.map +1 -1
  378. package/dist/sdk/cli-detection.d.ts +1 -1
  379. package/dist/sdk/cli-detection.d.ts.map +1 -1
  380. package/dist/sdk/cli-detection.js +47 -7
  381. package/dist/sdk/cli-detection.js.map +1 -1
  382. package/dist/sdk/messageLogger.d.ts.map +1 -1
  383. package/dist/sdk/messageLogger.js +38 -10
  384. package/dist/sdk/messageLogger.js.map +1 -1
  385. package/dist/sdk/messageQueue.d.ts.map +1 -1
  386. package/dist/sdk/messageQueue.js +26 -0
  387. package/dist/sdk/messageQueue.js.map +1 -1
  388. package/dist/sdk/providers/__mocks__/grok.d.ts +1 -1
  389. package/dist/sdk/providers/__mocks__/grok.d.ts.map +1 -1
  390. package/dist/sdk/providers/__mocks__/grok.js +1 -1
  391. package/dist/sdk/providers/__mocks__/grok.js.map +1 -1
  392. package/dist/sdk/providers/agentctl-session-env.d.ts +8 -0
  393. package/dist/sdk/providers/agentctl-session-env.d.ts.map +1 -0
  394. package/dist/sdk/providers/agentctl-session-env.js +52 -0
  395. package/dist/sdk/providers/agentctl-session-env.js.map +1 -0
  396. package/dist/sdk/providers/claude-ollama.d.ts +2 -1
  397. package/dist/sdk/providers/claude-ollama.d.ts.map +1 -1
  398. package/dist/sdk/providers/claude-ollama.js +1 -0
  399. package/dist/sdk/providers/claude-ollama.js.map +1 -1
  400. package/dist/sdk/providers/claude-retention.d.ts +19 -0
  401. package/dist/sdk/providers/claude-retention.d.ts.map +1 -0
  402. package/dist/sdk/providers/claude-retention.js +169 -0
  403. package/dist/sdk/providers/claude-retention.js.map +1 -0
  404. package/dist/sdk/providers/claude.d.ts +52 -5
  405. package/dist/sdk/providers/claude.d.ts.map +1 -1
  406. package/dist/sdk/providers/claude.js +593 -71
  407. package/dist/sdk/providers/claude.js.map +1 -1
  408. package/dist/sdk/providers/codex-protocol/generated/AgentMessageInputContent.d.ts +8 -0
  409. package/dist/sdk/providers/codex-protocol/generated/AgentMessageInputContent.d.ts.map +1 -0
  410. package/dist/sdk/providers/codex-protocol/generated/AgentMessageInputContent.js +3 -0
  411. package/dist/sdk/providers/codex-protocol/generated/AgentMessageInputContent.js.map +1 -0
  412. package/dist/sdk/providers/codex-protocol/generated/InternalChatMessageMetadataPassthrough.d.ts +10 -0
  413. package/dist/sdk/providers/codex-protocol/generated/InternalChatMessageMetadataPassthrough.d.ts.map +1 -0
  414. package/dist/sdk/providers/codex-protocol/generated/InternalChatMessageMetadataPassthrough.js +3 -0
  415. package/dist/sdk/providers/codex-protocol/generated/InternalChatMessageMetadataPassthrough.js.map +1 -0
  416. package/dist/sdk/providers/codex-protocol/generated/LegacyAppPathString.d.ts +23 -0
  417. package/dist/sdk/providers/codex-protocol/generated/LegacyAppPathString.d.ts.map +1 -0
  418. package/dist/sdk/providers/codex-protocol/generated/LegacyAppPathString.js +3 -0
  419. package/dist/sdk/providers/codex-protocol/generated/LegacyAppPathString.js.map +1 -0
  420. package/dist/sdk/providers/codex-protocol/generated/MultiAgentMode.d.ts +8 -0
  421. package/dist/sdk/providers/codex-protocol/generated/MultiAgentMode.d.ts.map +1 -0
  422. package/dist/sdk/providers/codex-protocol/generated/MultiAgentMode.js +3 -0
  423. package/dist/sdk/providers/codex-protocol/generated/MultiAgentMode.js.map +1 -0
  424. package/dist/sdk/providers/codex-protocol/generated/ReasoningEffort.d.ts +1 -1
  425. package/dist/sdk/providers/codex-protocol/generated/ReasoningEffort.d.ts.map +1 -1
  426. package/dist/sdk/providers/codex-protocol/generated/ResponseItem.d.ts +38 -1
  427. package/dist/sdk/providers/codex-protocol/generated/ResponseItem.d.ts.map +1 -1
  428. package/dist/sdk/providers/codex-protocol/generated/v2/AdditionalFileSystemPermissions.d.ts +3 -3
  429. package/dist/sdk/providers/codex-protocol/generated/v2/AdditionalFileSystemPermissions.d.ts.map +1 -1
  430. package/dist/sdk/providers/codex-protocol/generated/v2/CapabilityRootLocation.d.ts +9 -0
  431. package/dist/sdk/providers/codex-protocol/generated/v2/CapabilityRootLocation.d.ts.map +1 -0
  432. package/dist/sdk/providers/codex-protocol/generated/v2/CapabilityRootLocation.js +3 -0
  433. package/dist/sdk/providers/codex-protocol/generated/v2/CapabilityRootLocation.js.map +1 -0
  434. package/dist/sdk/providers/codex-protocol/generated/v2/CommandExecutionRequestApprovalParams.d.ts +6 -2
  435. package/dist/sdk/providers/codex-protocol/generated/v2/CommandExecutionRequestApprovalParams.d.ts.map +1 -1
  436. package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolFunctionSpec.d.ts +8 -0
  437. package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolFunctionSpec.d.ts.map +1 -0
  438. package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolFunctionSpec.js +3 -0
  439. package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolFunctionSpec.js.map +1 -0
  440. package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolNamespaceSpec.d.ts +7 -0
  441. package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolNamespaceSpec.d.ts.map +1 -0
  442. package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolNamespaceSpec.js +3 -0
  443. package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolNamespaceSpec.js.map +1 -0
  444. package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolNamespaceTool.d.ts +5 -0
  445. package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolNamespaceTool.d.ts.map +1 -0
  446. package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolNamespaceTool.js +3 -0
  447. package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolNamespaceTool.js.map +1 -0
  448. package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolSpec.d.ts +6 -7
  449. package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolSpec.d.ts.map +1 -1
  450. package/dist/sdk/providers/codex-protocol/generated/v2/FileSystemPath.d.ts +2 -2
  451. package/dist/sdk/providers/codex-protocol/generated/v2/FileSystemPath.d.ts.map +1 -1
  452. package/dist/sdk/providers/codex-protocol/generated/v2/McpToolCallAppContext.d.ts +6 -0
  453. package/dist/sdk/providers/codex-protocol/generated/v2/McpToolCallAppContext.d.ts.map +1 -0
  454. package/dist/sdk/providers/codex-protocol/generated/v2/McpToolCallAppContext.js +3 -0
  455. package/dist/sdk/providers/codex-protocol/generated/v2/McpToolCallAppContext.js.map +1 -0
  456. package/dist/sdk/providers/codex-protocol/generated/v2/PermissionsRequestApprovalParams.d.ts +1 -0
  457. package/dist/sdk/providers/codex-protocol/generated/v2/PermissionsRequestApprovalParams.d.ts.map +1 -1
  458. package/dist/sdk/providers/codex-protocol/generated/v2/SelectedCapabilityRoot.d.ts +15 -0
  459. package/dist/sdk/providers/codex-protocol/generated/v2/SelectedCapabilityRoot.d.ts.map +1 -0
  460. package/dist/sdk/providers/codex-protocol/generated/v2/SelectedCapabilityRoot.js +3 -0
  461. package/dist/sdk/providers/codex-protocol/generated/v2/SelectedCapabilityRoot.js.map +1 -0
  462. package/dist/sdk/providers/codex-protocol/generated/v2/SortDirection.d.ts +2 -0
  463. package/dist/sdk/providers/codex-protocol/generated/v2/SortDirection.d.ts.map +1 -0
  464. package/dist/sdk/providers/codex-protocol/generated/v2/SortDirection.js +3 -0
  465. package/dist/sdk/providers/codex-protocol/generated/v2/SortDirection.js.map +1 -0
  466. package/dist/sdk/providers/codex-protocol/generated/v2/SubAgentActivityKind.d.ts +2 -0
  467. package/dist/sdk/providers/codex-protocol/generated/v2/SubAgentActivityKind.d.ts.map +1 -0
  468. package/dist/sdk/providers/codex-protocol/generated/v2/SubAgentActivityKind.js +3 -0
  469. package/dist/sdk/providers/codex-protocol/generated/v2/SubAgentActivityKind.js.map +1 -0
  470. package/dist/sdk/providers/codex-protocol/generated/v2/Thread.d.ts +8 -0
  471. package/dist/sdk/providers/codex-protocol/generated/v2/Thread.d.ts.map +1 -1
  472. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadCompactStartParams.d.ts +4 -0
  473. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadCompactStartParams.d.ts.map +1 -0
  474. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadCompactStartParams.js +3 -0
  475. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadCompactStartParams.js.map +1 -0
  476. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadCompactStartResponse.d.ts +2 -0
  477. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadCompactStartResponse.d.ts.map +1 -0
  478. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadCompactStartResponse.js +3 -0
  479. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadCompactStartResponse.js.map +1 -0
  480. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadForkParams.d.ts +64 -0
  481. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadForkParams.d.ts.map +1 -0
  482. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadForkParams.js +3 -0
  483. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadForkParams.js.map +1 -0
  484. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadForkResponse.d.ts +46 -0
  485. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadForkResponse.d.ts.map +1 -0
  486. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadForkResponse.js +3 -0
  487. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadForkResponse.js.map +1 -0
  488. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadItem.d.ts +19 -1
  489. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadItem.d.ts.map +1 -1
  490. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadReadResponse.d.ts +5 -0
  491. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadReadResponse.d.ts.map +1 -0
  492. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadReadResponse.js +3 -0
  493. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadReadResponse.js.map +1 -0
  494. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadResumeInitialTurnsPageParams.d.ts +17 -0
  495. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadResumeInitialTurnsPageParams.d.ts.map +1 -0
  496. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadResumeInitialTurnsPageParams.js +3 -0
  497. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadResumeInitialTurnsPageParams.js.map +1 -0
  498. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadResumeParams.d.ts +7 -7
  499. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadResumeParams.d.ts.map +1 -1
  500. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadResumeResponse.d.ts +13 -2
  501. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadResumeResponse.d.ts.map +1 -1
  502. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadRollbackParams.d.ts +11 -0
  503. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadRollbackParams.d.ts.map +1 -0
  504. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadRollbackParams.js +3 -0
  505. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadRollbackParams.js.map +1 -0
  506. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadRollbackResponse.d.ts +12 -0
  507. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadRollbackResponse.d.ts.map +1 -0
  508. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadRollbackResponse.js +3 -0
  509. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadRollbackResponse.js.map +1 -0
  510. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadSource.d.ts +1 -1
  511. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadSource.d.ts.map +1 -1
  512. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadStartParams.d.ts +13 -9
  513. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadStartParams.d.ts.map +1 -1
  514. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadStartResponse.d.ts +8 -2
  515. package/dist/sdk/providers/codex-protocol/generated/v2/ThreadStartResponse.d.ts.map +1 -1
  516. package/dist/sdk/providers/codex-protocol/generated/v2/ToolRequestUserInputParams.d.ts +1 -0
  517. package/dist/sdk/providers/codex-protocol/generated/v2/ToolRequestUserInputParams.d.ts.map +1 -1
  518. package/dist/sdk/providers/codex-protocol/generated/v2/TurnEnvironmentParams.d.ts +2 -2
  519. package/dist/sdk/providers/codex-protocol/generated/v2/TurnEnvironmentParams.d.ts.map +1 -1
  520. package/dist/sdk/providers/codex-protocol/generated/v2/TurnStartParams.d.ts +17 -5
  521. package/dist/sdk/providers/codex-protocol/generated/v2/TurnStartParams.d.ts.map +1 -1
  522. package/dist/sdk/providers/codex-protocol/generated/v2/TurnSteerParams.d.ts +8 -1
  523. package/dist/sdk/providers/codex-protocol/generated/v2/TurnSteerParams.d.ts.map +1 -1
  524. package/dist/sdk/providers/codex-protocol/generated/v2/TurnsPage.d.ts +7 -0
  525. package/dist/sdk/providers/codex-protocol/generated/v2/TurnsPage.d.ts.map +1 -0
  526. package/dist/sdk/providers/codex-protocol/generated/v2/TurnsPage.js +3 -0
  527. package/dist/sdk/providers/codex-protocol/generated/v2/TurnsPage.js.map +1 -0
  528. package/dist/sdk/providers/codex-protocol/index.d.ts +7 -0
  529. package/dist/sdk/providers/codex-protocol/index.d.ts.map +1 -1
  530. package/dist/sdk/providers/codex.d.ts +26 -4
  531. package/dist/sdk/providers/codex.d.ts.map +1 -1
  532. package/dist/sdk/providers/codex.js +457 -37
  533. package/dist/sdk/providers/codex.js.map +1 -1
  534. package/dist/sdk/providers/env-filter.d.ts.map +1 -1
  535. package/dist/sdk/providers/env-filter.js +19 -1
  536. package/dist/sdk/providers/env-filter.js.map +1 -1
  537. package/dist/sdk/providers/gemini-tools.d.ts +28 -0
  538. package/dist/sdk/providers/gemini-tools.d.ts.map +1 -0
  539. package/dist/sdk/providers/gemini-tools.js +57 -0
  540. package/dist/sdk/providers/gemini-tools.js.map +1 -0
  541. package/dist/sdk/providers/gemini.d.ts.map +1 -1
  542. package/dist/sdk/providers/gemini.js +4 -2
  543. package/dist/sdk/providers/gemini.js.map +1 -1
  544. package/dist/sdk/providers/grok-acp.d.ts +1 -1
  545. package/dist/sdk/providers/grok-acp.d.ts.map +1 -1
  546. package/dist/sdk/providers/grok-acp.js +1 -1
  547. package/dist/sdk/providers/grok-acp.js.map +1 -1
  548. package/dist/sdk/providers/index.d.ts +1 -0
  549. package/dist/sdk/providers/index.d.ts.map +1 -1
  550. package/dist/sdk/providers/index.js +6 -0
  551. package/dist/sdk/providers/index.js.map +1 -1
  552. package/dist/sdk/providers/opencode-tools.d.ts +36 -0
  553. package/dist/sdk/providers/opencode-tools.d.ts.map +1 -0
  554. package/dist/sdk/providers/opencode-tools.js +78 -0
  555. package/dist/sdk/providers/opencode-tools.js.map +1 -0
  556. package/dist/sdk/providers/opencode.d.ts +53 -5
  557. package/dist/sdk/providers/opencode.d.ts.map +1 -1
  558. package/dist/sdk/providers/opencode.js +379 -71
  559. package/dist/sdk/providers/opencode.js.map +1 -1
  560. package/dist/sdk/providers/pi-rpc-client.d.ts +90 -0
  561. package/dist/sdk/providers/pi-rpc-client.d.ts.map +1 -0
  562. package/dist/sdk/providers/pi-rpc-client.js +168 -0
  563. package/dist/sdk/providers/pi-rpc-client.js.map +1 -0
  564. package/dist/sdk/providers/pi-tools.d.ts +38 -0
  565. package/dist/sdk/providers/pi-tools.d.ts.map +1 -0
  566. package/dist/sdk/providers/pi-tools.js +214 -0
  567. package/dist/sdk/providers/pi-tools.js.map +1 -0
  568. package/dist/sdk/providers/pi.d.ts +84 -0
  569. package/dist/sdk/providers/pi.d.ts.map +1 -0
  570. package/dist/sdk/providers/pi.js +686 -0
  571. package/dist/sdk/providers/pi.js.map +1 -0
  572. package/dist/sdk/providers/staticSlashCommands.d.ts +4 -0
  573. package/dist/sdk/providers/staticSlashCommands.d.ts.map +1 -0
  574. package/dist/sdk/providers/staticSlashCommands.js +14 -0
  575. package/dist/sdk/providers/staticSlashCommands.js.map +1 -0
  576. package/dist/sdk/providers/types.d.ts +144 -17
  577. package/dist/sdk/providers/types.d.ts.map +1 -1
  578. package/dist/sdk/remote-spawn.d.ts.map +1 -1
  579. package/dist/sdk/remote-spawn.js.map +1 -1
  580. package/dist/sdk/slashCommandEmulation.d.ts +9 -0
  581. package/dist/sdk/slashCommandEmulation.d.ts.map +1 -1
  582. package/dist/sdk/slashCommandEmulation.js +15 -0
  583. package/dist/sdk/slashCommandEmulation.js.map +1 -1
  584. package/dist/sdk/types.d.ts +40 -0
  585. package/dist/sdk/types.d.ts.map +1 -1
  586. package/dist/security/approvalAuditLog.d.ts +3 -2
  587. package/dist/security/approvalAuditLog.d.ts.map +1 -1
  588. package/dist/security/approvalAuditLog.js +62 -2
  589. package/dist/security/approvalAuditLog.js.map +1 -1
  590. package/dist/services/BrowserProfileService.d.ts +21 -0
  591. package/dist/services/BrowserProfileService.d.ts.map +1 -1
  592. package/dist/services/BrowserProfileService.js +74 -1
  593. package/dist/services/BrowserProfileService.js.map +1 -1
  594. package/dist/services/CacheMissBillingMonitor.d.ts +25 -0
  595. package/dist/services/CacheMissBillingMonitor.d.ts.map +1 -0
  596. package/dist/services/CacheMissBillingMonitor.js +179 -0
  597. package/dist/services/CacheMissBillingMonitor.js.map +1 -0
  598. package/dist/services/CodexUpdateChecker.d.ts.map +1 -1
  599. package/dist/services/CodexUpdateChecker.js +3 -2
  600. package/dist/services/CodexUpdateChecker.js.map +1 -1
  601. package/dist/services/ModelInfoService.d.ts +58 -9
  602. package/dist/services/ModelInfoService.d.ts.map +1 -1
  603. package/dist/services/ModelInfoService.js +127 -14
  604. package/dist/services/ModelInfoService.js.map +1 -1
  605. package/dist/services/ProjectQueueScheduler.d.ts +91 -0
  606. package/dist/services/ProjectQueueScheduler.d.ts.map +1 -0
  607. package/dist/services/ProjectQueueScheduler.js +404 -0
  608. package/dist/services/ProjectQueueScheduler.js.map +1 -0
  609. package/dist/services/ProjectQueueService.d.ts +60 -0
  610. package/dist/services/ProjectQueueService.d.ts.map +1 -0
  611. package/dist/services/ProjectQueueService.js +804 -0
  612. package/dist/services/ProjectQueueService.js.map +1 -0
  613. package/dist/services/RelayClientService.d.ts +5 -0
  614. package/dist/services/RelayClientService.d.ts.map +1 -1
  615. package/dist/services/RelayClientService.js +26 -12
  616. package/dist/services/RelayClientService.js.map +1 -1
  617. package/dist/services/SafeRestartService.d.ts +48 -0
  618. package/dist/services/SafeRestartService.d.ts.map +1 -0
  619. package/dist/services/SafeRestartService.js +173 -0
  620. package/dist/services/SafeRestartService.js.map +1 -0
  621. package/dist/services/ServerSettingsService.d.ts +41 -1
  622. package/dist/services/ServerSettingsService.d.ts.map +1 -1
  623. package/dist/services/ServerSettingsService.js +110 -1
  624. package/dist/services/ServerSettingsService.js.map +1 -1
  625. package/dist/services/SessionQueuePersistenceService.d.ts +55 -0
  626. package/dist/services/SessionQueuePersistenceService.d.ts.map +1 -0
  627. package/dist/services/SessionQueuePersistenceService.js +264 -0
  628. package/dist/services/SessionQueuePersistenceService.js.map +1 -0
  629. package/dist/services/WorkstreamService.d.ts +92 -0
  630. package/dist/services/WorkstreamService.d.ts.map +1 -0
  631. package/dist/services/WorkstreamService.js +627 -0
  632. package/dist/services/WorkstreamService.js.map +1 -0
  633. package/dist/services/index.d.ts +4 -0
  634. package/dist/services/index.d.ts.map +1 -1
  635. package/dist/services/index.js +4 -0
  636. package/dist/services/index.js.map +1 -1
  637. package/dist/services/projectWorkIdle.d.ts +42 -0
  638. package/dist/services/projectWorkIdle.d.ts.map +1 -0
  639. package/dist/services/projectWorkIdle.js +50 -0
  640. package/dist/services/projectWorkIdle.js.map +1 -0
  641. package/dist/services/voice/SpeechBackend.d.ts +18 -1
  642. package/dist/services/voice/SpeechBackend.d.ts.map +1 -1
  643. package/dist/services/voice/SpeechBackend.js +3 -0
  644. package/dist/services/voice/SpeechBackend.js.map +1 -1
  645. package/dist/services/voice/audioRetention.d.ts +20 -0
  646. package/dist/services/voice/audioRetention.d.ts.map +1 -1
  647. package/dist/services/voice/audioRetention.js +2 -0
  648. package/dist/services/voice/audioRetention.js.map +1 -1
  649. package/dist/services/voice/deepgramBackend.d.ts.map +1 -1
  650. package/dist/services/voice/deepgramBackend.js +4 -1
  651. package/dist/services/voice/deepgramBackend.js.map +1 -1
  652. package/dist/services/voice/localNemoBackend.d.ts +31 -0
  653. package/dist/services/voice/localNemoBackend.d.ts.map +1 -0
  654. package/dist/services/voice/localNemoBackend.js +181 -0
  655. package/dist/services/voice/localNemoBackend.js.map +1 -0
  656. package/dist/services/voice/localParakeetBackend.d.ts +31 -0
  657. package/dist/services/voice/localParakeetBackend.d.ts.map +1 -0
  658. package/dist/services/voice/localParakeetBackend.js +180 -0
  659. package/dist/services/voice/localParakeetBackend.js.map +1 -0
  660. package/dist/services/voice/localSttRuntime.d.ts +21 -0
  661. package/dist/services/voice/localSttRuntime.d.ts.map +1 -0
  662. package/dist/services/voice/localSttRuntime.js +87 -0
  663. package/dist/services/voice/localSttRuntime.js.map +1 -0
  664. package/dist/services/voice/localWhisperBackend.d.ts +2 -1
  665. package/dist/services/voice/localWhisperBackend.d.ts.map +1 -1
  666. package/dist/services/voice/localWhisperBackend.js +47 -34
  667. package/dist/services/voice/localWhisperBackend.js.map +1 -1
  668. package/dist/services/voice/nemo_worker.py +232 -0
  669. package/dist/services/voice/parakeet_worker.py +151 -0
  670. package/dist/services/voice/registry.d.ts +19 -4
  671. package/dist/services/voice/registry.d.ts.map +1 -1
  672. package/dist/services/voice/registry.js +72 -22
  673. package/dist/services/voice/registry.js.map +1 -1
  674. package/dist/services/voice/serialQueue.d.ts +17 -0
  675. package/dist/services/voice/serialQueue.d.ts.map +1 -0
  676. package/dist/services/voice/serialQueue.js +24 -0
  677. package/dist/services/voice/serialQueue.js.map +1 -0
  678. package/dist/services/voice/whisper_worker.py +94 -0
  679. package/dist/services/voice/xaiSttBackend.d.ts +1 -1
  680. package/dist/services/voice/xaiSttBackend.d.ts.map +1 -1
  681. package/dist/services/voice/xaiSttBackend.js +15 -3
  682. package/dist/services/voice/xaiSttBackend.js.map +1 -1
  683. package/dist/sessions/agent-excerpt.d.ts +29 -0
  684. package/dist/sessions/agent-excerpt.d.ts.map +1 -0
  685. package/dist/sessions/agent-excerpt.js +128 -0
  686. package/dist/sessions/agent-excerpt.js.map +1 -0
  687. package/dist/sessions/claude-messages.d.ts.map +1 -1
  688. package/dist/sessions/claude-messages.js +75 -4
  689. package/dist/sessions/claude-messages.js.map +1 -1
  690. package/dist/sessions/claude-summary.d.ts +33 -0
  691. package/dist/sessions/claude-summary.d.ts.map +1 -0
  692. package/dist/sessions/claude-summary.js +461 -0
  693. package/dist/sessions/claude-summary.js.map +1 -0
  694. package/dist/sessions/codex-discovery.d.ts +46 -0
  695. package/dist/sessions/codex-discovery.d.ts.map +1 -0
  696. package/dist/sessions/codex-discovery.js +269 -0
  697. package/dist/sessions/codex-discovery.js.map +1 -0
  698. package/dist/sessions/codex-reader.d.ts +96 -13
  699. package/dist/sessions/codex-reader.d.ts.map +1 -1
  700. package/dist/sessions/codex-reader.js +1069 -141
  701. package/dist/sessions/codex-reader.js.map +1 -1
  702. package/dist/sessions/dag.d.ts +25 -4
  703. package/dist/sessions/dag.d.ts.map +1 -1
  704. package/dist/sessions/dag.js +37 -4
  705. package/dist/sessions/dag.js.map +1 -1
  706. package/dist/sessions/gemini-reader.d.ts +3 -1
  707. package/dist/sessions/gemini-reader.d.ts.map +1 -1
  708. package/dist/sessions/gemini-reader.js +17 -8
  709. package/dist/sessions/gemini-reader.js.map +1 -1
  710. package/dist/sessions/grok-reader.d.ts +1 -0
  711. package/dist/sessions/grok-reader.d.ts.map +1 -1
  712. package/dist/sessions/grok-reader.js +11 -5
  713. package/dist/sessions/grok-reader.js.map +1 -1
  714. package/dist/sessions/normalization.d.ts +3 -1
  715. package/dist/sessions/normalization.d.ts.map +1 -1
  716. package/dist/sessions/normalization.js +72 -16
  717. package/dist/sessions/normalization.js.map +1 -1
  718. package/dist/sessions/null-reader.d.ts +31 -0
  719. package/dist/sessions/null-reader.d.ts.map +1 -0
  720. package/dist/sessions/null-reader.js +30 -0
  721. package/dist/sessions/null-reader.js.map +1 -0
  722. package/dist/sessions/opencode-db-reader.d.ts +66 -0
  723. package/dist/sessions/opencode-db-reader.d.ts.map +1 -0
  724. package/dist/sessions/opencode-db-reader.js +333 -0
  725. package/dist/sessions/opencode-db-reader.js.map +1 -0
  726. package/dist/sessions/opencode-reader.d.ts +50 -0
  727. package/dist/sessions/opencode-reader.d.ts.map +1 -1
  728. package/dist/sessions/opencode-reader.js +375 -71
  729. package/dist/sessions/opencode-reader.js.map +1 -1
  730. package/dist/sessions/pagination.d.ts.map +1 -1
  731. package/dist/sessions/pagination.js +119 -3
  732. package/dist/sessions/pagination.js.map +1 -1
  733. package/dist/sessions/persisted-augments.d.ts +2 -1
  734. package/dist/sessions/persisted-augments.d.ts.map +1 -1
  735. package/dist/sessions/persisted-augments.js +2 -2
  736. package/dist/sessions/persisted-augments.js.map +1 -1
  737. package/dist/sessions/pi-fork.d.ts +12 -0
  738. package/dist/sessions/pi-fork.d.ts.map +1 -0
  739. package/dist/sessions/pi-fork.js +125 -0
  740. package/dist/sessions/pi-fork.js.map +1 -0
  741. package/dist/sessions/pi-reader.d.ts +81 -0
  742. package/dist/sessions/pi-reader.d.ts.map +1 -0
  743. package/dist/sessions/pi-reader.js +413 -0
  744. package/dist/sessions/pi-reader.js.map +1 -0
  745. package/dist/sessions/provider-resolution.d.ts +10 -3
  746. package/dist/sessions/provider-resolution.d.ts.map +1 -1
  747. package/dist/sessions/provider-resolution.js +62 -6
  748. package/dist/sessions/provider-resolution.js.map +1 -1
  749. package/dist/sessions/reader.d.ts +17 -24
  750. package/dist/sessions/reader.d.ts.map +1 -1
  751. package/dist/sessions/reader.js +86 -157
  752. package/dist/sessions/reader.js.map +1 -1
  753. package/dist/sessions/recap-overlays.d.ts +38 -0
  754. package/dist/sessions/recap-overlays.d.ts.map +1 -0
  755. package/dist/sessions/recap-overlays.js +176 -0
  756. package/dist/sessions/recap-overlays.js.map +1 -0
  757. package/dist/sessions/summary-parser-worker-client.d.ts +80 -0
  758. package/dist/sessions/summary-parser-worker-client.d.ts.map +1 -0
  759. package/dist/sessions/summary-parser-worker-client.js +539 -0
  760. package/dist/sessions/summary-parser-worker-client.js.map +1 -0
  761. package/dist/sessions/summary-parser-worker-entry.d.ts +2 -0
  762. package/dist/sessions/summary-parser-worker-entry.d.ts.map +1 -0
  763. package/dist/sessions/summary-parser-worker-entry.js +29 -0
  764. package/dist/sessions/summary-parser-worker-entry.js.map +1 -0
  765. package/dist/sessions/summary-parser-worker-protocol.d.ts +105 -0
  766. package/dist/sessions/summary-parser-worker-protocol.d.ts.map +1 -0
  767. package/dist/sessions/summary-parser-worker-protocol.js +35 -0
  768. package/dist/sessions/summary-parser-worker-protocol.js.map +1 -0
  769. package/dist/sessions/summary-parser-worker-runner.d.ts +3 -0
  770. package/dist/sessions/summary-parser-worker-runner.d.ts.map +1 -0
  771. package/dist/sessions/summary-parser-worker-runner.js +158 -0
  772. package/dist/sessions/summary-parser-worker-runner.js.map +1 -0
  773. package/dist/sessions/types.d.ts +30 -1
  774. package/dist/sessions/types.d.ts.map +1 -1
  775. package/dist/startupEnv.d.ts +2 -0
  776. package/dist/startupEnv.d.ts.map +1 -0
  777. package/dist/startupEnv.js +97 -0
  778. package/dist/startupEnv.js.map +1 -0
  779. package/dist/subscriptions.d.ts.map +1 -1
  780. package/dist/subscriptions.js +28 -18
  781. package/dist/subscriptions.js.map +1 -1
  782. package/dist/supervisor/ExternalSessionTracker.d.ts +5 -1
  783. package/dist/supervisor/ExternalSessionTracker.d.ts.map +1 -1
  784. package/dist/supervisor/ExternalSessionTracker.js +98 -6
  785. package/dist/supervisor/ExternalSessionTracker.js.map +1 -1
  786. package/dist/supervisor/Process.d.ts +252 -32
  787. package/dist/supervisor/Process.d.ts.map +1 -1
  788. package/dist/supervisor/Process.js +1233 -219
  789. package/dist/supervisor/Process.js.map +1 -1
  790. package/dist/supervisor/Supervisor.d.ts +201 -5
  791. package/dist/supervisor/Supervisor.d.ts.map +1 -1
  792. package/dist/supervisor/Supervisor.js +1074 -55
  793. package/dist/supervisor/Supervisor.js.map +1 -1
  794. package/dist/supervisor/WorkerQueue.d.ts +3 -1
  795. package/dist/supervisor/WorkerQueue.d.ts.map +1 -1
  796. package/dist/supervisor/WorkerQueue.js +1 -0
  797. package/dist/supervisor/WorkerQueue.js.map +1 -1
  798. package/dist/supervisor/composeTimeAnchor.d.ts +36 -0
  799. package/dist/supervisor/composeTimeAnchor.d.ts.map +1 -0
  800. package/dist/supervisor/composeTimeAnchor.js +51 -0
  801. package/dist/supervisor/composeTimeAnchor.js.map +1 -0
  802. package/dist/supervisor/deferredDeliverySettings.d.ts +23 -0
  803. package/dist/supervisor/deferredDeliverySettings.d.ts.map +1 -0
  804. package/dist/supervisor/deferredDeliverySettings.js +40 -0
  805. package/dist/supervisor/deferredDeliverySettings.js.map +1 -0
  806. package/dist/supervisor/liveness.d.ts +5 -2
  807. package/dist/supervisor/liveness.d.ts.map +1 -1
  808. package/dist/supervisor/liveness.js +40 -2
  809. package/dist/supervisor/liveness.js.map +1 -1
  810. package/dist/supervisor/types.d.ts +56 -5
  811. package/dist/supervisor/types.d.ts.map +1 -1
  812. package/dist/supervisor/types.js +0 -2
  813. package/dist/supervisor/types.js.map +1 -1
  814. package/dist/uploads/AttachmentStagingService.d.ts +94 -0
  815. package/dist/uploads/AttachmentStagingService.d.ts.map +1 -0
  816. package/dist/uploads/AttachmentStagingService.js +673 -0
  817. package/dist/uploads/AttachmentStagingService.js.map +1 -0
  818. package/dist/uploads/index.d.ts +2 -0
  819. package/dist/uploads/index.d.ts.map +1 -1
  820. package/dist/uploads/index.js +1 -0
  821. package/dist/uploads/index.js.map +1 -1
  822. package/dist/uploads/manager.d.ts +1 -0
  823. package/dist/uploads/manager.d.ts.map +1 -1
  824. package/dist/uploads/manager.js +72 -12
  825. package/dist/uploads/manager.js.map +1 -1
  826. package/dist/utils/codexRolloutFiles.d.ts +16 -0
  827. package/dist/utils/codexRolloutFiles.d.ts.map +1 -0
  828. package/dist/utils/codexRolloutFiles.js +45 -0
  829. package/dist/utils/codexRolloutFiles.js.map +1 -0
  830. package/dist/utils/jsonl.d.ts +8 -0
  831. package/dist/utils/jsonl.d.ts.map +1 -1
  832. package/dist/utils/jsonl.js +158 -5
  833. package/dist/utils/jsonl.js.map +1 -1
  834. package/dist/utils/publicShareViewerUrl.d.ts.map +1 -1
  835. package/dist/utils/publicShareViewerUrl.js +2 -15
  836. package/dist/utils/publicShareViewerUrl.js.map +1 -1
  837. package/dist/watcher/EventBus.d.ts +42 -4
  838. package/dist/watcher/EventBus.d.ts.map +1 -1
  839. package/dist/watcher/EventBus.js.map +1 -1
  840. package/dist/watcher/FileWatcher.d.ts +47 -0
  841. package/dist/watcher/FileWatcher.d.ts.map +1 -1
  842. package/dist/watcher/FileWatcher.js +185 -14
  843. package/dist/watcher/FileWatcher.js.map +1 -1
  844. package/dist/watcher/index.d.ts +2 -2
  845. package/dist/watcher/index.d.ts.map +1 -1
  846. package/dist/watcher/index.js.map +1 -1
  847. package/dist/yaModuleEnv.d.ts +6 -6
  848. package/dist/yaModuleEnv.d.ts.map +1 -1
  849. package/dist/yaModuleEnv.js +12 -12
  850. package/dist/yaModuleEnv.js.map +1 -1
  851. package/package.json +5 -6
  852. package/client-dist/assets/de-BuEb60Yc.js +0 -6
  853. package/client-dist/assets/es-CRlmPKnE.js +0 -6
  854. package/client-dist/assets/fr-Cglgjc2X.js +0 -6
  855. package/client-dist/assets/index-BNj7ibmq.js +0 -524
  856. package/client-dist/assets/index-CAmsUazi.css +0 -1
  857. package/client-dist/assets/ja-DMb9mFPv.js +0 -6
  858. package/client-dist/assets/zh-CN-D1tbfamz.js +0 -6
@@ -14,9 +14,14 @@ import * as fs from "node:fs/promises";
14
14
  import * as path from "node:path";
15
15
  import { DEFAULT_PROVIDER, } from "../../bundled/@yep-anywhere/shared/dist/index.js";
16
16
  import { getLogger } from "../logging/logger.js";
17
- const logger = getLogger();
17
+ import { getProjectIdentityKey } from "../projects/paths.js";
18
+ import { readCodexRolloutMetadata, } from "../sessions/codex-discovery.js";
19
+ import { getCodexRolloutDiscoveryIdentity, getCodexRolloutSessionId, } from "../utils/codexRolloutFiles.js";
20
+ import { SessionDiscoveryIndex } from "./SessionDiscoveryIndex.js";
18
21
  const LOG_CACHE_PERF = process.env.SESSION_INDEX_LOG_PERF === "true";
19
- const CURRENT_VERSION = 1;
22
+ const DEFAULT_SUMMARY_PARSE_CONCURRENCY = 1;
23
+ const DEFAULT_WARMUP_PROGRESS_LOG_INTERVAL_MS = 5000;
24
+ const CURRENT_VERSION = 2;
20
25
  /**
21
26
  * Claude-specific session index service.
22
27
  *
@@ -34,11 +39,27 @@ export class SessionIndexService {
34
39
  fullValidationIntervalMs;
35
40
  writeLockTimeoutMs;
36
41
  writeLockStaleMs;
42
+ summaryParseConcurrency;
43
+ warmupProgressLogIntervalMs;
37
44
  lastFullValidationAt = new Map();
38
45
  dirtyDirs = new Set();
39
46
  dirtySessionsByDir = new Map();
47
+ /** Scopes with a persisted index file (loaded or written this run). */
48
+ persistedIndexScopes = new Set();
49
+ /** In-flight background full validations, keyed by validation key. */
50
+ backgroundValidations = new Map();
51
+ /** Serializes background validations to bound concurrent I/O. */
52
+ backgroundValidationChain = Promise.resolve();
40
53
  inFlightSessionLoads = new Map();
54
+ inFlightSessionSummaryLoads = new Map();
41
55
  inFlightTitleLoads = new Map();
56
+ inFlightSummaryParses = new Map();
57
+ codexDiscoveryIndexes = new Map();
58
+ summaryParseQueue = [];
59
+ activeSummaryParses = 0;
60
+ warmupJobs = new Map();
61
+ recentWarmupJobs = [];
62
+ warmupProgressTimer = null;
42
63
  cacheStats = {
43
64
  requests: 0,
44
65
  fastHits: 0,
@@ -49,6 +70,7 @@ export class SessionIndexService {
49
70
  totalDurationMs: 0,
50
71
  };
51
72
  unsubscribeEventBus = null;
73
+ eventBus = null;
52
74
  constructor(options = {}) {
53
75
  const home = process.env.HOME ?? process.env.USERPROFILE ?? ".";
54
76
  this.dataDir =
@@ -59,7 +81,11 @@ export class SessionIndexService {
59
81
  this.fullValidationIntervalMs = Math.max(0, options.fullValidationIntervalMs ?? 0);
60
82
  this.writeLockTimeoutMs = Math.max(0, options.writeLockTimeoutMs ?? 2000);
61
83
  this.writeLockStaleMs = Math.max(1000, options.writeLockStaleMs ?? 10000);
84
+ this.summaryParseConcurrency = Math.max(1, Math.floor(options.summaryParseConcurrency ?? DEFAULT_SUMMARY_PARSE_CONCURRENCY));
85
+ this.warmupProgressLogIntervalMs = Math.max(1000, options.warmupProgressLogIntervalMs ??
86
+ DEFAULT_WARMUP_PROGRESS_LOG_INTERVAL_MS);
62
87
  if (options.eventBus) {
88
+ this.eventBus = options.eventBus;
63
89
  this.unsubscribeEventBus = options.eventBus.subscribe((event) => {
64
90
  if (event.type !== "file-change")
65
91
  return;
@@ -79,7 +105,7 @@ export class SessionIndexService {
79
105
  const firstKey = this.indexCache.keys().next().value;
80
106
  if (firstKey) {
81
107
  this.indexCache.delete(firstKey);
82
- logger.debug(`[SessionIndexService] Evicted cache entry for ${firstKey} (cache size: ${this.indexCache.size})`);
108
+ getLogger().debug(`[SessionIndexService] Evicted cache entry for ${firstKey} (cache size: ${this.indexCache.size})`);
83
109
  }
84
110
  else {
85
111
  break;
@@ -147,6 +173,7 @@ export class SessionIndexService {
147
173
  if (parsed.version === CURRENT_VERSION &&
148
174
  parsed.projectId === projectId) {
149
175
  this.indexCache.set(cacheKey, parsed);
176
+ this.persistedIndexScopes.add(cacheKey);
150
177
  this.evictIfNeeded();
151
178
  return parsed;
152
179
  }
@@ -163,7 +190,7 @@ export class SessionIndexService {
163
190
  catch (error) {
164
191
  // File doesn't exist or is invalid - start fresh
165
192
  if (error.code !== "ENOENT") {
166
- logger.warn({ err: error }, `[SessionIndexService] Failed to load index for ${scopeKey}, starting fresh`);
193
+ getLogger().warn({ err: error }, `[SessionIndexService] Failed to load index for ${scopeKey}, starting fresh`);
167
194
  }
168
195
  const fresh = {
169
196
  version: CURRENT_VERSION,
@@ -217,12 +244,13 @@ export class SessionIndexService {
217
244
  await fs.writeFile(tempPath, content, "utf-8");
218
245
  await fs.rename(tempPath, indexPath);
219
246
  });
247
+ this.persistedIndexScopes.add(scopeKey);
220
248
  }
221
249
  catch (error) {
222
250
  await fs.unlink(tempPath).catch(() => {
223
251
  // Best-effort cleanup for failed atomic writes.
224
252
  });
225
- logger.error({ err: error }, `[SessionIndexService] Failed to save index for ${scopeKey}`);
253
+ getLogger().error({ err: error }, `[SessionIndexService] Failed to save index for ${scopeKey}`);
226
254
  throw error;
227
255
  }
228
256
  }
@@ -294,11 +322,23 @@ export class SessionIndexService {
294
322
  return `${this.getScopeKey(sessionDir, reader)}::${projectId}::${sessionId}`;
295
323
  }
296
324
  markSessionDirty(sessionDir, sessionId, reader) {
297
- const scopeKey = this.getScopeKey(sessionDir, reader);
325
+ this.markSessionDirtyByScopeKey(this.getScopeKey(sessionDir, reader), sessionId);
326
+ }
327
+ markSessionDirtyByScopeKey(scopeKey, sessionId) {
298
328
  const current = this.dirtySessionsByDir.get(scopeKey) ?? new Set();
299
329
  current.add(sessionId);
300
330
  this.dirtySessionsByDir.set(scopeKey, current);
301
331
  }
332
+ clearSessionDirty(sessionDir, sessionId, reader) {
333
+ const scopeKey = this.getScopeKey(sessionDir, reader);
334
+ const dirty = this.dirtySessionsByDir.get(scopeKey);
335
+ if (!dirty)
336
+ return;
337
+ dirty.delete(sessionId);
338
+ if (dirty.size === 0) {
339
+ this.dirtySessionsByDir.delete(scopeKey);
340
+ }
341
+ }
302
342
  markDirDirty(sessionDir, reader) {
303
343
  this.dirtyDirs.add(this.getScopeKey(sessionDir, reader));
304
344
  }
@@ -320,6 +360,27 @@ export class SessionIndexService {
320
360
  }
321
361
  }
322
362
  }
363
+ markLoadedCodexSessionDirty(sessionId, changeType) {
364
+ // Only loaded indexes can prove membership, so scopes known solely from
365
+ // validation timestamps or dirty marks can never match here.
366
+ let marked = false;
367
+ for (const [scopeKey, index] of this.indexCache) {
368
+ if (!scopeKey.startsWith("codex::"))
369
+ continue;
370
+ if (!index.sessions[sessionId])
371
+ continue;
372
+ this.markCodexScopeDirty(scopeKey, sessionId, changeType);
373
+ marked = true;
374
+ }
375
+ return marked;
376
+ }
377
+ markCodexScopeDirty(scopeKey, sessionId, changeType) {
378
+ if (changeType === "create" || changeType === "delete") {
379
+ this.dirtyDirs.add(scopeKey);
380
+ return;
381
+ }
382
+ this.markSessionDirtyByScopeKey(scopeKey, sessionId);
383
+ }
323
384
  buildSummariesFromIndex(index, projectId, options) {
324
385
  const summaries = [];
325
386
  const activeAfterMs = options?.activeAfterMs;
@@ -330,23 +391,28 @@ export class SessionIndexService {
330
391
  Date.parse(cached.updatedAt) < activeAfterMs) {
331
392
  continue;
332
393
  }
333
- summaries.push({
334
- id: sessionId,
335
- projectId,
336
- title: cached.title,
337
- fullTitle: cached.fullTitle,
338
- createdAt: cached.createdAt,
339
- updatedAt: cached.updatedAt,
340
- messageCount: cached.messageCount,
341
- ownership: { owner: "none" },
342
- contextUsage: cached.contextUsage,
343
- provider: cached.provider ?? DEFAULT_PROVIDER,
344
- model: cached.model,
345
- });
394
+ summaries.push(this.toSessionSummary(sessionId, cached, projectId));
346
395
  }
347
396
  summaries.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
348
397
  return summaries;
349
398
  }
399
+ toSessionSummary(sessionId, cached, projectId) {
400
+ return {
401
+ id: sessionId,
402
+ projectId,
403
+ title: cached.title,
404
+ fullTitle: cached.fullTitle,
405
+ createdAt: cached.createdAt,
406
+ updatedAt: cached.updatedAt,
407
+ messageCount: cached.messageCount,
408
+ ownership: { owner: "none" },
409
+ contextUsage: cached.contextUsage,
410
+ provider: cached.provider ?? DEFAULT_PROVIDER,
411
+ model: cached.model,
412
+ parentSessionId: cached.parentSessionId,
413
+ lastAgentText: cached.lastAgentText,
414
+ };
415
+ }
350
416
  toCachedSummary(summary, mtime, size) {
351
417
  return {
352
418
  title: summary.title,
@@ -359,6 +425,8 @@ export class SessionIndexService {
359
425
  fileMtime: mtime,
360
426
  provider: summary.provider,
361
427
  model: summary.model,
428
+ parentSessionId: summary.parentSessionId,
429
+ lastAgentText: summary.lastAgentText,
362
430
  };
363
431
  }
364
432
  toEmptyCachedSummary(mtime, size) {
@@ -375,7 +443,7 @@ export class SessionIndexService {
375
443
  provider: DEFAULT_PROVIDER,
376
444
  };
377
445
  }
378
- recordCallStats(mode, durationMs, statCalls, parseCalls, sessionDir) {
446
+ recordCallStats(mode, durationMs, statCalls, parseCalls, sessionDir, details = {}) {
379
447
  this.cacheStats.requests += 1;
380
448
  this.cacheStats.statCalls += statCalls;
381
449
  this.cacheStats.parseCalls += parseCalls;
@@ -387,7 +455,240 @@ export class SessionIndexService {
387
455
  if (mode === "full")
388
456
  this.cacheStats.fullScans += 1;
389
457
  if (LOG_CACHE_PERF || durationMs >= 250) {
390
- logger.info(`[SessionIndexService] mode=${mode} dir=${sessionDir} durationMs=${durationMs} statCalls=${statCalls} parseCalls=${parseCalls}`);
458
+ getLogger().info({
459
+ event: "session_index_perf",
460
+ mode,
461
+ sessionDir,
462
+ durationMs,
463
+ statCalls,
464
+ parseCalls,
465
+ ...details,
466
+ }, "SESSION_INDEX: performance");
467
+ }
468
+ }
469
+ snapshotWarmupJob(job, now = Date.now()) {
470
+ return {
471
+ key: job.key,
472
+ status: job.status,
473
+ scopeKey: job.scopeKey,
474
+ validationKey: job.validationKey,
475
+ sessionDir: job.sessionDir,
476
+ projectId: job.projectId,
477
+ startedAt: new Date(job.startedAtMs).toISOString(),
478
+ updatedAt: new Date(job.updatedAtMs).toISOString(),
479
+ ...(job.completedAtMs
480
+ ? { completedAt: new Date(job.completedAtMs).toISOString() }
481
+ : {}),
482
+ elapsedMs: now - job.startedAtMs,
483
+ totalFiles: job.totalFiles,
484
+ completedFiles: job.completedFiles,
485
+ cacheHits: job.cacheHits,
486
+ cacheMisses: job.cacheMisses,
487
+ cacheMissBytes: job.cacheMissBytes,
488
+ parsedBytes: job.parsedBytes,
489
+ parseCalls: job.parseCalls,
490
+ activeParses: job.activeParses,
491
+ queuedParses: job.queuedParses,
492
+ coalescedParses: job.coalescedParses,
493
+ ...(job.lastSessionId ? { lastSessionId: job.lastSessionId } : {}),
494
+ ...(job.lastFilePath ? { lastFilePath: job.lastFilePath } : {}),
495
+ ...(job.error ? { error: job.error } : {}),
496
+ };
497
+ }
498
+ startWarmupJob(args) {
499
+ const now = Date.now();
500
+ const existing = this.warmupJobs.get(args.validationKey);
501
+ if (existing && existing.status === "running") {
502
+ existing.updatedAtMs = now;
503
+ return existing;
504
+ }
505
+ const job = {
506
+ key: args.validationKey,
507
+ status: "running",
508
+ scopeKey: args.scopeKey,
509
+ validationKey: args.validationKey,
510
+ sessionDir: args.sessionDir,
511
+ projectId: args.projectId,
512
+ startedAtMs: now,
513
+ updatedAtMs: now,
514
+ lastLoggedAtMs: 0,
515
+ totalFiles: 0,
516
+ completedFiles: 0,
517
+ cacheHits: 0,
518
+ cacheMisses: 0,
519
+ cacheMissBytes: 0,
520
+ parsedBytes: 0,
521
+ parseCalls: 0,
522
+ activeParses: 0,
523
+ queuedParses: 0,
524
+ coalescedParses: 0,
525
+ };
526
+ this.warmupJobs.set(job.key, job);
527
+ this.ensureWarmupProgressTimer();
528
+ this.logWarmupProgress(job, "start", true);
529
+ return job;
530
+ }
531
+ updateWarmupJob(jobKey, update) {
532
+ const job = this.warmupJobs.get(jobKey);
533
+ if (job?.status !== "running")
534
+ return;
535
+ const now = Date.now();
536
+ update(job, now);
537
+ job.updatedAtMs = now;
538
+ }
539
+ completeWarmupJob(jobKey) {
540
+ const job = this.warmupJobs.get(jobKey);
541
+ if (job?.status !== "running")
542
+ return;
543
+ const now = Date.now();
544
+ job.status = "completed";
545
+ job.completedAtMs = now;
546
+ job.updatedAtMs = now;
547
+ this.logWarmupProgress(job, "complete", true);
548
+ this.rememberCompletedWarmupJob(job, now);
549
+ }
550
+ failWarmupJob(jobKey, error) {
551
+ const job = this.warmupJobs.get(jobKey);
552
+ if (job?.status !== "running")
553
+ return;
554
+ const now = Date.now();
555
+ job.status = "failed";
556
+ job.error = error instanceof Error ? error.message : String(error);
557
+ job.completedAtMs = now;
558
+ job.updatedAtMs = now;
559
+ this.logWarmupProgress(job, "failed", true);
560
+ this.rememberCompletedWarmupJob(job, now);
561
+ }
562
+ rememberCompletedWarmupJob(job, now) {
563
+ this.warmupJobs.delete(job.key);
564
+ this.recentWarmupJobs.unshift(this.snapshotWarmupJob(job, now));
565
+ this.recentWarmupJobs = this.recentWarmupJobs.slice(0, 20);
566
+ if (this.warmupJobs.size === 0) {
567
+ this.stopWarmupProgressTimer();
568
+ }
569
+ }
570
+ ensureWarmupProgressTimer() {
571
+ if (this.warmupProgressTimer)
572
+ return;
573
+ this.warmupProgressTimer = setInterval(() => {
574
+ const now = Date.now();
575
+ for (const job of this.warmupJobs.values()) {
576
+ this.logWarmupProgress(job, "progress", false, now);
577
+ }
578
+ if (this.warmupJobs.size === 0) {
579
+ this.stopWarmupProgressTimer();
580
+ }
581
+ }, this.warmupProgressLogIntervalMs);
582
+ this.warmupProgressTimer.unref?.();
583
+ }
584
+ stopWarmupProgressTimer() {
585
+ if (!this.warmupProgressTimer)
586
+ return;
587
+ clearInterval(this.warmupProgressTimer);
588
+ this.warmupProgressTimer = null;
589
+ }
590
+ logWarmupProgress(job, phase, force, now = Date.now()) {
591
+ if (!force &&
592
+ now - job.lastLoggedAtMs < this.warmupProgressLogIntervalMs) {
593
+ return;
594
+ }
595
+ job.lastLoggedAtMs = now;
596
+ getLogger().info({
597
+ event: "session_index_warmup_progress",
598
+ phase,
599
+ summaryParseConcurrency: this.summaryParseConcurrency,
600
+ globalActiveParses: this.activeSummaryParses,
601
+ globalQueuedParses: this.summaryParseQueue.length,
602
+ ...this.snapshotWarmupJob(job, now),
603
+ }, "SESSION_INDEX: warmup progress");
604
+ }
605
+ enqueueSummaryParse(args) {
606
+ const parseKey = `${args.scopeKey}::${args.sessionId}::${args.mtime}::${args.size}`;
607
+ const existing = this.inFlightSummaryParses.get(parseKey);
608
+ if (existing) {
609
+ this.updateWarmupJob(args.validationKey, (job) => {
610
+ job.coalescedParses += 1;
611
+ job.lastSessionId = args.sessionId;
612
+ job.lastFilePath = args.filePath;
613
+ });
614
+ return existing.then((summary) => {
615
+ this.updateWarmupJob(args.validationKey, (job) => {
616
+ job.completedFiles += 1;
617
+ job.parsedBytes += args.size;
618
+ job.lastSessionId = args.sessionId;
619
+ job.lastFilePath = args.filePath;
620
+ });
621
+ return summary;
622
+ });
623
+ }
624
+ const promise = new Promise((resolve, reject) => {
625
+ const task = {
626
+ key: parseKey,
627
+ jobKey: args.validationKey,
628
+ sessionId: args.sessionId,
629
+ filePath: args.filePath,
630
+ size: args.size,
631
+ run: () => args.reader.getSessionSummary(args.sessionId, args.projectId),
632
+ resolve,
633
+ reject,
634
+ };
635
+ this.summaryParseQueue.push(task);
636
+ this.updateWarmupJob(args.validationKey, (job) => {
637
+ job.queuedParses += 1;
638
+ job.lastSessionId = args.sessionId;
639
+ job.lastFilePath = args.filePath;
640
+ });
641
+ this.drainSummaryParseQueue();
642
+ });
643
+ this.inFlightSummaryParses.set(parseKey, promise);
644
+ promise.then(() => {
645
+ if (this.inFlightSummaryParses.get(parseKey) === promise) {
646
+ this.inFlightSummaryParses.delete(parseKey);
647
+ }
648
+ }, () => {
649
+ if (this.inFlightSummaryParses.get(parseKey) === promise) {
650
+ this.inFlightSummaryParses.delete(parseKey);
651
+ }
652
+ });
653
+ return promise;
654
+ }
655
+ drainSummaryParseQueue() {
656
+ while (this.activeSummaryParses < this.summaryParseConcurrency &&
657
+ this.summaryParseQueue.length > 0) {
658
+ const task = this.summaryParseQueue.shift();
659
+ if (!task)
660
+ return;
661
+ this.activeSummaryParses += 1;
662
+ this.updateWarmupJob(task.jobKey, (job) => {
663
+ job.queuedParses = Math.max(0, job.queuedParses - 1);
664
+ job.activeParses += 1;
665
+ job.parseCalls += 1;
666
+ job.lastSessionId = task.sessionId;
667
+ job.lastFilePath = task.filePath;
668
+ });
669
+ void (async () => {
670
+ try {
671
+ const summary = await task.run();
672
+ this.updateWarmupJob(task.jobKey, (job) => {
673
+ job.completedFiles += 1;
674
+ job.parsedBytes += task.size;
675
+ job.lastSessionId = task.sessionId;
676
+ job.lastFilePath = task.filePath;
677
+ });
678
+ task.resolve(summary);
679
+ }
680
+ catch (error) {
681
+ this.failWarmupJob(task.jobKey, error);
682
+ task.reject(error);
683
+ }
684
+ finally {
685
+ this.activeSummaryParses = Math.max(0, this.activeSummaryParses - 1);
686
+ this.updateWarmupJob(task.jobKey, (job) => {
687
+ job.activeParses = Math.max(0, job.activeParses - 1);
688
+ });
689
+ this.drainSummaryParseQueue();
690
+ }
691
+ })();
391
692
  }
392
693
  }
393
694
  /**
@@ -415,11 +716,7 @@ export class SessionIndexService {
415
716
  return;
416
717
  }
417
718
  if (event.provider === "codex") {
418
- // Codex indexes are project-scoped over a shared sessions tree
419
- // (codex::<sessionsDir>::<projectPath>), so a raw file event does not
420
- // tell us which project scope owns the changed session. Mark all loaded
421
- // Codex scopes dirty and let the next request reconcile via listSessionFiles.
422
- this.markMatchingScopesDirty("codex::");
719
+ this.handleCodexFileChange(event);
423
720
  return;
424
721
  }
425
722
  if (event.provider === "gemini") {
@@ -427,6 +724,84 @@ export class SessionIndexService {
427
724
  this.markMatchingScopesDirty("gemini::");
428
725
  }
429
726
  }
727
+ handleCodexFileChange(event) {
728
+ const sessionId = getCodexRolloutSessionId(event.relativePath);
729
+ if (!sessionId) {
730
+ this.markMatchingScopesDirty("codex::");
731
+ return;
732
+ }
733
+ if (this.markLoadedCodexSessionDirty(sessionId, event.changeType)) {
734
+ return;
735
+ }
736
+ void this.resolveAndMarkCodexFileChange(event, sessionId);
737
+ }
738
+ async resolveAndMarkCodexFileChange(event, sessionId) {
739
+ try {
740
+ const resolved = await this.resolveCodexFileChange(event);
741
+ if (resolved && !resolved.isSubagent) {
742
+ this.markCodexScopeDirty(resolved.scopeKey, resolved.sessionId, event.changeType);
743
+ return;
744
+ }
745
+ }
746
+ catch (error) {
747
+ getLogger().debug({ err: error, filePath: event.path }, "[SessionIndexService] Failed to resolve Codex file change");
748
+ }
749
+ if (!this.markLoadedCodexSessionDirty(sessionId, event.changeType)) {
750
+ this.markMatchingScopesDirty("codex::");
751
+ }
752
+ }
753
+ async resolveCodexFileChange(event) {
754
+ const sessionsDir = this.getCodexSessionsDirForEvent(event);
755
+ const discoveryIndex = this.getCodexDiscoveryIndex(sessionsDir);
756
+ const identity = getCodexRolloutDiscoveryIdentity(sessionsDir, event.path);
757
+ if (event.changeType === "delete") {
758
+ const record = await discoveryIndex.getRecord(identity.shardKey, identity.key);
759
+ if (!record)
760
+ return null;
761
+ await discoveryIndex.removeRecord(identity.shardKey, identity.key);
762
+ void discoveryIndex.flush();
763
+ return this.codexMetadataToDirtyScope(sessionsDir, record.metadata);
764
+ }
765
+ const metadata = await readCodexRolloutMetadata({
766
+ sessionsDir,
767
+ filePath: event.path,
768
+ discoveryIndex,
769
+ });
770
+ void discoveryIndex.flush();
771
+ if (!metadata)
772
+ return null;
773
+ return this.codexMetadataToDirtyScope(sessionsDir, metadata);
774
+ }
775
+ codexMetadataToDirtyScope(sessionsDir, metadata) {
776
+ return {
777
+ sessionId: metadata.id,
778
+ scopeKey: `codex::${sessionsDir}::${getProjectIdentityKey(metadata.cwd)}`,
779
+ isSubagent: metadata.isSubagent,
780
+ };
781
+ }
782
+ getCodexDiscoveryIndex(sessionsDir) {
783
+ const resolvedSessionsDir = path.resolve(sessionsDir);
784
+ let discoveryIndex = this.codexDiscoveryIndexes.get(resolvedSessionsDir);
785
+ if (!discoveryIndex) {
786
+ discoveryIndex = new SessionDiscoveryIndex({
787
+ baseDir: path.join(this.dataDir, "session-discovery"),
788
+ provider: "codex",
789
+ sourceRoot: resolvedSessionsDir,
790
+ });
791
+ this.codexDiscoveryIndexes.set(resolvedSessionsDir, discoveryIndex);
792
+ }
793
+ return discoveryIndex;
794
+ }
795
+ getCodexSessionsDirForEvent(event) {
796
+ const relativeDir = path.dirname(event.relativePath.replace(/\\/g, "/"));
797
+ let current = path.resolve(path.dirname(event.path));
798
+ if (relativeDir === ".")
799
+ return current;
800
+ for (const _segment of relativeDir.split("/")) {
801
+ current = path.dirname(current);
802
+ }
803
+ return current;
804
+ }
430
805
  async applyIncrementalDirtyUpdates(sessionDir, projectId, reader, index) {
431
806
  const scopeKey = this.getScopeKey(sessionDir, reader);
432
807
  const dirty = this.dirtySessionsByDir.get(scopeKey);
@@ -436,46 +811,82 @@ export class SessionIndexService {
436
811
  let indexChanged = false;
437
812
  let statCalls = 0;
438
813
  let parseCalls = 0;
439
- for (const sessionId of Array.from(dirty)) {
440
- const cached = index.sessions[sessionId];
441
- if (cached) {
442
- statCalls += 1;
443
- const changed = await reader.getSessionSummaryIfChanged(sessionId, projectId, cached.fileMtime, cached.indexedBytes);
444
- if (!changed)
814
+ let warmupJobKey = null;
815
+ let warmupJobCacheMissBytes = 0;
816
+ const incrementalValidationKey = `${scopeKey}::incremental`;
817
+ try {
818
+ for (const sessionId of Array.from(dirty)) {
819
+ const cached = index.sessions[sessionId];
820
+ if (cached) {
821
+ statCalls += 1;
822
+ const changed = await reader.getSessionSummaryIfChanged(sessionId, projectId, cached.fileMtime, cached.indexedBytes);
823
+ if (!changed)
824
+ continue;
825
+ parseCalls += 1;
826
+ index.sessions[sessionId] = this.toCachedSummary(changed.summary, changed.mtime, changed.size);
827
+ indexChanged = true;
445
828
  continue;
446
- parseCalls += 1;
447
- index.sessions[sessionId] = this.toCachedSummary(changed.summary, changed.mtime, changed.size);
448
- indexChanged = true;
449
- continue;
450
- }
451
- parseCalls += 1;
452
- const summary = await reader.getSessionSummary(sessionId, projectId);
453
- const filePath = (await reader.getSessionFilePath?.(sessionId)) ??
454
- path.join(sessionDir, `${sessionId}.jsonl`);
455
- if (summary) {
829
+ }
830
+ const filePath = (await reader.getSessionFilePath?.(sessionId)) ??
831
+ path.join(sessionDir, `${sessionId}.jsonl`);
832
+ let stats;
456
833
  try {
457
- const stats = await fs.stat(filePath);
834
+ stats = await fs.stat(filePath);
458
835
  statCalls += 1;
459
- index.sessions[sessionId] = this.toCachedSummary(summary, stats.mtimeMs, stats.size);
460
- indexChanged = true;
461
836
  }
462
837
  catch {
463
- // Ignore race where file disappeared after read.
838
+ if (index.sessions[sessionId]) {
839
+ delete index.sessions[sessionId];
840
+ indexChanged = true;
841
+ }
842
+ continue;
843
+ }
844
+ parseCalls += 1;
845
+ warmupJobCacheMissBytes += stats.size;
846
+ if (!warmupJobKey) {
847
+ const job = this.startWarmupJob({
848
+ scopeKey,
849
+ validationKey: incrementalValidationKey,
850
+ sessionDir,
851
+ projectId,
852
+ });
853
+ warmupJobKey = job.key;
854
+ this.updateWarmupJob(job.key, (current) => {
855
+ current.totalFiles = dirty.size;
856
+ });
857
+ }
858
+ this.updateWarmupJob(warmupJobKey, (current) => {
859
+ current.cacheMisses += 1;
860
+ current.cacheMissBytes = warmupJobCacheMissBytes;
861
+ });
862
+ const summary = await this.enqueueSummaryParse({
863
+ sessionDir,
864
+ projectId,
865
+ reader,
866
+ scopeKey,
867
+ validationKey: warmupJobKey,
868
+ sessionId,
869
+ filePath,
870
+ size: stats.size,
871
+ mtime: stats.mtimeMs,
872
+ });
873
+ if (summary) {
874
+ index.sessions[sessionId] = this.toCachedSummary(summary, stats.mtimeMs, stats.size);
875
+ indexChanged = true;
876
+ continue;
464
877
  }
465
- continue;
466
- }
467
- try {
468
- const stats = await fs.stat(filePath);
469
- statCalls += 1;
470
878
  index.sessions[sessionId] = this.toEmptyCachedSummary(stats.mtimeMs, stats.size);
471
879
  indexChanged = true;
472
880
  }
473
- catch {
474
- if (index.sessions[sessionId]) {
475
- delete index.sessions[sessionId];
476
- indexChanged = true;
477
- }
881
+ }
882
+ catch (error) {
883
+ if (warmupJobKey) {
884
+ this.failWarmupJob(warmupJobKey, error);
478
885
  }
886
+ throw error;
887
+ }
888
+ if (warmupJobKey) {
889
+ this.completeWarmupJob(warmupJobKey);
479
890
  }
480
891
  this.dirtySessionsByDir.delete(scopeKey);
481
892
  return { indexChanged, statCalls, parseCalls };
@@ -486,6 +897,11 @@ export class SessionIndexService {
486
897
  let indexChanged = false;
487
898
  let statCalls = 0;
488
899
  let parseCalls = 0;
900
+ let totalFiles = 0;
901
+ let cacheHits = 0;
902
+ let cacheMissBytes = 0;
903
+ let largestCacheMisses = [];
904
+ let warmupJobKey = null;
489
905
  try {
490
906
  // Enumerate session files — delegate to reader if it supports custom
491
907
  // enumeration (e.g., Gemini JSON where session ID is inside the file),
@@ -503,16 +919,21 @@ export class SessionIndexService {
503
919
  filePath: path.join(sessionDir, f),
504
920
  }));
505
921
  }
922
+ totalFiles = sessionFiles.length;
506
923
  const STAT_BATCH = 100;
507
924
  const allStats = Array.from({
508
925
  length: sessionFiles.length,
509
926
  });
510
927
  for (let b = 0; b < sessionFiles.length; b += STAT_BATCH) {
511
928
  const end = Math.min(b + STAT_BATCH, sessionFiles.length);
512
- const batch = await Promise.all(sessionFiles
513
- .slice(b, end)
514
- .map((f) => fs.stat(f.filePath).catch(() => null)));
515
- statCalls += batch.length;
929
+ const batch = await Promise.all(sessionFiles.slice(b, end).map((f) => {
930
+ // A shared container file (e.g. a provider database) is not
931
+ // statted: its mtime/size cannot validate individual sessions.
932
+ if (f.sharedFilePath)
933
+ return Promise.resolve(null);
934
+ statCalls += 1;
935
+ return fs.stat(f.filePath).catch(() => null);
936
+ }));
516
937
  for (let j = 0; j < batch.length; j++) {
517
938
  allStats[b + j] = batch[j] ?? null;
518
939
  }
@@ -524,6 +945,41 @@ export class SessionIndexService {
524
945
  continue;
525
946
  const sessionId = entry.sessionId;
526
947
  seenSessionIds.add(sessionId);
948
+ if (entry.sharedFilePath) {
949
+ // Validate through the reader's own cheap change check (e.g. a DB
950
+ // row's updated-time + message count). Stat-based comparison can
951
+ // never hit for these entries — the container's mtime moves on any
952
+ // write while the cached mtime/size are row-derived — which made
953
+ // every full validation re-summarize every DB session.
954
+ const cachedShared = index.sessions[sessionId];
955
+ const changed = await reader.getSessionSummaryIfChanged(sessionId, projectId, cachedShared?.fileMtime ?? -1, cachedShared?.indexedBytes ?? -1);
956
+ if (changed) {
957
+ parseCalls += 1;
958
+ index.sessions[sessionId] = this.toCachedSummary(changed.summary, changed.mtime, changed.size);
959
+ indexChanged = true;
960
+ if (options?.activeAfterMs === undefined ||
961
+ Date.parse(changed.summary.updatedAt) >= options.activeAfterMs) {
962
+ summaries.push(changed.summary);
963
+ }
964
+ continue;
965
+ }
966
+ if (cachedShared) {
967
+ cacheHits += 1;
968
+ if (cachedShared.isEmpty)
969
+ continue;
970
+ if (options?.activeAfterMs !== undefined &&
971
+ Date.parse(cachedShared.updatedAt) < options.activeAfterMs) {
972
+ continue;
973
+ }
974
+ summaries.push(this.toSessionSummary(sessionId, cachedShared, projectId));
975
+ continue;
976
+ }
977
+ // Unknown session that yields no summary (e.g. still empty): cache
978
+ // the emptiness so later validations stay row-level cheap.
979
+ index.sessions[sessionId] = this.toEmptyCachedSummary(-1, -1);
980
+ indexChanged = true;
981
+ continue;
982
+ }
527
983
  const stats = allStats[i];
528
984
  if (!stats)
529
985
  continue;
@@ -533,33 +989,66 @@ export class SessionIndexService {
533
989
  if (cached &&
534
990
  cached.fileMtime === mtime &&
535
991
  cached.indexedBytes === size) {
992
+ cacheHits += 1;
536
993
  if (cached.isEmpty)
537
994
  continue;
538
995
  if (options?.activeAfterMs !== undefined &&
539
996
  Date.parse(cached.updatedAt) < options.activeAfterMs) {
540
997
  continue;
541
998
  }
542
- summaries.push({
543
- id: sessionId,
544
- projectId,
545
- title: cached.title,
546
- fullTitle: cached.fullTitle,
547
- createdAt: cached.createdAt,
548
- updatedAt: cached.updatedAt,
549
- messageCount: cached.messageCount,
550
- ownership: { owner: "none" },
551
- contextUsage: cached.contextUsage,
552
- provider: cached.provider ?? DEFAULT_PROVIDER,
553
- model: cached.model,
554
- });
999
+ summaries.push(this.toSessionSummary(sessionId, cached, projectId));
555
1000
  }
556
1001
  else {
557
- cacheMisses.push({ sessionId, mtime, size });
1002
+ cacheMissBytes += size;
1003
+ cacheMisses.push({
1004
+ sessionId,
1005
+ filePath: entry.filePath,
1006
+ mtime,
1007
+ size,
1008
+ });
558
1009
  }
559
1010
  }
560
- for (const { sessionId, mtime, size } of cacheMisses) {
1011
+ largestCacheMisses = cacheMisses
1012
+ .slice()
1013
+ .sort((a, b) => b.size - a.size)
1014
+ .slice(0, 5)
1015
+ .map(({ sessionId, filePath, mtime, size }) => ({
1016
+ sessionId,
1017
+ filePath,
1018
+ mtime,
1019
+ size,
1020
+ }));
1021
+ if (cacheMisses.length > 0) {
1022
+ const scopeKey = this.getScopeKey(sessionDir, reader);
1023
+ const validationKey = this.getValidationKey(sessionDir, reader, options);
1024
+ const job = this.startWarmupJob({
1025
+ scopeKey,
1026
+ validationKey,
1027
+ sessionDir,
1028
+ projectId,
1029
+ });
1030
+ warmupJobKey = job.key;
1031
+ this.updateWarmupJob(job.key, (current) => {
1032
+ current.totalFiles = totalFiles;
1033
+ current.completedFiles = cacheHits;
1034
+ current.cacheHits = cacheHits;
1035
+ current.cacheMisses = cacheMisses.length;
1036
+ current.cacheMissBytes = cacheMissBytes;
1037
+ });
1038
+ }
1039
+ for (const { sessionId, filePath, mtime, size } of cacheMisses) {
561
1040
  parseCalls += 1;
562
- const summary = await reader.getSessionSummary(sessionId, projectId);
1041
+ const summary = await this.enqueueSummaryParse({
1042
+ sessionDir,
1043
+ projectId,
1044
+ reader,
1045
+ scopeKey: this.getScopeKey(sessionDir, reader),
1046
+ validationKey: warmupJobKey ?? this.getValidationKey(sessionDir, reader, options),
1047
+ sessionId,
1048
+ filePath,
1049
+ size,
1050
+ mtime,
1051
+ });
563
1052
  if (summary) {
564
1053
  if (options?.activeAfterMs === undefined ||
565
1054
  Date.parse(summary.updatedAt) >= options.activeAfterMs) {
@@ -573,22 +1062,50 @@ export class SessionIndexService {
573
1062
  indexChanged = true;
574
1063
  }
575
1064
  }
1065
+ if (warmupJobKey) {
1066
+ this.completeWarmupJob(warmupJobKey);
1067
+ }
576
1068
  for (const sessionId of Object.keys(index.sessions)) {
577
1069
  if (!options?.activeAfterMs && !seenSessionIds.has(sessionId)) {
578
1070
  delete index.sessions[sessionId];
579
1071
  indexChanged = true;
580
1072
  }
581
1073
  }
582
- if (indexChanged) {
1074
+ // Persist even a no-change (possibly empty) index: a scope with no
1075
+ // index file would otherwise block a request in-line again on the
1076
+ // first list after every server restart.
1077
+ if (indexChanged ||
1078
+ !this.persistedIndexScopes.has(this.getScopeKey(sessionDir, reader))) {
583
1079
  await this.saveIndex(sessionDir, reader);
584
1080
  }
585
1081
  summaries.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
586
1082
  this.lastFullValidationAt.set(this.getValidationKey(sessionDir, reader, options), Date.now());
587
1083
  this.clearDirDirtyState(sessionDir, reader);
588
- return { summaries, statCalls, parseCalls };
1084
+ return {
1085
+ summaries,
1086
+ statCalls,
1087
+ parseCalls,
1088
+ totalFiles,
1089
+ cacheHits,
1090
+ cacheMisses: cacheMisses.length,
1091
+ cacheMissBytes,
1092
+ largestCacheMisses,
1093
+ };
589
1094
  }
590
- catch {
591
- return { summaries: [], statCalls, parseCalls };
1095
+ catch (error) {
1096
+ if (warmupJobKey) {
1097
+ this.failWarmupJob(warmupJobKey, error);
1098
+ }
1099
+ return {
1100
+ summaries: [],
1101
+ statCalls,
1102
+ parseCalls,
1103
+ totalFiles,
1104
+ cacheHits,
1105
+ cacheMisses: parseCalls,
1106
+ cacheMissBytes,
1107
+ largestCacheMisses,
1108
+ };
592
1109
  }
593
1110
  }
594
1111
  getDebugStats() {
@@ -602,6 +1119,16 @@ export class SessionIndexService {
602
1119
  dirtySessionCount,
603
1120
  };
604
1121
  }
1122
+ getWarmupStatus() {
1123
+ const now = Date.now();
1124
+ return {
1125
+ summaryParseConcurrency: this.summaryParseConcurrency,
1126
+ activeParses: this.activeSummaryParses,
1127
+ queuedParses: this.summaryParseQueue.length,
1128
+ activeJobs: Array.from(this.warmupJobs.values()).map((job) => this.snapshotWarmupJob(job, now)),
1129
+ recentJobs: this.recentWarmupJobs,
1130
+ };
1131
+ }
605
1132
  /**
606
1133
  * Get sessions using the cache, only re-parsing files that have changed.
607
1134
  * This is the main entry point for listing sessions with caching.
@@ -639,7 +1166,11 @@ export class SessionIndexService {
639
1166
  // Fast path: no dirty signals and recent full validation.
640
1167
  if (!fullValidationDue && !hasDirDirty && !hasDirtySessions) {
641
1168
  const summaries = this.buildSummariesFromIndex(index, projectId, options);
642
- this.recordCallStats("fast", Date.now() - start, 0, 0, sessionDir);
1169
+ this.recordCallStats("fast", Date.now() - start, 0, 0, sessionDir, {
1170
+ scopeKey,
1171
+ validationKey,
1172
+ indexedSessions: Object.keys(index.sessions).length,
1173
+ });
643
1174
  return summaries;
644
1175
  }
645
1176
  // Incremental path: only specific sessions are dirty.
@@ -649,13 +1180,149 @@ export class SessionIndexService {
649
1180
  await this.saveIndex(sessionDir, reader);
650
1181
  }
651
1182
  const summaries = this.buildSummariesFromIndex(index, projectId, options);
652
- this.recordCallStats("incremental", Date.now() - start, incremental.statCalls, incremental.parseCalls, sessionDir);
1183
+ this.recordCallStats("incremental", Date.now() - start, incremental.statCalls, incremental.parseCalls, sessionDir, {
1184
+ scopeKey,
1185
+ validationKey,
1186
+ dirtySessions: dirtySessions?.size ?? 0,
1187
+ indexedSessions: Object.keys(index.sessions).length,
1188
+ });
1189
+ return summaries;
1190
+ }
1191
+ // Full validation is due only because the TTL lapsed (no directory-level
1192
+ // dirty signal). The TTL walk is a consistency backstop for missed
1193
+ // watcher events, so a scope that already has a previously validated
1194
+ // (this run) or persisted index serves it immediately and revalidates in
1195
+ // the background — a fresh browser window after server idle must not pay
1196
+ // the walk in-line. Background-discovered changes reach clients as
1197
+ // session-updated/session-created bus events. Directory-dirty scopes
1198
+ // (watcher saw a create/delete) still validate in-line, and interval <= 0
1199
+ // keeps its validate-every-request contract. First-ever scans (no usable
1200
+ // index) also still block: there is nothing to serve.
1201
+ const canServeStaleWhileRevalidating = this.fullValidationIntervalMs > 0 &&
1202
+ !hasDirDirty &&
1203
+ (lastFullValidation > 0 || this.persistedIndexScopes.has(scopeKey));
1204
+ if (canServeStaleWhileRevalidating) {
1205
+ let statCalls = 0;
1206
+ let parseCalls = 0;
1207
+ if (hasDirtySessions) {
1208
+ const incremental = await this.applyIncrementalDirtyUpdates(sessionDir, projectId, reader, index);
1209
+ statCalls = incremental.statCalls;
1210
+ parseCalls = incremental.parseCalls;
1211
+ if (incremental.indexChanged) {
1212
+ await this.saveIndex(sessionDir, reader);
1213
+ }
1214
+ }
1215
+ this.scheduleBackgroundValidation(sessionDir, projectId, reader, options);
1216
+ const summaries = this.buildSummariesFromIndex(index, projectId, options);
1217
+ this.recordCallStats("fast", Date.now() - start, statCalls, parseCalls, sessionDir, {
1218
+ scopeKey,
1219
+ validationKey,
1220
+ staleWhileRevalidate: true,
1221
+ indexedSessions: Object.keys(index.sessions).length,
1222
+ });
653
1223
  return summaries;
654
1224
  }
655
1225
  const full = await this.runFullValidation(sessionDir, projectId, reader, index, options);
656
- this.recordCallStats("full", Date.now() - start, full.statCalls, full.parseCalls, sessionDir);
1226
+ this.recordCallStats("full", Date.now() - start, full.statCalls, full.parseCalls, sessionDir, {
1227
+ scopeKey,
1228
+ validationKey,
1229
+ indexedSessions: Object.keys(index.sessions).length,
1230
+ totalFiles: full.totalFiles,
1231
+ cacheHits: full.cacheHits,
1232
+ cacheMisses: full.cacheMisses,
1233
+ cacheMissBytes: full.cacheMissBytes,
1234
+ largestCacheMisses: full.largestCacheMisses,
1235
+ });
657
1236
  return full.summaries;
658
1237
  }
1238
+ /**
1239
+ * Queue a background full validation for a scope/options variant, deduped
1240
+ * while one is pending and serialized across scopes so a burst of
1241
+ * stale-served requests (the per-project walk behind /api/sessions) does
1242
+ * not stampede the filesystem.
1243
+ */
1244
+ scheduleBackgroundValidation(sessionDir, projectId, reader, options) {
1245
+ const validationKey = this.getValidationKey(sessionDir, reader, options);
1246
+ if (this.backgroundValidations.has(validationKey)) {
1247
+ return;
1248
+ }
1249
+ const run = this.backgroundValidationChain
1250
+ .then(() => this.runBackgroundValidation(sessionDir, projectId, reader, options))
1251
+ .catch((error) => {
1252
+ getLogger().warn({ err: error }, `[SessionIndexService] Background validation failed for ${validationKey}`);
1253
+ })
1254
+ .finally(() => {
1255
+ this.backgroundValidations.delete(validationKey);
1256
+ });
1257
+ this.backgroundValidations.set(validationKey, run);
1258
+ this.backgroundValidationChain = run;
1259
+ }
1260
+ async runBackgroundValidation(sessionDir, projectId, reader, options) {
1261
+ const validationKey = this.getValidationKey(sessionDir, reader, options);
1262
+ // A queued validation may have been satisfied while waiting in the chain.
1263
+ const lastFullValidation = this.lastFullValidationAt.get(validationKey) ?? 0;
1264
+ if (lastFullValidation > 0 &&
1265
+ Date.now() - lastFullValidation < this.fullValidationIntervalMs) {
1266
+ return;
1267
+ }
1268
+ const start = Date.now();
1269
+ const scopeKey = this.getScopeKey(sessionDir, reader);
1270
+ const index = await this.loadIndex(sessionDir, projectId, reader);
1271
+ const before = new Map(Object.entries(index.sessions));
1272
+ const full = await this.runFullValidation(sessionDir, projectId, reader, index, options);
1273
+ this.recordCallStats("full", Date.now() - start, full.statCalls, full.parseCalls, sessionDir, {
1274
+ scopeKey,
1275
+ validationKey,
1276
+ background: true,
1277
+ indexedSessions: Object.keys(index.sessions).length,
1278
+ totalFiles: full.totalFiles,
1279
+ cacheHits: full.cacheHits,
1280
+ cacheMisses: full.cacheMisses,
1281
+ cacheMissBytes: full.cacheMissBytes,
1282
+ largestCacheMisses: full.largestCacheMisses,
1283
+ });
1284
+ this.emitBackgroundIndexChanges(index, before, projectId);
1285
+ }
1286
+ /**
1287
+ * Emit bus events for sessions a background validation changed, so clients
1288
+ * that were served a stale response converge without refetching. Unchanged
1289
+ * entries keep their object identity through runFullValidation (only
1290
+ * changed rows are reassigned), so reference comparison is exact. Deleted
1291
+ * sessions have no removal event; they disappear on the next refetch.
1292
+ */
1293
+ emitBackgroundIndexChanges(index, before, projectId) {
1294
+ if (!this.eventBus) {
1295
+ return;
1296
+ }
1297
+ const timestamp = new Date().toISOString();
1298
+ for (const [sessionId, cached] of Object.entries(index.sessions)) {
1299
+ if (cached.isEmpty)
1300
+ continue;
1301
+ const previous = before.get(sessionId);
1302
+ if (previous === cached)
1303
+ continue;
1304
+ if (!previous || previous.isEmpty) {
1305
+ this.eventBus.emit({
1306
+ type: "session-created",
1307
+ session: this.toSessionSummary(sessionId, cached, projectId),
1308
+ timestamp,
1309
+ });
1310
+ continue;
1311
+ }
1312
+ this.eventBus.emit({
1313
+ type: "session-updated",
1314
+ sessionId,
1315
+ projectId,
1316
+ title: cached.title,
1317
+ messageCount: cached.messageCount,
1318
+ updatedAt: cached.updatedAt,
1319
+ contextUsage: cached.contextUsage,
1320
+ model: cached.model,
1321
+ lastAgentText: cached.lastAgentText,
1322
+ timestamp,
1323
+ });
1324
+ }
1325
+ }
659
1326
  /**
660
1327
  * Invalidate the cache for a specific session.
661
1328
  * Call this when you know a session file has been modified.
@@ -672,6 +1339,7 @@ export class SessionIndexService {
672
1339
  */
673
1340
  clearCache(sessionDir) {
674
1341
  this.indexCache.delete(sessionDir);
1342
+ this.persistedIndexScopes.delete(sessionDir);
675
1343
  this.clearDirDirtyState(sessionDir);
676
1344
  this.lastFullValidationAt.delete(sessionDir);
677
1345
  }
@@ -682,56 +1350,158 @@ export class SessionIndexService {
682
1350
  return this.dataDir;
683
1351
  }
684
1352
  /**
685
- * Get just the title for a single session, using cache when possible.
686
- * More efficient than getSessionsWithCache when you only need one session.
1353
+ * Get one session summary, using cached metadata when the indexed file stats
1354
+ * still match. This is the cache-first single-session companion to
1355
+ * getSessionsWithCache.
687
1356
  */
688
- async getSessionTitle(sessionDir, projectId, sessionId, reader) {
1357
+ async getSessionSummaryWithCache(sessionDir, projectId, sessionId, reader) {
689
1358
  const loadKey = this.getTitleLoadKey(sessionDir, projectId, sessionId, reader);
690
- const inFlight = this.inFlightTitleLoads.get(loadKey);
1359
+ const inFlight = this.inFlightSessionSummaryLoads.get(loadKey);
691
1360
  if (inFlight)
692
1361
  return inFlight;
693
- const promise = this.getSessionTitleInternal(sessionDir, projectId, sessionId, reader);
694
- this.inFlightTitleLoads.set(loadKey, promise);
1362
+ const promise = this.getSessionSummaryWithCacheInternal(sessionDir, projectId, sessionId, reader);
1363
+ this.inFlightSessionSummaryLoads.set(loadKey, promise);
695
1364
  try {
696
1365
  return await promise;
697
1366
  }
698
1367
  finally {
699
- if (this.inFlightTitleLoads.get(loadKey) === promise) {
700
- this.inFlightTitleLoads.delete(loadKey);
1368
+ if (this.inFlightSessionSummaryLoads.get(loadKey) === promise) {
1369
+ this.inFlightSessionSummaryLoads.delete(loadKey);
701
1370
  }
702
1371
  }
703
1372
  }
704
- async getSessionTitleInternal(sessionDir, projectId, sessionId, reader) {
1373
+ async getSessionSummaryWithCacheInternal(sessionDir, projectId, sessionId, reader) {
1374
+ const scopeKey = this.getScopeKey(sessionDir, reader);
705
1375
  const index = await this.loadIndex(sessionDir, projectId, reader);
706
1376
  const cached = index.sessions[sessionId];
1377
+ const dirtySessions = this.dirtySessionsByDir.get(scopeKey);
1378
+ const isDirty = dirtySessions?.has(sessionId) ?? false;
707
1379
  const filePath = (await reader.getSessionFilePath?.(sessionId)) ??
708
1380
  path.join(sessionDir, `${sessionId}.jsonl`);
1381
+ let stats;
709
1382
  try {
710
- const stats = await fs.stat(filePath);
711
- const mtime = stats.mtimeMs;
712
- const size = stats.size;
713
- if (cached &&
714
- cached.fileMtime === mtime &&
715
- cached.indexedBytes === size) {
716
- if (cached.isEmpty)
717
- return null;
718
- return cached.title;
719
- }
720
- const summary = await reader.getSessionSummary(sessionId, projectId);
1383
+ stats = await fs.stat(filePath);
1384
+ }
1385
+ catch {
1386
+ // Some readers can resolve a session across fallback locations even when
1387
+ // they do not expose a concrete file path for the index. Preserve that
1388
+ // behavior, but skip caching because we have no reliable mtime/size key.
1389
+ try {
1390
+ const summary = await reader.getSessionSummary(sessionId, projectId);
1391
+ if (summary) {
1392
+ this.clearSessionDirty(sessionDir, sessionId, reader);
1393
+ return summary;
1394
+ }
1395
+ }
1396
+ catch {
1397
+ // Fall through to clear any stale indexed entry below.
1398
+ }
1399
+ if (cached) {
1400
+ delete index.sessions[sessionId];
1401
+ await this.saveIndex(sessionDir, reader).catch(() => {
1402
+ // Save failures are already logged by saveIndex.
1403
+ });
1404
+ }
1405
+ this.clearSessionDirty(sessionDir, sessionId, reader);
1406
+ return null;
1407
+ }
1408
+ const mtime = stats.mtimeMs;
1409
+ const size = stats.size;
1410
+ if (cached &&
1411
+ !isDirty &&
1412
+ cached.fileMtime === mtime &&
1413
+ cached.indexedBytes === size) {
1414
+ return cached.isEmpty
1415
+ ? null
1416
+ : this.toSessionSummary(sessionId, cached, projectId);
1417
+ }
1418
+ const validationKey = `${scopeKey}::single:${sessionId}`;
1419
+ try {
1420
+ const summary = await this.enqueueSummaryParse({
1421
+ sessionDir,
1422
+ projectId,
1423
+ reader,
1424
+ scopeKey,
1425
+ validationKey,
1426
+ sessionId,
1427
+ filePath,
1428
+ size,
1429
+ mtime,
1430
+ });
721
1431
  if (summary) {
722
1432
  index.sessions[sessionId] = this.toCachedSummary(summary, mtime, size);
1433
+ this.clearSessionDirty(sessionDir, sessionId, reader);
723
1434
  await this.saveIndex(sessionDir, reader);
724
- return summary.title;
1435
+ return summary;
725
1436
  }
726
1437
  index.sessions[sessionId] = this.toEmptyCachedSummary(mtime, size);
1438
+ this.clearSessionDirty(sessionDir, sessionId, reader);
727
1439
  await this.saveIndex(sessionDir, reader);
728
1440
  }
729
1441
  catch {
730
- // File error - return null
1442
+ // Reader errors should not break callers that only need display metadata.
731
1443
  }
732
1444
  return null;
733
1445
  }
1446
+ /**
1447
+ * Get one session summary only if the existing index row is fresh.
1448
+ *
1449
+ * Unlike getSessionSummaryWithCache, this method never parses on a cache miss.
1450
+ * It is for lightweight routes that can fall back to provider head metadata
1451
+ * without creating full-summary parse churn.
1452
+ */
1453
+ async getCachedSessionSummary(sessionDir, projectId, sessionId, reader) {
1454
+ const scopeKey = this.getScopeKey(sessionDir, reader);
1455
+ const index = await this.loadIndex(sessionDir, projectId, reader);
1456
+ const cached = index.sessions[sessionId];
1457
+ if (!cached || cached.isEmpty) {
1458
+ return null;
1459
+ }
1460
+ const dirtySessions = this.dirtySessionsByDir.get(scopeKey);
1461
+ if (dirtySessions?.has(sessionId)) {
1462
+ return null;
1463
+ }
1464
+ const filePath = (await reader.getSessionFilePath?.(sessionId)) ??
1465
+ path.join(sessionDir, `${sessionId}.jsonl`);
1466
+ let stats;
1467
+ try {
1468
+ stats = await fs.stat(filePath);
1469
+ }
1470
+ catch {
1471
+ return null;
1472
+ }
1473
+ if (cached.fileMtime !== stats.mtimeMs ||
1474
+ cached.indexedBytes !== stats.size) {
1475
+ return null;
1476
+ }
1477
+ return this.toSessionSummary(sessionId, cached, projectId);
1478
+ }
1479
+ /**
1480
+ * Get just the title for a single session, using cache when possible.
1481
+ * More efficient than getSessionsWithCache when you only need one session.
1482
+ */
1483
+ async getSessionTitle(sessionDir, projectId, sessionId, reader) {
1484
+ const loadKey = this.getTitleLoadKey(sessionDir, projectId, sessionId, reader);
1485
+ const inFlight = this.inFlightTitleLoads.get(loadKey);
1486
+ if (inFlight)
1487
+ return inFlight;
1488
+ const promise = this.getSessionTitleInternal(sessionDir, projectId, sessionId, reader);
1489
+ this.inFlightTitleLoads.set(loadKey, promise);
1490
+ try {
1491
+ return await promise;
1492
+ }
1493
+ finally {
1494
+ if (this.inFlightTitleLoads.get(loadKey) === promise) {
1495
+ this.inFlightTitleLoads.delete(loadKey);
1496
+ }
1497
+ }
1498
+ }
1499
+ async getSessionTitleInternal(sessionDir, projectId, sessionId, reader) {
1500
+ const summary = await this.getSessionSummaryWithCache(sessionDir, projectId, sessionId, reader);
1501
+ return summary?.title ?? null;
1502
+ }
734
1503
  dispose() {
1504
+ this.stopWarmupProgressTimer();
735
1505
  this.unsubscribeEventBus?.();
736
1506
  this.unsubscribeEventBus = null;
737
1507
  }