codex-overleaf-link 2.4.1 → 2.5.1

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 (397) hide show
  1. package/README.md +275 -305
  2. package/README.zh-CN.md +290 -320
  3. package/extension/bootstrap/background.js +99 -19
  4. package/extension/bootstrap/manifest.template.json +9 -4
  5. package/extension/bootstrap/popup.html +11 -16
  6. package/extension/bootstrap/popupFallback.js +55 -0
  7. package/extension/bootstrap/update.js +25 -2
  8. package/extension/bootstrap/updateStatus.js +1 -0
  9. package/extension/runtime-manifest.json +3 -1
  10. package/extension/src/background.js +234 -56
  11. package/extension/src/backgroundBootstrapMigration.js +181 -0
  12. package/extension/src/backgroundSharedSessions.js +440 -0
  13. package/extension/src/backgroundUpdateCoordinator.js +541 -381
  14. package/extension/src/backgroundUpdateSafety.js +173 -0
  15. package/extension/src/content/activeTurnControl.js +16 -2
  16. package/extension/src/content/applyResultFormatters.js +46 -73
  17. package/extension/src/content/assetTransferBroker.js +244 -12
  18. package/extension/src/content/changeHistoryView.js +175 -0
  19. package/extension/src/content/composerAttachments.js +117 -67
  20. package/extension/src/content/composerPanel.js +41 -8
  21. package/extension/src/content/contentRuntime.js +1084 -1099
  22. package/extension/src/content/diagnosticsController.js +122 -97
  23. package/extension/src/content/diagnosticsExport.js +236 -0
  24. package/extension/src/content/diagnosticsPanel.js +78 -19
  25. package/extension/src/content/diffReviewPanel.js +8 -5
  26. package/extension/src/content/directoryCleanupRecovery.js +54 -0
  27. package/extension/src/content/generated/content.bundle.js +14680 -3606
  28. package/extension/src/content/generated/content.bundle.meta.json +30 -3
  29. package/extension/src/content/globalPreferencesController.js +1 -1
  30. package/extension/src/content/legacyGlobalRegistry.js +25 -1
  31. package/extension/src/content/localSkillsPanel.js +141 -16
  32. package/extension/src/content/markdownDomRenderer.js +9 -4
  33. package/extension/src/content/markdownText.js +5 -6
  34. package/extension/src/content/modelPicker.js +8 -5
  35. package/extension/src/content/nativeCompatibilityController.js +45 -20
  36. package/extension/src/content/otWarmMirror.js +4 -5
  37. package/extension/src/content/otWarmMirrorController.js +17 -20
  38. package/extension/src/content/pageBridgeClient.js +33 -5
  39. package/extension/src/content/panelMaintenance.js +87 -132
  40. package/extension/src/content/panelRenderer.js +10 -0
  41. package/extension/src/content/pendingInputView.js +109 -76
  42. package/extension/src/content/projectProviderSelection.js +13 -4
  43. package/extension/src/content/projectSessionCleanup.js +109 -62
  44. package/extension/src/content/projectSettingsCoordinator.js +39 -2
  45. package/extension/src/content/providerSettingsCoordinator.js +63 -14
  46. package/extension/src/content/providerSettingsDialog.js +724 -113
  47. package/extension/src/content/recentProjects.js +21 -6
  48. package/extension/src/content/runActivitySummary.js +665 -0
  49. package/extension/src/content/runCompletionMeta.js +344 -0
  50. package/extension/src/content/runController.js +40 -15
  51. package/extension/src/content/runFailureNotice.js +34 -12
  52. package/extension/src/content/runGuidanceController.js +76 -30
  53. package/extension/src/content/runGuidanceView.js +59 -10
  54. package/extension/src/content/runPresence.js +306 -0
  55. package/extension/src/content/runQueueScheduler.js +150 -43
  56. package/extension/src/content/runRecoveryActions.js +146 -0
  57. package/extension/src/content/runResultActions.js +11 -8
  58. package/extension/src/content/runReviewController.js +574 -0
  59. package/extension/src/content/runScrollLayout.js +21 -2
  60. package/extension/src/content/runTimelineView.js +315 -290
  61. package/extension/src/content/scopedPersistencePanelState.js +51 -6
  62. package/extension/src/content/selectionContextView.js +300 -0
  63. package/extension/src/content/sensitivePreflight.js +140 -0
  64. package/extension/src/content/sessionForkController.js +80 -17
  65. package/extension/src/content/sessionManager.js +1 -1
  66. package/extension/src/content/sessionPersistence.js +6 -1
  67. package/extension/src/content/settingsPanel.js +84 -55
  68. package/extension/src/content/settingsWorkbench.js +379 -0
  69. package/extension/src/content/sharedSessionViewSync.js +109 -0
  70. package/extension/src/content/subagentActivityView.js +195 -0
  71. package/extension/src/content/trackedChangeCaptureController.js +7 -3
  72. package/extension/src/content/updateIdle.js +4 -1
  73. package/extension/src/content/updateNotice.js +179 -56
  74. package/extension/src/content/updateSafetyReceiver.js +58 -0
  75. package/extension/src/content/writebackController.js +308 -2
  76. package/extension/src/content/writebackOrchestrator.js +213 -199
  77. package/extension/src/content/writebackPlan.js +231 -0
  78. package/extension/src/content/writebackRecovery.js +122 -0
  79. package/extension/src/content/writingStyleSettings.js +600 -0
  80. package/extension/src/content/writtenChangesView.js +152 -0
  81. package/extension/src/page/binaryAssetUploader.js +223 -23
  82. package/extension/src/page/fileMover.js +256 -0
  83. package/extension/src/page/overleafProjectSnapshot.js +1 -0
  84. package/extension/src/page/ownedDirectoryCleanup.js +94 -0
  85. package/extension/src/page/referenceProjects.js +149 -0
  86. package/extension/src/page/reviewContext.js +113 -0
  87. package/extension/src/page/saveState.js +20 -6
  88. package/extension/src/page/snapshotRouter.js +124 -48
  89. package/extension/src/page/textCoordinates.js +102 -0
  90. package/extension/src/page/textFileCreator.js +442 -71
  91. package/extension/src/page/trackedChangeCapture.js +53 -57
  92. package/extension/src/page/trackedChangeOwnership.js +216 -0
  93. package/extension/src/page/trackedChangeReplay.js +184 -0
  94. package/extension/src/page/trackedChangesLifecycle.js +343 -339
  95. package/extension/src/page/treeOperations.js +33 -12
  96. package/extension/src/page/updateSafetyProbe.js +41 -0
  97. package/extension/src/page/writebackReceiptJournal.js +114 -0
  98. package/extension/src/page/writebackRouter.js +242 -201
  99. package/extension/src/pageBridge.js +73 -102
  100. package/extension/src/popup.js +261 -65
  101. package/extension/src/shared/agentTranscript.js +41 -4
  102. package/extension/src/shared/auditRecords.js +73 -0
  103. package/extension/src/shared/changeHistoryModel.js +94 -0
  104. package/extension/src/shared/compatibility.js +22 -6
  105. package/extension/src/shared/compileAdapter.js +101 -37
  106. package/extension/src/shared/composerAttachmentDraft.js +151 -0
  107. package/extension/src/shared/directoryCleanupProof.js +43 -0
  108. package/extension/src/shared/failureReasons.js +329 -3
  109. package/extension/src/shared/globalPreferences.js +31 -14
  110. package/extension/src/shared/governanceRules.js +4 -37
  111. package/extension/src/shared/i18n.js +389 -25
  112. package/extension/src/shared/managedUpdateProjection.js +8 -5
  113. package/extension/src/shared/nativeRequestIdentity.js +1 -0
  114. package/extension/src/shared/pageRpcContract.js +9 -2
  115. package/extension/src/shared/projectFiles.js +21 -44
  116. package/extension/src/shared/providerProfiles.js +114 -3
  117. package/extension/src/shared/runActivityModel.js +361 -0
  118. package/extension/src/shared/runExecutionSnapshot.js +8 -2
  119. package/extension/src/shared/runExecutionSnapshotCodec.js +16 -4
  120. package/extension/src/shared/runInputQueue.js +48 -5
  121. package/extension/src/shared/scopedPersistenceBrowserAdapter.js +6 -3
  122. package/extension/src/shared/selectionContext.js +37 -0
  123. package/extension/src/shared/sessionState.js +166 -30
  124. package/extension/src/shared/settlementFacts.js +10 -2
  125. package/extension/src/shared/sharedSessionBridge.js +311 -0
  126. package/extension/src/shared/sharedSessionTransfer.js +140 -0
  127. package/extension/src/shared/staleGuard.js +118 -13
  128. package/extension/src/shared/storageDb.js +77 -78
  129. package/extension/src/shared/storageMigration.js +74 -111
  130. package/extension/src/shared/storageRunActions.js +211 -22
  131. package/extension/src/shared/storageValuePruning.js +40 -0
  132. package/extension/src/shared/subagentActivityModel.js +174 -0
  133. package/extension/src/shared/undoOperations.js +216 -6
  134. package/extension/src/shared/updateConsent.js +42 -11
  135. package/extension/src/shared/updateRuntimeIdentity.js +1 -1
  136. package/extension/src/shared/writebackIntent.js +78 -0
  137. package/extension/src/shared/writebackOperationEvidence.js +4 -15
  138. package/extension/src/shared/writebackSettlement.js +67 -48
  139. package/extension/src/shared/writingStyle.js +33 -0
  140. package/extension/styles/panel.css +1987 -385
  141. package/extension/styles/popup.css +110 -0
  142. package/native-host/src/anthropicBridgeRequest.js +6 -3
  143. package/native-host/src/anthropicBridgeResponse.js +6 -2
  144. package/native-host/src/anthropicMessagesBridge.js +24 -16
  145. package/native-host/src/bootstrapMigration.js +296 -0
  146. package/native-host/src/bootstrapMigrationContract.js +101 -0
  147. package/native-host/src/bootstrapUpdate.js +233 -0
  148. package/native-host/src/bootstrapUpdateWatchdog.js +44 -0
  149. package/native-host/src/chatBridgeResponse.js +10 -0
  150. package/native-host/src/chatCompletionsBridge.js +21 -15
  151. package/native-host/src/codexConfigPaths.js +106 -0
  152. package/native-host/src/codexHome.js +66 -73
  153. package/native-host/src/codexHomeScope.js +124 -0
  154. package/native-host/src/codexInheritedAuth.js +90 -0
  155. package/native-host/src/codexLocalSkills.js +301 -0
  156. package/native-host/src/codexModelRecovery.js +107 -0
  157. package/native-host/src/codexPromptAssembly.js +33 -12
  158. package/native-host/src/codexProviderLaunch.js +3 -3
  159. package/native-host/src/codexProviderTest.js +24 -26
  160. package/native-host/src/codexRuntimeIdentity.js +1 -0
  161. package/native-host/src/codexSessionRunner.js +211 -318
  162. package/native-host/src/codexSessionTiming.js +21 -8
  163. package/native-host/src/codexSkillIsolation.js +170 -0
  164. package/native-host/src/codexThreadFork.js +19 -3
  165. package/native-host/src/index.js +19 -7
  166. package/native-host/src/managedInstall.js +115 -39
  167. package/native-host/src/managedInstallRecovery.js +140 -0
  168. package/native-host/src/managedRuntimeEvidence.js +57 -0
  169. package/native-host/src/mirrorWorkspace.js +92 -22
  170. package/native-host/src/nativeDoctor.js +15 -0
  171. package/native-host/src/nativeEnvironment.js +70 -0
  172. package/native-host/src/nativeHelperLifecycle.js +21 -0
  173. package/native-host/src/nativeHostRegistration.js +33 -0
  174. package/native-host/src/nativeQuotas.js +15 -8
  175. package/native-host/src/nativeRunLifecycle.js +71 -0
  176. package/native-host/src/overleafWorkspaceRules.js +16 -0
  177. package/native-host/src/processStopBarrier.js +115 -0
  178. package/native-host/src/projectPathPlatform.js +30 -0
  179. package/native-host/src/providerHttp.js +80 -0
  180. package/native-host/src/providerModelCatalog.js +4 -3
  181. package/native-host/src/providerProfile.js +17 -3
  182. package/native-host/src/providerReasoning.js +10 -11
  183. package/native-host/src/providerRuntime.js +1 -0
  184. package/native-host/src/providerStore.js +76 -14
  185. package/native-host/src/releaseTransport.js +14 -5
  186. package/native-host/src/responsesPassthroughBridge.js +266 -52
  187. package/native-host/src/runtimeInstaller.js +21 -1
  188. package/native-host/src/selectionScope.js +86 -0
  189. package/native-host/src/skills/parallel-subagents/SKILL.md +31 -3
  190. package/native-host/src/skills/writing-style-builder/SKILL.md +146 -0
  191. package/native-host/src/subagentAdmission.js +26 -0
  192. package/native-host/src/subagentBroker.js +176 -159
  193. package/native-host/src/subagentTelemetry.js +325 -0
  194. package/native-host/src/subagentWorkspace.js +103 -0
  195. package/native-host/src/subagentWorkspacePath.js +34 -0
  196. package/native-host/src/taskRunnerRuntime.js +130 -57
  197. package/native-host/src/tomlStatements.js +140 -0
  198. package/native-host/src/turnAttachments.js +113 -0
  199. package/native-host/src/updateManager.js +406 -38
  200. package/native-host/src/updateNetworkControl.js +75 -0
  201. package/native-host/src/updateTrust.js +21 -2
  202. package/native-host/src/vendor/pdfjs/LICENSE +177 -0
  203. package/native-host/src/vendor/pdfjs/SOURCE.txt +3 -0
  204. package/native-host/src/vendor/pdfjs/cmaps/78-EUC-H.bcmap +0 -0
  205. package/native-host/src/vendor/pdfjs/cmaps/78-EUC-V.bcmap +0 -0
  206. package/native-host/src/vendor/pdfjs/cmaps/78-H.bcmap +0 -0
  207. package/native-host/src/vendor/pdfjs/cmaps/78-RKSJ-H.bcmap +0 -0
  208. package/native-host/src/vendor/pdfjs/cmaps/78-RKSJ-V.bcmap +0 -0
  209. package/native-host/src/vendor/pdfjs/cmaps/78-V.bcmap +0 -0
  210. package/native-host/src/vendor/pdfjs/cmaps/78ms-RKSJ-H.bcmap +0 -0
  211. package/native-host/src/vendor/pdfjs/cmaps/78ms-RKSJ-V.bcmap +0 -0
  212. package/native-host/src/vendor/pdfjs/cmaps/83pv-RKSJ-H.bcmap +0 -0
  213. package/native-host/src/vendor/pdfjs/cmaps/90ms-RKSJ-H.bcmap +0 -0
  214. package/native-host/src/vendor/pdfjs/cmaps/90ms-RKSJ-V.bcmap +0 -0
  215. package/native-host/src/vendor/pdfjs/cmaps/90msp-RKSJ-H.bcmap +0 -0
  216. package/native-host/src/vendor/pdfjs/cmaps/90msp-RKSJ-V.bcmap +0 -0
  217. package/native-host/src/vendor/pdfjs/cmaps/90pv-RKSJ-H.bcmap +0 -0
  218. package/native-host/src/vendor/pdfjs/cmaps/90pv-RKSJ-V.bcmap +0 -0
  219. package/native-host/src/vendor/pdfjs/cmaps/Add-H.bcmap +0 -0
  220. package/native-host/src/vendor/pdfjs/cmaps/Add-RKSJ-H.bcmap +0 -0
  221. package/native-host/src/vendor/pdfjs/cmaps/Add-RKSJ-V.bcmap +0 -0
  222. package/native-host/src/vendor/pdfjs/cmaps/Add-V.bcmap +0 -0
  223. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-0.bcmap +0 -0
  224. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-1.bcmap +0 -0
  225. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-2.bcmap +0 -0
  226. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-3.bcmap +0 -0
  227. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-4.bcmap +0 -0
  228. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-5.bcmap +0 -0
  229. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-6.bcmap +0 -0
  230. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
  231. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-0.bcmap +0 -0
  232. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-1.bcmap +0 -0
  233. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-2.bcmap +0 -0
  234. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-3.bcmap +0 -0
  235. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-4.bcmap +0 -0
  236. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-5.bcmap +0 -0
  237. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
  238. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-0.bcmap +0 -0
  239. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-1.bcmap +0 -0
  240. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-2.bcmap +0 -0
  241. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-3.bcmap +0 -0
  242. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-4.bcmap +0 -0
  243. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-5.bcmap +0 -0
  244. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-6.bcmap +0 -0
  245. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
  246. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-0.bcmap +0 -0
  247. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-1.bcmap +0 -0
  248. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-2.bcmap +0 -0
  249. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
  250. package/native-host/src/vendor/pdfjs/cmaps/B5-H.bcmap +0 -0
  251. package/native-host/src/vendor/pdfjs/cmaps/B5-V.bcmap +0 -0
  252. package/native-host/src/vendor/pdfjs/cmaps/B5pc-H.bcmap +0 -0
  253. package/native-host/src/vendor/pdfjs/cmaps/B5pc-V.bcmap +0 -0
  254. package/native-host/src/vendor/pdfjs/cmaps/CNS-EUC-H.bcmap +0 -0
  255. package/native-host/src/vendor/pdfjs/cmaps/CNS-EUC-V.bcmap +0 -0
  256. package/native-host/src/vendor/pdfjs/cmaps/CNS1-H.bcmap +0 -0
  257. package/native-host/src/vendor/pdfjs/cmaps/CNS1-V.bcmap +0 -0
  258. package/native-host/src/vendor/pdfjs/cmaps/CNS2-H.bcmap +0 -0
  259. package/native-host/src/vendor/pdfjs/cmaps/CNS2-V.bcmap +3 -0
  260. package/native-host/src/vendor/pdfjs/cmaps/ETHK-B5-H.bcmap +0 -0
  261. package/native-host/src/vendor/pdfjs/cmaps/ETHK-B5-V.bcmap +0 -0
  262. package/native-host/src/vendor/pdfjs/cmaps/ETen-B5-H.bcmap +0 -0
  263. package/native-host/src/vendor/pdfjs/cmaps/ETen-B5-V.bcmap +0 -0
  264. package/native-host/src/vendor/pdfjs/cmaps/ETenms-B5-H.bcmap +3 -0
  265. package/native-host/src/vendor/pdfjs/cmaps/ETenms-B5-V.bcmap +0 -0
  266. package/native-host/src/vendor/pdfjs/cmaps/EUC-H.bcmap +0 -0
  267. package/native-host/src/vendor/pdfjs/cmaps/EUC-V.bcmap +0 -0
  268. package/native-host/src/vendor/pdfjs/cmaps/Ext-H.bcmap +0 -0
  269. package/native-host/src/vendor/pdfjs/cmaps/Ext-RKSJ-H.bcmap +0 -0
  270. package/native-host/src/vendor/pdfjs/cmaps/Ext-RKSJ-V.bcmap +0 -0
  271. package/native-host/src/vendor/pdfjs/cmaps/Ext-V.bcmap +0 -0
  272. package/native-host/src/vendor/pdfjs/cmaps/GB-EUC-H.bcmap +0 -0
  273. package/native-host/src/vendor/pdfjs/cmaps/GB-EUC-V.bcmap +0 -0
  274. package/native-host/src/vendor/pdfjs/cmaps/GB-H.bcmap +4 -0
  275. package/native-host/src/vendor/pdfjs/cmaps/GB-V.bcmap +0 -0
  276. package/native-host/src/vendor/pdfjs/cmaps/GBK-EUC-H.bcmap +0 -0
  277. package/native-host/src/vendor/pdfjs/cmaps/GBK-EUC-V.bcmap +0 -0
  278. package/native-host/src/vendor/pdfjs/cmaps/GBK2K-H.bcmap +0 -0
  279. package/native-host/src/vendor/pdfjs/cmaps/GBK2K-V.bcmap +0 -0
  280. package/native-host/src/vendor/pdfjs/cmaps/GBKp-EUC-H.bcmap +0 -0
  281. package/native-host/src/vendor/pdfjs/cmaps/GBKp-EUC-V.bcmap +0 -0
  282. package/native-host/src/vendor/pdfjs/cmaps/GBT-EUC-H.bcmap +0 -0
  283. package/native-host/src/vendor/pdfjs/cmaps/GBT-EUC-V.bcmap +0 -0
  284. package/native-host/src/vendor/pdfjs/cmaps/GBT-H.bcmap +0 -0
  285. package/native-host/src/vendor/pdfjs/cmaps/GBT-V.bcmap +0 -0
  286. package/native-host/src/vendor/pdfjs/cmaps/GBTpc-EUC-H.bcmap +0 -0
  287. package/native-host/src/vendor/pdfjs/cmaps/GBTpc-EUC-V.bcmap +0 -0
  288. package/native-host/src/vendor/pdfjs/cmaps/GBpc-EUC-H.bcmap +0 -0
  289. package/native-host/src/vendor/pdfjs/cmaps/GBpc-EUC-V.bcmap +0 -0
  290. package/native-host/src/vendor/pdfjs/cmaps/H.bcmap +0 -0
  291. package/native-host/src/vendor/pdfjs/cmaps/HKdla-B5-H.bcmap +0 -0
  292. package/native-host/src/vendor/pdfjs/cmaps/HKdla-B5-V.bcmap +0 -0
  293. package/native-host/src/vendor/pdfjs/cmaps/HKdlb-B5-H.bcmap +0 -0
  294. package/native-host/src/vendor/pdfjs/cmaps/HKdlb-B5-V.bcmap +0 -0
  295. package/native-host/src/vendor/pdfjs/cmaps/HKgccs-B5-H.bcmap +0 -0
  296. package/native-host/src/vendor/pdfjs/cmaps/HKgccs-B5-V.bcmap +0 -0
  297. package/native-host/src/vendor/pdfjs/cmaps/HKm314-B5-H.bcmap +0 -0
  298. package/native-host/src/vendor/pdfjs/cmaps/HKm314-B5-V.bcmap +0 -0
  299. package/native-host/src/vendor/pdfjs/cmaps/HKm471-B5-H.bcmap +0 -0
  300. package/native-host/src/vendor/pdfjs/cmaps/HKm471-B5-V.bcmap +0 -0
  301. package/native-host/src/vendor/pdfjs/cmaps/HKscs-B5-H.bcmap +0 -0
  302. package/native-host/src/vendor/pdfjs/cmaps/HKscs-B5-V.bcmap +0 -0
  303. package/native-host/src/vendor/pdfjs/cmaps/Hankaku.bcmap +0 -0
  304. package/native-host/src/vendor/pdfjs/cmaps/Hiragana.bcmap +0 -0
  305. package/native-host/src/vendor/pdfjs/cmaps/KSC-EUC-H.bcmap +0 -0
  306. package/native-host/src/vendor/pdfjs/cmaps/KSC-EUC-V.bcmap +0 -0
  307. package/native-host/src/vendor/pdfjs/cmaps/KSC-H.bcmap +0 -0
  308. package/native-host/src/vendor/pdfjs/cmaps/KSC-Johab-H.bcmap +0 -0
  309. package/native-host/src/vendor/pdfjs/cmaps/KSC-Johab-V.bcmap +0 -0
  310. package/native-host/src/vendor/pdfjs/cmaps/KSC-V.bcmap +0 -0
  311. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-H.bcmap +0 -0
  312. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
  313. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
  314. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-V.bcmap +0 -0
  315. package/native-host/src/vendor/pdfjs/cmaps/KSCpc-EUC-H.bcmap +0 -0
  316. package/native-host/src/vendor/pdfjs/cmaps/KSCpc-EUC-V.bcmap +0 -0
  317. package/native-host/src/vendor/pdfjs/cmaps/Katakana.bcmap +0 -0
  318. package/native-host/src/vendor/pdfjs/cmaps/LICENSE +36 -0
  319. package/native-host/src/vendor/pdfjs/cmaps/NWP-H.bcmap +0 -0
  320. package/native-host/src/vendor/pdfjs/cmaps/NWP-V.bcmap +0 -0
  321. package/native-host/src/vendor/pdfjs/cmaps/RKSJ-H.bcmap +0 -0
  322. package/native-host/src/vendor/pdfjs/cmaps/RKSJ-V.bcmap +0 -0
  323. package/native-host/src/vendor/pdfjs/cmaps/Roman.bcmap +0 -0
  324. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UCS2-H.bcmap +0 -0
  325. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UCS2-V.bcmap +0 -0
  326. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF16-H.bcmap +0 -0
  327. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF16-V.bcmap +0 -0
  328. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF32-H.bcmap +0 -0
  329. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF32-V.bcmap +0 -0
  330. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF8-H.bcmap +0 -0
  331. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF8-V.bcmap +0 -0
  332. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UCS2-H.bcmap +0 -0
  333. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UCS2-V.bcmap +0 -0
  334. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF16-H.bcmap +0 -0
  335. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF16-V.bcmap +0 -0
  336. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF32-H.bcmap +0 -0
  337. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF32-V.bcmap +0 -0
  338. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF8-H.bcmap +0 -0
  339. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF8-V.bcmap +0 -0
  340. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-H.bcmap +0 -0
  341. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
  342. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
  343. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-V.bcmap +0 -0
  344. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF16-H.bcmap +0 -0
  345. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF16-V.bcmap +0 -0
  346. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF32-H.bcmap +0 -0
  347. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF32-V.bcmap +0 -0
  348. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF8-H.bcmap +0 -0
  349. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF8-V.bcmap +0 -0
  350. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
  351. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
  352. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
  353. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
  354. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
  355. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
  356. package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
  357. package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
  358. package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
  359. package/native-host/src/vendor/pdfjs/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
  360. package/native-host/src/vendor/pdfjs/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
  361. package/native-host/src/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
  362. package/native-host/src/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
  363. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UCS2-H.bcmap +0 -0
  364. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UCS2-V.bcmap +0 -0
  365. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF16-H.bcmap +0 -0
  366. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF16-V.bcmap +0 -0
  367. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF32-H.bcmap +0 -0
  368. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF32-V.bcmap +0 -0
  369. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF8-H.bcmap +0 -0
  370. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF8-V.bcmap +0 -0
  371. package/native-host/src/vendor/pdfjs/cmaps/V.bcmap +0 -0
  372. package/native-host/src/vendor/pdfjs/cmaps/WP-Symbol.bcmap +0 -0
  373. package/native-host/src/vendor/pdfjs/pdf.mjs +26740 -0
  374. package/native-host/src/vendor/pdfjs/pdf.worker.mjs +62201 -0
  375. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitDingbats.pfb +0 -0
  376. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixed.pfb +0 -0
  377. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedBold.pfb +0 -0
  378. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
  379. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedItalic.pfb +0 -0
  380. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerif.pfb +0 -0
  381. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifBold.pfb +0 -0
  382. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
  383. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifItalic.pfb +0 -0
  384. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSymbol.pfb +0 -0
  385. package/native-host/src/vendor/pdfjs/standard_fonts/LICENSE_FOXIT +27 -0
  386. package/native-host/src/vendor/pdfjs/standard_fonts/LICENSE_LIBERATION +102 -0
  387. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Bold.ttf +0 -0
  388. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
  389. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Italic.ttf +0 -0
  390. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Regular.ttf +0 -0
  391. package/native-host/src/writingStyleEvidence.js +102 -0
  392. package/native-host/src/writingStylePdfWorker.js +35 -0
  393. package/native-host/src/writingStyleProfile.js +165 -0
  394. package/native-host/src/writingStyleRuntime.js +475 -0
  395. package/native-host/src/writingStyleStore.js +73 -0
  396. package/package.json +1 -1
  397. package/scripts/install-managed.mjs +1 -0
@@ -1,10 +1,10 @@
1
1
  (function initUndoOperations(root, factory) {
2
2
  if (typeof module === 'object' && module.exports) {
3
- module.exports = factory();
3
+ module.exports = factory(require('./staleGuard'));
4
4
  } else {
5
- root.CodexOverleafUndoOperations = factory();
5
+ root.CodexOverleafUndoOperations = factory(root.CodexOverleafStaleGuard);
6
6
  }
7
- })(typeof globalThis !== 'undefined' ? globalThis : window, function undoOperationsFactory() {
7
+ })(typeof globalThis !== 'undefined' ? globalThis : window, function undoOperationsFactory(StaleGuard) {
8
8
  'use strict';
9
9
 
10
10
  function buildUndoOperations(project, appliedOperations) {
@@ -15,6 +15,7 @@
15
15
  }
16
16
  }
17
17
 
18
+ const sourceFilesByPath = new Map(workingFilesByPath);
18
19
  const undo = [];
19
20
  const fullRestoreEditPaths = new Set();
20
21
 
@@ -29,7 +30,8 @@
29
30
  }
30
31
  const currentBeforeEdit = workingFilesByPath.get(operation.path);
31
32
  if (!fullRestoreEditPaths.has(operation.path)) {
32
- const inversePatches = buildInverseTextPatches(currentBeforeEdit, operation.patches);
33
+ const inversePatches = buildInverseTextPatches(sourceFilesByPath.get(operation.path), operation.patches,
34
+ operation.verifiedContent, operation.path);
33
35
  if (inversePatches.length) {
34
36
  undo.push(normalizeUndoOperation({
35
37
  type: 'edit',
@@ -70,10 +72,13 @@
70
72
  if (!operation.path || !operation.to) {
71
73
  continue;
72
74
  }
75
+ if (operation.moveProof && !operation.moveProof.targetEntityId) continue;
73
76
  undo.push(normalizeUndoOperation({
74
77
  type: 'move',
75
78
  path: operation.to,
76
79
  to: operation.path,
80
+ ...(operation.moveProof ? { moveProof: { ...operation.moveProof,
81
+ sourceEntityId: operation.moveProof.targetEntityId, targetEntityId: operation.moveProof.sourceEntityId } } : {}),
77
82
  reason: 'Undo move'
78
83
  }));
79
84
  } else if (operation.type === 'delete') {
@@ -89,12 +94,13 @@
89
94
  }
90
95
 
91
96
  applyOperationToFiles(workingFilesByPath, operation);
97
+ applyOperationToFiles(sourceFilesByPath, { ...operation, verifiedContent: undefined });
92
98
  }
93
99
 
94
100
  return undo.reverse();
95
101
  }
96
102
 
97
- function buildInverseTextPatches(textBeforeEdit, patches) {
103
+ function buildInverseTextPatches(textBeforeEdit, patches, verifiedContent, path) {
98
104
  if (!Array.isArray(patches) || !patches.length) {
99
105
  return [];
100
106
  }
@@ -108,7 +114,7 @@
108
114
  }
109
115
 
110
116
  let offset = 0;
111
- return normalized.patches.map(patch => {
117
+ const inverse = normalized.patches.map(patch => {
112
118
  const from = patch.from + offset;
113
119
  const to = from + patch.insert.length;
114
120
  offset += patch.insert.length - (patch.to - patch.from);
@@ -119,6 +125,41 @@
119
125
  insert: patch.expected
120
126
  };
121
127
  });
128
+ if (typeof verifiedContent !== 'string' || verifiedContent === applied.text) return inverse;
129
+ // The stored checkpoint uses the verified editor post-image. Its inverse
130
+ // must use those same offsets, while Native patches retain their source
131
+ // representation for later operations in the batch.
132
+ const prepared = StaleGuard.prepareOperationPatches({ type: 'edit', path, patches: inverse }, verifiedContent,
133
+ StaleGuard.buildBaseFileLookup([{ path, content: applied.text }]));
134
+ return prepared.ok && applyTextPatches(verifiedContent, prepared.patches).ok ? prepared.patches : [];
135
+ }
136
+
137
+ function selectExpectedFilesForTrackedUndo(project, operations = [], trackedChanges = [], previousExpectedFiles = []) {
138
+ const paths = new Set();
139
+ for (const change of trackedChanges || []) if (change?.path) paths.add(change.path);
140
+ for (const operation of operations || []) {
141
+ if (operation?.path) paths.add(operation.path);
142
+ if (operation?.to) paths.add(operation.to);
143
+ }
144
+ const expectedByPath = new Map();
145
+ for (const file of previousExpectedFiles || []) {
146
+ if (paths.has(file?.path) && typeof file?.content === 'string' && !expectedByPath.has(file.path)) {
147
+ expectedByPath.set(file.path, { path: file.path, content: file.content });
148
+ }
149
+ }
150
+ // Reconstruct the pre-image with the same inverse patches as plain Undo.
151
+ // This preserves the editor's unchanged line endings and collaborator
152
+ // content, including when the ZIP baseline used a different representation.
153
+ const hasVerifiedPatches = operations.some(operation => typeof operation?.verifiedContent === 'string'
154
+ && Array.isArray(operation.patches) && operation.patches.length);
155
+ const checkpoint = hasVerifiedPatches ? buildUndoCheckpoint(project, operations) : null;
156
+ const restored = checkpoint ? buildExpectedFilesAfterOperations({ files: checkpoint.undoBaseFiles }, checkpoint.undoOperations) : new Map();
157
+ for (const file of project?.files || []) {
158
+ if (paths.has(file?.path) && typeof file?.content === 'string' && !expectedByPath.has(file.path)) {
159
+ expectedByPath.set(file.path, { path: file.path, content: restored.get(file.path) ?? file.content });
160
+ }
161
+ }
162
+ return Array.from(expectedByPath.values());
122
163
  }
123
164
 
124
165
  function buildUndoCheckpoint(project, appliedOperations) {
@@ -130,6 +171,166 @@
130
171
  };
131
172
  }
132
173
 
174
+ // File creation has its own inverse even when text edits use Reviewing.
175
+ // Store post-images, never infer an empty pre-image for a missing file.
176
+ function buildCreatedFileUndoCheckpoint(project, appliedOperations, previous = {}) {
177
+ const originalPaths = new Set((project?.files || []).map(file => file?.path));
178
+ const priorFiles = filesListToMap(previous.undoBaseFiles);
179
+ const created = new Map();
180
+ for (const operation of previous.undoOperations || []) {
181
+ const proof = operation?.undoCreatedFile;
182
+ if (operation?.type !== 'delete' || proof?.v !== 1) continue;
183
+ if (proof.kind === 'text' && priorFiles.has(operation.path)) {
184
+ created.set(operation.path, { kind: 'text', content: priorFiles.get(operation.path), createdDirectories: proof.createdDirectories });
185
+ } else if (proof.kind === 'binary' && /^[a-f0-9]{64}$/i.test(proof.sha256 || '')) {
186
+ created.set(operation.path, { kind: 'binary', sha256: proof.sha256.toLowerCase(), createdDirectories: proof.createdDirectories });
187
+ }
188
+ }
189
+ for (const operation of appliedOperations || []) {
190
+ if (!operation?.path) continue;
191
+ const path = operation.path;
192
+ if (operation.type === 'create' || operation.type === 'binary-create') {
193
+ if (originalPaths.has(path) && !created.has(path)) continue;
194
+ if (operation.type === 'create' && typeof operation.content === 'string') {
195
+ created.set(path, { kind: 'text', content: typeof operation.verifiedContent === 'string'
196
+ ? operation.verifiedContent : operation.content, createdDirectories: operation.createdDirectories });
197
+ } else {
198
+ const hash = operation.sha256 || operation.assetRef?.sha256;
199
+ if (operation.previousExists !== true && /^[a-f0-9]{64}$/i.test(hash || '')) {
200
+ created.set(path, { kind: 'binary', sha256: hash.toLowerCase(), createdDirectories: operation.createdDirectories });
201
+ }
202
+ }
203
+ } else if (operation.type === 'edit' && created.get(path)?.kind === 'text') {
204
+ const files = new Map([[path, created.get(path).content]]);
205
+ applyOperationToFiles(files, operation);
206
+ created.set(path, { ...created.get(path), kind: 'text', content: files.get(path) });
207
+ } else if (['delete', 'rename', 'move', 'overwrite-binary'].includes(operation.type)) {
208
+ // Existing rename/overwrite recovery retains ownership of these cases.
209
+ created.delete(path);
210
+ if (operation.to) created.delete(operation.to);
211
+ }
212
+ }
213
+ const undoBaseFiles = [], undoOperations = [];
214
+ for (const [path, proof] of Array.from(created).reverse()) {
215
+ const undoCreatedFile = proof.kind === 'binary'
216
+ ? { v: 1, kind: 'binary', sha256: proof.sha256 } : { v: 1, kind: 'text' };
217
+ if (Array.isArray(proof.createdDirectories) && proof.createdDirectories.length) {
218
+ undoCreatedFile.createdDirectories = proof.createdDirectories.map(item => ({ ...item }));
219
+ }
220
+ undoOperations.push({ ...normalizeUndoOperation({ type: 'delete', path, reason: 'Undo create' }), undoCreatedFile });
221
+ if (proof.kind === 'text') undoBaseFiles.push({ path, content: proof.content });
222
+ }
223
+ // Reviewing has no text insertion/deletion refs for a native metadata move.
224
+ // Keep its identity-bound inverse with the other file-level proofs.
225
+ undoOperations.push(...buildUndoOperations(project, appliedOperations).filter(operation => operation.type === 'move' && operation.moveProof));
226
+ return { undoOperations, undoBaseFiles };
227
+ }
228
+
229
+ function isFileUndoOperation(operation) {
230
+ return operation?.undoCreatedFile?.v === 1
231
+ || (operation?.type === 'move' && operation.moveProof?.v === 1)
232
+ || (operation?.type === 'create' && typeof operation.content === 'string');
233
+ }
234
+
235
+ // A deleted original has no editor post-image. Its inverse is a guarded
236
+ // file creation, backed by both the forward delete and the captured original.
237
+ // This also recovers older Track-on records that omitted that inverse.
238
+ function getFileUndoOperations(run = {}) {
239
+ const operations = (run.undoOperations || []).filter(isFileUndoOperation);
240
+ const before = filesListToMap(run.undoExpectedFiles);
241
+ const after = buildExpectedFilesAfterOperations({ files: run.undoExpectedFiles }, run.appliedOperations);
242
+ const deleted = new Set((run.appliedOperations || []).filter(operation => operation?.type === 'delete'
243
+ && before.has(operation.path) && !after.has(operation.path)).map(operation => operation.path));
244
+ return [...operations.filter(operation => !deleted.has(operation.path)), ...Array.from(deleted, path =>
245
+ normalizeUndoOperation({ type: 'create', path, content: before.get(path), reason: 'Undo delete' }))];
246
+ }
247
+
248
+ function prepareRunUndo(run = {}) {
249
+ const files = getFileUndoOperations(run);
250
+ const restored = new Set(files.filter(operation => operation.type === 'create').map(operation => operation.path));
251
+ const pending = [...files], operations = [];
252
+ for (const operation of run.undoOperations || []) {
253
+ if (isFileUndoOperation(operation)) {
254
+ const index = pending.findIndex(file => file.path === operation.path && file.type === operation.type);
255
+ if (index >= 0) operations.push(...pending.splice(index, 1));
256
+ } else if (!restored.has(operation.path)) operations.push(operation);
257
+ }
258
+ return { ...run, undoOperations: [...operations, ...pending] };
259
+ }
260
+
261
+ function textUndoRun(run = {}) {
262
+ const restored = new Set(getFileUndoOperations(run).flatMap(operation => operation.type === 'create' ? [operation.path]
263
+ : operation.type === 'move' ? [operation.path, operation.to] : []));
264
+ return { ...run,
265
+ undoExpectedFiles: (run.undoExpectedFiles || []).filter(file => !restored.has(file.path)),
266
+ undoTrackedChanges: (run.undoTrackedChanges || []).filter(ref => !restored.has(ref.path))
267
+ };
268
+ }
269
+
270
+ function mergeFileUndoResult(textResult, fileResult, operations) {
271
+ const applied = [...(textResult.applied || []), ...(fileResult.applied || [])];
272
+ const skipped = [...(textResult.skipped || []), ...(fileResult.skipped || [])];
273
+ for (const operation of operations) {
274
+ if (!(fileResult.applied || []).some(entry => entry.operation?.path === operation.path
275
+ && entry.operation?.type === operation.type && entry.result?.ok === true && entry.result?.verified === true
276
+ && entry.result.verification === 'overleaf-zip')
277
+ && !(fileResult.skipped || []).some(entry => entry.operation?.path === operation.path)) {
278
+ skipped.push({ operation, result: { ok: false, code: 'undo_operation_failed',
279
+ reason: 'The file restoration has no verified server receipt.' } });
280
+ }
281
+ }
282
+ return { ...textResult, ok: textResult.ok !== false && fileResult.ok !== false && !skipped.length, applied, skipped };
283
+ }
284
+
285
+ // Consume only independently verified rollback receipts. Forward writes
286
+ // remain audit evidence; recovery arrays describe only unfinished work.
287
+ function advanceUndoCheckpoint(run = {}, result = {}, verifyText = () => false) {
288
+ const operations = Array.isArray(run?.undoOperations) ? run.undoOperations : [];
289
+ const applied = Array.isArray(result.applied) ? result.applied : [];
290
+ const skipped = Array.isArray(result.skipped) ? result.skipped : [];
291
+ const failed = path => skipped.some(entry => {
292
+ const target = entry?.operation?.path || entry?.trackedChange?.path || entry?.result?.failure?.file;
293
+ return !target || target === path;
294
+ });
295
+ if (result.failure || result.error) return run;
296
+ const textPaths = new Set((run.undoExpectedFiles || [])
297
+ .filter(file => file?.path && typeof file.content === 'string' && !failed(file.path)
298
+ && typeof verifyText === 'function' && verifyText(file) === true)
299
+ .map(file => file.path));
300
+ const deletedPaths = new Set(operations.filter(operation => operation?.type === 'delete'
301
+ && operation.undoCreatedFile?.v === 1 && !failed(operation.path)
302
+ && applied.some(entry => entry?.operation?.type === 'delete' && entry.operation.path === operation.path
303
+ && JSON.stringify(entry.operation.undoCreatedFile) === JSON.stringify(operation.undoCreatedFile)
304
+ && entry.result?.ok === true && entry.result.verified === true
305
+ && entry.result.verification === 'overleaf-zip')).map(operation => operation.path));
306
+ const restoredPaths = new Set(operations.filter(operation => operation?.type === 'create'
307
+ && !failed(operation.path) && applied.some(entry => entry?.operation?.type === 'create'
308
+ && entry.operation.path === operation.path && entry.operation.content === operation.content
309
+ && entry.result?.ok === true && entry.result.verified === true
310
+ && entry.result.verification === 'overleaf-zip')).map(operation => operation.path));
311
+ const movedPaths = new Set(operations.filter(operation => operation?.type === 'move' && operation.moveProof?.v === 1
312
+ && !failed(operation.path) && applied.some(entry => entry?.operation?.type === 'move'
313
+ && entry.operation.path === operation.path && entry.operation.to === operation.to
314
+ && JSON.stringify(entry.operation.moveProof) === JSON.stringify(operation.moveProof)
315
+ && entry.result?.ok === true && entry.result.verified === true && entry.result.verification === 'overleaf-zip'))
316
+ .flatMap(operation => [operation.path, operation.to]));
317
+ for (const path of restoredPaths) textPaths.add(path);
318
+ for (const path of movedPaths) textPaths.add(path);
319
+ if (!textPaths.size && !deletedPaths.size) return run;
320
+ const pending = operations.filter(operation => !restoredPaths.has(operation.path) && !(operation?.type === 'edit' && textPaths.has(operation.path))
321
+ && !(operation?.type === 'move' && movedPaths.has(operation.path))
322
+ && !(operation?.type === 'delete' && operation.undoCreatedFile?.v === 1 && deletedPaths.has(operation.path)));
323
+ const needed = new Set(pending.flatMap(operation => [operation?.path, operation?.to]).filter(Boolean));
324
+ return { ...run,
325
+ undoOperations: pending,
326
+ undoBaseFiles: (run.undoBaseFiles || []).filter(file => needed.has(file?.path)
327
+ || (!textPaths.has(file?.path) && !deletedPaths.has(file?.path))),
328
+ undoExpectedFiles: (run.undoExpectedFiles || []).filter(file => !textPaths.has(file?.path)),
329
+ undoTrackedChanges: (run.undoTrackedChanges || []).filter(ref => !textPaths.has(ref?.path)),
330
+ trackedChangeCaptures: (run.trackedChangeCaptures || []).filter(capture => !textPaths.has(capture?.path))
331
+ };
332
+ }
333
+
133
334
  function buildSnapshotRestoreUndo(run = {}) {
134
335
  const undoOperations = Array.isArray(run.undoOperations) ? run.undoOperations : [];
135
336
  const originalByPath = buildOriginalFilesForSnapshotUndo(run, undoOperations);
@@ -311,6 +512,7 @@
311
512
  insert: String(patch.insert ?? '')
312
513
  }));
313
514
  }
515
+ if (operation.type === 'move' && operation.moveProof?.v === 1) normalized.moveProof = JSON.parse(JSON.stringify(operation.moveProof));
314
516
  return normalized;
315
517
  }
316
518
 
@@ -369,9 +571,17 @@
369
571
  }
370
572
 
371
573
  return {
574
+ isFileUndoOperation,
575
+ getFileUndoOperations,
576
+ prepareRunUndo,
577
+ textUndoRun,
578
+ mergeFileUndoResult,
372
579
  buildUndoCheckpoint,
580
+ buildCreatedFileUndoCheckpoint,
581
+ advanceUndoCheckpoint,
373
582
  buildExpectedFilesAfterOperations,
374
583
  buildUndoOperations,
584
+ selectExpectedFilesForTrackedUndo,
375
585
  buildSnapshotRestoreUndo
376
586
  };
377
587
  });
@@ -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),
@@ -73,11 +78,24 @@
73
78
  deadlineAt: finiteNumber(value.deadlineAt),
74
79
  heartbeatAt: finiteNumber(value.heartbeatAt),
75
80
  postponeUntil: finiteNumber(value.postponeUntil),
81
+ cooldownUntil: finiteNumber(value.cooldownUntil),
76
82
  code: safeToken(value.code),
77
- message: String(value.message || '').replace(/\s+/g, ' ').trim().slice(0, 300)
83
+ message: String(value.message || '').replace(/\s+/g, ' ').trim().slice(0, 300),
84
+ manualReason: normalizeManualReason(value.manualReason)
78
85
  };
79
86
  }
80
87
 
88
+ // Signed per-locale reason a release needs a one-time reinstall.
89
+ function normalizeManualReason(value) {
90
+ if (!value || typeof value !== 'object') return {};
91
+ const out = {};
92
+ for (const locale of ['en', 'zh']) {
93
+ const text = String(value[locale] || '').replace(/\s+/g, ' ').trim().slice(0, 400);
94
+ if (text) out[locale] = text;
95
+ }
96
+ return out;
97
+ }
98
+
81
99
  function normalizeConsentState(value = {}) {
82
100
  return {
83
101
  schemaVersion: 1,
@@ -101,11 +119,19 @@
101
119
  const state = normalizeUpdateState(updateValue, options.currentVersion);
102
120
  const consent = normalizeConsentState(consentValue);
103
121
  const newer = compareStableVersions(state.latestVersion, state.currentVersion) > 0;
104
- const snoozed = newer &&
105
- consent.snoozedVersion === state.latestVersion &&
106
- consent.snoozedUntil > now;
107
122
  const execution = EXECUTION_STATES.has(state.state);
108
123
  const available = state.state === 'update_available' && newer;
124
+ // A newer release that only a reinstall can apply. It is shown even after
125
+ // an automatic check, because no Update now button can ever resolve it.
126
+ // Compare with the running version: after the reinstall the stored state
127
+ // still names the old one, and the notice must clear by itself.
128
+ const runningVersion = safeVersion(options.currentVersion) || state.currentVersion;
129
+ const manualInstall = state.state === 'manual_install_required'
130
+ && (compareStableVersions(state.latestVersion, runningVersion) > 0
131
+ || (state.code === 'prerelease_promotion_requires_manual_update'
132
+ && state.latestVersion === runningVersion));
133
+ const snoozed = (newer || manualInstall) &&
134
+ consent.snoozedVersion === state.latestVersion && consent.snoozedUntil > now;
109
135
  const progress = getProgressModel(state);
110
136
  const quietFailure = state.state === 'failed' &&
111
137
  state.initiatedBy !== 'manual' &&
@@ -124,16 +150,21 @@
124
150
  },
125
151
  progress,
126
152
  available,
153
+ manualInstall,
127
154
  snoozed,
128
155
  execution,
129
- showPanel: (available && !snoozed) || execution || state.state === 'rolled_back' ||
130
- visibleFailure,
131
- badge: getBadge(state, { available, snoozed }),
156
+ showPanel: state.cancelRequested || state.recoveryPending
157
+ || (state.state === 'checking' && state.initiatedBy === 'manual')
158
+ || ((available || manualInstall) && !snoozed) || execution || state.state === 'rolled_back' || visibleFailure,
159
+ badge: getBadge(state, { available: available || manualInstall, snoozed }),
132
160
  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)
161
+ check: !state.cancelRequested && !state.recoveryPending && ['idle', 'committed', 'rolled_back', 'failed', 'manual_install_required'].includes(state.state),
162
+ copyInstall: manualInstall,
163
+ install: available && !state.cancelRequested && !state.recoveryPending,
164
+ later: !state.recoveryPending && (available || manualInstall || ['staged', 'waiting_for_idle'].includes(state.state)),
165
+ cancel: !state.recoveryPending && (state.cancelRequested || ['checking', 'downloading', 'staged', 'waiting_for_idle'].includes(state.state)),
166
+ recover: state.recoveryPending,
167
+ retry: !state.cancelRequested && !state.recoveryPending && ['failed', 'rolled_back'].includes(state.state)
137
168
  }
138
169
  };
139
170
  }
@@ -18,7 +18,7 @@
18
18
  if (!status.managed || !result.installedVersion || !result.nativeVersion ||
19
19
  !result.extensionVersion || !result.runtimeVersion) return result;
20
20
  if (['authorized', 'bound'].includes(status.authorization?.state) ||
21
- ['staged', 'activation_pending', 'applying', 'awaiting_health'].includes(status.transaction?.state)) {
21
+ ['staged', 'activation_pending', 'applying', 'bootstrap_pending', 'bootstrap_rolling_back', 'awaiting_health', 'rolling_back'].includes(status.transaction?.state)) {
22
22
  return { ...result, state: 'transaction_active' };
23
23
  }
24
24
  if (status.installedAligned !== true) return { ...result, state: 'repair_required' };
@@ -0,0 +1,78 @@
1
+ (function (root, factory) {
2
+ if (typeof module === 'object' && module.exports) module.exports = factory(require('./undoOperations'));
3
+ else root.CodexOverleafModuleRegistry.define('WritebackIntent', ['UndoOperations'], factory);
4
+ })(typeof globalThis !== 'undefined' ? globalThis : window, function (Undo) {
5
+ 'use strict';
6
+ const MAX_BYTES = 300 * 1024;
7
+ const types = new Set(['edit', 'create', 'delete', 'rename', 'move', 'binary-create', 'overwrite-binary']);
8
+ const path = value => typeof value === 'string' && value && !value.startsWith('/')
9
+ && !/^[A-Za-z]:/.test(value) && !value.replace(/\\/g, '/').split('/').some(part => !part || part === '.' || part === '..');
10
+ function normalize(value) {
11
+ if (!value || typeof value !== 'object' || !value.id || !value.projectId || !value.accountScopeId
12
+ || !value.sessionId || !value.runId || !Array.isArray(value.operations) || value.operations.length > 100) return null;
13
+ const operations = [];
14
+ for (const input of value.operations) {
15
+ if (!types.has(input?.type) || !path(input.path) || (input.to && !path(input.to))) return null;
16
+ const op = { type: input.type, path: input.path };
17
+ for (const key of ['to', 'content', 'replaceAll', 'find', 'replace', 'sha256', 'mimeType']) {
18
+ if (typeof input[key] === 'string') op[key] = input[key];
19
+ }
20
+ if (Number.isSafeInteger(input.size)) op.size = input.size;
21
+ if (input.moveProof !== undefined) {
22
+ const proof = input.moveProof;
23
+ if (input.type !== 'move' || proof?.v !== 1 || !['text', 'binary'].includes(proof.kind)
24
+ || !/^[a-f0-9]{64}$/i.test(proof.sha256 || '')) return null;
25
+ op.moveProof = { v: 1, kind: proof.kind, sha256: proof.sha256.toLowerCase() };
26
+ if (proof.entityType !== undefined) {
27
+ if (!['doc', 'file'].includes(proof.entityType)) return null;
28
+ op.moveProof.entityType = proof.entityType;
29
+ }
30
+ for (const key of ['sourceEntityId', 'targetEntityId']) {
31
+ if (proof[key] !== undefined) {
32
+ if (typeof proof[key] !== 'string' || !proof[key] || proof[key].length > 160 || /[\0\r\n]/.test(proof[key])) return null;
33
+ op.moveProof[key] = proof[key];
34
+ }
35
+ }
36
+ }
37
+ if (Array.isArray(input.patches)) {
38
+ if (input.patches.length > 1000) return null;
39
+ op.patches = input.patches.map(p => ({ from: p.from, to: p.to, expected: String(p.expected ?? ''), insert: String(p.insert ?? '') }));
40
+ if (op.patches.some(p => !Number.isSafeInteger(p.from) || !Number.isSafeInteger(p.to) || p.from < 0 || p.to < p.from)) return null;
41
+ }
42
+ operations.push(op);
43
+ }
44
+ const paths = new Set(operations.flatMap(op => [op.path, op.to].filter(Boolean)));
45
+ const baseFiles = (Array.isArray(value.baseFiles) ? value.baseFiles : [])
46
+ .filter(file => paths.has(file?.path) && typeof file.content === 'string')
47
+ .map(file => ({ path: file.path, content: file.content }));
48
+ const result = { v: 1, id: String(value.id).slice(0, 160), projectId: String(value.projectId).slice(0, 160),
49
+ accountScopeId: String(value.accountScopeId).slice(0, 160), sessionId: String(value.sessionId).slice(0, 160),
50
+ runId: String(value.runId).slice(0, 160), createdAt: String(value.createdAt || '').slice(0, 64),
51
+ requireReviewing: value.requireReviewing === true, operations, baseFiles };
52
+ if (typeof value.requestId === 'string') result.requestId = value.requestId.slice(0, 160);
53
+ const size = typeof TextEncoder === 'function' ? new TextEncoder().encode(JSON.stringify(result)).length : JSON.stringify(result).length * 2;
54
+ return size <= MAX_BYTES ? result : null;
55
+ }
56
+ function expectedFiles(value) {
57
+ return Undo.buildExpectedFilesAfterOperations({ files: value.baseFiles }, value.operations.filter(op => !op.type.includes('binary')));
58
+ }
59
+ function normalizeSaveCheck(value) {
60
+ if (!value?.projectId || !value.accountScopeId || !value.sessionId || !value.runId
61
+ || !Array.isArray(value.files) || value.files.length > 1000) return null;
62
+ const files = [];
63
+ for (const file of value.files) {
64
+ if (!path(file?.path)) return null;
65
+ if (file.absent === true) files.push({ path: file.path, absent: true });
66
+ else if (/^[a-f0-9]{64}$/i.test(file.sha256 || '')) {
67
+ if (file.kind !== undefined && !['text', 'binary'].includes(file.kind)) return null;
68
+ files.push({ path: file.path, sha256: file.sha256.toLowerCase(),
69
+ ...(file.kind ? { kind: file.kind } : {}) });
70
+ }
71
+ else return null;
72
+ }
73
+ return files.length ? { v: 1, projectId: String(value.projectId).slice(0, 160),
74
+ accountScopeId: String(value.accountScopeId).slice(0, 160), sessionId: String(value.sessionId).slice(0, 160),
75
+ runId: String(value.runId).slice(0, 160), createdAt: String(value.createdAt || '').slice(0, 64), files } : null;
76
+ }
77
+ return { normalize, normalizeSaveCheck, expectedFiles, MAX_BYTES };
78
+ });
@@ -1,10 +1,10 @@
1
1
  (function initCodexOverleafWritebackOperationEvidence(root, factory) {
2
2
  if (typeof module === 'object' && module.exports) {
3
- module.exports = factory();
3
+ module.exports = factory(require('./failureReasons'));
4
4
  } else {
5
- root.CodexOverleafModuleRegistry.define('WritebackOperationEvidence', [], factory);
5
+ root.CodexOverleafModuleRegistry.define('WritebackOperationEvidence', ['FailureReasons'], factory);
6
6
  }
7
- })(typeof window !== 'undefined' ? window : globalThis, function writebackOperationEvidenceFactory() {
7
+ })(typeof window !== 'undefined' ? window : globalThis, function writebackOperationEvidenceFactory(FailureReasons) {
8
8
  'use strict';
9
9
 
10
10
  function normalizeOperationEvidence(operations = [], applyResult = {}) {
@@ -99,18 +99,7 @@
99
99
  }
100
100
 
101
101
  function normalizeFailure(result, operation) {
102
- if (result?.failure && typeof result.failure === 'object') return cloneValue(result.failure);
103
- if (!result?.code) return null;
104
- return {
105
- code: result.code,
106
- stage: result.stage || 'write',
107
- severity: result.severity || 'error',
108
- userMessage: result.reason || result.message || result.code,
109
- retryable: result.retryable === true,
110
- file: operation?.path || operation?.to || '',
111
- changedDocument: result.changedDocument === true,
112
- terminalState: result.terminalState || ''
113
- };
102
+ return FailureReasons.normalizeWritebackFailure(result, operation);
114
103
  }
115
104
 
116
105
  function normalizeTrackedChanges(value) {