codex-overleaf-link 2.4.0 → 2.5.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 (327) hide show
  1. package/README.md +272 -311
  2. package/README.zh-CN.md +287 -326
  3. package/extension/bootstrap/background.js +47 -10
  4. package/extension/bootstrap/manifest.template.json +9 -4
  5. package/extension/bootstrap/popup.html +10 -16
  6. package/extension/bootstrap/update.js +25 -2
  7. package/extension/runtime-manifest.json +3 -1
  8. package/extension/src/background.js +28 -3
  9. package/extension/src/backgroundSharedSessions.js +380 -0
  10. package/extension/src/backgroundUpdateCoordinator.js +442 -379
  11. package/extension/src/content/activeTurnControl.js +8 -0
  12. package/extension/src/content/assetTransferBroker.js +186 -12
  13. package/extension/src/content/changeHistoryView.js +175 -0
  14. package/extension/src/content/composerAttachments.js +24 -22
  15. package/extension/src/content/composerPanel.js +23 -8
  16. package/extension/src/content/contentRuntime.js +572 -571
  17. package/extension/src/content/diagnosticsController.js +1 -2
  18. package/extension/src/content/diagnosticsExport.js +222 -0
  19. package/extension/src/content/diagnosticsPanel.js +48 -19
  20. package/extension/src/content/diffReviewPanel.js +8 -5
  21. package/extension/src/content/generated/content.bundle.js +8974 -1781
  22. package/extension/src/content/generated/content.bundle.meta.json +22 -3
  23. package/extension/src/content/legacyGlobalRegistry.js +19 -1
  24. package/extension/src/content/localSkillsPanel.js +42 -7
  25. package/extension/src/content/markdownDomRenderer.js +9 -4
  26. package/extension/src/content/modelPicker.js +1 -1
  27. package/extension/src/content/pageBridgeClient.js +18 -3
  28. package/extension/src/content/panelMaintenance.js +51 -120
  29. package/extension/src/content/panelRenderer.js +4 -0
  30. package/extension/src/content/pendingInputView.js +109 -76
  31. package/extension/src/content/providerSettingsCoordinator.js +17 -6
  32. package/extension/src/content/providerSettingsDialog.js +661 -108
  33. package/extension/src/content/recentProjects.js +364 -356
  34. package/extension/src/content/runActivitySummary.js +631 -0
  35. package/extension/src/content/runController.js +3 -1
  36. package/extension/src/content/runFailureNotice.js +14 -1
  37. package/extension/src/content/runGuidanceController.js +4 -3
  38. package/extension/src/content/runPresence.js +306 -0
  39. package/extension/src/content/runQueueScheduler.js +2 -1
  40. package/extension/src/content/runResultActions.js +123 -3
  41. package/extension/src/content/runTimelineView.js +194 -164
  42. package/extension/src/content/scopedPersistenceCoordinator.js +2 -1
  43. package/extension/src/content/scopedPersistencePanelState.js +45 -2
  44. package/extension/src/content/selectionContextView.js +300 -0
  45. package/extension/src/content/sessionPersistence.js +10 -2
  46. package/extension/src/content/settingsPanel.js +93 -54
  47. package/extension/src/content/settingsWorkbench.js +374 -0
  48. package/extension/src/content/sharedSessionViewSync.js +72 -0
  49. package/extension/src/content/subagentActivityView.js +195 -0
  50. package/extension/src/content/trackedChangeCaptureController.js +7 -3
  51. package/extension/src/content/updateNotice.js +121 -50
  52. package/extension/src/content/writebackController.js +257 -0
  53. package/extension/src/content/writebackOrchestrator.js +146 -141
  54. package/extension/src/content/writebackPlan.js +231 -0
  55. package/extension/src/content/writebackRecovery.js +122 -0
  56. package/extension/src/content/writingStyleSettings.js +576 -0
  57. package/extension/src/content/writtenChangesView.js +152 -0
  58. package/extension/src/page/binaryAssetUploader.js +97 -19
  59. package/extension/src/page/overleafProjectSnapshot.js +1 -0
  60. package/extension/src/page/referenceProjects.js +148 -0
  61. package/extension/src/page/saveState.js +58 -3
  62. package/extension/src/page/snapshotRouter.js +44 -13
  63. package/extension/src/page/textCoordinates.js +102 -0
  64. package/extension/src/page/textFileCreator.js +350 -59
  65. package/extension/src/page/trackedChangeCapture.js +42 -56
  66. package/extension/src/page/trackedChangeOwnership.js +198 -0
  67. package/extension/src/page/trackedChangeReplay.js +164 -0
  68. package/extension/src/page/trackedChangesLifecycle.js +139 -150
  69. package/extension/src/page/treeOperations.js +36 -29
  70. package/extension/src/page/writebackReceiptJournal.js +112 -0
  71. package/extension/src/page/writebackRouter.js +176 -136
  72. package/extension/src/pageBridge.js +59 -101
  73. package/extension/src/popup.js +203 -59
  74. package/extension/src/shared/agentTranscript.js +18 -4
  75. package/extension/src/shared/auditRecords.js +71 -0
  76. package/extension/src/shared/changeHistoryModel.js +94 -0
  77. package/extension/src/shared/compatibility.js +1 -1
  78. package/extension/src/shared/compileAdapter.js +42 -0
  79. package/extension/src/shared/failureReasons.js +20 -0
  80. package/extension/src/shared/globalPreferences.js +1 -1
  81. package/extension/src/shared/i18n.js +187 -65
  82. package/extension/src/shared/managedUpdateProjection.js +6 -3
  83. package/extension/src/shared/pageRpcContract.js +7 -1
  84. package/extension/src/shared/providerProfiles.js +109 -0
  85. package/extension/src/shared/runActivityModel.js +361 -0
  86. package/extension/src/shared/runExecutionSnapshot.js +8 -2
  87. package/extension/src/shared/runExecutionSnapshotCodec.js +16 -4
  88. package/extension/src/shared/scopedPersistenceBrowserAdapter.js +6 -3
  89. package/extension/src/shared/selectionContext.js +28 -0
  90. package/extension/src/shared/sessionState.js +97 -6
  91. package/extension/src/shared/sharedSessionBridge.js +288 -0
  92. package/extension/src/shared/storageDb.js +23 -55
  93. package/extension/src/shared/storageMigration.js +3 -0
  94. package/extension/src/shared/storageRunActions.js +54 -4
  95. package/extension/src/shared/storageValuePruning.js +40 -0
  96. package/extension/src/shared/subagentActivityModel.js +174 -0
  97. package/extension/src/shared/undoOperations.js +87 -0
  98. package/extension/src/shared/updateConsent.js +37 -8
  99. package/extension/src/shared/writebackIntent.js +62 -0
  100. package/extension/src/shared/writebackSettlement.js +29 -10
  101. package/extension/src/shared/writingStyle.js +33 -0
  102. package/extension/styles/panel.css +2136 -744
  103. package/extension/styles/popup.css +110 -0
  104. package/native-host/src/anthropicBridgeRequest.js +2 -1
  105. package/native-host/src/codexModelRecovery.js +107 -0
  106. package/native-host/src/codexPromptAssembly.js +2 -0
  107. package/native-host/src/codexProviderLaunch.js +3 -3
  108. package/native-host/src/codexRuntimeIdentity.js +1 -0
  109. package/native-host/src/codexSessionRunner.js +146 -177
  110. package/native-host/src/codexSessionTiming.js +71 -0
  111. package/native-host/src/managedInstall.js +5 -4
  112. package/native-host/src/nativeEnvironment.js +70 -0
  113. package/native-host/src/nativeQuotas.js +15 -8
  114. package/native-host/src/overleafWorkspaceRules.js +16 -0
  115. package/native-host/src/processStopBarrier.js +80 -0
  116. package/native-host/src/providerModelCatalog.js +4 -3
  117. package/native-host/src/providerProfile.js +13 -1
  118. package/native-host/src/providerReasoning.js +9 -5
  119. package/native-host/src/providerStore.js +4 -0
  120. package/native-host/src/readProgressGuard.js +84 -17
  121. package/native-host/src/releaseTransport.js +14 -5
  122. package/native-host/src/selectionScope.js +58 -0
  123. package/native-host/src/skills/parallel-subagents/SKILL.md +31 -3
  124. package/native-host/src/skills/writing-style-builder/SKILL.md +146 -0
  125. package/native-host/src/subagentBroker.js +102 -98
  126. package/native-host/src/subagentTelemetry.js +316 -0
  127. package/native-host/src/subagentWorkspace.js +103 -0
  128. package/native-host/src/subagentWorkspacePath.js +31 -0
  129. package/native-host/src/taskRunnerRuntime.js +55 -5
  130. package/native-host/src/turnAttachments.js +113 -0
  131. package/native-host/src/updateManager.js +122 -12
  132. package/native-host/src/updateNetworkControl.js +75 -0
  133. package/native-host/src/updateTrust.js +21 -2
  134. package/native-host/src/vendor/pdfjs/LICENSE +177 -0
  135. package/native-host/src/vendor/pdfjs/SOURCE.txt +3 -0
  136. package/native-host/src/vendor/pdfjs/cmaps/78-EUC-H.bcmap +0 -0
  137. package/native-host/src/vendor/pdfjs/cmaps/78-EUC-V.bcmap +0 -0
  138. package/native-host/src/vendor/pdfjs/cmaps/78-H.bcmap +0 -0
  139. package/native-host/src/vendor/pdfjs/cmaps/78-RKSJ-H.bcmap +0 -0
  140. package/native-host/src/vendor/pdfjs/cmaps/78-RKSJ-V.bcmap +0 -0
  141. package/native-host/src/vendor/pdfjs/cmaps/78-V.bcmap +0 -0
  142. package/native-host/src/vendor/pdfjs/cmaps/78ms-RKSJ-H.bcmap +0 -0
  143. package/native-host/src/vendor/pdfjs/cmaps/78ms-RKSJ-V.bcmap +0 -0
  144. package/native-host/src/vendor/pdfjs/cmaps/83pv-RKSJ-H.bcmap +0 -0
  145. package/native-host/src/vendor/pdfjs/cmaps/90ms-RKSJ-H.bcmap +0 -0
  146. package/native-host/src/vendor/pdfjs/cmaps/90ms-RKSJ-V.bcmap +0 -0
  147. package/native-host/src/vendor/pdfjs/cmaps/90msp-RKSJ-H.bcmap +0 -0
  148. package/native-host/src/vendor/pdfjs/cmaps/90msp-RKSJ-V.bcmap +0 -0
  149. package/native-host/src/vendor/pdfjs/cmaps/90pv-RKSJ-H.bcmap +0 -0
  150. package/native-host/src/vendor/pdfjs/cmaps/90pv-RKSJ-V.bcmap +0 -0
  151. package/native-host/src/vendor/pdfjs/cmaps/Add-H.bcmap +0 -0
  152. package/native-host/src/vendor/pdfjs/cmaps/Add-RKSJ-H.bcmap +0 -0
  153. package/native-host/src/vendor/pdfjs/cmaps/Add-RKSJ-V.bcmap +0 -0
  154. package/native-host/src/vendor/pdfjs/cmaps/Add-V.bcmap +0 -0
  155. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-0.bcmap +0 -0
  156. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-1.bcmap +0 -0
  157. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-2.bcmap +0 -0
  158. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-3.bcmap +0 -0
  159. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-4.bcmap +0 -0
  160. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-5.bcmap +0 -0
  161. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-6.bcmap +0 -0
  162. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
  163. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-0.bcmap +0 -0
  164. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-1.bcmap +0 -0
  165. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-2.bcmap +0 -0
  166. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-3.bcmap +0 -0
  167. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-4.bcmap +0 -0
  168. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-5.bcmap +0 -0
  169. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
  170. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-0.bcmap +0 -0
  171. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-1.bcmap +0 -0
  172. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-2.bcmap +0 -0
  173. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-3.bcmap +0 -0
  174. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-4.bcmap +0 -0
  175. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-5.bcmap +0 -0
  176. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-6.bcmap +0 -0
  177. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
  178. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-0.bcmap +0 -0
  179. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-1.bcmap +0 -0
  180. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-2.bcmap +0 -0
  181. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
  182. package/native-host/src/vendor/pdfjs/cmaps/B5-H.bcmap +0 -0
  183. package/native-host/src/vendor/pdfjs/cmaps/B5-V.bcmap +0 -0
  184. package/native-host/src/vendor/pdfjs/cmaps/B5pc-H.bcmap +0 -0
  185. package/native-host/src/vendor/pdfjs/cmaps/B5pc-V.bcmap +0 -0
  186. package/native-host/src/vendor/pdfjs/cmaps/CNS-EUC-H.bcmap +0 -0
  187. package/native-host/src/vendor/pdfjs/cmaps/CNS-EUC-V.bcmap +0 -0
  188. package/native-host/src/vendor/pdfjs/cmaps/CNS1-H.bcmap +0 -0
  189. package/native-host/src/vendor/pdfjs/cmaps/CNS1-V.bcmap +0 -0
  190. package/native-host/src/vendor/pdfjs/cmaps/CNS2-H.bcmap +0 -0
  191. package/native-host/src/vendor/pdfjs/cmaps/CNS2-V.bcmap +3 -0
  192. package/native-host/src/vendor/pdfjs/cmaps/ETHK-B5-H.bcmap +0 -0
  193. package/native-host/src/vendor/pdfjs/cmaps/ETHK-B5-V.bcmap +0 -0
  194. package/native-host/src/vendor/pdfjs/cmaps/ETen-B5-H.bcmap +0 -0
  195. package/native-host/src/vendor/pdfjs/cmaps/ETen-B5-V.bcmap +0 -0
  196. package/native-host/src/vendor/pdfjs/cmaps/ETenms-B5-H.bcmap +3 -0
  197. package/native-host/src/vendor/pdfjs/cmaps/ETenms-B5-V.bcmap +0 -0
  198. package/native-host/src/vendor/pdfjs/cmaps/EUC-H.bcmap +0 -0
  199. package/native-host/src/vendor/pdfjs/cmaps/EUC-V.bcmap +0 -0
  200. package/native-host/src/vendor/pdfjs/cmaps/Ext-H.bcmap +0 -0
  201. package/native-host/src/vendor/pdfjs/cmaps/Ext-RKSJ-H.bcmap +0 -0
  202. package/native-host/src/vendor/pdfjs/cmaps/Ext-RKSJ-V.bcmap +0 -0
  203. package/native-host/src/vendor/pdfjs/cmaps/Ext-V.bcmap +0 -0
  204. package/native-host/src/vendor/pdfjs/cmaps/GB-EUC-H.bcmap +0 -0
  205. package/native-host/src/vendor/pdfjs/cmaps/GB-EUC-V.bcmap +0 -0
  206. package/native-host/src/vendor/pdfjs/cmaps/GB-H.bcmap +4 -0
  207. package/native-host/src/vendor/pdfjs/cmaps/GB-V.bcmap +0 -0
  208. package/native-host/src/vendor/pdfjs/cmaps/GBK-EUC-H.bcmap +0 -0
  209. package/native-host/src/vendor/pdfjs/cmaps/GBK-EUC-V.bcmap +0 -0
  210. package/native-host/src/vendor/pdfjs/cmaps/GBK2K-H.bcmap +0 -0
  211. package/native-host/src/vendor/pdfjs/cmaps/GBK2K-V.bcmap +0 -0
  212. package/native-host/src/vendor/pdfjs/cmaps/GBKp-EUC-H.bcmap +0 -0
  213. package/native-host/src/vendor/pdfjs/cmaps/GBKp-EUC-V.bcmap +0 -0
  214. package/native-host/src/vendor/pdfjs/cmaps/GBT-EUC-H.bcmap +0 -0
  215. package/native-host/src/vendor/pdfjs/cmaps/GBT-EUC-V.bcmap +0 -0
  216. package/native-host/src/vendor/pdfjs/cmaps/GBT-H.bcmap +0 -0
  217. package/native-host/src/vendor/pdfjs/cmaps/GBT-V.bcmap +0 -0
  218. package/native-host/src/vendor/pdfjs/cmaps/GBTpc-EUC-H.bcmap +0 -0
  219. package/native-host/src/vendor/pdfjs/cmaps/GBTpc-EUC-V.bcmap +0 -0
  220. package/native-host/src/vendor/pdfjs/cmaps/GBpc-EUC-H.bcmap +0 -0
  221. package/native-host/src/vendor/pdfjs/cmaps/GBpc-EUC-V.bcmap +0 -0
  222. package/native-host/src/vendor/pdfjs/cmaps/H.bcmap +0 -0
  223. package/native-host/src/vendor/pdfjs/cmaps/HKdla-B5-H.bcmap +0 -0
  224. package/native-host/src/vendor/pdfjs/cmaps/HKdla-B5-V.bcmap +0 -0
  225. package/native-host/src/vendor/pdfjs/cmaps/HKdlb-B5-H.bcmap +0 -0
  226. package/native-host/src/vendor/pdfjs/cmaps/HKdlb-B5-V.bcmap +0 -0
  227. package/native-host/src/vendor/pdfjs/cmaps/HKgccs-B5-H.bcmap +0 -0
  228. package/native-host/src/vendor/pdfjs/cmaps/HKgccs-B5-V.bcmap +0 -0
  229. package/native-host/src/vendor/pdfjs/cmaps/HKm314-B5-H.bcmap +0 -0
  230. package/native-host/src/vendor/pdfjs/cmaps/HKm314-B5-V.bcmap +0 -0
  231. package/native-host/src/vendor/pdfjs/cmaps/HKm471-B5-H.bcmap +0 -0
  232. package/native-host/src/vendor/pdfjs/cmaps/HKm471-B5-V.bcmap +0 -0
  233. package/native-host/src/vendor/pdfjs/cmaps/HKscs-B5-H.bcmap +0 -0
  234. package/native-host/src/vendor/pdfjs/cmaps/HKscs-B5-V.bcmap +0 -0
  235. package/native-host/src/vendor/pdfjs/cmaps/Hankaku.bcmap +0 -0
  236. package/native-host/src/vendor/pdfjs/cmaps/Hiragana.bcmap +0 -0
  237. package/native-host/src/vendor/pdfjs/cmaps/KSC-EUC-H.bcmap +0 -0
  238. package/native-host/src/vendor/pdfjs/cmaps/KSC-EUC-V.bcmap +0 -0
  239. package/native-host/src/vendor/pdfjs/cmaps/KSC-H.bcmap +0 -0
  240. package/native-host/src/vendor/pdfjs/cmaps/KSC-Johab-H.bcmap +0 -0
  241. package/native-host/src/vendor/pdfjs/cmaps/KSC-Johab-V.bcmap +0 -0
  242. package/native-host/src/vendor/pdfjs/cmaps/KSC-V.bcmap +0 -0
  243. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-H.bcmap +0 -0
  244. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
  245. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
  246. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-V.bcmap +0 -0
  247. package/native-host/src/vendor/pdfjs/cmaps/KSCpc-EUC-H.bcmap +0 -0
  248. package/native-host/src/vendor/pdfjs/cmaps/KSCpc-EUC-V.bcmap +0 -0
  249. package/native-host/src/vendor/pdfjs/cmaps/Katakana.bcmap +0 -0
  250. package/native-host/src/vendor/pdfjs/cmaps/LICENSE +36 -0
  251. package/native-host/src/vendor/pdfjs/cmaps/NWP-H.bcmap +0 -0
  252. package/native-host/src/vendor/pdfjs/cmaps/NWP-V.bcmap +0 -0
  253. package/native-host/src/vendor/pdfjs/cmaps/RKSJ-H.bcmap +0 -0
  254. package/native-host/src/vendor/pdfjs/cmaps/RKSJ-V.bcmap +0 -0
  255. package/native-host/src/vendor/pdfjs/cmaps/Roman.bcmap +0 -0
  256. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UCS2-H.bcmap +0 -0
  257. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UCS2-V.bcmap +0 -0
  258. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF16-H.bcmap +0 -0
  259. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF16-V.bcmap +0 -0
  260. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF32-H.bcmap +0 -0
  261. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF32-V.bcmap +0 -0
  262. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF8-H.bcmap +0 -0
  263. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF8-V.bcmap +0 -0
  264. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UCS2-H.bcmap +0 -0
  265. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UCS2-V.bcmap +0 -0
  266. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF16-H.bcmap +0 -0
  267. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF16-V.bcmap +0 -0
  268. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF32-H.bcmap +0 -0
  269. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF32-V.bcmap +0 -0
  270. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF8-H.bcmap +0 -0
  271. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF8-V.bcmap +0 -0
  272. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-H.bcmap +0 -0
  273. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
  274. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
  275. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-V.bcmap +0 -0
  276. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF16-H.bcmap +0 -0
  277. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF16-V.bcmap +0 -0
  278. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF32-H.bcmap +0 -0
  279. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF32-V.bcmap +0 -0
  280. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF8-H.bcmap +0 -0
  281. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF8-V.bcmap +0 -0
  282. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
  283. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
  284. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
  285. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
  286. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
  287. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
  288. package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
  289. package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
  290. package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
  291. package/native-host/src/vendor/pdfjs/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
  292. package/native-host/src/vendor/pdfjs/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
  293. package/native-host/src/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
  294. package/native-host/src/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
  295. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UCS2-H.bcmap +0 -0
  296. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UCS2-V.bcmap +0 -0
  297. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF16-H.bcmap +0 -0
  298. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF16-V.bcmap +0 -0
  299. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF32-H.bcmap +0 -0
  300. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF32-V.bcmap +0 -0
  301. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF8-H.bcmap +0 -0
  302. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF8-V.bcmap +0 -0
  303. package/native-host/src/vendor/pdfjs/cmaps/V.bcmap +0 -0
  304. package/native-host/src/vendor/pdfjs/cmaps/WP-Symbol.bcmap +0 -0
  305. package/native-host/src/vendor/pdfjs/pdf.mjs +26740 -0
  306. package/native-host/src/vendor/pdfjs/pdf.worker.mjs +62201 -0
  307. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitDingbats.pfb +0 -0
  308. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixed.pfb +0 -0
  309. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedBold.pfb +0 -0
  310. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
  311. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedItalic.pfb +0 -0
  312. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerif.pfb +0 -0
  313. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifBold.pfb +0 -0
  314. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
  315. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifItalic.pfb +0 -0
  316. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSymbol.pfb +0 -0
  317. package/native-host/src/vendor/pdfjs/standard_fonts/LICENSE_FOXIT +27 -0
  318. package/native-host/src/vendor/pdfjs/standard_fonts/LICENSE_LIBERATION +102 -0
  319. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Bold.ttf +0 -0
  320. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
  321. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Italic.ttf +0 -0
  322. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Regular.ttf +0 -0
  323. package/native-host/src/writingStyleEvidence.js +102 -0
  324. package/native-host/src/writingStylePdfWorker.js +35 -0
  325. package/native-host/src/writingStyleProfile.js +165 -0
  326. package/native-host/src/writingStyleRuntime.js +447 -0
  327. package/package.json +1 -1
@@ -1,18 +1,23 @@
1
1
  (function initStorageDb(root, factory) {
2
2
  if (typeof module === 'object' && module.exports) {
3
3
  module.exports = factory(require('./storageRunActions'), require('./runInputQueue'),
4
- require('./settlementFacts'), require('./storageSessionClaims'), require('./sessionState'));
4
+ require('./settlementFacts'), require('./storageSessionClaims'), require('./sessionState'), require('./runActivityModel'), require('./sharedSessionBridge'), require('./subagentActivityModel'), require('./storageValuePruning'));
5
5
  } else {
6
6
  root.CodexOverleafModuleRegistry.define('StorageDb', [
7
7
  'StorageRunActions',
8
8
  'RunInputQueue',
9
9
  'SettlementFacts',
10
10
  'StorageSessionClaims',
11
- 'SessionState'
11
+ 'SessionState',
12
+ 'RunActivityModel',
13
+ 'SharedSessionBridge',
14
+ 'SubagentActivityModel',
15
+ 'StorageValuePruning'
12
16
  ], factory);
13
17
  }
14
- })(typeof globalThis !== 'undefined' ? globalThis : window, function storageDbFactory(StorageRunActions, RunInputQueue, SettlementFacts, StorageSessionClaims, SessionState) {
18
+ })(typeof globalThis !== 'undefined' ? globalThis : window, function storageDbFactory(StorageRunActions, RunInputQueue, SettlementFacts, StorageSessionClaims, SessionState, RunActivityModel, SharedSessionBridge, SubagentActivityModel, StorageValuePruning) {
15
19
  'use strict';
20
+ const { removeEmptySummaryFields, removeEmptyFields } = StorageValuePruning;
16
21
  if (!StorageRunActions?.compactRunsForStorage || !StorageRunActions?.compactRunActionPayload || !StorageRunActions?.compactProviderSnapshot || !StorageRunActions?.compactRunExecutionSnapshot || !StorageRunActions?.compactStructuredEventValue || !StorageRunActions?.hashString || !RunInputQueue?.compactForStorage || !SettlementFacts?.compactSettlementFacts || !StorageSessionClaims?.createSessionClaimer) {
17
22
  throw new Error('Codex Overleaf storage run-action helpers are unavailable.');
18
23
  }
@@ -280,6 +285,7 @@
280
285
  codexThreadId: typeof input.codexThreadId === 'string' ? input.codexThreadId : '',
281
286
  status: typeof input.status === 'string' && input.status ? input.status : 'active',
282
287
  focusFiles: normalizePathList(input.focusFiles),
288
+ selectionContext: SessionState.normalizeSelectionContext(input.selectionContext),
283
289
  projectReferenceFiles: SessionState.normalizeProjectReferenceFiles(input.projectReferenceFiles),
284
290
  pendingInputs: RunInputQueue.compactForStorage(input.pendingInputs, {
285
291
  normalizeField: normalizeTextField,
@@ -655,8 +661,10 @@
655
661
  return StorageRunActions.compactRunsForStorage(runs, options, SESSION_STORAGE_LIMITS.maxRunsPerSession, compactRunForStorage);
656
662
  }
657
663
  function compactRunForStorage(run, keepActionPayload) {
664
+ run = SessionState.recoverRecordedRunFailure(run);
658
665
  var actionPayload = StorageRunActions.compactRunActionPayload(run, keepActionPayload);
659
666
  var compact = {
667
+ ...SessionState.pickWritebackRecovery(run),
660
668
  id: run.id,
661
669
  task: normalizeDisplayTextForStorage(run.task || 'untitled task', SESSION_STORAGE_LIMITS.taskChars),
662
670
  mode: typeof run.mode === 'string' ? redactSecretLikeText(run.mode) : '', ...StorageRunActions.compactProviderSnapshot(run),
@@ -664,12 +672,13 @@
664
672
  model: normalizeTextField(run.model, 80),
665
673
  reasoningEffort: typeof run.reasoningEffort === 'string' ? redactSecretLikeText(run.reasoningEffort) : '',
666
674
  speedTier: typeof run.speedTier === 'string' ? redactSecretLikeText(run.speedTier) : '',
667
- status: normalizeRunStatus(run.status),
675
+ status: SessionState.normalizeRunStatus(run.status, run),
668
676
  statusText: normalizeDisplayTextForStorage(run.statusText, SESSION_STORAGE_LIMITS.statusTextChars),
669
677
  runProjectId: normalizeProjectPrefKey(run.runProjectId),
670
678
  startedAt: typeof run.startedAt === 'string' ? redactSecretLikeText(run.startedAt) : '',
671
679
  finishedAt: typeof run.finishedAt === 'string' ? redactSecretLikeText(run.finishedAt) : '',
672
680
  events: compactRunEventsForStorage(run.events),
681
+ ...(run.subagents?.length ? { subagents: SubagentActivityModel.normalize(run.subagents, sanitizeAssistantVisibleText) } : {}),
673
682
  attachments: compactRunAttachmentsForStorage(run.attachments),
674
683
  appliedOperations: actionPayload.appliedOperations,
675
684
  undoOperations: actionPayload.undoOperations,
@@ -719,6 +728,13 @@
719
728
  streamKey: typeof event.streamKey === 'string' ? redactSecretLikeText(event.streamKey) : '',
720
729
  streamRole: typeof event.streamRole === 'string' ? redactSecretLikeText(event.streamRole) : ''
721
730
  };
731
+ // Persist the bounded display projection, never the raw tool payload.
732
+ // Hydration uses the same model; dropping this metadata demotes tools
733
+ // to hidden diagnostics after an otherwise successful history reload.
734
+ var activity = RunActivityModel.capture(event, sanitizeAssistantVisibleText);
735
+ if (activity) compact.activity = activity;
736
+ var streamPhase = RunActivityModel.normalizePhase(event.streamPhase);
737
+ if (streamPhase) compact.streamPhase = streamPhase;
722
738
  if (event.subagent === true) {
723
739
  compact.subagent = true;
724
740
  }
@@ -914,25 +930,6 @@
914
930
  .trim(), maxChars || SESSION_STORAGE_LIMITS.pathChars);
915
931
  }
916
932
 
917
- function normalizeRunStatus(status) {
918
- // Welcome-panel + write-guard: the run-status
919
- // enum gained three post-navigation values. The storage normalizer must
920
- // accept them so a settled run round-trips intact through `buildSessionRecord`.
921
- // Unknown legacy values fall through to `completed` (the historical default).
922
- return [
923
- 'pending',
924
- 'running',
925
- 'completed',
926
- 'failed',
927
- 'background_completed',
928
- 'needs_review_after_navigation',
929
- 'abandoned_after_navigation',
930
- // v1.8.1: reload-orphaned runs settle to 'interrupted' (v1.7.6); the
931
- // storage round-trip must not rewrite them to a false 'completed'.
932
- 'interrupted'
933
- ].indexOf(status) !== -1 ? status : 'completed';
934
- }
935
-
936
933
  function normalizeEventStatus(status) {
937
934
  return VALID_EVENT_STATUSES[status] ? status : 'info';
938
935
  }
@@ -1106,37 +1103,7 @@
1106
1103
  return 'error';
1107
1104
  }
1108
1105
 
1109
- function removeEmptySummaryFields(value) {
1110
- var result = {};
1111
- var keys = Object.keys(value || {});
1112
- for (var i = 0; i < keys.length; i++) {
1113
- var key = keys[i];
1114
- var item = value[key];
1115
- if (item === undefined || item === '' || item === null) {
1116
- continue;
1117
- }
1118
- if (Array.isArray(item) && item.length === 0) {
1119
- continue;
1120
- }
1121
- if (item && typeof item === 'object' && !Array.isArray(item) && Object.keys(item).length === 0) {
1122
- continue;
1123
- }
1124
- result[key] = item;
1125
- }
1126
- return result;
1127
- }
1128
1106
 
1129
- function removeEmptyFields(value) {
1130
- var result = {};
1131
- var keys = Object.keys(value);
1132
- for (var i = 0; i < keys.length; i++) {
1133
- var key = keys[i];
1134
- if (value[key] !== undefined && value[key] !== '') {
1135
- result[key] = value[key];
1136
- }
1137
- }
1138
- return result;
1139
- }
1140
1107
 
1141
1108
  // Welcome-panel + write-guard: the Recent-projects
1142
1109
  // dashboard variant calls `listRecentProjectsAcrossAccount` to get the
@@ -1328,7 +1295,7 @@
1328
1295
  }
1329
1296
  var hashString = StorageRunActions.hashString;
1330
1297
 
1331
- return {
1298
+ return SharedSessionBridge.decorate({
1332
1299
  TARGET_SCHEMA_VERSION: TARGET_SCHEMA_VERSION,
1333
1300
  DB_NAME: DB_NAME,
1334
1301
  STORES: STORES,
@@ -1343,6 +1310,7 @@
1343
1310
  clearStore: clearStore,
1344
1311
  clearAllStores: clearAllStores,
1345
1312
  buildSessionRecord: buildSessionRecord,
1313
+ mergeSessionReviewState: StorageRunActions.mergeSessionReviewState,
1346
1314
  buildTurnRecord: buildTurnRecord,
1347
1315
  buildEventRecord: buildEventRecord,
1348
1316
  buildArtifactRecord: buildArtifactRecord,
@@ -1354,5 +1322,5 @@
1354
1322
  filterRecentProjectsAcrossAccount: filterRecentProjectsAcrossAccount,
1355
1323
  derivePrimaryStatusBadge: derivePrimaryStatusBadge,
1356
1324
  getAllSessions: getAllSessions
1357
- };
1325
+ });
1358
1326
  });
@@ -50,6 +50,9 @@
50
50
  }
51
51
 
52
52
  function withProjectPreferenceLock(projectId, work) {
53
+ if (StorageDb.sharedSessionsEnabled?.()) {
54
+ return StorageDb.withSharedLock('preferences', { projectId: projectId }, work);
55
+ }
53
56
  var lockName = 'codex-overleaf-project-prefs:' + compactScopePart(projectId);
54
57
  var lockManager = typeof navigator !== 'undefined' && navigator && navigator.locks;
55
58
  if (lockManager && typeof lockManager.request === 'function') {
@@ -1,14 +1,18 @@
1
1
  (function initStorageRunActions(root, factory) {
2
2
  if (typeof module === 'object' && module.exports) {
3
- module.exports = factory();
3
+ module.exports = factory(require('./selectionContext'), require('./writebackIntent'), require('./writingStyle'));
4
4
  } else {
5
- root.CodexOverleafStorageRunActions = factory();
5
+ root.CodexOverleafModuleRegistry.define('StorageRunActions', ['SelectionContext', 'WritebackIntent', 'WritingStyle'], factory);
6
6
  }
7
- })(typeof globalThis !== 'undefined' ? globalThis : window, function storageRunActionsFactory() {
7
+ })(typeof globalThis !== 'undefined' ? globalThis : window, function storageRunActionsFactory(SelectionContext, WritebackIntent, WritingStyle) {
8
8
  'use strict';
9
9
 
10
10
  var MAX_PERSISTED_ACTION_RUNS_PER_SESSION = 2;
11
- var MAX_PERSISTED_ACTION_BYTES_PER_RUN = 320 * 1024;
11
+ // Undo/Accept need whole pre- and post-images of every written file, so one
12
+ // run that edits a 120 KB roadmap and creates a 100 KB chapter already needs
13
+ // ~560 KB. The old 320 KB cap silently dropped the whole payload and the
14
+ // buttons vanished after a reload. Two runs per session keep this bounded.
15
+ var MAX_PERSISTED_ACTION_BYTES_PER_RUN = 2 * 1024 * 1024;
12
16
 
13
17
  function compactRunsForStorage(runs, options, maxRuns, compactRun) {
14
18
  if (typeof compactRun !== 'function') {
@@ -126,6 +130,8 @@
126
130
  compact.focusFiles = snapshot.focusFiles.slice(0, 100)
127
131
  .filter(function (value) { return typeof value === 'string'; }).map(normalize);
128
132
  }
133
+ compact.selectionContext = SelectionContext.normalize(snapshot.selectionContext);
134
+ compact.writingStyle = WritingStyle.normalizeSnapshot(snapshot.writingStyle);
129
135
  return { executionSnapshot: compact };
130
136
  }
131
137
 
@@ -159,6 +165,49 @@
159
165
  return out;
160
166
  }
161
167
 
168
+ // Review terminal states are monotonic even when a later session snapshot is stale.
169
+ function mergeSessionReviewState(incoming, existing, reviewRunIds) {
170
+ if (!existing || incoming.id !== existing.id || incoming.projectId !== existing.projectId
171
+ || !incoming.accountScopeId || incoming.accountScopeId !== existing.accountScopeId) return incoming;
172
+ var terminal = run => ['accepted', 'rejected'].includes(run?.trackedChangeStatus);
173
+ var incomingRuns = new Map((incoming.runs || []).map(run => [run.id, run]));
174
+ var existingRuns = new Map((existing.runs || []).map(run => [run.id, run]));
175
+ var requestedIds = new Set(reviewRunIds || []);
176
+ var explicitReview = Array.from(requestedIds).some(id =>
177
+ ['accepted', 'rejected', 'needs_review'].includes(incomingRuns.get(id)?.trackedChangeStatus));
178
+ var newer = (Date.parse(incoming.updatedAt) || 0) >= (Date.parse(existing.updatedAt) || 0);
179
+ if (!newer && !explicitReview) return incoming;
180
+ var base = newer ? incoming : existing;
181
+ var fields = ['trackedChangeStatus', 'undoStatus', 'undoTrackedChanges', 'undoExpectedFiles',
182
+ 'undoOperations', 'undoBaseFiles', 'appliedOperations', 'trackedChangeCaptures', 'settlement', 'settlementFacts'];
183
+ var changed = false;
184
+ var runs = (base.runs || []).map(function (run) {
185
+ var previous = existingRuns.get(run.id), candidate = incomingRuns.get(run.id);
186
+ // Never revive a removed run or change the first durably recorded review decision.
187
+ var source = terminal(previous) ? previous
188
+ : explicitReview && requestedIds.has(run.id) ? candidate : null;
189
+ if (!source || source === run) return run;
190
+ if (source.runProjectId && source.runProjectId !== incoming.projectId) return run;
191
+ var merged = { ...run };
192
+ for (var field of fields) {
193
+ if (Object.prototype.hasOwnProperty.call(source, field)) {
194
+ merged[field] = JSON.parse(JSON.stringify(source[field]));
195
+ } else {
196
+ delete merged[field];
197
+ }
198
+ }
199
+ changed = true;
200
+ return merged;
201
+ });
202
+ if (!changed) return base;
203
+ var merged = { ...base, runs };
204
+ if (explicitReview && !newer) {
205
+ merged.updatedAt = new Date(Math.max(Date.now(), Date.parse(existing.updatedAt) || 0,
206
+ Date.parse(incoming.updatedAt) || 0) + 1).toISOString();
207
+ }
208
+ return merged;
209
+ }
210
+
162
211
  function hashString(value) {
163
212
  var hash = 2166136261;
164
213
  var text = String(value || '');
@@ -171,6 +220,7 @@
171
220
 
172
221
  return {
173
222
  compactStructuredEventValue: compactStructuredEventValue,
223
+ mergeSessionReviewState: mergeSessionReviewState,
174
224
  compactRunsForStorage: compactRunsForStorage,
175
225
  compactRunActionPayload: compactRunActionPayload,
176
226
  compactProviderSnapshot: compactProviderSnapshot,
@@ -0,0 +1,40 @@
1
+ (function (root, factory) {
2
+ if (typeof module === 'object' && module.exports) module.exports = factory();
3
+ else root.CodexOverleafModuleRegistry.define('StorageValuePruning', [], factory);
4
+ })(typeof globalThis !== 'undefined' ? globalThis : this, function () {
5
+ 'use strict';
6
+
7
+ function removeEmptySummaryFields(value) {
8
+ var result = {};
9
+ var keys = Object.keys(value || {});
10
+ for (var i = 0; i < keys.length; i++) {
11
+ var key = keys[i];
12
+ var item = value[key];
13
+ if (item === undefined || item === '' || item === null) {
14
+ continue;
15
+ }
16
+ if (Array.isArray(item) && item.length === 0) {
17
+ continue;
18
+ }
19
+ if (item && typeof item === 'object' && !Array.isArray(item) && Object.keys(item).length === 0) {
20
+ continue;
21
+ }
22
+ result[key] = item;
23
+ }
24
+ return result;
25
+ }
26
+
27
+ function removeEmptyFields(value) {
28
+ var result = {};
29
+ var keys = Object.keys(value);
30
+ for (var i = 0; i < keys.length; i++) {
31
+ var key = keys[i];
32
+ if (value[key] !== undefined && value[key] !== '') {
33
+ result[key] = value[key];
34
+ }
35
+ }
36
+ return result;
37
+ }
38
+
39
+ return { removeEmptySummaryFields, removeEmptyFields };
40
+ });
@@ -0,0 +1,174 @@
1
+ (function initSubagentActivityModel(root, factory) {
2
+ if (typeof module === 'object' && module.exports) {
3
+ module.exports = factory(require('./agentTranscript'), require('./runActivityModel'));
4
+ } else root.CodexOverleafModuleRegistry.define('SubagentActivityModel', ['AgentTranscript', 'RunActivityModel'], factory);
5
+ })(typeof globalThis !== 'undefined' ? globalThis : window, function subagentActivityModelFactory(Transcript, Activity) {
6
+ 'use strict';
7
+ const MAX_AGENTS = 16, MAX_EVENTS = 100, MAX_CHARS = 48000;
8
+ const STATES = new Set(['pending', 'running', 'completed', 'failed', 'cancelled', 'unknown']);
9
+ const TERMINAL = new Set(['completed', 'failed', 'cancelled']);
10
+ const string = value => typeof value === 'string' ? value : '';
11
+ function clean(value, sanitize = string, limit = 24000) {
12
+ return string(sanitize(string(value))).slice(0, limit);
13
+ }
14
+ function trim(agent) {
15
+ if (agent.events.length > MAX_EVENTS) { agent.events = agent.events.slice(-MAX_EVENTS); agent.clipped = true; }
16
+ while (agent.events.length > 1 && JSON.stringify(agent.events).length > MAX_CHARS) {
17
+ agent.events.shift(); agent.clipped = true;
18
+ }
19
+ return agent;
20
+ }
21
+ function normalize(agents, sanitize = string) {
22
+ const seen = new Set();
23
+ return (Array.isArray(agents) ? agents : []).slice(0, MAX_AGENTS).filter(agent => {
24
+ if (!agent || !['broker', 'codex'].includes(agent.source)) return false;
25
+ const id = agent.source === 'broker' ? agent.jobId : agent.threadId;
26
+ if (typeof id !== 'string' || !/^[a-zA-Z0-9][a-zA-Z0-9_.:-]{0,159}$/.test(id)) return false;
27
+ const key = agent.source + ':' + id;
28
+ if (seen.has(key)) return false;
29
+ seen.add(key); return true;
30
+ }).map(agent => trim({
31
+ v: 1, source: agent.source, key: agent.source + ':' + (agent.source === 'broker' ? agent.jobId : agent.threadId),
32
+ jobId: clean(agent.jobId, sanitize, 160), threadId: clean(agent.threadId, sanitize, 160),
33
+ parentThreadId: clean(agent.parentThreadId, sanitize, 160),
34
+ title: clean(agent.title, sanitize, 160), task: clean(agent.task, sanitize, 4096),
35
+ model: clean(agent.model, sanitize, 160), reasoningEffort: clean(agent.reasoningEffort, sanitize, 32),
36
+ status: STATES.has(agent.status) ? agent.status : 'unknown',
37
+ startedAt: clean(agent.startedAt, sanitize, 64), updatedAt: clean(agent.updatedAt, sanitize, 64),
38
+ finishedAt: clean(agent.finishedAt, sanitize, 64),
39
+ lastSequence: Number.isSafeInteger(agent.lastSequence) ? agent.lastSequence : 0,
40
+ nativeEventSeq: Number.isSafeInteger(agent.nativeEventSeq) ? agent.nativeEventSeq : 0,
41
+ clipped: agent.clipped === true, historyUnavailable: agent.historyUnavailable === true,
42
+ events: (Array.isArray(agent.events) ? agent.events : []).filter(event => event && typeof event.title === 'string')
43
+ .slice(-MAX_EVENTS).map(event => ({
44
+ title: clean(event.title, sanitize), status: clean(event.status, sanitize, 32),
45
+ timestamp: clean(event.timestamp, sanitize, 64),
46
+ kind: event.kind === 'stream' ? 'stream' : 'activity',
47
+ streamKey: clean(event.streamKey, sanitize, 600), streamRole: event.streamRole === 'assistant' ? 'assistant' : '',
48
+ streamPhase: Activity.normalizePhase(event.streamPhase),
49
+ activity: Activity.normalize(event.activity, sanitize)
50
+ }))
51
+ }));
52
+ }
53
+ function effectiveStatus(agent, run) {
54
+ if (TERMINAL.has(agent.status) || agent.status === 'unknown' || run.status === 'running') return agent.status;
55
+ return ['cancelled', 'rejected'].includes(run.status) ? 'cancelled' : 'unknown';
56
+ }
57
+ function terminalTime(agent, run) {
58
+ const terminal = [agent.finishedAt, run.status === 'running' ? '' : run.finishedAt]
59
+ .map(value => Date.parse(value || '')).find(Number.isFinite);
60
+ const evidence = [agent.startedAt, agent.updatedAt, ...(agent.events || []).map(event => event.timestamp)];
61
+ if (run.status !== 'running') evidence.push(run.startedAt, run.updatedAt, ...(run.events || []).map(event => event.timestamp));
62
+ return terminal ?? Math.max(...evidence.map(value => Date.parse(value || '')).filter(Number.isFinite));
63
+ }
64
+ function elapsedMs(agent, run, now = Date.now()) {
65
+ const start = Date.parse(agent.startedAt || '');
66
+ const live = run.status === 'running' && ['pending', 'running'].includes(effectiveStatus(agent, run));
67
+ return Number.isFinite(start) ? Math.max(0, (live ? now : terminalTime(agent, run)) - start) : null;
68
+ }
69
+ function append(agent, input, sanitize) {
70
+ const event = {
71
+ title: clean(input.title, sanitize), status: input.status || 'running',
72
+ timestamp: input.timestamp || new Date().toISOString(),
73
+ kind: input.kind === 'stream' ? 'stream' : 'activity',
74
+ streamKey: input.streamKey || '', streamRole: input.streamRole || '',
75
+ streamPhase: Activity.normalizePhase(input.streamPhase),
76
+ activity: Activity.normalize(input.activity, sanitize)
77
+ };
78
+ if (!event.title) return;
79
+ const key = event.kind === 'stream' ? 'stream:' + event.streamKey : event.activity?.id;
80
+ const previous = key && agent.events.find(old => (old.kind === 'stream' ? 'stream:' + old.streamKey : old.activity?.id) === key);
81
+ if (previous) {
82
+ if (previous.status === 'completed' && event.status === 'running' && input.appendText) return;
83
+ const fullText = input.appendText ? previous.title + event.title : event.title;
84
+ if (fullText.length > 24000) agent.clipped = true;
85
+ const activity = previous.activity && event.activity ? { ...previous.activity, ...event.activity,
86
+ command: event.activity.command || previous.activity.command,
87
+ output: event.activity.output || previous.activity.output,
88
+ paths: event.activity.paths?.length ? event.activity.paths : previous.activity.paths,
89
+ files: event.activity.files?.length ? event.activity.files : previous.activity.files } : event.activity || previous.activity;
90
+ Object.assign(previous, event, { title: fullText.slice(0, 24000), activity });
91
+ } else agent.events.push(event);
92
+ trim(agent);
93
+ }
94
+ function addAnswer(agent, answer, timestamp, sanitize) {
95
+ if (!answer) return;
96
+ const last = agent.events.filter(event => event.kind === 'stream' && event.streamRole === 'assistant').at(-1);
97
+ const safe = clean(answer, sanitize);
98
+ if (last?.title.trim() === safe.trim()) { last.status = 'completed'; return; }
99
+ append(agent, { kind: 'stream', streamRole: 'assistant', streamPhase: 'final_answer',
100
+ streamKey: last?.streamPhase === 'final_answer' ? last.streamKey : 'answer:' + agent.key,
101
+ title: safe, status: 'completed', timestamp }, sanitize);
102
+ }
103
+ function ingest(run, raw, options = {}) {
104
+ const type = string(raw?.type), detail = raw?.detail || {};
105
+ if (type === 'codex.subagent.drained') return true;
106
+ if (!['codex.subagent.queued', 'codex.subagent.started', 'codex.subagent.completed',
107
+ 'codex.subagent.failed', 'codex.subagent.rejected', 'codex.subagent.event', 'codex.subagent.observed'].includes(type)) return false;
108
+ const source = detail.source === 'codex' ? 'codex' : 'broker';
109
+ const id = source === 'broker' ? string(detail.jobId || detail.id) : string(detail.threadId);
110
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9_.:-]{0,159}$/.test(id)) return true;
111
+ const sanitize = options.sanitize || string, key = source + ':' + id;
112
+ const agents = run.subagents || (run.subagents = []);
113
+ let agent = agents.find(item => item.key === key);
114
+ if (!agent) {
115
+ if (agents.length >= MAX_AGENTS) return true;
116
+ agent = { v: 1, source, key, jobId: source === 'broker' ? id : '', threadId: source === 'codex' ? id : '',
117
+ title: id, task: '', status: 'pending', events: [], nativeEventSeq: 0, lastSequence: 0 };
118
+ agents.push(agent);
119
+ }
120
+ const seq = Number(options.nativeEventSeq) || 0;
121
+ if (seq > 0 && seq <= (agent.nativeEventSeq || 0)) return true;
122
+ const sequence = Number(detail.sequence) || 0;
123
+ if (sequence > 0 && sequence <= (agent.lastSequence || 0)) return true;
124
+ agent.nativeEventSeq = Math.max(agent.nativeEventSeq || 0, seq);
125
+ agent.lastSequence = Math.max(agent.lastSequence || 0, sequence);
126
+ const timestamp = string(raw.timestamp) || new Date().toISOString(), at = Date.parse(string(raw.timestamp));
127
+ const wasTerminal = TERMINAL.has(agent.status), previousEnd = terminalTime(agent, run);
128
+ if (Number.isFinite(at) && at < Date.parse(agent.startedAt || '')) return true;
129
+ agent.updatedAt = timestamp;
130
+ for (const field of ['title', 'task', 'threadId', 'parentThreadId', 'model', 'reasoningEffort']) {
131
+ const value = detail[field] || (field === 'title' ? raw.title : '');
132
+ if (typeof value === 'string' && value) agent[field] = clean(value, sanitize, field === 'task' ? 4096 : 160);
133
+ }
134
+ agent.clipped ||= detail.historyClipped === true;
135
+ agent.historyUnavailable ||= detail.historyUnavailable === true;
136
+ let next = type.endsWith('.queued') ? 'pending' : type.endsWith('.started') ? 'running'
137
+ : type.endsWith('.completed') ? 'completed' : type.endsWith('.rejected') ? 'failed'
138
+ : type.endsWith('.failed') ? (detail.status === 'cancelled' ? 'cancelled' : 'failed') : detail.status;
139
+ const inner = type === 'codex.subagent.event' ? detail.event : null;
140
+ const method = inner?.detail?.method, params = inner?.detail?.params || {};
141
+ if (method === 'turn/started') next = 'running';
142
+ if (method === 'turn/completed' && source === 'codex') next = params.turn?.status === 'interrupted' ? 'cancelled' : params.turn?.status;
143
+ const reopening = wasTerminal && method === 'turn/started';
144
+ if (STATES.has(next) && (!wasTerminal || TERMINAL.has(next) || reopening)) agent.status = next;
145
+ if (reopening) { agent.startedAt = timestamp; agent.finishedAt = ''; }
146
+ if (agent.status === 'running' && !agent.startedAt) agent.startedAt = timestamp;
147
+ if (TERMINAL.has(agent.status) || run.status !== 'running') {
148
+ // Late snapshots describe the same stopped interval; only a new turn resets it.
149
+ const end = wasTerminal || run.status !== 'running' || !Number.isFinite(at) ? previousEnd : at;
150
+ if (Number.isFinite(end)) agent.finishedAt = new Date(end).toISOString();
151
+ }
152
+ if (inner) {
153
+ const boundThread = inner.detail?.threadId || params.threadId || params.thread?.id;
154
+ if (boundThread) agent.threadId = clean(boundThread, sanitize, 160);
155
+ if (params.thread?.model) agent.model = clean(params.thread.model, sanitize, 160);
156
+ const mapped = Transcript.mapAgentEventToActivity(inner, { locale: options.locale });
157
+ const activity = Activity.capture({ ...mapped, technicalDetail: mapped?.technicalDetail || inner }, sanitize);
158
+ if (mapped?.visible && mapped.kind !== 'technical' && (!mapped.streamRole || mapped.streamRole === 'assistant')) {
159
+ const itemId = params.item?.id || params.itemId || inner.detail?.itemId;
160
+ const turnId = params.turnId || inner.detail?.turnId || '';
161
+ append(agent, { ...mapped, timestamp, activity,
162
+ streamKey: mapped.kind === 'stream' ? turnId + ':' + (itemId || mapped.streamKey || 'assistant') : '' }, sanitize);
163
+ }
164
+ }
165
+ if (TERMINAL.has(agent.status)) {
166
+ for (const event of agent.events) if (event.kind === 'stream' && event.status === 'running') event.status = 'completed';
167
+ addAnswer(agent, detail.summary, timestamp, sanitize);
168
+ if (detail.reason) append(agent, { title: clean(detail.reason, sanitize, 1200), status: 'warning', timestamp,
169
+ activity: { kind: 'notice', id: key + ':failure', state: agent.status === 'failed' ? 'failed' : 'warning' } }, sanitize);
170
+ }
171
+ return true;
172
+ }
173
+ return { normalize, ingest, effectiveStatus, elapsedMs };
174
+ });
@@ -130,6 +130,91 @@
130
130
  };
131
131
  }
132
132
 
133
+ // File creation has its own inverse even when text edits use Reviewing.
134
+ // Store post-images, never infer an empty pre-image for a missing file.
135
+ function buildCreatedFileUndoCheckpoint(project, appliedOperations, previous = {}) {
136
+ const originalPaths = new Set((project?.files || []).map(file => file?.path));
137
+ const priorFiles = filesListToMap(previous.undoBaseFiles);
138
+ const created = new Map();
139
+ for (const operation of previous.undoOperations || []) {
140
+ const proof = operation?.undoCreatedFile;
141
+ if (operation?.type !== 'delete' || proof?.v !== 1) continue;
142
+ if (proof.kind === 'text' && priorFiles.has(operation.path)) {
143
+ created.set(operation.path, { kind: 'text', content: priorFiles.get(operation.path) });
144
+ } else if (proof.kind === 'binary' && /^[a-f0-9]{64}$/i.test(proof.sha256 || '')) {
145
+ created.set(operation.path, { kind: 'binary', sha256: proof.sha256.toLowerCase() });
146
+ }
147
+ }
148
+ for (const operation of appliedOperations || []) {
149
+ if (!operation?.path) continue;
150
+ const path = operation.path;
151
+ if (operation.type === 'create' || operation.type === 'binary-create') {
152
+ if (originalPaths.has(path) && !created.has(path)) continue;
153
+ if (operation.type === 'create' && typeof operation.content === 'string') {
154
+ created.set(path, { kind: 'text', content: typeof operation.verifiedContent === 'string'
155
+ ? operation.verifiedContent : operation.content });
156
+ } else {
157
+ const hash = operation.sha256 || operation.assetRef?.sha256;
158
+ if (operation.previousExists !== true && /^[a-f0-9]{64}$/i.test(hash || '')) {
159
+ created.set(path, { kind: 'binary', sha256: hash.toLowerCase() });
160
+ }
161
+ }
162
+ } else if (operation.type === 'edit' && created.get(path)?.kind === 'text') {
163
+ const files = new Map([[path, created.get(path).content]]);
164
+ applyOperationToFiles(files, operation);
165
+ created.set(path, { kind: 'text', content: files.get(path) });
166
+ } else if (['delete', 'rename', 'move', 'overwrite-binary'].includes(operation.type)) {
167
+ // Existing rename/overwrite recovery retains ownership of these cases.
168
+ created.delete(path);
169
+ if (operation.to) created.delete(operation.to);
170
+ }
171
+ }
172
+ const undoBaseFiles = [], undoOperations = [];
173
+ for (const [path, proof] of Array.from(created).reverse()) {
174
+ const undoCreatedFile = proof.kind === 'binary'
175
+ ? { v: 1, kind: 'binary', sha256: proof.sha256 } : { v: 1, kind: 'text' };
176
+ undoOperations.push({ ...normalizeUndoOperation({ type: 'delete', path, reason: 'Undo create' }), undoCreatedFile });
177
+ if (proof.kind === 'text') undoBaseFiles.push({ path, content: proof.content });
178
+ }
179
+ return { undoOperations, undoBaseFiles };
180
+ }
181
+
182
+ // Consume only independently verified rollback receipts. Forward writes
183
+ // remain audit evidence; recovery arrays describe only unfinished work.
184
+ function advanceUndoCheckpoint(run = {}, result = {}, verifyText = () => false) {
185
+ const operations = Array.isArray(run?.undoOperations) ? run.undoOperations : [];
186
+ if (!operations.some(operation => operation?.undoCreatedFile?.v === 1)) return run;
187
+ const applied = Array.isArray(result.applied) ? result.applied : [];
188
+ const skipped = Array.isArray(result.skipped) ? result.skipped : [];
189
+ const failed = path => skipped.some(entry => {
190
+ const target = entry?.operation?.path || entry?.trackedChange?.path || entry?.result?.failure?.file;
191
+ return !target || target === path;
192
+ });
193
+ if (result.failure || result.error) return run;
194
+ const textPaths = new Set((run.undoExpectedFiles || [])
195
+ .filter(file => file?.path && typeof file.content === 'string' && !failed(file.path)
196
+ && typeof verifyText === 'function' && verifyText(file) === true)
197
+ .map(file => file.path));
198
+ const deletedPaths = new Set(operations.filter(operation => operation?.type === 'delete'
199
+ && operation.undoCreatedFile?.v === 1 && !failed(operation.path)
200
+ && applied.some(entry => entry?.operation?.type === 'delete' && entry.operation.path === operation.path
201
+ && JSON.stringify(entry.operation.undoCreatedFile) === JSON.stringify(operation.undoCreatedFile)
202
+ && entry.result?.ok === true && entry.result.verified === true
203
+ && entry.result.verification === 'overleaf-zip')).map(operation => operation.path));
204
+ if (!textPaths.size && !deletedPaths.size) return run;
205
+ const pending = operations.filter(operation => !(operation?.type === 'edit' && textPaths.has(operation.path))
206
+ && !(operation?.type === 'delete' && operation.undoCreatedFile?.v === 1 && deletedPaths.has(operation.path)));
207
+ const needed = new Set(pending.flatMap(operation => [operation?.path, operation?.to]).filter(Boolean));
208
+ return { ...run,
209
+ undoOperations: pending,
210
+ undoBaseFiles: (run.undoBaseFiles || []).filter(file => needed.has(file?.path)
211
+ || (!textPaths.has(file?.path) && !deletedPaths.has(file?.path))),
212
+ undoExpectedFiles: (run.undoExpectedFiles || []).filter(file => !textPaths.has(file?.path)),
213
+ undoTrackedChanges: (run.undoTrackedChanges || []).filter(ref => !textPaths.has(ref?.path)),
214
+ trackedChangeCaptures: (run.trackedChangeCaptures || []).filter(capture => !textPaths.has(capture?.path))
215
+ };
216
+ }
217
+
133
218
  function buildSnapshotRestoreUndo(run = {}) {
134
219
  const undoOperations = Array.isArray(run.undoOperations) ? run.undoOperations : [];
135
220
  const originalByPath = buildOriginalFilesForSnapshotUndo(run, undoOperations);
@@ -370,6 +455,8 @@
370
455
 
371
456
  return {
372
457
  buildUndoCheckpoint,
458
+ buildCreatedFileUndoCheckpoint,
459
+ advanceUndoCheckpoint,
373
460
  buildExpectedFilesAfterOperations,
374
461
  buildUndoOperations,
375
462
  buildSnapshotRestoreUndo