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
@@ -0,0 +1,311 @@
1
+ (function (root, factory) {
2
+ if (typeof module === 'object' && module.exports) module.exports = factory(require('./sharedSessionTransfer'));
3
+ else root.CodexOverleafModuleRegistry.define('SharedSessionBridge', ['SharedSessionTransfer'], factory);
4
+ })(typeof globalThis !== 'undefined' ? globalThis : this, function (Transfer) {
5
+ 'use strict';
6
+ const MESSAGE = 'codex-overleaf/shared-sessions-v1';
7
+ const LOCK_PORT = 'codex-overleaf/shared-session-lock-v1';
8
+ const CHANGE_KEY = 'codex-overleaf-shared-sessions-changed-v1';
9
+ const BASE = Symbol('shared-session-base');
10
+ const failure = (code, message) => Object.assign(new Error(message), { code });
11
+ const clone = value => value == null ? value : JSON.parse(JSON.stringify(value));
12
+ const clean = record => {
13
+ const result = clone(record);
14
+ if (result) delete result.sharedRevision;
15
+ return result;
16
+ };
17
+
18
+ function createBridge(environment = globalThis) {
19
+ const chromeApi = environment.chrome;
20
+ const clientId = environment.crypto?.randomUUID?.() || 'page-' + Date.now() + '-' + Math.random();
21
+ const migrations = new Map(), baselines = new Map(), heldLocks = new Map();
22
+ let legacy, wrapped;
23
+ function enabled() {
24
+ return Boolean(chromeApi?.runtime?.sendMessage && chromeApi?.runtime?.connect
25
+ && environment.location?.protocol === 'https:'
26
+ && ['overleaf.com', 'www.overleaf.com', 'cn.overleaf.com'].includes(environment.location?.hostname)
27
+ && /^\/project(?:\/|$)/.test(environment.location?.pathname || ''));
28
+ }
29
+ function capture(projectId = '', accountScopeId) {
30
+ const current = environment.codexOverleafDeriveAccountScopeId?.();
31
+ if (!current || (accountScopeId && current !== accountScopeId))
32
+ throw failure('account_scope_unavailable', 'A stable matching Overleaf account is required for shared history.');
33
+ return { accountScopeId: current, projectId };
34
+ }
35
+ function assertScope(value) { capture(value.projectId, value.accountScopeId); }
36
+ const cacheKey = (value, id) => value.accountScopeId + ':' + id;
37
+ const lockKey = (kind, value) => kind === 'review' ? 'review:' + JSON.stringify([value.accountScopeId, value.projectId, value.runId]) : kind === 'preferences' ? 'preferences' : 'state:' + value.accountScopeId;
38
+ async function request(method, value, args = {}) {
39
+ assertScope(value);
40
+ const lock = heldLocks.get(lockKey('state', value));
41
+ if (lock?.lost) throw failure('storage_lock_lost', 'The background storage connection was lost.');
42
+ const response = await chromeApi.runtime.sendMessage({
43
+ ...args, type: MESSAGE, method, scope: value, clientId, lockToken: lock?.token || ''
44
+ });
45
+ assertScope(value);
46
+ if (!response?.ok)
47
+ throw failure(response?.error?.code || 'shared_store_unavailable',
48
+ response?.error?.message || 'Shared history is unavailable. Reload the extension and this page.');
49
+ return response.result;
50
+ }
51
+
52
+ // Live ports own the locks. Worker/page termination releases them without
53
+ // allowing a stale client to silently fall back to an origin-local lock.
54
+ async function acquire(kind, value, work, onLost) {
55
+ assertScope(value);
56
+ const key = lockKey(kind, value), port = chromeApi.runtime.connect({ name: LOCK_PORT });
57
+ let timer, heartbeat, released = false, lock = null, rejectGrant;
58
+ const granted = new Promise((resolve, reject) => {
59
+ rejectGrant = reject;
60
+ port.onMessage.addListener(message => {
61
+ if (message?.type === 'busy') { reject(failure('review_busy', 'Another page is reviewing this run. Wait for it to finish.')); return; }
62
+ if (message?.type !== 'granted' || lock || released) return;
63
+ clearTimeout(timer);
64
+ lock = { token: message.token, deadlineAt: message.deadlineAt, lost: false };
65
+ heldLocks.set(key, lock);
66
+ resolve();
67
+ });
68
+ port.onDisconnect.addListener(() => {
69
+ // Read lastError to consume the runtime's disconnected-port warning.
70
+ void chromeApi.runtime.lastError;
71
+ if (lock) { lock.lost = true; if (!released) onLost?.(lock.token); }
72
+ if (!released) reject(failure('storage_lock_lost', 'The shared history lock disconnected.'));
73
+ });
74
+ timer = environment.setTimeout(() => reject(failure('storage_lock_timeout',
75
+ 'Another page is saving history. Retry after it finishes.')), 20000);
76
+ });
77
+ try {
78
+ heartbeat = environment.setInterval(() => {
79
+ try { port.postMessage({ type: 'ping' }); }
80
+ catch (_error) {
81
+ if (lock) lock.lost = true;
82
+ rejectGrant(failure('storage_lock_lost', 'The shared history lock disconnected.'));
83
+ }
84
+ }, 15000);
85
+ port.postMessage({ type: 'acquire', kind, scope: value });
86
+ await granted;
87
+ assertScope(value);
88
+ const assertOwner = () => { assertScope(value); if (lock.lost) throw failure('storage_lock_lost', 'The shared review owner disconnected.'); };
89
+ assertOwner.token = lock.token;
90
+ assertOwner.markDispatched = async () => {
91
+ assertOwner();
92
+ const lease = await request('review-dispatched', value, { runId: value.runId, reviewToken: lock.token });
93
+ assertOwner(); assertOwner.deadlineAt = lease.deadlineAt; return lease.deadlineAt;
94
+ };
95
+ const result = await work(assertOwner);
96
+ assertScope(value);
97
+ if (lock.lost) throw failure('storage_lock_lost', 'The shared history lock was lost before completion.');
98
+ return result;
99
+ } finally {
100
+ released = true;
101
+ if (kind === 'review' && lock && !lock.lost) {
102
+ await new Promise(resolve => {
103
+ const done = message => { if (message?.type === 'released') { port.onMessage.removeListener(done); environment.clearTimeout(releaseTimer); resolve(); } };
104
+ const releaseTimer = environment.setTimeout(resolve, 2000);
105
+ port.onMessage.addListener(done);
106
+ try { port.postMessage({ type: 'release-review', token: lock.token }); } catch (_) { resolve(); }
107
+ });
108
+ }
109
+ environment.clearTimeout(timer);
110
+ environment.clearInterval(heartbeat);
111
+ if (heldLocks.get(key) === lock) heldLocks.delete(key);
112
+ port.disconnect();
113
+ }
114
+ }
115
+ async function migrate(value) {
116
+ const account = value.accountScopeId;
117
+ if (!migrations.has(account)) {
118
+ const pending = (async () => {
119
+ const status = await request('migration-status', value);
120
+ if (status.complete) return;
121
+ if (!legacy) throw failure('shared_store_unavailable', 'Legacy history storage is not ready.');
122
+ // Read the original site DB once. Only explicitly owned records may
123
+ // cross origins. Unknown-account rows remain untouched for recovery.
124
+ const records = (await legacy.getAllSessions())
125
+ .filter(record => record?.accountScopeId === account && record.projectId && record.id);
126
+ await acquire('state', value, async () => {
127
+ for (const record of records) {
128
+ const recordScope = capture(record.projectId, account);
129
+ await request('import', recordScope, {
130
+ record: legacy.buildSessionRecord(record, { preserveRunActionPayload: true })
131
+ });
132
+ }
133
+ await request('migration-complete', value);
134
+ });
135
+ })();
136
+ migrations.set(account, pending);
137
+ pending.catch(() => { if (migrations.get(account) === pending) migrations.delete(account); });
138
+ }
139
+ await migrations.get(account);
140
+ assertScope(value);
141
+ }
142
+ async function withLock(kind, input, work) {
143
+ const value = capture(input.projectId, input.accountScopeId);
144
+ await migrate(value); // Before acquiring either lock: no migration/lock cycle.
145
+ return acquire(kind, value, work);
146
+ }
147
+ async function withWrite(value, work) {
148
+ await migrate(value);
149
+ const held = heldLocks.get(lockKey('state', value));
150
+ if (held) {
151
+ if (held.lost) throw failure('storage_lock_lost', 'The shared history lock was lost.');
152
+ return work();
153
+ }
154
+ return acquire('state', value, work);
155
+ }
156
+ function tag(record, value, adopt) {
157
+ if (!record) return record;
158
+ const base = clean(record);
159
+ if (adopt) baselines.set(cacheKey(value, record.id), base);
160
+ Object.defineProperty(record, BASE, { value: base, enumerable: true });
161
+ return record;
162
+ }
163
+ async function list(projectId = '', adopt = true) {
164
+ const value = capture(projectId);
165
+ await migrate(value);
166
+ const result = []; let after = '';
167
+ do {
168
+ const page = await request('list', value, { after });
169
+ for (const record of page.records) {
170
+ result.push(tag(record, value, adopt && !heldLocks.has(lockKey('state', value))));
171
+ }
172
+ after = page.next;
173
+ } while (after);
174
+ return result;
175
+ }
176
+ function adopt(records) {
177
+ const value = capture();
178
+ for (const record of records) {
179
+ if (record.accountScopeId === value.accountScopeId)
180
+ baselines.set(cacheKey(value, record.id), clean(record));
181
+ }
182
+ }
183
+ function hasLocalChanges(session) {
184
+ const base = baselines.get(cacheKey(capture(), session.id));
185
+ return Boolean(base && (session.updatedAt !== base.updatedAt || session.task !== base.task));
186
+ }
187
+ function wasStored(id) { return baselines.has(cacheKey(capture(), id)); }
188
+ async function put(records, options = {}) {
189
+ if (!records.length) return [];
190
+ const value = capture(records[0].projectId, records[0].accountScopeId);
191
+ if (records.some(record => record.projectId !== value.projectId || record.accountScopeId !== value.accountScopeId))
192
+ throw failure('shared_store_scope_mismatch', 'A session batch must belong to one account and project.');
193
+ return withWrite(value, async () => {
194
+ const entries = records.map(record => ({
195
+ record: clean(record),
196
+ base: record[BASE] || baselines.get(cacheKey(value, record.id)) || null
197
+ }));
198
+ const transfer = await Transfer.encode(entries);
199
+ const written = await request(transfer.method, value, { ...transfer.payload, reviewRunIds: options.reviewRunIds || [] });
200
+ // Keep the caller's submitted view as its merge baseline. A merged
201
+ // remote change has not necessarily been applied to the visible UI.
202
+ for (const entry of entries) baselines.set(cacheKey(value, entry.record.id), clean(entry.record));
203
+ return written;
204
+ });
205
+ }
206
+ async function get(id) {
207
+ const value = capture();
208
+ await migrate(value);
209
+ const record = await request('get', value, { id });
210
+ return tag(record, value, !heldLocks.has(lockKey('state', value)));
211
+ }
212
+ async function erase(method, projectId = '', id, accountScopeId) {
213
+ const value = capture(projectId, accountScopeId);
214
+ return withWrite(value, () => request(method, value, { id }));
215
+ }
216
+ function decorate(api) {
217
+ legacy = api;
218
+ wrapped = { ...api };
219
+ const route = (name, shared) => {
220
+ wrapped[name] = function (...args) {
221
+ return enabled() ? shared(...args) : api[name](...args);
222
+ };
223
+ };
224
+ route('buildSessionRecord', (input, options) => {
225
+ const record = api.buildSessionRecord(input, options);
226
+ const base = input[BASE] || baselines.get(cacheKey({ accountScopeId: record.accountScopeId }, record.id));
227
+ if (base) Object.defineProperty(record, BASE, { value: clone(base), enumerable: true });
228
+ return record;
229
+ });
230
+ route('getAllSessions', () => list());
231
+ route('getRecord', (store, id) => store === 'sessions' ? get(id) : api.getRecord(store, id));
232
+ route('getAllByIndex', async (store, index, value) => {
233
+ if (store !== 'sessions') return api.getAllByIndex(store, index, value);
234
+ const records = await list(index === 'projectId' ? value : '');
235
+ return records.filter(record => record[index] === value);
236
+ });
237
+ route('claimSessionsForAccount', async (projectId, accountScopeId, deleted = []) => {
238
+ capture(projectId, accountScopeId);
239
+ return (await list(projectId)).filter(record => !deleted.includes(record.id));
240
+ });
241
+ route('putRecord', async (store, record) =>
242
+ store === 'sessions' ? (await put([record]))[0] : api.putRecord(store, record));
243
+ route('putRecords', (store, records, options) =>
244
+ store === 'sessions' ? put(records, options) : api.putRecords(store, records));
245
+ route('deleteRecord', (store, id, expectedScope) =>
246
+ store === 'sessions' ? erase('delete', expectedScope?.projectId || '', id, expectedScope?.accountScopeId)
247
+ : api.deleteRecord(store, id));
248
+ route('deleteByIndex', async (store, index, value) => {
249
+ if (store !== 'sessions') return api.deleteByIndex(store, index, value);
250
+ if (index === 'projectId') return erase('clear-project', value);
251
+ for (const record of (await list()).filter(record => record[index] === value))
252
+ await erase('delete', record.projectId, record.id);
253
+ });
254
+ route('clearStore', store =>
255
+ store === 'sessions' ? erase('clear-account') : api.clearStore(store));
256
+ route('clearAllStores', async () => {
257
+ const value = capture();
258
+ await erase('clear-account');
259
+ // Preserve other accounts' legacy backups. Auxiliary stores remain
260
+ // site-local and retain their existing explicit clear-all semantics.
261
+ for (const record of await api.getAllSessions()) {
262
+ if (record.accountScopeId === value.accountScopeId) await api.deleteRecord('sessions', record.id);
263
+ }
264
+ await api.clearAuxiliaryStores();
265
+ baselines.clear();
266
+ });
267
+ route('listRecentProjectsAcrossAccount', async options => {
268
+ if (!options?.accountScopeId) return [];
269
+ capture('', options.accountScopeId);
270
+ return api.filterRecentProjectsAcrossAccount(await list(), options);
271
+ });
272
+ Object.assign(wrapped, {
273
+ sharedSessionsEnabled: enabled,
274
+ withSharedReviewLock: async (input, work) => {
275
+ const value = { ...capture(input.projectId, input.accountScopeId), runId: input.runId };
276
+ return acquire('review', value, work, input.onLost);
277
+ },
278
+ hasSharedReviewOwner: input => request('review-owner', capture(input.projectId, input.accountScopeId), { runId: input.runId }),
279
+ withSharedLock: withLock,
280
+ readSharedProjectSnapshot: projectId => list(projectId, false),
281
+ adoptSharedSessionBaseline: adopt,
282
+ hasUnpersistedSharedSession: hasLocalChanges,
283
+ wasSharedSessionStored: wasStored
284
+ });
285
+ return wrapped;
286
+ }
287
+ function subscribe(listener) {
288
+ if (!enabled() || !chromeApi.storage?.onChanged) return () => {};
289
+ const onChange = (changes, area) => {
290
+ const change = changes[CHANGE_KEY]?.newValue;
291
+ if (area !== 'local' || !change || change.clientId === clientId) return;
292
+ const account = environment.codexOverleafDeriveAccountScopeId?.();
293
+ if (account && change.accountScopeId === account) listener(change);
294
+ };
295
+ chromeApi.storage.onChanged.addListener(onChange);
296
+ return () => chromeApi.storage.onChanged.removeListener(onChange);
297
+ }
298
+ return { enabled, decorate, withLock, subscribe,
299
+ async readMeta(input) {
300
+ const value = capture(input.projectId, input.accountScopeId);
301
+ await migrate(value);
302
+ return request('meta-read', value);
303
+ },
304
+ async writeMeta(input, meta) {
305
+ const value = capture(input.projectId, input.accountScopeId);
306
+ return request('meta-write', value, { meta });
307
+ }
308
+ };
309
+ }
310
+ return { createBridge, ...createBridge() };
311
+ });
@@ -0,0 +1,140 @@
1
+ (function (root, factory) {
2
+ if (typeof module === 'object' && module.exports) module.exports = factory();
3
+ else root.CodexOverleafModuleRegistry.define('SharedSessionTransfer', [], factory);
4
+ })(typeof globalThis !== 'undefined' ? globalThis : window, function () {
5
+ 'use strict';
6
+ const MAX_WIRE_BYTES = 24 * 1024 * 1024;
7
+ // The old UTF-16 estimate admitted up to 3 UTF-8 bytes per code unit.
8
+ // Retain that finite Unicode window without enlarging ordinary ASCII writes.
9
+ const MAX_RECORD_BYTES = MAX_WIRE_BYTES * 3 / 2;
10
+ const MAX_RESPONSE_BYTES = MAX_RECORD_BYTES;
11
+ const MAX_DECODED_BYTES = 2 * MAX_RECORD_BYTES + 64 * 1024;
12
+ const error = (code, message) => Object.assign(new Error(message), { code });
13
+ const tooLarge = () => error('shared_session_too_large', 'The session batch exceeds the bounded shared storage transfer limit.');
14
+ const invalid = () => error('shared_session_transfer_invalid', 'The shared history transfer is invalid or incomplete.');
15
+ const byteLength = text => new TextEncoder().encode(text).byteLength;
16
+
17
+ function serialize(value, limit) {
18
+ // Count a lower bound during serialization, before a large aggregate string
19
+ // can be produced. The final UTF-8 check also includes commas and escaping.
20
+ let lowerBound = 0;
21
+ const text = JSON.stringify(value, function (key, item) {
22
+ if (key && !Array.isArray(this)) lowerBound += byteLength(JSON.stringify(key)) + 1;
23
+ if (typeof item === 'string') {
24
+ if (item.length > limit) throw tooLarge();
25
+ lowerBound += byteLength(JSON.stringify(item));
26
+ } else if (item === null) lowerBound += 4;
27
+ else if (typeof item === 'number') lowerBound += Number.isFinite(item) ? String(item).length : 4;
28
+ else if (typeof item === 'boolean') lowerBound += String(item).length;
29
+ else if (item && typeof item === 'object') lowerBound += 2;
30
+ if (lowerBound > limit) throw tooLarge();
31
+ return item;
32
+ });
33
+ if (typeof text !== 'string') throw invalid();
34
+ const bytes = byteLength(text);
35
+ if (bytes > limit) throw tooLarge();
36
+ return { text, bytes };
37
+ }
38
+
39
+ function validateRecord(record) {
40
+ const value = serialize(record, MAX_RECORD_BYTES);
41
+ if (value.bytes > MAX_WIRE_BYTES && value.text.length * 2 > MAX_WIRE_BYTES) throw tooLarge();
42
+ }
43
+
44
+ function validateResponse(records) { serialize(records, MAX_RESPONSE_BYTES); }
45
+
46
+ function validateEntries(entries) {
47
+ if (!Array.isArray(entries)) throw invalid();
48
+ for (const entry of entries) {
49
+ if (!entry || !entry.record || typeof entry.record !== 'object' || Array.isArray(entry.record)) throw invalid();
50
+ validateRecord(entry.record);
51
+ if (entry.base != null) {
52
+ if (typeof entry.base !== 'object' || Array.isArray(entry.base)) throw invalid();
53
+ // A previously stored merged baseline may be larger than new records;
54
+ // allow a bounded old base so a smaller candidate can repair it.
55
+ serialize(entry.base, MAX_DECODED_BYTES);
56
+ }
57
+ }
58
+ }
59
+
60
+ async function readLimited(stream, limit) {
61
+ const reader = stream.getReader(), chunks = [];
62
+ let length = 0;
63
+ try {
64
+ while (true) {
65
+ const result = await reader.read();
66
+ if (result.done) break;
67
+ length += result.value.byteLength;
68
+ if (length > limit) { await reader.cancel().catch(() => {}); throw tooLarge(); }
69
+ chunks.push(result.value);
70
+ }
71
+ } finally { reader.releaseLock(); }
72
+ const output = new Uint8Array(length); let offset = 0;
73
+ for (const chunk of chunks) { output.set(chunk, offset); offset += chunk.byteLength; }
74
+ return output;
75
+ }
76
+
77
+ function toBase64(bytes) {
78
+ let text = '';
79
+ for (let i = 0; i < bytes.length; i += 0x8000) text += String.fromCharCode(...bytes.subarray(i, i + 0x8000));
80
+ return btoa(text);
81
+ }
82
+ function fromBase64(value) {
83
+ if (typeof value !== 'string' || !value.length || value.length % 4
84
+ || !/^[A-Za-z0-9+/]*={0,2}$/.test(value)) throw invalid();
85
+ const text = atob(value);
86
+ const bytes = new Uint8Array(text.length);
87
+ for (let i = 0; i < text.length; i++) bytes[i] = text.charCodeAt(i);
88
+ return bytes;
89
+ }
90
+
91
+ async function encode(entries, environment = globalThis) {
92
+ validateEntries(entries);
93
+ const raw = serialize(entries, MAX_DECODED_BYTES);
94
+ if (raw.bytes <= MAX_WIRE_BYTES || (raw.bytes <= MAX_RECORD_BYTES && raw.text.length * 2 <= MAX_WIRE_BYTES)) {
95
+ return { method: 'put', payload: { entries } };
96
+ }
97
+ if (typeof environment.CompressionStream !== 'function') {
98
+ throw error('shared_session_compression_unavailable',
99
+ 'Lossless transfer compression is unavailable. History remains in memory; retry with a supported browser.');
100
+ }
101
+ const input = new Blob([raw.text]).stream();
102
+ const packed = await readLimited(input.pipeThrough(new environment.CompressionStream('gzip')),
103
+ Math.floor((MAX_WIRE_BYTES - 1024) * 3 / 4));
104
+ const payload = { encoding: 'gzip-base64', version: 1, decodedBytes: raw.bytes, data: toBase64(packed) };
105
+ serialize(payload, MAX_WIRE_BYTES);
106
+ // A distinct method makes an older worker reject rather than acknowledge
107
+ // an absent `entries` array as a successful empty write.
108
+ return { method: 'put-compressed', payload };
109
+ }
110
+
111
+ async function decode(message, environment = globalThis) {
112
+ if (message.method !== 'put-compressed') {
113
+ const entries = message.method === 'import' ? [{ record: message.record }] : message.entries || [];
114
+ const raw = serialize(entries, MAX_RECORD_BYTES);
115
+ if (raw.bytes > MAX_WIRE_BYTES && raw.text.length * 2 > MAX_WIRE_BYTES) throw tooLarge();
116
+ validateEntries(entries); return entries;
117
+ }
118
+ const payload = { encoding: message.encoding, version: message.version, decodedBytes: message.decodedBytes, data: message.data };
119
+ serialize(payload, MAX_WIRE_BYTES);
120
+ if (message.entries != null || payload.encoding !== 'gzip-base64' || payload.version !== 1
121
+ || !Number.isSafeInteger(payload.decodedBytes) || payload.decodedBytes < 1 || payload.decodedBytes > MAX_DECODED_BYTES) throw invalid();
122
+ if (typeof environment.DecompressionStream !== 'function') throw error('shared_session_compression_unavailable',
123
+ 'Lossless transfer decompression is unavailable. Reload the extension and retry.');
124
+ let bytes;
125
+ try {
126
+ bytes = await readLimited(new Blob([fromBase64(payload.data)]).stream()
127
+ .pipeThrough(new environment.DecompressionStream('gzip')), MAX_DECODED_BYTES);
128
+ } catch (failure) {
129
+ if (['shared_session_too_large', 'shared_session_transfer_invalid'].includes(failure?.code)) throw failure;
130
+ throw invalid();
131
+ }
132
+ if (bytes.byteLength !== payload.decodedBytes) throw invalid();
133
+ let entries;
134
+ try { entries = JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes)); }
135
+ catch (_error) { throw invalid(); }
136
+ validateEntries(entries);
137
+ return entries;
138
+ }
139
+ return { MAX_WIRE_BYTES, MAX_RECORD_BYTES, MAX_RESPONSE_BYTES, MAX_DECODED_BYTES, byteLength, validateRecord, validateResponse, encode, decode };
140
+ });
@@ -17,7 +17,9 @@
17
17
  if (typeof file?.path === 'string') {
18
18
  const path = normalizePath(file.path);
19
19
  if (path) {
20
- lookup.set(path, normalizeText(file.content));
20
+ // Patch offsets refer to this exact UTF-16 string. Normalize only
21
+ // for comparisons, never discard the source coordinate system.
22
+ lookup.set(path, String(file.content ?? ''));
21
23
  }
22
24
  }
23
25
  }
@@ -40,13 +42,7 @@
40
42
  };
41
43
  }
42
44
 
43
- const baseContent = baseFileLookup.get(filePath);
44
- if (!baseContent || baseContent.trim().length === 0) {
45
- if (typeof console !== 'undefined') {
46
- console.warn('[codex-overleaf] staleGuard: base empty for', filePath, '→ skipping check');
47
- }
48
- return { ok: true };
49
- }
45
+ const baseContent = normalizeText(baseFileLookup.get(filePath));
50
46
  const current = normalizeText(currentContent);
51
47
  if (current !== baseContent) {
52
48
  if (typeof console !== 'undefined') {
@@ -55,7 +51,7 @@
55
51
  'base[0..80]:', JSON.stringify(baseContent.slice(0, 80)),
56
52
  'current[0..80]:', JSON.stringify(current.slice(0, 80)));
57
53
  }
58
- const patchRangeFreshness = checkPatchRangeFreshness(operation, current);
54
+ const patchRangeFreshness = checkPatchRangeFreshness(operation, currentContent, baseFileLookup);
59
55
  if (patchRangeFreshness) {
60
56
  return patchRangeFreshness;
61
57
  }
@@ -71,13 +67,17 @@
71
67
  return { ok: true };
72
68
  }
73
69
 
74
- function checkPatchRangeFreshness(operation, currentContent) {
75
- const patches = Array.isArray(operation?.patches) ? operation.patches : [];
70
+ function checkPatchRangeFreshness(operation, currentContent, baseFileLookup) {
71
+ const prepared = prepareOperationPatches(operation, currentContent, baseFileLookup);
72
+ if (!prepared.ok) {
73
+ return { ...prepared, code: 'stale_patch_range', reasonKey: 'stalePatchConflict' };
74
+ }
75
+ const patches = prepared.patches;
76
76
  if (!patches.length) {
77
77
  return null;
78
78
  }
79
79
 
80
- const current = normalizeText(currentContent);
80
+ const current = String(currentContent ?? '');
81
81
  for (const rawPatch of patches) {
82
82
  const from = Number(rawPatch?.from);
83
83
  const to = Number(rawPatch?.to);
@@ -107,12 +107,116 @@
107
107
  };
108
108
  }
109
109
 
110
+ // Bridge the raw Native baseline to the editor's line-ending representation.
111
+ // Logical LF offsets are only an intermediate coordinate system: both the
112
+ // range check and the eventual editor dispatch use the same raw patches.
113
+ function prepareOperationPatches(operation, currentContent, baseFileLookup) {
114
+ const patches = Array.isArray(operation?.patches) ? operation.patches : [];
115
+ const current = String(currentContent ?? '');
116
+ const path = normalizePath(operation?.path);
117
+ const base = baseFileLookup?.get(path);
118
+ if (!patches.length || typeof base !== 'string' || base === current) {
119
+ return { ok: true, patches };
120
+ }
121
+ const baseMap = lineEndingMap(base);
122
+ const currentMap = lineEndingMap(current);
123
+ // With no CRLF on either side, retain the existing raw range semantics.
124
+ if (!baseMap.removed.length && !currentMap.removed.length) return { ok: true, patches };
125
+
126
+ const groups = [];
127
+ let previousTo = 0;
128
+ for (const patch of patches) {
129
+ const from = Number(patch?.from), to = Number(patch?.to);
130
+ if (!Number.isInteger(from) || !Number.isInteger(to) || from < previousTo || to < from || to > base.length) {
131
+ return patchMappingFailure('invalid_patch');
132
+ }
133
+ if (base.slice(from, to) !== String(patch.expected ?? '')) return patchMappingFailure('stale_patch');
134
+ previousTo = to;
135
+ // Expand only a split CRLF or a new pair formed across an edit edge.
136
+ // Other neighbouring newlines belong to the editor and stay untouched.
137
+ let start = from, end = to;
138
+ const insert = String(patch.insert ?? '');
139
+ if (base[from - 1] === '\r' && (base[from] === '\n' || insert.startsWith('\n') || (!insert && base[to] === '\n'))) start -= 1;
140
+ if (base[to] === '\n' && (base[to - 1] === '\r' || insert.endsWith('\r') || (!insert && base[from - 1] === '\r'))) end += 1;
141
+ const previous = groups[groups.length - 1];
142
+ if (previous && start <= previous.end) {
143
+ previous.end = Math.max(previous.end, end);
144
+ previous.patches.push({ ...patch, from, to });
145
+ } else groups.push({ start, end, patches: [{ ...patch, from, to }] });
146
+ }
147
+
148
+ const mapped = [], sourceChanges = [];
149
+ for (const group of groups) {
150
+ const logicalFrom = baseMap.toLogical(group.start), logicalTo = baseMap.toLogical(group.end);
151
+ if (logicalTo > currentMap.length) return patchMappingFailure('invalid_patch');
152
+ const from = currentMap.toRaw(logicalFrom), to = currentMap.toRaw(logicalTo);
153
+ const expected = current.slice(from, to);
154
+ if (normalizeText(expected) !== normalizeText(base.slice(group.start, group.end))) {
155
+ return patchMappingFailure('stale_patch');
156
+ }
157
+ let insert = base.slice(group.start, group.end);
158
+ for (const patch of group.patches.slice().sort((left, right) => right.from - left.from)) {
159
+ if (insert.slice(patch.from - group.start, patch.to - group.start) !== String(patch.expected ?? '')) {
160
+ return patchMappingFailure('stale_patch');
161
+ }
162
+ insert = insert.slice(0, patch.from - group.start) + String(patch.insert ?? '') + insert.slice(patch.to - group.start);
163
+ }
164
+ sourceChanges.push({ from: group.start, to: group.end, insert });
165
+ const sourceEnding = nearestLineEnding(base, group.start);
166
+ const editorEnding = nearestLineEnding(current, from);
167
+ if (sourceEnding && editorEnding && sourceEnding !== editorEnding) {
168
+ insert = normalizeText(insert).replace(/\n/g, editorEnding);
169
+ }
170
+ // Leave equal surrounding text out of the dispatch/Track range.
171
+ let prefix = 0, oldEnd = expected.length, newEnd = insert.length;
172
+ while (prefix < oldEnd && prefix < newEnd && expected[prefix] === insert[prefix]) prefix += 1;
173
+ while (oldEnd > prefix && newEnd > prefix && expected[oldEnd - 1] === insert[newEnd - 1]) { oldEnd -= 1; newEnd -= 1; }
174
+ mapped.push({ from: from + prefix, to: from + oldEnd, expected: expected.slice(prefix, oldEnd), insert: insert.slice(prefix, newEnd) });
175
+ }
176
+ // A later operation in the same batch still addresses the original
177
+ // representation, so advance its baseline separately from editor text.
178
+ let sourceContent = base;
179
+ for (const patch of sourceChanges.reverse()) {
180
+ sourceContent = sourceContent.slice(0, patch.from) + patch.insert + sourceContent.slice(patch.to);
181
+ }
182
+ return { ok: true, patches: mapped, sourceContent };
183
+ }
184
+
185
+ function patchMappingFailure(code) {
186
+ return { ok: false, code, reason: 'Codex 要修改的位置已经无法和当前 Overleaf 内容对齐,所以没有写入。请重新运行任务。' };
187
+ }
188
+
189
+ function lineEndingMap(text) {
190
+ const removed = [];
191
+ for (let index = 0; index < text.length - 1; index += 1) {
192
+ if (text[index] === '\r' && text[index + 1] === '\n') removed.push(index);
193
+ }
194
+ function countBefore(offset, logical) {
195
+ let low = 0, high = removed.length;
196
+ while (low < high) {
197
+ const middle = (low + high) >>> 1;
198
+ if (removed[middle] - (logical ? middle : 0) < offset) low = middle + 1;
199
+ else high = middle;
200
+ }
201
+ return low;
202
+ }
203
+ return { removed, length: text.length - removed.length,
204
+ toLogical: offset => offset - countBefore(offset, false),
205
+ toRaw: offset => offset + countBefore(offset, true) };
206
+ }
207
+
208
+ function nearestLineEnding(text, offset) {
209
+ let newline = text.indexOf('\n', offset);
210
+ if (newline < 0) newline = text.lastIndexOf('\n', offset - 1);
211
+ return newline < 0 ? '' : text[newline - 1] === '\r' ? '\r\n' : '\n';
212
+ }
213
+
110
214
  function updateExpectedFileContent(baseFileLookup, filePath, content) {
111
215
  const path = normalizePath(filePath);
112
216
  if (!baseFileLookup || !path) {
113
217
  return;
114
218
  }
115
- baseFileLookup.set(path, normalizeText(content));
219
+ baseFileLookup.set(path, String(content ?? ''));
116
220
  }
117
221
 
118
222
  function removeExpectedFile(baseFileLookup, filePath) {
@@ -152,6 +256,7 @@
152
256
  return {
153
257
  buildBaseFileLookup,
154
258
  checkOperationFreshness,
259
+ prepareOperationPatches,
155
260
  updateExpectedFileContent,
156
261
  removeExpectedFile,
157
262
  moveExpectedFile,