codex-overleaf-link 2.4.1 → 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 (324) hide show
  1. package/README.md +272 -314
  2. package/README.zh-CN.md +287 -329
  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 +507 -507
  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 +8330 -1349
  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 +48 -121
  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 +10 -1
  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 +186 -154
  42. package/extension/src/content/selectionContextView.js +300 -0
  43. package/extension/src/content/sessionPersistence.js +6 -1
  44. package/extension/src/content/settingsPanel.js +77 -52
  45. package/extension/src/content/settingsWorkbench.js +374 -0
  46. package/extension/src/content/sharedSessionViewSync.js +72 -0
  47. package/extension/src/content/subagentActivityView.js +195 -0
  48. package/extension/src/content/trackedChangeCaptureController.js +7 -3
  49. package/extension/src/content/updateNotice.js +121 -50
  50. package/extension/src/content/writebackController.js +257 -0
  51. package/extension/src/content/writebackOrchestrator.js +146 -141
  52. package/extension/src/content/writebackPlan.js +231 -0
  53. package/extension/src/content/writebackRecovery.js +122 -0
  54. package/extension/src/content/writingStyleSettings.js +576 -0
  55. package/extension/src/content/writtenChangesView.js +152 -0
  56. package/extension/src/page/binaryAssetUploader.js +97 -19
  57. package/extension/src/page/overleafProjectSnapshot.js +1 -0
  58. package/extension/src/page/referenceProjects.js +148 -0
  59. package/extension/src/page/saveState.js +14 -2
  60. package/extension/src/page/snapshotRouter.js +44 -13
  61. package/extension/src/page/textCoordinates.js +102 -0
  62. package/extension/src/page/textFileCreator.js +350 -59
  63. package/extension/src/page/trackedChangeCapture.js +42 -56
  64. package/extension/src/page/trackedChangeOwnership.js +198 -0
  65. package/extension/src/page/trackedChangeReplay.js +164 -0
  66. package/extension/src/page/trackedChangesLifecycle.js +135 -149
  67. package/extension/src/page/treeOperations.js +26 -2
  68. package/extension/src/page/writebackReceiptJournal.js +112 -0
  69. package/extension/src/page/writebackRouter.js +175 -135
  70. package/extension/src/pageBridge.js +56 -101
  71. package/extension/src/popup.js +203 -59
  72. package/extension/src/shared/agentTranscript.js +18 -4
  73. package/extension/src/shared/auditRecords.js +71 -0
  74. package/extension/src/shared/changeHistoryModel.js +94 -0
  75. package/extension/src/shared/compatibility.js +1 -1
  76. package/extension/src/shared/compileAdapter.js +42 -0
  77. package/extension/src/shared/failureReasons.js +20 -0
  78. package/extension/src/shared/globalPreferences.js +1 -1
  79. package/extension/src/shared/i18n.js +93 -25
  80. package/extension/src/shared/managedUpdateProjection.js +6 -3
  81. package/extension/src/shared/pageRpcContract.js +7 -1
  82. package/extension/src/shared/providerProfiles.js +109 -0
  83. package/extension/src/shared/runActivityModel.js +361 -0
  84. package/extension/src/shared/runExecutionSnapshot.js +8 -2
  85. package/extension/src/shared/runExecutionSnapshotCodec.js +16 -4
  86. package/extension/src/shared/scopedPersistenceBrowserAdapter.js +6 -3
  87. package/extension/src/shared/selectionContext.js +28 -0
  88. package/extension/src/shared/sessionState.js +97 -6
  89. package/extension/src/shared/sharedSessionBridge.js +288 -0
  90. package/extension/src/shared/storageDb.js +22 -55
  91. package/extension/src/shared/storageMigration.js +3 -0
  92. package/extension/src/shared/storageRunActions.js +10 -4
  93. package/extension/src/shared/storageValuePruning.js +40 -0
  94. package/extension/src/shared/subagentActivityModel.js +174 -0
  95. package/extension/src/shared/undoOperations.js +87 -0
  96. package/extension/src/shared/updateConsent.js +37 -8
  97. package/extension/src/shared/writebackIntent.js +62 -0
  98. package/extension/src/shared/writebackSettlement.js +29 -10
  99. package/extension/src/shared/writingStyle.js +33 -0
  100. package/extension/styles/panel.css +1972 -384
  101. package/extension/styles/popup.css +110 -0
  102. package/native-host/src/anthropicBridgeRequest.js +2 -1
  103. package/native-host/src/codexModelRecovery.js +107 -0
  104. package/native-host/src/codexPromptAssembly.js +2 -0
  105. package/native-host/src/codexProviderLaunch.js +3 -3
  106. package/native-host/src/codexRuntimeIdentity.js +1 -0
  107. package/native-host/src/codexSessionRunner.js +106 -140
  108. package/native-host/src/codexSessionTiming.js +3 -0
  109. package/native-host/src/managedInstall.js +5 -4
  110. package/native-host/src/nativeEnvironment.js +70 -0
  111. package/native-host/src/nativeQuotas.js +15 -8
  112. package/native-host/src/overleafWorkspaceRules.js +16 -0
  113. package/native-host/src/processStopBarrier.js +80 -0
  114. package/native-host/src/providerModelCatalog.js +4 -3
  115. package/native-host/src/providerProfile.js +13 -1
  116. package/native-host/src/providerReasoning.js +9 -5
  117. package/native-host/src/providerStore.js +4 -0
  118. package/native-host/src/releaseTransport.js +14 -5
  119. package/native-host/src/selectionScope.js +58 -0
  120. package/native-host/src/skills/parallel-subagents/SKILL.md +31 -3
  121. package/native-host/src/skills/writing-style-builder/SKILL.md +146 -0
  122. package/native-host/src/subagentBroker.js +102 -98
  123. package/native-host/src/subagentTelemetry.js +316 -0
  124. package/native-host/src/subagentWorkspace.js +103 -0
  125. package/native-host/src/subagentWorkspacePath.js +31 -0
  126. package/native-host/src/taskRunnerRuntime.js +55 -5
  127. package/native-host/src/turnAttachments.js +113 -0
  128. package/native-host/src/updateManager.js +122 -12
  129. package/native-host/src/updateNetworkControl.js +75 -0
  130. package/native-host/src/updateTrust.js +21 -2
  131. package/native-host/src/vendor/pdfjs/LICENSE +177 -0
  132. package/native-host/src/vendor/pdfjs/SOURCE.txt +3 -0
  133. package/native-host/src/vendor/pdfjs/cmaps/78-EUC-H.bcmap +0 -0
  134. package/native-host/src/vendor/pdfjs/cmaps/78-EUC-V.bcmap +0 -0
  135. package/native-host/src/vendor/pdfjs/cmaps/78-H.bcmap +0 -0
  136. package/native-host/src/vendor/pdfjs/cmaps/78-RKSJ-H.bcmap +0 -0
  137. package/native-host/src/vendor/pdfjs/cmaps/78-RKSJ-V.bcmap +0 -0
  138. package/native-host/src/vendor/pdfjs/cmaps/78-V.bcmap +0 -0
  139. package/native-host/src/vendor/pdfjs/cmaps/78ms-RKSJ-H.bcmap +0 -0
  140. package/native-host/src/vendor/pdfjs/cmaps/78ms-RKSJ-V.bcmap +0 -0
  141. package/native-host/src/vendor/pdfjs/cmaps/83pv-RKSJ-H.bcmap +0 -0
  142. package/native-host/src/vendor/pdfjs/cmaps/90ms-RKSJ-H.bcmap +0 -0
  143. package/native-host/src/vendor/pdfjs/cmaps/90ms-RKSJ-V.bcmap +0 -0
  144. package/native-host/src/vendor/pdfjs/cmaps/90msp-RKSJ-H.bcmap +0 -0
  145. package/native-host/src/vendor/pdfjs/cmaps/90msp-RKSJ-V.bcmap +0 -0
  146. package/native-host/src/vendor/pdfjs/cmaps/90pv-RKSJ-H.bcmap +0 -0
  147. package/native-host/src/vendor/pdfjs/cmaps/90pv-RKSJ-V.bcmap +0 -0
  148. package/native-host/src/vendor/pdfjs/cmaps/Add-H.bcmap +0 -0
  149. package/native-host/src/vendor/pdfjs/cmaps/Add-RKSJ-H.bcmap +0 -0
  150. package/native-host/src/vendor/pdfjs/cmaps/Add-RKSJ-V.bcmap +0 -0
  151. package/native-host/src/vendor/pdfjs/cmaps/Add-V.bcmap +0 -0
  152. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-0.bcmap +0 -0
  153. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-1.bcmap +0 -0
  154. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-2.bcmap +0 -0
  155. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-3.bcmap +0 -0
  156. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-4.bcmap +0 -0
  157. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-5.bcmap +0 -0
  158. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-6.bcmap +0 -0
  159. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
  160. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-0.bcmap +0 -0
  161. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-1.bcmap +0 -0
  162. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-2.bcmap +0 -0
  163. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-3.bcmap +0 -0
  164. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-4.bcmap +0 -0
  165. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-5.bcmap +0 -0
  166. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
  167. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-0.bcmap +0 -0
  168. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-1.bcmap +0 -0
  169. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-2.bcmap +0 -0
  170. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-3.bcmap +0 -0
  171. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-4.bcmap +0 -0
  172. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-5.bcmap +0 -0
  173. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-6.bcmap +0 -0
  174. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
  175. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-0.bcmap +0 -0
  176. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-1.bcmap +0 -0
  177. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-2.bcmap +0 -0
  178. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
  179. package/native-host/src/vendor/pdfjs/cmaps/B5-H.bcmap +0 -0
  180. package/native-host/src/vendor/pdfjs/cmaps/B5-V.bcmap +0 -0
  181. package/native-host/src/vendor/pdfjs/cmaps/B5pc-H.bcmap +0 -0
  182. package/native-host/src/vendor/pdfjs/cmaps/B5pc-V.bcmap +0 -0
  183. package/native-host/src/vendor/pdfjs/cmaps/CNS-EUC-H.bcmap +0 -0
  184. package/native-host/src/vendor/pdfjs/cmaps/CNS-EUC-V.bcmap +0 -0
  185. package/native-host/src/vendor/pdfjs/cmaps/CNS1-H.bcmap +0 -0
  186. package/native-host/src/vendor/pdfjs/cmaps/CNS1-V.bcmap +0 -0
  187. package/native-host/src/vendor/pdfjs/cmaps/CNS2-H.bcmap +0 -0
  188. package/native-host/src/vendor/pdfjs/cmaps/CNS2-V.bcmap +3 -0
  189. package/native-host/src/vendor/pdfjs/cmaps/ETHK-B5-H.bcmap +0 -0
  190. package/native-host/src/vendor/pdfjs/cmaps/ETHK-B5-V.bcmap +0 -0
  191. package/native-host/src/vendor/pdfjs/cmaps/ETen-B5-H.bcmap +0 -0
  192. package/native-host/src/vendor/pdfjs/cmaps/ETen-B5-V.bcmap +0 -0
  193. package/native-host/src/vendor/pdfjs/cmaps/ETenms-B5-H.bcmap +3 -0
  194. package/native-host/src/vendor/pdfjs/cmaps/ETenms-B5-V.bcmap +0 -0
  195. package/native-host/src/vendor/pdfjs/cmaps/EUC-H.bcmap +0 -0
  196. package/native-host/src/vendor/pdfjs/cmaps/EUC-V.bcmap +0 -0
  197. package/native-host/src/vendor/pdfjs/cmaps/Ext-H.bcmap +0 -0
  198. package/native-host/src/vendor/pdfjs/cmaps/Ext-RKSJ-H.bcmap +0 -0
  199. package/native-host/src/vendor/pdfjs/cmaps/Ext-RKSJ-V.bcmap +0 -0
  200. package/native-host/src/vendor/pdfjs/cmaps/Ext-V.bcmap +0 -0
  201. package/native-host/src/vendor/pdfjs/cmaps/GB-EUC-H.bcmap +0 -0
  202. package/native-host/src/vendor/pdfjs/cmaps/GB-EUC-V.bcmap +0 -0
  203. package/native-host/src/vendor/pdfjs/cmaps/GB-H.bcmap +4 -0
  204. package/native-host/src/vendor/pdfjs/cmaps/GB-V.bcmap +0 -0
  205. package/native-host/src/vendor/pdfjs/cmaps/GBK-EUC-H.bcmap +0 -0
  206. package/native-host/src/vendor/pdfjs/cmaps/GBK-EUC-V.bcmap +0 -0
  207. package/native-host/src/vendor/pdfjs/cmaps/GBK2K-H.bcmap +0 -0
  208. package/native-host/src/vendor/pdfjs/cmaps/GBK2K-V.bcmap +0 -0
  209. package/native-host/src/vendor/pdfjs/cmaps/GBKp-EUC-H.bcmap +0 -0
  210. package/native-host/src/vendor/pdfjs/cmaps/GBKp-EUC-V.bcmap +0 -0
  211. package/native-host/src/vendor/pdfjs/cmaps/GBT-EUC-H.bcmap +0 -0
  212. package/native-host/src/vendor/pdfjs/cmaps/GBT-EUC-V.bcmap +0 -0
  213. package/native-host/src/vendor/pdfjs/cmaps/GBT-H.bcmap +0 -0
  214. package/native-host/src/vendor/pdfjs/cmaps/GBT-V.bcmap +0 -0
  215. package/native-host/src/vendor/pdfjs/cmaps/GBTpc-EUC-H.bcmap +0 -0
  216. package/native-host/src/vendor/pdfjs/cmaps/GBTpc-EUC-V.bcmap +0 -0
  217. package/native-host/src/vendor/pdfjs/cmaps/GBpc-EUC-H.bcmap +0 -0
  218. package/native-host/src/vendor/pdfjs/cmaps/GBpc-EUC-V.bcmap +0 -0
  219. package/native-host/src/vendor/pdfjs/cmaps/H.bcmap +0 -0
  220. package/native-host/src/vendor/pdfjs/cmaps/HKdla-B5-H.bcmap +0 -0
  221. package/native-host/src/vendor/pdfjs/cmaps/HKdla-B5-V.bcmap +0 -0
  222. package/native-host/src/vendor/pdfjs/cmaps/HKdlb-B5-H.bcmap +0 -0
  223. package/native-host/src/vendor/pdfjs/cmaps/HKdlb-B5-V.bcmap +0 -0
  224. package/native-host/src/vendor/pdfjs/cmaps/HKgccs-B5-H.bcmap +0 -0
  225. package/native-host/src/vendor/pdfjs/cmaps/HKgccs-B5-V.bcmap +0 -0
  226. package/native-host/src/vendor/pdfjs/cmaps/HKm314-B5-H.bcmap +0 -0
  227. package/native-host/src/vendor/pdfjs/cmaps/HKm314-B5-V.bcmap +0 -0
  228. package/native-host/src/vendor/pdfjs/cmaps/HKm471-B5-H.bcmap +0 -0
  229. package/native-host/src/vendor/pdfjs/cmaps/HKm471-B5-V.bcmap +0 -0
  230. package/native-host/src/vendor/pdfjs/cmaps/HKscs-B5-H.bcmap +0 -0
  231. package/native-host/src/vendor/pdfjs/cmaps/HKscs-B5-V.bcmap +0 -0
  232. package/native-host/src/vendor/pdfjs/cmaps/Hankaku.bcmap +0 -0
  233. package/native-host/src/vendor/pdfjs/cmaps/Hiragana.bcmap +0 -0
  234. package/native-host/src/vendor/pdfjs/cmaps/KSC-EUC-H.bcmap +0 -0
  235. package/native-host/src/vendor/pdfjs/cmaps/KSC-EUC-V.bcmap +0 -0
  236. package/native-host/src/vendor/pdfjs/cmaps/KSC-H.bcmap +0 -0
  237. package/native-host/src/vendor/pdfjs/cmaps/KSC-Johab-H.bcmap +0 -0
  238. package/native-host/src/vendor/pdfjs/cmaps/KSC-Johab-V.bcmap +0 -0
  239. package/native-host/src/vendor/pdfjs/cmaps/KSC-V.bcmap +0 -0
  240. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-H.bcmap +0 -0
  241. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
  242. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
  243. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-V.bcmap +0 -0
  244. package/native-host/src/vendor/pdfjs/cmaps/KSCpc-EUC-H.bcmap +0 -0
  245. package/native-host/src/vendor/pdfjs/cmaps/KSCpc-EUC-V.bcmap +0 -0
  246. package/native-host/src/vendor/pdfjs/cmaps/Katakana.bcmap +0 -0
  247. package/native-host/src/vendor/pdfjs/cmaps/LICENSE +36 -0
  248. package/native-host/src/vendor/pdfjs/cmaps/NWP-H.bcmap +0 -0
  249. package/native-host/src/vendor/pdfjs/cmaps/NWP-V.bcmap +0 -0
  250. package/native-host/src/vendor/pdfjs/cmaps/RKSJ-H.bcmap +0 -0
  251. package/native-host/src/vendor/pdfjs/cmaps/RKSJ-V.bcmap +0 -0
  252. package/native-host/src/vendor/pdfjs/cmaps/Roman.bcmap +0 -0
  253. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UCS2-H.bcmap +0 -0
  254. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UCS2-V.bcmap +0 -0
  255. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF16-H.bcmap +0 -0
  256. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF16-V.bcmap +0 -0
  257. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF32-H.bcmap +0 -0
  258. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF32-V.bcmap +0 -0
  259. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF8-H.bcmap +0 -0
  260. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF8-V.bcmap +0 -0
  261. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UCS2-H.bcmap +0 -0
  262. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UCS2-V.bcmap +0 -0
  263. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF16-H.bcmap +0 -0
  264. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF16-V.bcmap +0 -0
  265. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF32-H.bcmap +0 -0
  266. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF32-V.bcmap +0 -0
  267. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF8-H.bcmap +0 -0
  268. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF8-V.bcmap +0 -0
  269. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-H.bcmap +0 -0
  270. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
  271. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
  272. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-V.bcmap +0 -0
  273. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF16-H.bcmap +0 -0
  274. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF16-V.bcmap +0 -0
  275. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF32-H.bcmap +0 -0
  276. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF32-V.bcmap +0 -0
  277. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF8-H.bcmap +0 -0
  278. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF8-V.bcmap +0 -0
  279. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
  280. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
  281. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
  282. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
  283. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
  284. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
  285. package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
  286. package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
  287. package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
  288. package/native-host/src/vendor/pdfjs/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
  289. package/native-host/src/vendor/pdfjs/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
  290. package/native-host/src/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
  291. package/native-host/src/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
  292. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UCS2-H.bcmap +0 -0
  293. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UCS2-V.bcmap +0 -0
  294. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF16-H.bcmap +0 -0
  295. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF16-V.bcmap +0 -0
  296. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF32-H.bcmap +0 -0
  297. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF32-V.bcmap +0 -0
  298. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF8-H.bcmap +0 -0
  299. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF8-V.bcmap +0 -0
  300. package/native-host/src/vendor/pdfjs/cmaps/V.bcmap +0 -0
  301. package/native-host/src/vendor/pdfjs/cmaps/WP-Symbol.bcmap +0 -0
  302. package/native-host/src/vendor/pdfjs/pdf.mjs +26740 -0
  303. package/native-host/src/vendor/pdfjs/pdf.worker.mjs +62201 -0
  304. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitDingbats.pfb +0 -0
  305. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixed.pfb +0 -0
  306. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedBold.pfb +0 -0
  307. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
  308. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedItalic.pfb +0 -0
  309. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerif.pfb +0 -0
  310. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifBold.pfb +0 -0
  311. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
  312. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifItalic.pfb +0 -0
  313. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSymbol.pfb +0 -0
  314. package/native-host/src/vendor/pdfjs/standard_fonts/LICENSE_FOXIT +27 -0
  315. package/native-host/src/vendor/pdfjs/standard_fonts/LICENSE_LIBERATION +102 -0
  316. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Bold.ttf +0 -0
  317. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
  318. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Italic.ttf +0 -0
  319. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Regular.ttf +0 -0
  320. package/native-host/src/writingStyleEvidence.js +102 -0
  321. package/native-host/src/writingStylePdfWorker.js +35 -0
  322. package/native-host/src/writingStyleProfile.js +165 -0
  323. package/native-host/src/writingStyleRuntime.js +447 -0
  324. 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,
@@ -1355,5 +1322,5 @@
1355
1322
  filterRecentProjectsAcrossAccount: filterRecentProjectsAcrossAccount,
1356
1323
  derivePrimaryStatusBadge: derivePrimaryStatusBadge,
1357
1324
  getAllSessions: getAllSessions
1358
- };
1325
+ });
1359
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
 
@@ -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
@@ -13,6 +13,7 @@
13
13
  'idle',
14
14
  'checking',
15
15
  'update_available',
16
+ 'manual_install_required',
16
17
  'downloading',
17
18
  'staged',
18
19
  'waiting_for_idle',
@@ -41,6 +42,7 @@
41
42
  idle: { value: 0, determinate: true, phase: 'idle' },
42
43
  checking: { value: 0, determinate: false, phase: 'checking' },
43
44
  update_available: { value: 0, determinate: true, phase: 'available' },
45
+ manual_install_required: { value: 0, determinate: true, phase: 'manual' },
44
46
  downloading: { value: 35, determinate: false, phase: 'downloading' },
45
47
  staged: { value: 65, determinate: true, phase: 'staged' },
46
48
  waiting_for_idle: { value: 65, determinate: true, phase: 'waiting' },
@@ -66,6 +68,9 @@
66
68
  blocker: blockers[0] || '',
67
69
  blockers,
68
70
  transactionId: safeId(value.transactionId),
71
+ operationId: safeId(value.operationId),
72
+ cancelRequested: value.cancelRequested === true,
73
+ recoveryPending: value.recoveryPending === true,
69
74
  initiatedBy: ['automatic', 'manual'].includes(value.initiatedBy) ? value.initiatedBy : '',
70
75
  lastCheckedAt: finiteNumber(value.lastCheckedAt),
71
76
  stagedAt: finiteNumber(value.stagedAt),
@@ -74,10 +79,22 @@
74
79
  heartbeatAt: finiteNumber(value.heartbeatAt),
75
80
  postponeUntil: finiteNumber(value.postponeUntil),
76
81
  code: safeToken(value.code),
77
- message: String(value.message || '').replace(/\s+/g, ' ').trim().slice(0, 300)
82
+ message: String(value.message || '').replace(/\s+/g, ' ').trim().slice(0, 300),
83
+ manualReason: normalizeManualReason(value.manualReason)
78
84
  };
79
85
  }
80
86
 
87
+ // Signed per-locale reason a release needs a one-time reinstall.
88
+ function normalizeManualReason(value) {
89
+ if (!value || typeof value !== 'object') return {};
90
+ const out = {};
91
+ for (const locale of ['en', 'zh']) {
92
+ const text = String(value[locale] || '').replace(/\s+/g, ' ').trim().slice(0, 400);
93
+ if (text) out[locale] = text;
94
+ }
95
+ return out;
96
+ }
97
+
81
98
  function normalizeConsentState(value = {}) {
82
99
  return {
83
100
  schemaVersion: 1,
@@ -106,6 +123,13 @@
106
123
  consent.snoozedUntil > now;
107
124
  const execution = EXECUTION_STATES.has(state.state);
108
125
  const available = state.state === 'update_available' && newer;
126
+ // A newer release that only a reinstall can apply. It is shown even after
127
+ // an automatic check, because no Update now button can ever resolve it.
128
+ // Compare with the running version: after the reinstall the stored state
129
+ // still names the old one, and the notice must clear by itself.
130
+ const runningVersion = safeVersion(options.currentVersion) || state.currentVersion;
131
+ const manualInstall = state.state === 'manual_install_required'
132
+ && compareStableVersions(state.latestVersion, runningVersion) > 0;
109
133
  const progress = getProgressModel(state);
110
134
  const quietFailure = state.state === 'failed' &&
111
135
  state.initiatedBy !== 'manual' &&
@@ -124,16 +148,21 @@
124
148
  },
125
149
  progress,
126
150
  available,
151
+ manualInstall,
127
152
  snoozed,
128
153
  execution,
129
- showPanel: (available && !snoozed) || execution || state.state === 'rolled_back' ||
130
- visibleFailure,
131
- badge: getBadge(state, { available, snoozed }),
154
+ showPanel: state.cancelRequested || state.recoveryPending
155
+ || (state.state === 'checking' && state.initiatedBy === 'manual')
156
+ || ((available || manualInstall) && !snoozed) || execution || state.state === 'rolled_back' || visibleFailure,
157
+ badge: getBadge(state, { available: available || manualInstall, snoozed }),
132
158
  actions: {
133
- check: ['idle', 'committed', 'rolled_back', 'failed'].includes(state.state),
134
- install: available,
135
- later: available || ['staged', 'waiting_for_idle'].includes(state.state),
136
- retry: ['failed', 'rolled_back'].includes(state.state)
159
+ check: !state.cancelRequested && !state.recoveryPending && ['idle', 'committed', 'rolled_back', 'failed', 'manual_install_required'].includes(state.state),
160
+ copyInstall: manualInstall,
161
+ install: available && !state.cancelRequested && !state.recoveryPending,
162
+ later: !state.recoveryPending && (available || manualInstall || ['staged', 'waiting_for_idle'].includes(state.state)),
163
+ cancel: !state.recoveryPending && (state.cancelRequested || ['checking', 'downloading', 'staged', 'waiting_for_idle'].includes(state.state)),
164
+ recover: state.recoveryPending,
165
+ retry: !state.cancelRequested && !state.recoveryPending && ['failed', 'rolled_back'].includes(state.state)
137
166
  }
138
167
  };
139
168
  }