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
@@ -17,6 +17,7 @@
17
17
  ? Math.max(0, Number(deps.writebackOpenSettleMs))
18
18
  : 1200;
19
19
  const diagnosticsRevision = String(deps.diagnosticsRevision || '');
20
+ const now = deps.now || Date.now;
20
21
  // Cross-world cancel signal reader. Returns the current page-bridge
21
22
  // sequence number, which monotonically increments when content-side
22
23
  // calls pageBridge.cancelActiveWrite. applyOperationsCore captures the
@@ -269,6 +270,11 @@
269
270
  fallbackUserMessage: 'The edit anchor no longer matches current Overleaf content.',
270
271
  fallbackNextAction: 'Rerun the task against the current document.'
271
272
  },
273
+ write_operation_failed: {
274
+ stage: 'write', severity: 'error', defaultRetryable: true,
275
+ fallbackUserMessage: 'Editor write call failed.',
276
+ fallbackNextAction: 'Retry after the editor is stable.'
277
+ },
272
278
  write_observed_mismatch: {
273
279
  stage: 'verify', severity: 'error', defaultRetryable: false,
274
280
  fallbackUserMessage: 'Codex attempted to write, but the content read back from Overleaf did not match the approved change.',
@@ -398,7 +404,8 @@
398
404
  for (let attempt = 0; attempt < 2; attempt++) {
399
405
  if (!isEditingConfirmedForNoTraceUndo(getReviewingState({}))) {
400
406
  toggle = await setReviewingEnabled(false, { waitMs: 1800 });
401
- if (!toggle.ok) return toggle;
407
+ if (!toggle.ok && (!['editing_not_confirmed', 'reviewing_disable_failed'].includes(toggle.code)
408
+ || !isEditingConfirmedForNoTraceUndo(getReviewingState({})))) return toggle;
402
409
  changed = changed || toggle.changed === true;
403
410
  }
404
411
  await delay(180);
@@ -447,20 +454,8 @@
447
454
  document: window.document,
448
455
  treeOperations
449
456
  });
450
- // Cross-world cancel baseline. The user clicks cancel during writeback →
451
- // content-side calls pageBridge.cancelActiveWrite → the sequence number
452
- // bumps. Two layers of responsiveness:
453
- // 1. Between-ops check — short-circuits the next iteration so the
454
- // remaining ops never start.
455
- // 2. Race the in-flight op against a cancellation poller (50ms
456
- // interval) so a click DURING a slow op (e.g. inside a 5s
457
- // waitForActiveFile poll) is observed within ~50ms instead of
458
- // having to wait out the op's internal timeout. The op promise
459
- // keeps running in the page world after the race resolves — its
460
- // eventual result is ignored. This is "user-perceived instant
461
- // cancel": the spinner stops, the run settles to cancelled, and
462
- // any DOM mutation already in flight on the op cannot be undone
463
- // from here anyway.
457
+ // Preserve the actual result of an in-flight operation so its readback and
458
+ // undo evidence survive cancellation. The checkpoints stop undispatched work.
464
459
  const cancelBaselineSequence = readWriteCancellationSequence();
465
460
  const cancelledSkipResult = {
466
461
  ok: false,
@@ -477,58 +472,34 @@
477
472
  changedDocument: false
478
473
  }
479
474
  };
480
- const cancelledInFlightResult = {
481
- ...cancelledSkipResult,
482
- reason: 'The Codex run was cancelled while an Overleaf write operation was already in flight. The editor may have changed; review the current file before starting a new run.',
483
- failure: {
484
- ...cancelledSkipResult.failure,
485
- severity: 'warning',
486
- userMessage: 'The Codex run was cancelled during an in-flight write. The editor may already contain part of that write.',
487
- nextAction: 'Review the current Overleaf file before starting a new run.',
488
- changedDocument: true
475
+ const createCandidates = operations.map(normalizeOperationPaths).filter(operation => operation.type === 'create'
476
+ && operations.filter(other => [other.path, other.to].includes(operation.path)).length === 1);
477
+ const createBatch = createCandidates.length && typeof deps.beginTextCreateBatch === 'function'
478
+ ? await deps.beginTextCreateBatch(createCandidates, { isCurrent: () =>
479
+ treeOperations.getProjectId?.() === runProjectId && readWriteCancellationSequence() === cancelBaselineSequence }) : null;
480
+ const deferredCreates = [];
481
+ const reopenQueue = [];
482
+ const deadlineFailure = () => Number.isFinite(options.deadlineAt) && now() >= options.deadlineAt
483
+ ? { ok: false, code: 'writeback_deadline_exceeded', changedDocument: false,
484
+ reason: 'The undo time budget expired before this operation could start.' } : null;
485
+ const editOptions = () => ({ baseFileLookup, runProjectId,
486
+ recheckWriteProject: writeGuardSurface ? () => {
487
+ const expired = deadlineFailure();
488
+ return expired ? { applied: [], skipped: [{ operation: {}, result: expired }] }
489
+ : writeGuardSurface.runWriteGuard({ runProjectId });
490
+ } : null,
491
+ trackReviewingChanges: options.trackReviewingChanges === true, noTraceUndo: options.noTraceUndo === true });
492
+ const record = (operation, result) => {
493
+ if (result.trackedChangeCapture) trackedChangeCaptures.push(result.trackedChangeCapture);
494
+ if (operation.type === 'edit' && result.ok && Array.isArray(result.trackedChanges)) {
495
+ trackedChanges.push(...result.trackedChanges);
489
496
  }
497
+ (result.ok ? applied : skipped).push({ operation, result });
498
+ options.onOperationResult?.({ operation, result });
490
499
  };
491
- // 50ms-poller racer using recursive setTimeout. setInterval is NOT
492
- // exposed in the test VM context that hosts pageBridge (only setTimeout /
493
- // clearTimeout are wired), so this implementation must avoid it. Each
494
- // tick re-schedules itself only while the racer has not resolved;
495
- // dispose() flips a flag so any tick that fires after dispose is a no-op.
496
- // Resolves the first time the cancellation sequence bumps past baseline.
497
- function createCancellationRacer() {
498
- let resolved = false;
499
- let resolveFn;
500
- const promise = new Promise(resolve => { resolveFn = resolve; });
501
- let timer = null;
502
- function tick() {
503
- if (resolved) return;
504
- if (readWriteCancellationSequence() !== cancelBaselineSequence) {
505
- resolved = true;
506
- resolveFn();
507
- return;
508
- }
509
- timer = window.setTimeout(tick, 50);
510
- }
511
- timer = window.setTimeout(tick, 50);
512
- return {
513
- promise,
514
- dispose() {
515
- resolved = true;
516
- if (timer) window.clearTimeout(timer);
517
- }
518
- };
519
- }
520
- const CANCELLED_RACE_SENTINEL = Symbol('writebackRouter.cancelled');
521
- async function raceOpAgainstCancellation(opPromise) {
522
- // Once an editor operation starts, preserve its actual result and undo
523
- // metadata. The loop's pre-operation cancellation check stops the tail.
524
- return await opPromise;
525
- }
526
500
 
527
501
  for (const rawOperation of operations) {
528
- // Cross-world cancel check. Cheap (synchronous read of a counter),
529
- // runs before the writeGuard re-check so a click-cancel that arrived
530
- // during the previous op's await microtasks short-circuits before we
531
- // burn time on guard / open-file work for the next op.
502
+ // Stop undispatched work when cancellation arrives during an awaited operation.
532
503
  if (readWriteCancellationSequence() !== cancelBaselineSequence) {
533
504
  skipped.push({ operation: normalizeOperationPaths(rawOperation), result: cancelledSkipResult });
534
505
  const remainingForCancel = operations.slice(operations.indexOf(rawOperation) + 1);
@@ -537,16 +508,11 @@
537
508
  }
538
509
  break;
539
510
  }
540
- // Per-op re-check: if a runProjectId was supplied and the page-side
541
- // guard is available, verify the editor still shows the same project
542
- // before committing the next write. Mismatch → push aborted_project_changed
543
- // for THIS op and every remaining op in the queue, then return.
511
+ // Re-check project ownership before this operation and preserve every skipped tail entry.
544
512
  if (runProjectId && writeGuardSurface) {
545
513
  const guardBlock = await writeGuardSurface.runWriteGuard({ runProjectId });
546
514
  if (guardBlock) {
547
- // First push the guard's structured skip for the current op so the
548
- // caller can attribute the abort to a real operation path, then
549
- // pad the remaining ops with the same failure shape.
515
+ // Keep the current path and the remaining operations attributable.
550
516
  const guardFailure = guardBlock.skipped[0].result;
551
517
  skipped.push({ operation: normalizeOperationPaths(rawOperation), result: guardFailure });
552
518
  const remaining = operations.slice(operations.indexOf(rawOperation) + 1);
@@ -557,23 +523,24 @@
557
523
  }
558
524
  }
559
525
  const operation = normalizeOperationPaths(rawOperation);
560
- const pathSafety = validateOperationProjectPaths(operation);
526
+ const pathSafety = deadlineFailure() || validateOperationProjectPaths(operation);
561
527
  if (!pathSafety.ok) {
562
528
  skipped.push({ operation, result: pathSafety });
563
529
  continue;
564
530
  }
565
- let raceResult;
531
+ let result;
566
532
  if (operation.type === 'edit') {
567
- raceResult = await raceOpAgainstCancellation(applyEditOperation(operation, {
568
- baseFileLookup, runProjectId,
569
- recheckWriteProject: writeGuardSurface ? () => writeGuardSurface.runWriteGuard({ runProjectId }) : null,
570
- trackReviewingChanges: options.trackReviewingChanges === true,
571
- noTraceUndo: options.noTraceUndo === true
572
- }));
533
+ result = await applyEditOperation(operation, editOptions());
534
+ if (isUntouchedOpenFailure(result)) {
535
+ reopenQueue.push({ operation, result });
536
+ continue;
537
+ }
573
538
  } else if (['binary-create', 'overwrite-binary'].includes(operation.type)) {
574
- raceResult = await raceOpAgainstCancellation(applyBinaryAssetOperation(operation, { baseFileLookup, baseBinaryFileLookup }));
539
+ result = await applyBinaryAssetOperation(operation, { baseFileLookup, baseBinaryFileLookup });
575
540
  } else if (['create', 'rename', 'move', 'delete'].includes(operation.type)) {
576
- raceResult = await raceOpAgainstCancellation(applyFileTreeOperation(operation, { baseFileLookup }));
541
+ result = await applyFileTreeOperation(operation, { baseFileLookup, runProjectId, deadlineAt: options.deadlineAt,
542
+ createBatch: createBatch?.targets.has(operation.path) ? createBatch : null,
543
+ retryCreates: options.retryCreates === true });
577
544
  } else {
578
545
  skipped.push({
579
546
  operation,
@@ -584,27 +551,37 @@
584
551
  });
585
552
  continue;
586
553
  }
587
- // Cancellation race winner: skip current op + the rest of the queue.
588
- // The op promise above keeps running in background; its eventual
589
- // result is discarded. The user perceives instant cancel because we
590
- // settle the loop here instead of waiting for the op to finish.
591
- if (raceResult === CANCELLED_RACE_SENTINEL) {
592
- skipped.push({ operation, result: cancelledInFlightResult });
593
- const remainingAfterCancel = operations.slice(operations.indexOf(rawOperation) + 1);
594
- for (const tailOperation of remainingAfterCancel) {
595
- skipped.push({ operation: normalizeOperationPaths(tailOperation), result: cancelledSkipResult });
596
- }
597
- break;
598
- }
599
- const result = raceResult;
600
- if (result.trackedChangeCapture) trackedChangeCaptures.push(result.trackedChangeCapture);
601
- if (operation.type === 'edit' && result.ok && Array.isArray(result.trackedChanges)) {
602
- trackedChanges.push(...result.trackedChanges);
554
+ if (operation.type === 'create' && createBatch?.pending.has(operation.path)
555
+ && !createBatch.blocked.has(operation.path)) {
556
+ deferredCreates.push({ operation, result });
557
+ continue;
603
558
  }
604
- (result.ok ? applied : skipped).push({ operation, result });
559
+ record(operation, result);
605
560
  }
606
561
 
607
- if (applied.length > 0) {
562
+ // A file that could not be opened mid-batch usually opens once the
563
+ // previous document has settled: give untouched open failures one pass.
564
+ if (reopenQueue.length && readWriteCancellationSequence() === cancelBaselineSequence
565
+ && !skipped.some(entry => entry.result?.code === 'aborted_project_changed')) {
566
+ await delay(deps.reopenRetryDelayMs ?? 1200);
567
+ }
568
+ for (const entry of reopenQueue) {
569
+ const blocked = readWriteCancellationSequence() !== cancelBaselineSequence
570
+ || skipped.some(item => item.result?.code === 'aborted_project_changed')
571
+ || Boolean(runProjectId && writeGuardSurface && await writeGuardSurface.runWriteGuard({ runProjectId }));
572
+ const result = blocked ? entry.result : await applyEditOperation(entry.operation, editOptions());
573
+ record(entry.operation, result);
574
+ }
575
+
576
+ if (deferredCreates.length) {
577
+ const confirmed = await deps.finishTextCreateBatch(createBatch, deferredCreates, applied);
578
+ for (const entry of confirmed) {
579
+ (entry.result.ok ? applied : skipped).push(entry);
580
+ if (entry.result.ok) recordFileTreeOperationSuccess(entry.operation, baseFileLookup);
581
+ options.onOperationResult?.(entry);
582
+ }
583
+ }
584
+ if (applied.some(entry => entry.result?.changedDocument !== false)) {
608
585
  compileBridge.markSourceEdited();
609
586
  }
610
587
 
@@ -617,29 +594,10 @@
617
594
  };
618
595
  }
619
596
 
620
-
621
-
622
-
623
-
624
-
625
-
626
-
627
-
628
-
629
-
630
-
631
-
632
-
633
-
634
-
635
-
636
-
637
-
638
-
639
-
640
-
641
-
642
-
597
+ function isUntouchedOpenFailure(result) {
598
+ return result?.ok === false && result.failure?.code === 'target_file_open_failed'
599
+ && result.failure.changedDocument === false;
600
+ }
643
601
 
644
602
  async function applyEditOperation(operation, options = {}) {
645
603
  const currentPath = getActiveFilePath();
@@ -778,12 +736,23 @@
778
736
  return result;
779
737
  }
780
738
 
781
- const verified = await verifyActiveEditorText(nextContent, operation.path);
739
+ const verified = await verifyActiveEditorText(nextContent, operation.path, deps.writeVerifyWaitMs ?? 2500, current);
782
740
  if (!verified.ok) {
783
741
  const decorated = attachWritebackDebug(verified, 'write_verification', operation, options.baseFileLookup, readActiveEditorText(), {
784
742
  initialActivePath: currentPath,
785
743
  editorReadyDebug: editorReady.debug || null
786
744
  });
745
+ const evidence = { originalCode: verified.code || '', writeMethod: result.method || '', writeStarted: true,
746
+ ...verified.evidence };
747
+ if (verified.evidence?.observedIsBefore && verified.evidence.activeMatchesTarget) {
748
+ // The editor still holds exactly the pre-write text: the write never landed, so a retry is safe.
749
+ decorated.failure = buildPageFailure('write_operation_failed', {
750
+ file: operation?.path || '', operationType: operation?.type || 'edit', changedDocument: false,
751
+ userMessage: `Overleaf did not accept the edit to ${operation?.path || 'the target file'}; the document was left unchanged.`,
752
+ technicalMessage: verified.reason || '', evidence
753
+ });
754
+ return decorated;
755
+ }
787
756
  // §9.3 write_observed_mismatch: the write call landed but the readback
788
757
  // does not match. changedDocument:true — the editor state moved, just
789
758
  // not as Codex expected.
@@ -793,12 +762,7 @@
793
762
  changedDocument: true,
794
763
  userMessage: `${operation?.path || 'The target file'} did not read back the content Codex wrote; the document state may differ from what was approved.`,
795
764
  technicalMessage: verified.reason || '',
796
- evidence: {
797
- originalCode: verified.code || '',
798
- expectedLength: verified.expectedLength,
799
- actualLength: verified.actualLength,
800
- writeStarted: true
801
- }
765
+ evidence
802
766
  });
803
767
  return decorated;
804
768
  }
@@ -808,12 +772,12 @@
808
772
  // Overleaf renders review markers asynchronously after the editor text
809
773
  // has already changed. A single 120 ms snapshot intermittently missed
810
774
  // those markers, leaving a Reviewing write with Undo but no Accept.
811
- // Poll both paths: normal Reviewing writes get a shorter capture window,
812
- // while Accept replay keeps the longer safety window used to prove that
813
- // it did not create fresh tracked changes.
775
+ // Complete normal Track attribution while this file is still active.
776
+ // Slow batches are covered by request receipts; Accept replay retains
777
+ // its independent safety window proving that no new tracking was added.
814
778
  const trackedDiff = trackReviewingChanges
815
779
  ? await captureTrackedWrite({ trackedBefore, captureBaseline, operation, beforeContent: current,
816
- postContent: nextContent, runProjectId: options.runProjectId })
780
+ postContent: nextContent, runProjectId: options.runProjectId, waitMs: deps.trackCaptureWaitMs ?? 35000 })
817
781
  : await waitForTrackedChangeDiff(trackedBefore, operationPaths, {
818
782
  waitMs: 3600, intervalMs: 180, stopOnFirst: true
819
783
  });
@@ -860,7 +824,7 @@
860
824
  }
861
825
 
862
826
 
863
- async function verifyActiveEditorText(expected, filePath, waitMs = 1000) {
827
+ async function verifyActiveEditorText(expected, filePath, waitMs = 1000, before) {
864
828
  const deadline = Date.now() + waitMs;
865
829
  let actual = readActiveEditorText();
866
830
  while (actual !== expected && Date.now() < deadline) {
@@ -877,10 +841,37 @@
877
841
  code: 'write_verification_failed',
878
842
  reason: `${filePath || '当前文件'} 写入后读回内容和 Codex 预期不一致,已停止把这次操作标记为成功。请刷新 Overleaf 后重试。`,
879
843
  expectedLength: String(expected || '').length,
880
- actualLength: String(actual || '').length
844
+ actualLength: String(actual || '').length,
845
+ evidence: describeReadbackMismatch(expected, actual, before, filePath)
881
846
  };
882
847
  }
883
848
 
849
+ // Content-free mismatch evidence: offsets, lengths and short hashes only.
850
+ function describeReadbackMismatch(expected, actual, before, filePath) {
851
+ const left = String(expected ?? ''), right = String(actual ?? '');
852
+ let firstDiff = 0;
853
+ while (firstDiff < left.length && left[firstDiff] === right[firstDiff]) firstDiff += 1;
854
+ let tail = 0;
855
+ while (tail < left.length - firstDiff && tail < right.length - firstDiff
856
+ && left[left.length - 1 - tail] === right[right.length - 1 - tail]) tail += 1;
857
+ const activePath = getActiveFilePath() || '';
858
+ return { expectedLength: left.length, actualLength: right.length, firstDiffOffset: firstDiff,
859
+ expectedDiffLength: left.length - firstDiff - tail, actualDiffLength: right.length - firstDiff - tail,
860
+ expectedHash: shortHash(left), actualHash: shortHash(right),
861
+ beforeHash: typeof before === 'string' ? shortHash(before) : '',
862
+ observedIsBefore: typeof before === 'string' && right === before,
863
+ activePath, activeMatchesTarget: !filePath || activePath === filePath };
864
+ }
865
+
866
+ function shortHash(value) {
867
+ let hash = 0x811c9dc5;
868
+ for (let index = 0; index < value.length; index += 1) {
869
+ hash ^= value.charCodeAt(index);
870
+ hash = Math.imul(hash, 0x01000193) >>> 0;
871
+ }
872
+ return hash.toString(16).padStart(8, '0');
873
+ }
874
+
884
875
  async function ensureEditorReadyForOperation(operation, baseFileLookup, initialActivePath) {
885
876
  if (!operation?.path) {
886
877
  return {
@@ -1376,8 +1367,20 @@
1376
1367
  }
1377
1368
 
1378
1369
  async function applyFileTreeOperation(operation, options = {}) {
1370
+ if (operation.type === 'delete' && operation.undoCreatedFile) {
1371
+ return applyCreatedFileUndo(operation, options);
1372
+ }
1379
1373
  const initialProjectId = treeOperations.getProjectId?.();
1380
1374
  const initialCancellationSequence = readWriteCancellationSequence();
1375
+ if (operation.type === 'create' && options.createBatch && typeof deps.createTextFile === 'function') {
1376
+ if (options.baseFileLookup?.has(operation.path) && options.retryCreates !== true) {
1377
+ return checkFileTreeOperationFreshness(operation, options.baseFileLookup);
1378
+ }
1379
+ return deps.createTextFile(operation, { batch: options.createBatch,
1380
+ allowExistingMatches: options.retryCreates === true,
1381
+ isCurrent: () => treeOperations.getProjectId?.() === initialProjectId
1382
+ && readWriteCancellationSequence() === initialCancellationSequence });
1383
+ }
1381
1384
  const freshness = await checkFileTreeOperationFreshness(operation, options.baseFileLookup);
1382
1385
  if (!freshness.ok) {
1383
1386
  return freshness;
@@ -1436,7 +1439,7 @@
1436
1439
  return { ...fileTreeVerificationFailed(operation, 'Server receipt is missing or stale.'), changedDocument: true };
1437
1440
  }
1438
1441
  recordFileTreeOperationSuccess(operation, options.baseFileLookup);
1439
- return { ok: true, method: created.method, verified: true };
1442
+ return { ...created, ok: true, method: created.method, verified: true };
1440
1443
  }
1441
1444
  return {
1442
1445
  ok: false,
@@ -1445,6 +1448,43 @@
1445
1448
  };
1446
1449
  }
1447
1450
 
1451
+ async function applyCreatedFileUndo(operation, options = {}) {
1452
+ const projectId = treeOperations.getProjectId?.();
1453
+ const cancellation = readWriteCancellationSequence();
1454
+ const proof = operation.undoCreatedFile;
1455
+ const expected = options.baseFileLookup?.get(operation.path);
1456
+ const text = proof?.v === 1 && proof.kind === 'text' && typeof expected === 'string';
1457
+ const binary = proof?.v === 1 && proof.kind === 'binary' && /^[a-f0-9]{64}$/i.test(proof.sha256 || '');
1458
+ const isCurrent = () => Boolean(projectId) && projectId === options.runProjectId
1459
+ && treeOperations.getProjectId?.() === projectId && readWriteCancellationSequence() === cancellation;
1460
+ if (!isCurrent() || (!text && !binary) || typeof deps.deleteTextFile !== 'function') {
1461
+ return { ok: false, code: 'undo_operation_failed', changedDocument: false,
1462
+ reason: 'Verified created-file deletion is unavailable for this run.' };
1463
+ }
1464
+ if (text && projectPathExists(operation.path)) {
1465
+ const current = await readCurrentTextFileForFreshness(operation.path);
1466
+ if (!current.ok || current.text !== expected || !isCurrent()) {
1467
+ return { ok: false, code: 'undo_operation_failed', changedDocument: false,
1468
+ reason: 'The created file changed after this run and was left untouched.' };
1469
+ }
1470
+ }
1471
+ const result = await deps.deleteTextFile(operation, {
1472
+ isCurrent, undoCreatedFile: true, deadlineAt: options.deadlineAt,
1473
+ expectedContent: text ? expected : undefined,
1474
+ prepareTextPreimage: text ? () => readCurrentTextFileForFreshness(operation.path) : undefined,
1475
+ expectedSha256: binary ? proof.sha256.toLowerCase() : undefined,
1476
+ canDelete: () => isCurrent() && (binary || (treeOperations.getActiveFilePath?.() === operation.path
1477
+ && readActiveEditorText() === expected))
1478
+ });
1479
+ if (!result.ok) return result;
1480
+ if (!isCurrent() || result.verified !== true || result.verification !== 'overleaf-zip') {
1481
+ return { ok: false, code: 'undo_operation_failed', changedDocument: result.changedDocument !== false,
1482
+ reason: 'The created file has no current server deletion receipt.' };
1483
+ }
1484
+ recordFileTreeOperationSuccess(operation, options.baseFileLookup);
1485
+ return result;
1486
+ }
1487
+
1448
1488
  async function verifyFileTreeOperation(operation) {
1449
1489
  await delay(120);
1450
1490
  const sourcePath = operation.path;
@@ -1890,7 +1930,7 @@
1890
1930
  captureTrackedWrite, reconcileTrackedChangeCapture,
1891
1931
  waitForTrackedChangeDiff
1892
1932
  } = trackedChangesLifecycleModule.create({
1893
- window,
1933
+ window, confirmReviewWriteback: deps.confirmReviewWriteback,
1894
1934
  checkWritebackRunProjectId,
1895
1935
  buildNoTraceUndoBlockedResult,
1896
1936
  buildReviewingRequiredBlockedResult,