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
@@ -10,6 +10,13 @@
10
10
  function buildSyncApplyOperations(syncChanges = [], project = {}) {
11
11
  const existingPaths = new Set((project.files || []).map(file => file.path));
12
12
  return (syncChanges || []).map(change => {
13
+ // Keep an old Native move distinct so preflight can reject it safely.
14
+ // Falling through would turn a move into an empty create operation.
15
+ if (change.type === 'move') {
16
+ return { type: 'move', path: change.path, to: change.to,
17
+ moveProof: change.moveProof && typeof change.moveProof === 'object' ? { ...change.moveProof } : undefined,
18
+ reason: 'Move the existing Overleaf file while preserving its identity.' };
19
+ }
13
20
  if (change.type === 'binary-create' || change.type === 'overwrite-binary') {
14
21
  return {
15
22
  type: change.type,
@@ -22,6 +29,7 @@
22
29
  previousExists: change.previousExists === true,
23
30
  previousKind: change.previousKind || '',
24
31
  previousSize: Number.isFinite(Number(change.previousSize)) ? Number(change.previousSize) : undefined,
32
+ ...(typeof change.previousSha256 === 'string' ? { previousSha256: change.previousSha256 } : {}),
25
33
  reasonKey: change.type === 'overwrite-binary' ? 'localWorkspaceBinaryOverwrite' : 'localWorkspaceBinaryCreate',
26
34
  reason: change.type === 'overwrite-binary'
27
35
  ? 'Synced a binary asset replacement from the local Codex workspace.'
@@ -158,14 +166,18 @@
158
166
 
159
167
  if ((operation.type === 'rename' || operation.type === 'move') && operation.to) {
160
168
  const previous = filesByPath.get(operation.path) || originalByPath.get(operation.path);
169
+ const destination = filesByPath.get(operation.to);
170
+ const binary = operation.moveProof?.kind === 'binary' || previous?.kind === 'binary';
161
171
  filesByPath.delete(operation.path);
162
172
  filesByPath.set(operation.to, {
163
173
  ...(previous || {}),
174
+ ...(destination || {}),
164
175
  path: operation.to,
165
- kind: 'text',
166
- content: result.verifiedContent || previous?.content || '',
176
+ kind: binary ? 'binary' : 'text',
177
+ ...(!binary ? { content: result.verifiedContent ?? destination?.content ?? previous?.content ?? '' } : {}),
167
178
  source: 'verified-writeback'
168
179
  });
180
+ if (binary) delete filesByPath.get(operation.to).content;
169
181
  continue;
170
182
  }
171
183
 
@@ -227,6 +239,16 @@
227
239
  ? changeOrReason
228
240
  : { reason: changeOrReason };
229
241
  const reason = change.reason;
242
+ if (reason === 'snapshot_content_unavailable') {
243
+ return isEnglish
244
+ ? 'Current Overleaf content was not read; local changes were withheld until the file can be refreshed.'
245
+ : '未读取该文件当前的 Overleaf 内容;刷新取得内容前,本地改动不会写回。';
246
+ }
247
+ if (reason === 'selection_scope_violation') {
248
+ return isEnglish
249
+ ? 'This local change exceeded the captured selection and was withheld. Independently valid selection changes may still be written.'
250
+ : '该项本地改动超出了已附加的选区,已阻止写回;独立且合法的选区内改动仍可写入。';
251
+ }
230
252
  if (reason === 'generated_artifact') {
231
253
  return isEnglish
232
254
  ? 'LaTeX build artifact; not written back by default.'
@@ -240,6 +262,11 @@
240
262
  if (reason === 'binary_payload_exceeds_native_message_limit') {
241
263
  return formatBinaryPayloadLimitReason(change, locale);
242
264
  }
265
+ if (reason === 'subagent_unfinished_output') {
266
+ return isEnglish
267
+ ? 'The subagent did not finish; the main agent must review and adopt this file before it can sync.'
268
+ : '子代理未正常完成,主代理需核对并接管该文件后才能同步。';
269
+ }
243
270
  if (reason === 'subagent_unauthorized_edit') {
244
271
  return isEnglish
245
272
  ? "A subagent's change to this file was withheld from Overleaf — it either fell outside the subagent's assigned files or the subagent did not finish cleanly."
@@ -290,10 +317,289 @@
290
317
  return (syncChanges || []).filter(change => appliedPaths.has(change.path));
291
318
  }
292
319
 
320
+
321
+ // Verify the server revision independently of editor overlays. No writes or retries
322
+ // of writes are performed here; a missing acknowledgement never becomes success.
323
+ function buildSavedWritebackExpectations(applied = {}, project = {}) {
324
+ const expected = new Map();
325
+ const original = new Map((project.files || []).map(file => [file.path, file]));
326
+ const unsupported = [];
327
+ for (const entry of getAppliedEntries(applied)) {
328
+ const operation = entry?.operation || {};
329
+ const result = entry?.result || {};
330
+ const path = operation.path;
331
+ if (!path || result.ok === false) { unsupported.push(path || 'unknown'); continue; }
332
+ if (operation.type === 'delete') { expected.set(path, { absent: true }); continue; }
333
+ if (operation.type === 'rename' || operation.type === 'move') {
334
+ const moveProof = result.moveProof || operation.moveProof;
335
+ if (moveProof?.v === 1 && moveProof.kind === 'binary' && /^[a-f0-9]{64}$/i.test(moveProof.sha256 || '')) {
336
+ if (!operation.to || (operation.moveProof?.sha256 && operation.moveProof.sha256 !== moveProof.sha256)) { unsupported.push(path); continue; }
337
+ if (operation.to !== path) expected.set(path, { absent: true });
338
+ expected.set(operation.to, { sha256: moveProof.sha256.toLowerCase() });
339
+ continue;
340
+ }
341
+ const content = typeof result.verifiedContent === 'string'
342
+ ? result.verifiedContent : original.get(path)?.content;
343
+ if (!operation.to || typeof content !== 'string') { unsupported.push(path); continue; }
344
+ if (operation.to !== path) expected.set(path, { absent: true });
345
+ expected.set(operation.to, { content });
346
+ continue;
347
+ }
348
+ if (operation.type === 'binary-create' || operation.type === 'overwrite-binary') {
349
+ const hash = operation.sha256 || operation.assetRef?.sha256;
350
+ if (/^[a-f0-9]{64}$/i.test(hash || '')) expected.set(path, { sha256: hash.toLowerCase() });
351
+ else if (typeof operation.contentBase64 === 'string'
352
+ && (operation.contentBase64 || !operation.assetRef || operation.size === 0)) {
353
+ expected.set(path, { contentBase64: operation.contentBase64.replace(/\s/g, '') });
354
+ } else unsupported.push(path);
355
+ continue;
356
+ }
357
+ const content = typeof result.verifiedContent === 'string' ? result.verifiedContent
358
+ : operation.type === 'create' && typeof operation.content === 'string' ? operation.content
359
+ : operation.type === 'edit' && typeof operation.replaceAll === 'string' ? operation.replaceAll : undefined;
360
+ if (typeof content === 'string') expected.set(path, { content });
361
+ else unsupported.push(path);
362
+ }
363
+ return { expected, unsupported };
364
+ }
365
+
366
+ async function matchSavedWritebackSnapshot(snapshot, expectations, projectId) {
367
+ if (snapshot?.id !== projectId || snapshot?.ok === false
368
+ || snapshot?.capabilities?.method !== 'overleaf-zip'
369
+ || snapshot.capabilities.fullProjectSnapshot !== true || !Array.isArray(snapshot.files)
370
+ || snapshot.files.some(file => file?.source !== 'overleaf-zip')) {
371
+ return { matched: false, reason: 'authoritative_snapshot_unavailable' };
372
+ }
373
+ if (!expectations.expected.size || expectations.unsupported.length) {
374
+ return { matched: false, reason: 'expected_content_unavailable' };
375
+ }
376
+ const byPath = new Map(snapshot.files.map(file => [file.path, file]));
377
+ for (const [path, expected] of expectations.expected) {
378
+ const file = byPath.get(path);
379
+ if (expected.absent) {
380
+ if (file || snapshot.capabilities.skipped?.length) return { matched: false, reason: 'server_content_mismatch', path };
381
+ continue;
382
+ }
383
+ if (!file) return { matched: false, reason: 'server_content_mismatch', path };
384
+ if (typeof expected.content === 'string') {
385
+ if (file.content !== expected.content) return { matched: false, reason: 'server_content_mismatch', path };
386
+ } else {
387
+ if (typeof file.contentBase64 !== 'string') return { matched: false, reason: 'server_binary_unavailable', path };
388
+ if (expected.contentBase64 !== undefined) {
389
+ if (file.contentBase64.replace(/\s/g, '') !== expected.contentBase64) return { matched: false, reason: 'server_content_mismatch', path };
390
+ } else {
391
+ const hash = await binaryDigest(file.contentBase64);
392
+ if (!hash) return { matched: false, reason: 'binary_digest_unavailable', path };
393
+ if (hash !== expected.sha256) return { matched: false, reason: 'server_content_mismatch', path };
394
+ }
395
+ }
396
+ }
397
+ return { matched: true };
398
+ }
399
+
400
+ async function confirmPostWriteSave(options = {}) {
401
+ const { applied, project, runProjectId, assertCurrent, readSaveState, readSnapshot } = options;
402
+ if (!runProjectId || typeof assertCurrent !== 'function') {
403
+ return { verification: { ok: false, state: 'unavailable', signal: 'context_missing' } };
404
+ }
405
+ const now = options.now || Date.now;
406
+ const deadline = now() + 90000;
407
+ const attempts = [];
408
+ const isInterruption = error => ['codex_cancelled', 'aborted_project_changed', 'editor_project_id_unavailable'].includes(error?.code)
409
+ || error?.name === 'AbortError';
410
+ const probe = async duration => {
411
+ assertCurrent();
412
+ try {
413
+ const result = await readSaveState({ deadlineMs: Math.max(0, Math.min(duration, deadline - now())), requirePositiveSignal: true });
414
+ assertCurrent();
415
+ return result || { ok: false, state: 'unavailable', signal: 'unavailable' };
416
+ } catch (error) {
417
+ if (isInterruption(error)) throw error;
418
+ assertCurrent();
419
+ return { ok: false, state: 'unavailable', signal: 'unavailable', reason: String(error?.message || error).slice(0, 800) };
420
+ }
421
+ };
422
+ const receiptExpectations = buildSavedWritebackExpectations(applied, project);
423
+ assertCurrent();
424
+ if (await receiptsConfirmExpectedFiles(applied, receiptExpectations, runProjectId)) {
425
+ assertCurrent();
426
+ return { verification: { ok: true, state: 'verified_saved', source: 'server-receipts' } };
427
+ }
428
+ const primary = await probe(1500);
429
+ if (primary.ok === true && primary.state === 'verified_saved') {
430
+ return { verification: { ...primary, source: 'save-indicator' } };
431
+ }
432
+ const expectations = buildSavedWritebackExpectations(applied, project);
433
+ let lastReason = '';
434
+ if (primary.signal !== 'offline' && expectations.expected.size && !expectations.unsupported.length) {
435
+ for (let attempt = 0; attempt < 3 && deadline - now() > 1000; attempt++) {
436
+ assertCurrent();
437
+ try {
438
+ const snapshot = await readSnapshot({
439
+ force: true, maxAgeMs: 0, zipOnly: true, serverOnly: true,
440
+ includeBinaryFiles: true, allowEditorNavigation: false, requireFullProject: true,
441
+ zipTimeoutMs: Math.max(1, Math.min(30000, deadline - now())),
442
+ saveCheckId: String(now()) + '-' + attempt + '-' + Math.random().toString(36).slice(2, 8)
443
+ });
444
+ assertCurrent();
445
+ const match = await matchSavedWritebackSnapshot(snapshot, expectations, runProjectId);
446
+ assertCurrent();
447
+ attempts.push({ attempt: attempt + 1, result: match.matched ? 'matched' : match.reason, path: match.path || '' });
448
+ if (match.matched) return {
449
+ verification: { ok: true, state: 'verified_saved', source: 'overleaf-zip', recovered: true,
450
+ primary: { state: primary.state, signal: primary.signal, reason: primary.reason }, attempts },
451
+ snapshot
452
+ };
453
+ lastReason = match.reason;
454
+ } catch (error) {
455
+ if (isInterruption(error)) throw error;
456
+ assertCurrent();
457
+ lastReason = String(error?.message || error).slice(0, 800);
458
+ attempts.push({ attempt: attempt + 1, result: 'snapshot_unavailable', reason: lastReason });
459
+ }
460
+ }
461
+ }
462
+ const final = primary.signal === 'offline' ? primary : await probe(2000);
463
+ if (final.ok === true && final.state === 'verified_saved') {
464
+ return { verification: { ...final, source: 'save-indicator', recovered: true, attempts } };
465
+ }
466
+ return { verification: {
467
+ ok: false, state: final.state === 'unavailable' ? 'unavailable' : 'unknown_timeout',
468
+ signal: final.signal || primary.signal || 'unavailable',
469
+ reason: final.reason || primary.reason || 'No positive save evidence was available.',
470
+ recoveryReason: lastReason || (expectations.unsupported.length ? 'expected_content_unavailable' : ''),
471
+ attempts
472
+ } };
473
+ }
474
+
475
+ async function buildMirrorWritebackConfirmation(applied = {}) {
476
+ const entries = Array.isArray(applied.applied) ? applied.applied : [];
477
+ if (!entries.length) return null;
478
+ const postImages = new Map();
479
+ for (const entry of entries) {
480
+ const operation = entry?.operation, result = entry?.result;
481
+ if (operation?.type !== 'edit' || typeof operation.path !== 'string' || !operation.path || result?.ok !== true
482
+ || result.verified !== true || typeof result.verifiedContent !== 'string') return null;
483
+ // Several edits can target one file; the last verified readback is its post-image.
484
+ postImages.set(operation.path, result.verifiedContent);
485
+ }
486
+ try {
487
+ const expectedFiles = [];
488
+ for (const [path, content] of postImages) {
489
+ const sha256 = await textDigest(content);
490
+ if (!/^[a-f0-9]{64}$/.test(sha256)) return null;
491
+ expectedFiles.push({ path, sha256 });
492
+ }
493
+ return { paths: expectedFiles.map(file => file.path), expectedFiles };
494
+ } catch (_error) {
495
+ return null; // No digest evidence: use the authoritative snapshot fallback.
496
+ }
497
+ }
498
+
499
+ async function bytesDigest(bytes) {
500
+ if (!globalThis.crypto?.subtle) return '';
501
+ const digest = await globalThis.crypto.subtle.digest('SHA-256', bytes);
502
+ return Array.from(new Uint8Array(digest), byte => byte.toString(16).padStart(2, '0')).join('');
503
+ }
504
+
505
+ async function textDigest(content) {
506
+ return typeof TextEncoder === 'function' ? bytesDigest(new TextEncoder().encode(content)) : '';
507
+ }
508
+
509
+ async function binaryDigest(contentBase64) {
510
+ if (typeof contentBase64 !== 'string' || typeof atob !== 'function') return '';
511
+ let bytes;
512
+ try { bytes = Uint8Array.from(atob(contentBase64.replace(/\s/g, '')), value => value.charCodeAt(0)); }
513
+ catch (_error) { return ''; }
514
+ return bytesDigest(bytes);
515
+ }
516
+
517
+ async function receiptsConfirmExpectedFiles(applied, expectations, projectId) {
518
+ if (!expectations.expected.size || expectations.unsupported.length) return false;
519
+ const entries = getAppliedEntries(applied);
520
+ for (const [path, expected] of expectations.expected) {
521
+ if (typeof expected.content !== 'string') return false;
522
+ const receipt = [...entries].reverse().find(entry => entry.operation?.path === path)?.result?.saveReceipt;
523
+ if (receipt?.v !== 1 || receipt.source !== 'overleaf-zip' || receipt.projectId !== projectId
524
+ || receipt.path !== path || !Number.isFinite(Date.parse(receipt.verifiedAt || ''))
525
+ || !/^[a-f0-9]{64}$/.test(receipt.sha256 || '') || receipt.sha256 !== await textDigest(expected.content)) return false;
526
+ }
527
+ return true;
528
+ }
529
+
530
+ async function buildSaveCheck(applied, project, owner) {
531
+ const expectations = buildSavedWritebackExpectations(applied, project);
532
+ if (expectations.unsupported.length) return null;
533
+ const files = [];
534
+ for (const [path, expected] of expectations.expected) {
535
+ if (expected.absent) files.push({ path, absent: true });
536
+ else if (typeof expected.content === 'string') {
537
+ const sha256 = await textDigest(expected.content);
538
+ if (!sha256) return null;
539
+ files.push({ path, sha256, kind: 'text' });
540
+ } else {
541
+ const sha256 = expected.sha256 || await binaryDigest(expected.contentBase64);
542
+ if (!sha256) return null;
543
+ files.push({ path, sha256, kind: 'binary' });
544
+ }
545
+ }
546
+ return files.length ? { ...owner, v: 1, files } : null;
547
+ }
548
+
549
+ async function confirmSaveCheck(check, options) {
550
+ if (!check?.projectId || !Array.isArray(check.files) || !check.files.length
551
+ || check.files.some(file => !file?.path || (file.absent !== true && !/^[a-f0-9]{64}$/i.test(file.sha256 || '')))) {
552
+ return { ok: false, state: 'unavailable', reason: 'expected_content_unavailable' };
553
+ }
554
+ const now = options.now || Date.now, deadline = now() + 90000;
555
+ let reason = 'server_snapshot_unavailable';
556
+ for (let attempt = 0; attempt < 3 && now() < deadline; attempt++) {
557
+ options.assertCurrent();
558
+ let snapshot;
559
+ try {
560
+ snapshot = await options.readSnapshot({ force: true, maxAgeMs: 0, zipOnly: true, serverOnly: true,
561
+ includeBinaryFiles: true, allowEditorNavigation: false, requireFullProject: true,
562
+ zipTimeoutMs: Math.min(30000, Math.max(1, deadline - now())), saveCheckId: String(now()) + '-' + attempt });
563
+ } catch (error) {
564
+ if (['codex_cancelled', 'aborted_project_changed', 'editor_project_id_unavailable'].includes(error?.code)
565
+ || error?.name === 'AbortError') throw error;
566
+ options.assertCurrent();
567
+ continue;
568
+ }
569
+ options.assertCurrent();
570
+ if (snapshot?.ok === false || snapshot?.id !== check.projectId
571
+ || snapshot.capabilities?.fullProjectSnapshot !== true
572
+ || snapshot.capabilities?.method !== 'overleaf-zip' || !Array.isArray(snapshot.files)) continue;
573
+ const files = new Map(snapshot.files.map(file => [file.path, file]));
574
+ let matched = true;
575
+ for (const expected of check.files) {
576
+ const file = files.get(expected.path);
577
+ if (expected.absent) { if (file || snapshot.capabilities.skipped?.length) matched = false; continue; }
578
+ if (!file || file.source !== 'overleaf-zip') { matched = false; continue; }
579
+ const kind = typeof file.content === 'string' ? 'text'
580
+ : typeof file.contentBase64 === 'string' ? 'binary' : '';
581
+ if (!kind || (expected.kind && expected.kind !== kind)) { matched = false; continue; }
582
+ const hash = kind === 'binary' ? await binaryDigest(file.contentBase64) : await textDigest(file.content);
583
+ if (!hash || hash !== expected.sha256.toLowerCase()) matched = false;
584
+ }
585
+ options.assertCurrent();
586
+ if (matched) return { ok: true, state: 'verified_saved', source: 'overleaf-zip' };
587
+ reason = 'server_content_mismatch';
588
+ }
589
+ return { ok: false, state: 'unknown_timeout', reason };
590
+ }
591
+
293
592
  return {
593
+ confirmPostWriteSave,
594
+ buildMirrorWritebackConfirmation,
595
+ buildSaveCheck,
596
+ confirmSaveCheck,
597
+ buildSavedWritebackExpectations,
598
+ matchSavedWritebackSnapshot,
294
599
  buildSyncApplyOperations,
295
600
  computeSingleTextPatch,
296
601
  formatUnsupportedLocalChangeSummary,
602
+ formatUnsupportedLocalChangeReason,
297
603
  getAppliedOperationPaths,
298
604
  getAppliedSyncChanges,
299
605
  getSyncChangePatches,