@vybestack/llxprt-code-core 0.11.0 → 0.12.0-nightly.260910.2aac6841e

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 (417) hide show
  1. package/dist/index.d.ts +1 -1
  2. package/dist/index.js +1 -1
  3. package/dist/index.js.map +1 -1
  4. package/dist/prompt-config/defaults/default-prompts.json +3 -3
  5. package/dist/src/config/agentClientLifecycle.d.ts +4 -3
  6. package/dist/src/config/agentClientLifecycle.js +27 -14
  7. package/dist/src/config/agentClientLifecycle.js.map +1 -1
  8. package/dist/src/config/config.d.ts +2 -5
  9. package/dist/src/config/config.js +10 -23
  10. package/dist/src/config/config.js.map +1 -1
  11. package/dist/src/config/configBase.d.ts +5 -1
  12. package/dist/src/config/configBase.js +27 -6
  13. package/dist/src/config/configBase.js.map +1 -1
  14. package/dist/src/config/configBaseCore.d.ts +26 -8
  15. package/dist/src/config/configBaseCore.js +30 -26
  16. package/dist/src/config/configBaseCore.js.map +1 -1
  17. package/dist/src/config/configMcpRuntime.d.ts +16 -0
  18. package/dist/src/config/configMcpRuntime.js +31 -0
  19. package/dist/src/config/configMcpRuntime.js.map +1 -0
  20. package/dist/src/config/configMediaDefaults.d.ts +10 -0
  21. package/dist/src/config/configMediaDefaults.js +17 -0
  22. package/dist/src/config/configMediaDefaults.js.map +1 -0
  23. package/dist/src/config/configTestHarness.d.ts +4 -0
  24. package/dist/src/config/configTypes.d.ts +4 -54
  25. package/dist/src/config/configTypes.js +6 -82
  26. package/dist/src/config/configTypes.js.map +1 -1
  27. package/dist/src/config/index.d.ts +1 -2
  28. package/dist/src/config/index.js +1 -2
  29. package/dist/src/config/index.js.map +1 -1
  30. package/dist/src/config/models.d.ts +0 -4
  31. package/dist/src/config/models.js +0 -4
  32. package/dist/src/config/models.js.map +1 -1
  33. package/dist/src/config/toolRegistryFactory.d.ts +2 -2
  34. package/dist/src/core/clientContract.d.ts +4 -6
  35. package/dist/src/core/compression/transcriptPathNotice.d.ts +22 -0
  36. package/dist/src/core/compression/transcriptPathNotice.js +29 -0
  37. package/dist/src/core/compression/transcriptPathNotice.js.map +1 -0
  38. package/dist/src/core/contentGenerator.d.ts +2 -5
  39. package/dist/src/core/contentGenerator.js +10 -24
  40. package/dist/src/core/contentGenerator.js.map +1 -1
  41. package/dist/src/core/logger.d.ts +66 -0
  42. package/dist/src/core/logger.js +345 -30
  43. package/dist/src/core/logger.js.map +1 -1
  44. package/dist/src/core/prompts.d.ts +0 -1
  45. package/dist/src/core/prompts.js +5 -79
  46. package/dist/src/core/prompts.js.map +1 -1
  47. package/dist/src/core/turn.d.ts +3 -3
  48. package/dist/src/hooks/hookTranslator.js +5 -4
  49. package/dist/src/hooks/hookTranslator.js.map +1 -1
  50. package/dist/src/index.d.ts +8 -6
  51. package/dist/src/index.js +8 -6
  52. package/dist/src/index.js.map +1 -1
  53. package/dist/src/llm-types/index.d.ts +1 -1
  54. package/dist/src/llm-types/modelEnvelope.d.ts +2 -1
  55. package/dist/src/llm-types/modelEnvelope.js +17 -1
  56. package/dist/src/llm-types/modelEnvelope.js.map +1 -1
  57. package/dist/src/models/schema.d.ts +40 -40
  58. package/dist/src/policy/policies/read-only.toml +0 -5
  59. package/dist/src/prompt-config/TemplateEngine.js +0 -3
  60. package/dist/src/prompt-config/TemplateEngine.js.map +1 -1
  61. package/dist/src/prompt-config/defaults/providers/gemini/core.md +0 -2
  62. package/dist/src/prompt-config/defaults/providers/gemini/models/gemini-2.5-flash/core.md +0 -2
  63. package/dist/src/prompt-config/defaults/providers/gemini/models/gemini-2.5-flash/gemini-2-5-flash/core.md +0 -2
  64. package/dist/src/prompt-config/prompt-loader.d.ts +1 -1
  65. package/dist/src/prompt-config/prompt-loader.js +4 -4
  66. package/dist/src/prompt-config/prompt-loader.js.map +1 -1
  67. package/dist/src/prompt-config/types.d.ts +0 -1
  68. package/dist/src/recording/CheckpointService.d.ts +4 -0
  69. package/dist/src/recording/CheckpointService.js +67 -46
  70. package/dist/src/recording/CheckpointService.js.map +1 -1
  71. package/dist/src/recording/HistoryMutationService.d.ts +1 -1
  72. package/dist/src/recording/HistoryMutationService.js +27 -4
  73. package/dist/src/recording/HistoryMutationService.js.map +1 -1
  74. package/dist/src/recording/RecordingIntegration.d.ts +36 -2
  75. package/dist/src/recording/RecordingIntegration.js +224 -7
  76. package/dist/src/recording/RecordingIntegration.js.map +1 -1
  77. package/dist/src/recording/ReplayEngine.d.ts +8 -10
  78. package/dist/src/recording/ReplayEngine.js +161 -95
  79. package/dist/src/recording/ReplayEngine.js.map +1 -1
  80. package/dist/src/recording/SessionDiscovery.d.ts +4 -2
  81. package/dist/src/recording/SessionDiscovery.js +13 -5
  82. package/dist/src/recording/SessionDiscovery.js.map +1 -1
  83. package/dist/src/recording/SessionRecordingService.d.ts +23 -3
  84. package/dist/src/recording/SessionRecordingService.js +209 -51
  85. package/dist/src/recording/SessionRecordingService.js.map +1 -1
  86. package/dist/src/recording/SessionTransitionService.d.ts +7 -0
  87. package/dist/src/recording/SessionTransitionService.js +66 -13
  88. package/dist/src/recording/SessionTransitionService.js.map +1 -1
  89. package/dist/src/recording/index.d.ts +1 -0
  90. package/dist/src/recording/index.js +1 -0
  91. package/dist/src/recording/index.js.map +1 -1
  92. package/dist/src/recording/janitor/cleanupTypes.d.ts +3 -0
  93. package/dist/src/recording/janitor/cleanupTypes.js.map +1 -1
  94. package/dist/src/recording/janitor/mediaReclamation.d.ts +23 -0
  95. package/dist/src/recording/janitor/mediaReclamation.js +195 -0
  96. package/dist/src/recording/janitor/mediaReclamation.js.map +1 -0
  97. package/dist/src/recording/janitor/sessionJanitor.js +47 -1
  98. package/dist/src/recording/janitor/sessionJanitor.js.map +1 -1
  99. package/dist/src/recording/janitor/sessionScanner.d.ts +12 -9
  100. package/dist/src/recording/janitor/sessionScanner.js +248 -193
  101. package/dist/src/recording/janitor/sessionScanner.js.map +1 -1
  102. package/dist/src/recording/replay-test-helpers.d.ts +10 -1
  103. package/dist/src/recording/replay-test-helpers.js +24 -2
  104. package/dist/src/recording/replay-test-helpers.js.map +1 -1
  105. package/dist/src/recording/replayCheckpointMetadata.d.ts +28 -0
  106. package/dist/src/recording/replayCheckpointMetadata.js +96 -0
  107. package/dist/src/recording/replayCheckpointMetadata.js.map +1 -0
  108. package/dist/src/recording/replayErrorFormatting.d.ts +6 -0
  109. package/dist/src/recording/replayErrorFormatting.js +38 -0
  110. package/dist/src/recording/replayErrorFormatting.js.map +1 -0
  111. package/dist/src/recording/resumeSession.d.ts +3 -0
  112. package/dist/src/recording/resumeSession.js +7 -1
  113. package/dist/src/recording/resumeSession.js.map +1 -1
  114. package/dist/src/recording/semanticMediaPurgeReplayValidation.d.ts +14 -0
  115. package/dist/src/recording/semanticMediaPurgeReplayValidation.js +24 -0
  116. package/dist/src/recording/semanticMediaPurgeReplayValidation.js.map +1 -0
  117. package/dist/src/recording/session-media-package-blobs.d.ts +8 -0
  118. package/dist/src/recording/session-media-package-blobs.js +72 -0
  119. package/dist/src/recording/session-media-package-blobs.js.map +1 -0
  120. package/dist/src/recording/session-media-package-import.d.ts +26 -0
  121. package/dist/src/recording/session-media-package-import.js +124 -0
  122. package/dist/src/recording/session-media-package-import.js.map +1 -0
  123. package/dist/src/recording/session-media-package-state.d.ts +19 -0
  124. package/dist/src/recording/session-media-package-state.js +56 -0
  125. package/dist/src/recording/session-media-package-state.js.map +1 -0
  126. package/dist/src/recording/session-media-package-validation.d.ts +59 -0
  127. package/dist/src/recording/session-media-package-validation.js +286 -0
  128. package/dist/src/recording/session-media-package-validation.js.map +1 -0
  129. package/dist/src/recording/session-media-package-writer.d.ts +18 -0
  130. package/dist/src/recording/session-media-package-writer.js +70 -0
  131. package/dist/src/recording/session-media-package-writer.js.map +1 -0
  132. package/dist/src/recording/session-media-package.d.ts +27 -0
  133. package/dist/src/recording/session-media-package.js +366 -0
  134. package/dist/src/recording/session-media-package.js.map +1 -0
  135. package/dist/src/recording/types.d.ts +34 -2
  136. package/dist/src/recording/types.js.map +1 -1
  137. package/dist/src/runtime/AgentRuntimeContext.d.ts +22 -5
  138. package/dist/src/runtime/AgentRuntimeLoader.d.ts +6 -0
  139. package/dist/src/runtime/AgentRuntimeLoader.js +25 -6
  140. package/dist/src/runtime/AgentRuntimeLoader.js.map +1 -1
  141. package/dist/src/runtime/contracts/PromptEstimation.d.ts +1 -0
  142. package/dist/src/runtime/contracts/PromptEstimation.js.map +1 -1
  143. package/dist/src/runtime/contracts/RuntimeProvider.d.ts +3 -2
  144. package/dist/src/runtime/contracts/RuntimeProviderManager.d.ts +0 -2
  145. package/dist/src/runtime/createAgentRuntimeContext.js +28 -1
  146. package/dist/src/runtime/createAgentRuntimeContext.js.map +1 -1
  147. package/dist/src/runtime/providerRuntimeContext.d.ts +12 -0
  148. package/dist/src/runtime/providerRuntimeContext.js +3 -0
  149. package/dist/src/runtime/providerRuntimeContext.js.map +1 -1
  150. package/dist/src/runtime/runtimeAdapters.js +2 -2
  151. package/dist/src/runtime/runtimeAdapters.js.map +1 -1
  152. package/dist/src/services/history/ContentConverters.d.ts +11 -7
  153. package/dist/src/services/history/ContentConverters.js +11 -7
  154. package/dist/src/services/history/ContentConverters.js.map +1 -1
  155. package/dist/src/services/history/HistoryService.d.ts +18 -180
  156. package/dist/src/services/history/HistoryService.js +53 -523
  157. package/dist/src/services/history/HistoryService.js.map +1 -1
  158. package/dist/src/services/history/HistoryServiceCore.d.ts +278 -0
  159. package/dist/src/services/history/HistoryServiceCore.js +727 -0
  160. package/dist/src/services/history/HistoryServiceCore.js.map +1 -0
  161. package/dist/src/services/history/IContent.d.ts +118 -16
  162. package/dist/src/services/history/IContent.js +284 -4
  163. package/dist/src/services/history/IContent.js.map +1 -1
  164. package/dist/src/services/history/contentSize.js +22 -2
  165. package/dist/src/services/history/contentSize.js.map +1 -1
  166. package/dist/src/services/history/historyChronology.d.ts +7 -0
  167. package/dist/src/services/history/historyChronology.js +35 -3
  168. package/dist/src/services/history/historyChronology.js.map +1 -1
  169. package/dist/src/services/history/historyCloneUtils.d.ts +5 -4
  170. package/dist/src/services/history/historyCloneUtils.js +23 -16
  171. package/dist/src/services/history/historyCloneUtils.js.map +1 -1
  172. package/dist/src/services/history/historyCompressionQueue.d.ts +33 -0
  173. package/dist/src/services/history/historyCompressionQueue.js +81 -0
  174. package/dist/src/services/history/historyCompressionQueue.js.map +1 -0
  175. package/dist/src/services/history/historyEventTypes.d.ts +3 -0
  176. package/dist/src/services/history/historyMutationFailure.d.ts +15 -0
  177. package/dist/src/services/history/historyMutationFailure.js +22 -0
  178. package/dist/src/services/history/historyMutationFailure.js.map +1 -1
  179. package/dist/src/services/history/historyProviderPipeline.d.ts +1 -1
  180. package/dist/src/services/history/historyProviderPipeline.js +15 -5
  181. package/dist/src/services/history/historyProviderPipeline.js.map +1 -1
  182. package/dist/src/services/history/historyTokenEstimation.js +10 -6
  183. package/dist/src/services/history/historyTokenEstimation.js.map +1 -1
  184. package/dist/src/services/history/historyToolNormalization.d.ts +2 -0
  185. package/dist/src/services/history/historyToolNormalization.js +26 -9
  186. package/dist/src/services/history/historyToolNormalization.js.map +1 -1
  187. package/dist/src/services/history/provider-file-binding.d.ts +11 -0
  188. package/dist/src/services/history/provider-file-binding.js +70 -0
  189. package/dist/src/services/history/provider-file-binding.js.map +1 -0
  190. package/dist/src/services/history/semantic-media-purge.d.ts +66 -0
  191. package/dist/src/services/history/semantic-media-purge.js +404 -0
  192. package/dist/src/services/history/semantic-media-purge.js.map +1 -0
  193. package/dist/src/storage/SessionPersistenceService.d.ts +53 -2
  194. package/dist/src/storage/SessionPersistenceService.js +435 -23
  195. package/dist/src/storage/SessionPersistenceService.js.map +1 -1
  196. package/dist/src/storage/history-media-ownership.d.ts +38 -0
  197. package/dist/src/storage/history-media-ownership.js +136 -0
  198. package/dist/src/storage/history-media-ownership.js.map +1 -0
  199. package/dist/src/storage/local-media-store-child.d.ts +6 -0
  200. package/dist/src/storage/local-media-store-child.js +140 -0
  201. package/dist/src/storage/local-media-store-child.js.map +1 -0
  202. package/dist/src/storage/local-media-store-files.d.ts +44 -0
  203. package/dist/src/storage/local-media-store-files.js +460 -0
  204. package/dist/src/storage/local-media-store-files.js.map +1 -0
  205. package/dist/src/storage/local-media-store-lock-recovery.d.ts +15 -0
  206. package/dist/src/storage/local-media-store-lock-recovery.js +112 -0
  207. package/dist/src/storage/local-media-store-lock-recovery.js.map +1 -0
  208. package/dist/src/storage/local-media-store-persistence.d.ts +48 -0
  209. package/dist/src/storage/local-media-store-persistence.js +443 -0
  210. package/dist/src/storage/local-media-store-persistence.js.map +1 -0
  211. package/dist/src/storage/local-media-store-quota.d.ts +6 -0
  212. package/dist/src/storage/local-media-store-quota.js +66 -0
  213. package/dist/src/storage/local-media-store-quota.js.map +1 -0
  214. package/dist/src/storage/local-media-store-reservations.d.ts +55 -0
  215. package/dist/src/storage/local-media-store-reservations.js +377 -0
  216. package/dist/src/storage/local-media-store-reservations.js.map +1 -0
  217. package/dist/src/storage/local-media-store-types.d.ts +110 -0
  218. package/dist/src/storage/local-media-store-types.js +35 -0
  219. package/dist/src/storage/local-media-store-types.js.map +1 -0
  220. package/dist/src/storage/local-media-store-validation.d.ts +34 -0
  221. package/dist/src/storage/local-media-store-validation.js +449 -0
  222. package/dist/src/storage/local-media-store-validation.js.map +1 -0
  223. package/dist/src/storage/local-media-store.d.ts +47 -0
  224. package/dist/src/storage/local-media-store.js +353 -0
  225. package/dist/src/storage/local-media-store.js.map +1 -0
  226. package/dist/src/storage/media-admission-service.d.ts +49 -0
  227. package/dist/src/storage/media-admission-service.js +333 -0
  228. package/dist/src/storage/media-admission-service.js.map +1 -0
  229. package/dist/src/storage/media-lifecycle-metrics.d.ts +75 -0
  230. package/dist/src/storage/media-lifecycle-metrics.js +105 -0
  231. package/dist/src/storage/media-lifecycle-metrics.js.map +1 -0
  232. package/dist/src/storage/media-reference-lifecycle.d.ts +16 -0
  233. package/dist/src/storage/media-reference-lifecycle.js +84 -0
  234. package/dist/src/storage/media-reference-lifecycle.js.map +1 -0
  235. package/dist/src/storage/request-media-resolver.d.ts +67 -0
  236. package/dist/src/storage/request-media-resolver.js +325 -0
  237. package/dist/src/storage/request-media-resolver.js.map +1 -0
  238. package/dist/src/storage/session-media-service-factories.d.ts +19 -0
  239. package/dist/src/storage/session-media-service-factories.js +34 -0
  240. package/dist/src/storage/session-media-service-factories.js.map +1 -0
  241. package/dist/src/storage/session-persistence-helpers.d.ts +10 -0
  242. package/dist/src/storage/session-persistence-helpers.js +46 -0
  243. package/dist/src/storage/session-persistence-helpers.js.map +1 -0
  244. package/dist/src/test-utils/config.d.ts +2 -0
  245. package/dist/src/test-utils/config.js +5 -5
  246. package/dist/src/test-utils/config.js.map +1 -1
  247. package/dist/src/test-utils/runtime.d.ts +2 -0
  248. package/dist/src/test-utils/runtime.js +1 -2
  249. package/dist/src/test-utils/runtime.js.map +1 -1
  250. package/dist/src/tools-adapters/CoreShellToolHostAdapter.js +1 -9
  251. package/dist/src/tools-adapters/CoreShellToolHostAdapter.js.map +1 -1
  252. package/dist/src/tools-adapters/CoreSkillServiceAdapter.d.ts +0 -2
  253. package/dist/src/tools-adapters/CoreSkillServiceAdapter.js +0 -17
  254. package/dist/src/tools-adapters/CoreSkillServiceAdapter.js.map +1 -1
  255. package/dist/src/tools-adapters/CoreToolHostAdapter.d.ts +0 -21
  256. package/dist/src/tools-adapters/CoreToolHostAdapter.js +0 -8
  257. package/dist/src/tools-adapters/CoreToolHostAdapter.js.map +1 -1
  258. package/dist/src/utils/environmentContext.d.ts +8 -9
  259. package/dist/src/utils/environmentContext.js +11 -22
  260. package/dist/src/utils/environmentContext.js.map +1 -1
  261. package/dist/src/utils/errorParsing.d.ts +1 -2
  262. package/dist/src/utils/errorParsing.js +22 -41
  263. package/dist/src/utils/errorParsing.js.map +1 -1
  264. package/dist/src/utils/generateContentResponseUtilities.js +12 -0
  265. package/dist/src/utils/generateContentResponseUtilities.js.map +1 -1
  266. package/dist/src/utils/summarizer.d.ts +1 -2
  267. package/dist/src/utils/summarizer.js +6 -5
  268. package/dist/src/utils/summarizer.js.map +1 -1
  269. package/dist/src/utils/tool-utils.js +7 -1
  270. package/dist/src/utils/tool-utils.js.map +1 -1
  271. package/index.ts +0 -4
  272. package/package.json +38 -30
  273. package/src/config/agentClientLifecycle.ts +53 -22
  274. package/src/config/config.ts +11 -26
  275. package/src/config/configBase.ts +46 -7
  276. package/src/config/configBaseCore.ts +38 -36
  277. package/src/config/configMcpRuntime.ts +46 -0
  278. package/src/config/configMediaDefaults.ts +19 -0
  279. package/src/config/configTypes.ts +13 -53
  280. package/src/config/index.ts +1 -4
  281. package/src/config/models.ts +0 -6
  282. package/src/config/toolRegistryFactory.ts +2 -2
  283. package/src/core/clientContract.ts +4 -6
  284. package/src/core/compression/transcriptPathNotice.ts +31 -0
  285. package/src/core/contentGenerator.ts +15 -39
  286. package/src/core/logger.ts +370 -39
  287. package/src/core/prompts.ts +4 -114
  288. package/src/core/turn.ts +3 -3
  289. package/src/hooks/hookTranslator.ts +6 -4
  290. package/src/index.ts +7 -7
  291. package/src/llm-types/index.ts +5 -0
  292. package/src/llm-types/modelEnvelope.ts +26 -2
  293. package/src/policy/policies/read-only.toml +0 -5
  294. package/src/prompt-config/TemplateEngine.ts +0 -3
  295. package/src/prompt-config/defaults/providers/gemini/core.md +0 -2
  296. package/src/prompt-config/defaults/providers/gemini/models/gemini-2.5-flash/core.md +0 -2
  297. package/src/prompt-config/defaults/providers/gemini/models/gemini-2.5-flash/gemini-2-5-flash/core.md +0 -2
  298. package/src/prompt-config/prompt-loader.ts +7 -8
  299. package/src/prompt-config/types.ts +0 -1
  300. package/src/recording/CheckpointService.ts +110 -45
  301. package/src/recording/HistoryMutationService.ts +28 -3
  302. package/src/recording/RecordingIntegration.ts +258 -11
  303. package/src/recording/ReplayEngine.ts +220 -110
  304. package/src/recording/SessionDiscovery.ts +30 -4
  305. package/src/recording/SessionRecordingService.ts +253 -55
  306. package/src/recording/SessionTransitionService.ts +75 -12
  307. package/src/recording/index.ts +7 -0
  308. package/src/recording/janitor/cleanupTypes.ts +4 -0
  309. package/src/recording/janitor/mediaReclamation.ts +295 -0
  310. package/src/recording/janitor/sessionJanitor.ts +54 -1
  311. package/src/recording/janitor/sessionScanner.ts +319 -227
  312. package/src/recording/replay-test-helpers.ts +33 -2
  313. package/src/recording/replayCheckpointMetadata.ts +115 -0
  314. package/src/recording/replayErrorFormatting.ts +43 -0
  315. package/src/recording/resumeSession.ts +10 -0
  316. package/src/recording/semanticMediaPurgeReplayValidation.ts +35 -0
  317. package/src/recording/session-media-package-blobs.ts +116 -0
  318. package/src/recording/session-media-package-import.ts +189 -0
  319. package/src/recording/session-media-package-state.ts +120 -0
  320. package/src/recording/session-media-package-validation.ts +400 -0
  321. package/src/recording/session-media-package-writer.ts +117 -0
  322. package/src/recording/session-media-package.ts +692 -0
  323. package/src/recording/types.ts +37 -2
  324. package/src/runtime/AgentRuntimeContext.ts +28 -5
  325. package/src/runtime/AgentRuntimeLoader.ts +32 -7
  326. package/src/runtime/contracts/PromptEstimation.ts +1 -0
  327. package/src/runtime/contracts/RuntimeProvider.ts +3 -8
  328. package/src/runtime/contracts/RuntimeProviderManager.ts +0 -2
  329. package/src/runtime/createAgentRuntimeContext.ts +43 -1
  330. package/src/runtime/providerRuntimeContext.ts +22 -0
  331. package/src/runtime/runtimeAdapters.ts +2 -2
  332. package/src/services/history/ContentConverters.ts +11 -7
  333. package/src/services/history/HistoryService.ts +71 -696
  334. package/src/services/history/HistoryServiceCore.ts +1055 -0
  335. package/src/services/history/IContent.ts +460 -20
  336. package/src/services/history/contentSize.ts +22 -2
  337. package/src/services/history/historyChronology.ts +53 -3
  338. package/src/services/history/historyCloneUtils.ts +26 -22
  339. package/src/services/history/historyCompressionQueue.ts +102 -0
  340. package/src/services/history/historyEventTypes.ts +9 -0
  341. package/src/services/history/historyMutationFailure.ts +33 -0
  342. package/src/services/history/historyProviderPipeline.ts +19 -5
  343. package/src/services/history/historyTokenEstimation.ts +9 -5
  344. package/src/services/history/historyToolNormalization.ts +43 -11
  345. package/src/services/history/provider-file-binding.ts +115 -0
  346. package/src/services/history/semantic-media-purge.ts +593 -0
  347. package/src/storage/SessionPersistenceService.ts +667 -30
  348. package/src/storage/history-media-ownership.ts +185 -0
  349. package/src/storage/local-media-store-child.ts +163 -0
  350. package/src/storage/local-media-store-files.ts +643 -0
  351. package/src/storage/local-media-store-lock-recovery.ts +159 -0
  352. package/src/storage/local-media-store-persistence.ts +737 -0
  353. package/src/storage/local-media-store-quota.ts +111 -0
  354. package/src/storage/local-media-store-reservations.ts +485 -0
  355. package/src/storage/local-media-store-types.ts +161 -0
  356. package/src/storage/local-media-store-validation.ts +643 -0
  357. package/src/storage/local-media-store.ts +696 -0
  358. package/src/storage/media-admission-service.ts +512 -0
  359. package/src/storage/media-lifecycle-metrics.ts +228 -0
  360. package/src/storage/media-reference-lifecycle.ts +164 -0
  361. package/src/storage/request-media-resolver.ts +491 -0
  362. package/src/storage/session-media-service-factories.ts +48 -0
  363. package/src/storage/session-persistence-helpers.ts +85 -0
  364. package/src/test-utils/config.ts +7 -5
  365. package/src/test-utils/runtime.ts +3 -2
  366. package/src/tools-adapters/CoreShellToolHostAdapter.ts +1 -11
  367. package/src/tools-adapters/CoreSkillServiceAdapter.ts +0 -23
  368. package/src/tools-adapters/CoreToolHostAdapter.ts +0 -36
  369. package/src/utils/environmentContext.ts +11 -30
  370. package/src/utils/errorParsing.ts +19 -69
  371. package/src/utils/generateContentResponseUtilities.ts +28 -1
  372. package/src/utils/summarizer.ts +8 -10
  373. package/src/utils/tool-utils.ts +7 -1
  374. package/dist/src/code_assist/codeAssist.d.ts +0 -19
  375. package/dist/src/code_assist/codeAssist.js +0 -41
  376. package/dist/src/code_assist/codeAssist.js.map +0 -1
  377. package/dist/src/code_assist/contentGeneratorAdapters.d.ts +0 -49
  378. package/dist/src/code_assist/contentGeneratorAdapters.js +0 -197
  379. package/dist/src/code_assist/contentGeneratorAdapters.js.map +0 -1
  380. package/dist/src/code_assist/converter.d.ts +0 -74
  381. package/dist/src/code_assist/converter.js +0 -158
  382. package/dist/src/code_assist/converter.js.map +0 -1
  383. package/dist/src/code_assist/googleGenAIWrapper.d.ts +0 -27
  384. package/dist/src/code_assist/googleGenAIWrapper.js +0 -46
  385. package/dist/src/code_assist/googleGenAIWrapper.js.map +0 -1
  386. package/dist/src/code_assist/oauth-credential-storage.d.ts +0 -30
  387. package/dist/src/code_assist/oauth-credential-storage.js +0 -135
  388. package/dist/src/code_assist/oauth-credential-storage.js.map +0 -1
  389. package/dist/src/code_assist/server.d.ts +0 -44
  390. package/dist/src/code_assist/server.js +0 -154
  391. package/dist/src/code_assist/server.js.map +0 -1
  392. package/dist/src/code_assist/setup.d.ts +0 -20
  393. package/dist/src/code_assist/setup.js +0 -126
  394. package/dist/src/code_assist/setup.js.map +0 -1
  395. package/dist/src/code_assist/types.d.ts +0 -161
  396. package/dist/src/code_assist/types.js +0 -46
  397. package/dist/src/code_assist/types.js.map +0 -1
  398. package/dist/src/utils/getFolderStructure.d.ts +0 -31
  399. package/dist/src/utils/getFolderStructure.js +0 -240
  400. package/dist/src/utils/getFolderStructure.js.map +0 -1
  401. package/dist/src/utils/installationManager.d.ts +0 -16
  402. package/dist/src/utils/installationManager.js +0 -51
  403. package/dist/src/utils/installationManager.js.map +0 -1
  404. package/dist/src/utils/llm-edit-fixer.d.ts +0 -25
  405. package/dist/src/utils/llm-edit-fixer.js +0 -120
  406. package/dist/src/utils/llm-edit-fixer.js.map +0 -1
  407. package/src/code_assist/codeAssist.ts +0 -59
  408. package/src/code_assist/contentGeneratorAdapters.ts +0 -275
  409. package/src/code_assist/converter.ts +0 -288
  410. package/src/code_assist/googleGenAIWrapper.ts +0 -90
  411. package/src/code_assist/oauth-credential-storage.ts +0 -171
  412. package/src/code_assist/server.ts +0 -263
  413. package/src/code_assist/setup.ts +0 -189
  414. package/src/code_assist/types.ts +0 -201
  415. package/src/utils/getFolderStructure.ts +0 -382
  416. package/src/utils/installationManager.ts +0 -59
  417. package/src/utils/llm-edit-fixer.ts +0 -157
@@ -28,7 +28,17 @@
28
28
 
29
29
  import * as fs from 'node:fs';
30
30
  import * as readline from 'node:readline';
31
+ import {
32
+ appendCheckpointMetadataWarnings,
33
+ foldCheckpointMetadata,
34
+ } from './replayCheckpointMetadata.js';
35
+ export { foldCheckpointMetadata } from './replayCheckpointMetadata.js';
31
36
  import { readBoundedFirstLine } from './boundedHeaderReader.js';
37
+ import { formatReplayDiagnostic } from './replayErrorFormatting.js';
38
+ import {
39
+ isRecordWithNonNegativeIntegerPair,
40
+ isSemanticMediaPurgeFrontierWithinHistory,
41
+ } from './semanticMediaPurgeReplayValidation.js';
32
42
  import {
33
43
  type ReplayResult,
34
44
  type SessionMetadata,
@@ -37,11 +47,18 @@ import {
37
47
  type ContentPayload,
38
48
  type RewindPayload,
39
49
  type ProviderSwitchPayload,
40
- type CheckpointMetadataView,
41
50
  type SessionForkedPayload,
51
+ type SemanticMediaPurgePayload,
42
52
  type SessionRecordLine,
43
53
  } from './types.js';
44
- import { type IContent } from '../services/history/IContent.js';
54
+ import {
55
+ invalidateResponsesStatefulChain,
56
+ type IContent,
57
+ } from '../services/history/IContent.js';
58
+ import type { LocalMediaStore } from '../storage/local-media-store.js';
59
+ import { MediaAdmissionService } from '../storage/media-admission-service.js';
60
+ import { verifyHistoryMedia } from '../storage/media-reference-lifecycle.js';
61
+ const SUPPORTED_RECORDING_VERSIONS = new Set([1, 2]);
45
62
 
46
63
  // ---------------------------------------------------------------------------
47
64
  // Private replay accumulators
@@ -63,6 +80,7 @@ interface ReplayAccumulators {
63
80
  unparseableLineCount: number;
64
81
  /** Raw metadata event lines for post-replay folding. */
65
82
  rawMetadataEvents: SessionRecordLine[];
83
+ semanticMediaPurgeFrontier: SemanticMediaPurgePayload['frontier'] | undefined;
66
84
  }
67
85
 
68
86
  // @pseudocode line 11-17: Initialize accumulators
@@ -81,6 +99,7 @@ function createAccumulators(): ReplayAccumulators {
81
99
  _unknownEventCount: 0,
82
100
  unparseableLineCount: 0,
83
101
  rawMetadataEvents: [],
102
+ semanticMediaPurgeFrontier: undefined,
84
103
  };
85
104
  }
86
105
 
@@ -241,7 +260,54 @@ function handleCompressed(
241
260
  }
242
261
  }
243
262
 
244
- /** @pseudocode line 100-112: rewind — validate and apply rewind or record malformed. */
263
+ /**
264
+ * Locate the entry the rewind cut at, identified by its chronology `seq`.
265
+ *
266
+ * The match is exact. A neighbouring marker is NOT evidence of where the cut
267
+ * belongs: an entry with no marker can sit on either side of it, so inferring
268
+ * the cut from the next marked entry mis-cuts a history whose entries are only
269
+ * partly marked — a session resumed from a file recorded before chronology
270
+ * markers existed, or one whose `compressed` summary reached the journal
271
+ * unmarked.
272
+ *
273
+ * Returns `null` when no entry carries the recorded seq, which happens when the
274
+ * cut entry predates markers or was destroyed by a `compressed` event. The
275
+ * caller then falls back to the recorded count.
276
+ *
277
+ * @issue #2934
278
+ */
279
+ function findChronologyCutIndex(
280
+ history: readonly IContent[],
281
+ cutSeq: number,
282
+ ): number | null {
283
+ for (let index = 0; index < history.length; index++) {
284
+ // `cutSeq` is already a validated sequence number, so equality alone
285
+ // rejects both a missing marker and a nonsensical one.
286
+ if (history[index].metadata?.chronology?.seq === cutSeq) {
287
+ return index;
288
+ }
289
+ }
290
+ return null;
291
+ }
292
+
293
+ /** Legacy behaviour: drop `itemsToRemove` entries from the end. */
294
+ function applyCountRewind(
295
+ acc: ReplayAccumulators,
296
+ itemsToRemove: number,
297
+ ): void {
298
+ acc.history =
299
+ itemsToRemove >= acc.history.length
300
+ ? []
301
+ : acc.history.slice(0, acc.history.length - itemsToRemove);
302
+ }
303
+
304
+ /**
305
+ * @pseudocode line 100-112: rewind — validate and apply rewind or record malformed.
306
+ *
307
+ * A resolvable `cutSeq` marker takes precedence over the item count: the count
308
+ * is measured against live history, which diverges from the journal whenever an
309
+ * unjournalled mutation (density optimization) shrinks it (#2934).
310
+ */
245
311
  function handleRewind(
246
312
  payload: Record<string, unknown>,
247
313
  acc: ReplayAccumulators,
@@ -254,11 +320,28 @@ function handleRewind(
254
320
  acc.warnings.push(`Line ${lineNumber}: malformed rewind event, skipping`);
255
321
  return;
256
322
  }
257
- if (itemsToRemove >= acc.history.length) {
258
- acc.history = [];
259
- } else {
260
- acc.history = acc.history.slice(0, acc.history.length - itemsToRemove);
323
+
324
+ // An unreadable cut marker does not invalidate the count beside it. Dropping
325
+ // the whole event would leave the removed turns in the replayed history,
326
+ // which is the very symptom this marker exists to prevent, so the corruption
327
+ // is reported and the rewind still applies by count.
328
+ const cutSeq = rewindPayload.cutSeq;
329
+ if (cutSeq !== undefined && !isValidSequence(cutSeq)) {
330
+ acc.malformedCount++;
331
+ acc.warnings.push(
332
+ `Line ${lineNumber}: malformed rewind cut marker, falling back to item count`,
333
+ );
334
+ applyCountRewind(acc, itemsToRemove);
335
+ return;
336
+ }
337
+
338
+ const cutIndex =
339
+ cutSeq === undefined ? null : findChronologyCutIndex(acc.history, cutSeq);
340
+ if (cutIndex === null) {
341
+ applyCountRewind(acc, itemsToRemove);
342
+ return;
261
343
  }
344
+ acc.history = acc.history.slice(0, cutIndex);
262
345
  }
263
346
 
264
347
  /** @pseudocode line 114-120: provider_switch — update metadata or record malformed. */
@@ -365,6 +448,32 @@ function isValidSequence(value: unknown): value is number {
365
448
  return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0;
366
449
  }
367
450
 
451
+ function handleSemanticMediaPurge(
452
+ payload: Record<string, unknown>,
453
+ acc: ReplayAccumulators,
454
+ lineNumber: number,
455
+ ): void {
456
+ const history = payload['history'];
457
+ const frontier = payload['frontier'];
458
+ if (
459
+ !Array.isArray(history) ||
460
+ !history.every(isSpeakerContent) ||
461
+ !isRecordWithNonNegativeIntegerPair(frontier) ||
462
+ !isSemanticMediaPurgeFrontierWithinHistory(history, frontier)
463
+ ) {
464
+ acc.malformedCount++;
465
+ acc.warnings.push(
466
+ `Line ${lineNumber}: malformed semantic_media_purge event, skipping`,
467
+ );
468
+ return;
469
+ }
470
+ acc.history = [...history];
471
+ acc.semanticMediaPurgeFrontier = {
472
+ contentIndex: frontier.contentIndex,
473
+ blockIndex: frontier.blockIndex,
474
+ };
475
+ }
476
+
368
477
  function applyParsedEvent(
369
478
  parsed: Record<string, unknown> | null,
370
479
  acc: ReplayAccumulators,
@@ -373,6 +482,17 @@ function applyParsedEvent(
373
482
  if (parsed === null) {
374
483
  return undefined;
375
484
  }
485
+ const recordingVersion = parsed.v;
486
+ if (
487
+ typeof recordingVersion !== 'number' ||
488
+ !SUPPORTED_RECORDING_VERSIONS.has(recordingVersion)
489
+ ) {
490
+ return {
491
+ ok: false,
492
+ error: `Unsupported recording version ${String(recordingVersion)} at line ${acc.lineNumber}`,
493
+ warnings: acc.warnings,
494
+ };
495
+ }
376
496
  if (!isValidSequence(parsed.seq)) {
377
497
  acc.malformedCount++;
378
498
  acc.warnings.push(
@@ -505,6 +625,9 @@ function dispatchEvent(
505
625
  case 'session_metadata':
506
626
  handleSessionMetadata(payload, acc, lineNumber);
507
627
  break;
628
+ case 'semantic_media_purge':
629
+ handleSemanticMediaPurge(payload, acc, lineNumber);
630
+ break;
508
631
  case 'directories_changed':
509
632
  handleDirectoriesChanged(payload, acc, lineNumber);
510
633
  break;
@@ -580,9 +703,26 @@ function finalizeReplay(acc: ReplayAccumulators): ReplayResult {
580
703
  const folded = foldCheckpointMetadata(acc.rawMetadataEvents);
581
704
  const sessionName = deriveSessionName(acc.rawMetadataEvents);
582
705
  const ancestry = deriveAncestry(acc.rawMetadataEvents);
706
+ // A Codex parent id is scoped to the WebSocket connection that produced it, so a
707
+ // `responsesStored` marker restored from a persisted session recording (or a
708
+ // checkpoint fork replay) points at a dead parent by construction. Strip it so the
709
+ // resumed session starts a fresh chain (#3160).
710
+ //
711
+ // The strip is deliberately unconditional rather than Codex-only. `responsesStored`
712
+ // conflates two different lifetimes — "durably stored server-side" (non-Codex,
713
+ // store=true) and "chainable on this socket" (Codex, store=false; see
714
+ // buildRequestContext in openAIResponsesExecutor.ts) — and a recording carries
715
+ // nothing that tells them apart, nor whether a durable parent is still inside its
716
+ // retention window. A parent that cannot be shown to be live is treated as dead.
717
+ // The cost of being wrong is one full-history request, which the next turn
718
+ // re-chains from; the cost of guessing wrong the other way is a refused request.
719
+ const history = invalidateResponsesStatefulChain(acc.history);
583
720
  return {
584
721
  ok: true,
585
- history: acc.history,
722
+ // The helper returns `readonly IContent[]`; the spread widens it to the
723
+ // mutable `IContent[]` this result type declares. It is a type conversion,
724
+ // not a defensive copy — the entries are still shared by reference.
725
+ history: [...history],
586
726
  metadata: acc.metadata,
587
727
  lastSeq: acc.lastSeq,
588
728
  sequenceCorrupt: acc.sequenceCorrupt,
@@ -592,6 +732,9 @@ function finalizeReplay(acc: ReplayAccumulators): ReplayResult {
592
732
  checkpoints: folded,
593
733
  sessionName,
594
734
  ancestry,
735
+ ...(acc.semanticMediaPurgeFrontier === undefined
736
+ ? {}
737
+ : { semanticMediaPurgeFrontier: acc.semanticMediaPurgeFrontier }),
595
738
  };
596
739
  }
597
740
 
@@ -599,100 +742,6 @@ function finalizeReplay(acc: ReplayAccumulators): ReplayResult {
599
742
  // Metadata folding helpers (checkpoint lifecycle + session name)
600
743
  // ---------------------------------------------------------------------------
601
744
 
602
- function appendCheckpointMetadataWarnings(
603
- events: readonly SessionRecordLine[],
604
- warnings: string[],
605
- ): void {
606
- const knownIds = new Set<string>();
607
- const deletedIds = new Set<string>();
608
- for (const line of events) {
609
- const checkpointId = extractCheckpointId(line);
610
- if (checkpointId === null) continue;
611
- if (line.type === 'checkpoint_created') {
612
- if (knownIds.has(checkpointId)) {
613
- warnings.push(
614
- `Sequence ${line.seq}: checkpoint_created duplicates checkpoint ${checkpointId}`,
615
- );
616
- } else {
617
- knownIds.add(checkpointId);
618
- }
619
- } else if (
620
- line.type === 'checkpoint_renamed' ||
621
- line.type === 'checkpoint_deleted'
622
- ) {
623
- if (!knownIds.has(checkpointId)) {
624
- warnings.push(
625
- `Sequence ${line.seq}: ${line.type} references unknown checkpoint ${checkpointId}`,
626
- );
627
- } else if (deletedIds.has(checkpointId)) {
628
- warnings.push(
629
- `Sequence ${line.seq}: ${line.type} references deleted checkpoint ${checkpointId}`,
630
- );
631
- }
632
- if (line.type === 'checkpoint_deleted') deletedIds.add(checkpointId);
633
- }
634
- }
635
- }
636
-
637
- function extractCheckpointId(line: SessionRecordLine): string | null {
638
- if (typeof line.payload !== 'object' || line.payload === null) return null;
639
- const checkpointId =
640
- 'checkpointId' in line.payload ? line.payload.checkpointId : undefined;
641
- return typeof checkpointId === 'string' ? checkpointId : null;
642
- }
643
-
644
- /**
645
- * Fold checkpoint lifecycle events into a stable view ordered by sequence.
646
- * Each checkpoint is tracked by stable `checkpointId`. Created events set
647
- * the name, watermark, and createdAt; renamed events update the name;
648
- * deleted events set `deleted: true`.
649
- */
650
- export function foldCheckpointMetadata(
651
- events: readonly SessionRecordLine[],
652
- ): CheckpointMetadataView[] {
653
- const byId = new Map<string, CheckpointMetadataView>();
654
-
655
- for (const line of events) {
656
- foldCheckpointLine(line, byId);
657
- }
658
-
659
- return Array.from(byId.values()).sort((a, b) => a.sequence - b.sequence);
660
- }
661
-
662
- function foldCheckpointLine(
663
- line: SessionRecordLine,
664
- byId: Map<string, CheckpointMetadataView>,
665
- ): void {
666
- if (typeof line.payload !== 'object' || line.payload === null) return;
667
- const payload = line.payload;
668
- const checkpointId =
669
- 'checkpointId' in payload ? payload.checkpointId : undefined;
670
- if (typeof checkpointId !== 'string' || checkpointId.length === 0) return;
671
- const existing = byId.get(checkpointId);
672
- const name = 'name' in payload ? payload.name : undefined;
673
- if (
674
- line.type === 'checkpoint_created' &&
675
- typeof name === 'string' &&
676
- existing === undefined
677
- ) {
678
- byId.set(checkpointId, {
679
- checkpointId,
680
- name,
681
- sequence: line.seq,
682
- deleted: false,
683
- createdAt: line.ts,
684
- });
685
- } else if (
686
- line.type === 'checkpoint_renamed' &&
687
- typeof name === 'string' &&
688
- existing !== undefined
689
- ) {
690
- byId.set(checkpointId, { ...existing, name });
691
- } else if (line.type === 'checkpoint_deleted' && existing !== undefined) {
692
- byId.set(checkpointId, { ...existing, deleted: true });
693
- }
694
- }
695
-
696
745
  function isSessionForkedPayload(value: unknown): value is SessionForkedPayload {
697
746
  if (typeof value !== 'object' || value === null) return false;
698
747
  if (!('parentSessionId' in value) || !('parentSequence' in value)) {
@@ -810,16 +859,72 @@ async function readSessionStream(
810
859
  * @param expectedProjectHash - Must match the file's projectHash
811
860
  * @returns ReplayResult discriminated union — ok: true with data, or ok: false with error
812
861
  */
862
+ export interface ReplaySessionOptions {
863
+ readonly mediaStore?: LocalMediaStore;
864
+ }
865
+
813
866
  export async function replaySession(
814
867
  filePath: string,
815
868
  expectedProjectHash: string,
869
+ options: ReplaySessionOptions = {},
816
870
  ): Promise<ReplayResult> {
817
- return readSessionStream(filePath, expectedProjectHash, (rawLine, acc) => {
818
- const trimmed = rawLine.trim();
819
- const parsed =
820
- trimmed !== '' ? parseLine(rawLine, acc.lineNumber, acc) : null;
821
- return applyParsedEvent(parsed, acc, expectedProjectHash);
822
- });
871
+ const replay = await readSessionStream(
872
+ filePath,
873
+ expectedProjectHash,
874
+ (rawLine, acc) => {
875
+ const trimmed = rawLine.trim();
876
+ const parsed =
877
+ trimmed !== '' ? parseLine(rawLine, acc.lineNumber, acc) : null;
878
+ return applyParsedEvent(parsed, acc, expectedProjectHash);
879
+ },
880
+ );
881
+ return verifyReplayMedia(replay, options);
882
+ }
883
+
884
+ async function verifyReplayMedia(
885
+ replay: ReplayResult,
886
+ options: ReplaySessionOptions,
887
+ ): Promise<ReplayResult> {
888
+ if (!replay.ok) {
889
+ return replay;
890
+ }
891
+ try {
892
+ const admissionContext = {
893
+ turnId: 'session-replay',
894
+ source: 'session-replay',
895
+ preserveLegacyMimeParameters: true,
896
+ };
897
+ const admission =
898
+ options.mediaStore === undefined
899
+ ? undefined
900
+ : new MediaAdmissionService(options.mediaStore);
901
+ const history =
902
+ admission === undefined
903
+ ? replay.history
904
+ : await admission.admitContents(replay.history, admissionContext);
905
+ try {
906
+ await verifyHistoryMedia(history, options.mediaStore, 'session-replay');
907
+ } catch (error) {
908
+ if (admission === undefined) throw error;
909
+ try {
910
+ await admission.releaseContents(history, admissionContext);
911
+ } catch (releaseError) {
912
+ throw new AggregateError(
913
+ [error, releaseError],
914
+ 'Session replay media verification and owner release failed',
915
+ );
916
+ }
917
+ throw error;
918
+ }
919
+ await admission?.releaseContents(history, admissionContext);
920
+ return { ...replay, history };
921
+ } catch (error) {
922
+ return {
923
+ ok: false,
924
+ error: formatReplayDiagnostic(error),
925
+ warnings: replay.warnings,
926
+ };
927
+ }
823
928
  }
824
929
 
825
930
  function applyBoundedReplayLine(
@@ -846,10 +951,15 @@ export async function replaySessionThroughSequence(
846
951
  filePath: string,
847
952
  expectedProjectHash: string,
848
953
  maxSequence: number,
954
+ options: ReplaySessionOptions = {},
849
955
  ): Promise<ReplayResult> {
850
- return readSessionStream(filePath, expectedProjectHash, (rawLine, acc) =>
851
- applyBoundedReplayLine(rawLine, maxSequence, expectedProjectHash, acc),
956
+ const replay = await readSessionStream(
957
+ filePath,
958
+ expectedProjectHash,
959
+ (rawLine, acc) =>
960
+ applyBoundedReplayLine(rawLine, maxSequence, expectedProjectHash, acc),
852
961
  );
962
+ return verifyReplayMedia(replay, options);
853
963
  }
854
964
 
855
965
  /**
@@ -42,6 +42,7 @@ import {
42
42
  resumeSessionNotFoundMessage,
43
43
  } from './resumeNotFoundMessages.js';
44
44
  import { debugLogger } from '../utils/debugLogger.js';
45
+ import type { LocalMediaStore } from '../storage/local-media-store.js';
45
46
 
46
47
  /**
47
48
  * Result of successfully resolving a session reference.
@@ -137,15 +138,30 @@ export class SessionDiscovery {
137
138
  static async listContinueTargets(
138
139
  chatsDir: string,
139
140
  projectHash: string,
141
+ mediaStore?: LocalMediaStore,
140
142
  ): Promise<ContinueTarget[]> {
141
- return (await this.listContinueTargetsDetailed(chatsDir, projectHash))
142
- .targets;
143
+ const detailed = await this.listContinueTargetsDetailed(
144
+ chatsDir,
145
+ projectHash,
146
+ mediaStore,
147
+ );
148
+ if (detailed.recordingErrors.length > 0) {
149
+ throw new Error(
150
+ `Cannot discover continue targets: ${detailed.recordingErrors.join('; ')}`,
151
+ );
152
+ }
153
+ return detailed.targets;
143
154
  }
144
155
 
145
156
  static async listContinueTargetsDetailed(
146
157
  chatsDir: string,
147
158
  projectHash: string,
148
- ): Promise<{ targets: ContinueTarget[]; skippedCount: number }> {
159
+ mediaStore?: LocalMediaStore,
160
+ ): Promise<{
161
+ targets: ContinueTarget[];
162
+ skippedCount: number;
163
+ recordingErrors: readonly string[];
164
+ }> {
149
165
  const detailed = await this.listSessionsDetailed(chatsDir, projectHash);
150
166
  const sessionTargets: Array<ContinueTarget | null> = Array.from(
151
167
  { length: detailed.sessions.length },
@@ -155,6 +171,10 @@ export class SessionDiscovery {
155
171
  { length: detailed.sessions.length },
156
172
  () => [],
157
173
  );
174
+ const recordingErrors: Array<string | null> = Array.from(
175
+ { length: detailed.sessions.length },
176
+ () => null,
177
+ );
158
178
  let nextIndex = 0;
159
179
  let skippedCount = detailed.skippedCount;
160
180
  const worker = async (): Promise<void> => {
@@ -162,12 +182,15 @@ export class SessionDiscovery {
162
182
  const index = nextIndex;
163
183
  nextIndex += 1;
164
184
  const summary = detailed.sessions[index];
165
- const replay = await replaySession(summary.filePath, projectHash);
185
+ const replay = await replaySession(summary.filePath, projectHash, {
186
+ mediaStore,
187
+ });
166
188
  if (!replay.ok || replay.sequenceCorrupt) {
167
189
  const detail = replay.ok ? 'non-monotonic sequences' : replay.error;
168
190
  debugLogger.debug(
169
191
  `Skipping unreadable session recording ${summary.filePath}: ${detail}`,
170
192
  );
193
+ recordingErrors[index] = `${summary.filePath}: ${detail}`;
171
194
  skippedCount += 1;
172
195
  continue;
173
196
  }
@@ -194,6 +217,9 @@ export class SessionDiscovery {
194
217
  ...checkpointTargets.flat(),
195
218
  ],
196
219
  skippedCount,
220
+ recordingErrors: recordingErrors.filter(
221
+ (error): error is string => error !== null,
222
+ ),
197
223
  };
198
224
  }
199
225