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,181 @@
1
+ (function initBootstrapMigration(root) {
2
+ 'use strict';
3
+
4
+ const UPDATE_STATE_KEY = 'codex-overleaf-managed-update-state-v1';
5
+ const RETRY_ALARM = 'codex-overleaf-bootstrap-migration-retry';
6
+ const RETRY_MS = 4000;
7
+ const MAX_WAIT_MS = 2 * 60 * 1000;
8
+ let readyPromise;
9
+ let lockedOwner;
10
+ let setExecutionLocked;
11
+
12
+ function init(options) {
13
+ if (readyPromise) return readyPromise;
14
+ readyPromise = prepare(options);
15
+ return readyPromise;
16
+ }
17
+
18
+ async function prepare(options) {
19
+ let transaction;
20
+ let reloadProtected = false;
21
+ let rollbackState = 'bootstrap_pending';
22
+ const revision = String(root.__CODEX_OVERLEAF_BOOTSTRAP_REVISION__ || '');
23
+ const request = async (method, params = {}) => {
24
+ const response = await options.request({ id: crypto.randomUUID(), method,
25
+ params: { ...params, bootstrapRevision: revision } });
26
+ if (!response?.ok) throw Object.assign(new Error(response?.error?.message || 'Managed update request failed.'),
27
+ { code: response?.error?.code || 'update_health_failed' });
28
+ return response.result || {};
29
+ };
30
+ try {
31
+ const status = await request('update.status');
32
+ transaction = status.transaction;
33
+ if (transaction?.state !== 'bootstrap_pending') return { continueInitialization: true };
34
+ options.setExecutionLocked(true);
35
+ lockedOwner = { id: transaction.id, targetVersion: transaction.targetVersion, revision };
36
+ setExecutionLocked = options.setExecutionLocked;
37
+ if (!transaction.id || transaction.targetVersion !== root.CodexOverleafCompatibility?.BUILD_TARGET_VERSION) {
38
+ throw codedError('The running update does not match the pending Bootstrap transaction.');
39
+ }
40
+ reloadProtected = await options.protectReloadTabs(transaction);
41
+ if (!reloadProtected) throw codedError('The previous page refresh list could not be protected.');
42
+ await writeState({ state: 'awaiting_health', transactionId: transaction.id,
43
+ latestVersion: transaction.targetVersion, code: '', message: '' });
44
+
45
+ // The first reload may leave old content contexts alive. Recheck the same
46
+ // idle/save contract before replacing their loader and reloading again.
47
+ const deadline = Date.now() + MAX_WAIT_MS;
48
+ while (true) {
49
+ const gate = await options.verifySafety({ transactionId: transaction.id, targetVersion: transaction.targetVersion,
50
+ sourceVersion: transaction.sourceVersion, expectedState: 'bootstrap_pending' });
51
+ if (gate?.ok) break;
52
+ if (Date.now() >= deadline) throw codedError('The Bootstrap update did not reach a safe point.');
53
+ await writeState({ blockers: gate?.error?.blockers || ['busy'] });
54
+ await waitForRetry();
55
+ const refreshed = await request('update.status');
56
+ if (refreshed.transaction?.id !== transaction.id || refreshed.transaction?.state !== 'bootstrap_pending') {
57
+ throw Object.assign(codedError('The pending Bootstrap transaction changed before activation.'), { restoredStatus: refreshed });
58
+ }
59
+ }
60
+
61
+ const result = await request('update.bootstrap', { transactionId: transaction.id });
62
+ if (result.transactionId !== transaction.id || result.targetVersion !== transaction.targetVersion) {
63
+ throw codedError('The Bootstrap activation result does not match the pending update.');
64
+ }
65
+ await writeState({ blockers: [], blocker: '' });
66
+ if (result.state === 'reload_required') {
67
+ // Only one reload per worker. Native owns the persistent attempt limit
68
+ // so a broken target cannot create a loop across worker restarts.
69
+ chrome.runtime.reload();
70
+ return { continueInitialization: false, state: result.state };
71
+ }
72
+ if (result.state !== 'awaiting_health' || revision !== '3.1' || result.bootstrapRevision !== revision) {
73
+ throw codedError('The updated Bootstrap did not provide its loaded revision.');
74
+ }
75
+ rollbackState = 'awaiting_health';
76
+ if (!await options.releaseReloadTabs(transaction, 'awaiting_health')) throw codedError('The original page identities could not be confirmed.');
77
+ return { continueInitialization: true, state: result.state };
78
+ } catch (error) {
79
+ if (!transaction || transaction.state !== 'bootstrap_pending') return { continueInitialization: true };
80
+ if (!reloadProtected) {
81
+ await writeState({ state: 'failed', recoveryPending: true, code: 'update_recovery_pending' }).catch(() => {});
82
+ return { continueInitialization: false, state: 'failed' };
83
+ }
84
+ const code = /^[a-z0-9_]{1,80}$/.test(error?.code || '') ? error.code : 'update_health_failed';
85
+ await writeState({ state: 'rolling_back', code }).catch(() => {});
86
+ let restored = false;
87
+ try {
88
+ let status = error.restoredStatus;
89
+ let rollback = status && { transactionId: status.transaction?.id, state: status.transaction?.state,
90
+ version: status.activeVersion, restoredPair: status.restoredPair };
91
+ if (!hasRestoredSource(transaction, rollback, status)) {
92
+ rollback = await request('update.rollback', { transactionId: transaction.id,
93
+ expectedState: rollbackState, reasonCode: code });
94
+ status = await request('update.status');
95
+ }
96
+ if (!hasRestoredSource(transaction, rollback, status)) throw codedError('Bootstrap rollback is unconfirmed.');
97
+ await writeState({ state: 'rolled_back', currentVersion: transaction.sourceVersion,
98
+ transactionId: transaction.id, recoveryPending: false, blockers: [], blocker: '', code });
99
+ restored = true;
100
+ while (true) {
101
+ try {
102
+ // A new document must never inherit the old document's refresh
103
+ // authorization. The source worker sees an empty legacy list;
104
+ // the guarded evidence remains for a later natural/user refresh.
105
+ if (await options.hasReplacedReloadDocument(transaction)) break;
106
+ const gate = await options.verifySafety({ transactionId: transaction.id, targetVersion: transaction.targetVersion,
107
+ sourceVersion: transaction.sourceVersion, expectedState: 'rolled_back' });
108
+ if (gate?.ok && await options.releaseReloadTabs(transaction, 'rolled_back')) break;
109
+ } catch (_) { /* Restored files stay restored while a page probe retries. */ }
110
+ await waitForRetry();
111
+ }
112
+ chrome.runtime.reload();
113
+ return { continueInitialization: false, state: 'rolled_back' };
114
+ } catch (_rollbackError) {
115
+ if (restored) return { continueInitialization: false, state: 'rolled_back' };
116
+ await writeState({ state: 'failed', recoveryPending: true, transactionId: transaction.id,
117
+ code: 'update_recovery_pending', message: 'The installed update result has not been confirmed.' }).catch(() => {});
118
+ return { continueInitialization: false, state: 'failed' };
119
+ }
120
+ } finally {
121
+ await chrome.alarms?.clear?.(RETRY_ALARM).catch?.(() => {});
122
+ }
123
+ }
124
+
125
+ async function writeState(patch) {
126
+ const stored = await chrome.storage.local.get(UPDATE_STATE_KEY);
127
+ const state = root.CodexOverleafManagedUpdateProjection.transition(stored[UPDATE_STATE_KEY] || {}, patch,
128
+ { currentVersion: chrome.runtime.getManifest().version });
129
+ await chrome.storage.local.set({ [UPDATE_STATE_KEY]: state });
130
+ }
131
+
132
+ function waitForRetry() {
133
+ return new Promise(resolve => {
134
+ let settled = false;
135
+ let timer;
136
+ const finish = () => {
137
+ if (settled) return;
138
+ settled = true;
139
+ clearTimeout(timer);
140
+ chrome.alarms?.onAlarm?.removeListener?.(onAlarm);
141
+ resolve();
142
+ };
143
+ const onAlarm = alarm => { if (alarm?.name === RETRY_ALARM) finish(); };
144
+ chrome.alarms?.onAlarm?.addListener?.(onAlarm);
145
+ chrome.alarms?.create?.(RETRY_ALARM, { delayInMinutes: 0.5 });
146
+ timer = setTimeout(finish, RETRY_MS);
147
+ });
148
+ }
149
+
150
+ function hasRestoredSource(transaction, rollback, status) {
151
+ const pair = status?.restoredPair;
152
+ return rollback?.transactionId === transaction.id && rollback.state === 'rolled_back'
153
+ && rollback.version === transaction.sourceVersion && status?.transaction?.id === transaction.id
154
+ && status.transaction.state === 'rolled_back' && status.activeVersion === transaction.sourceVersion
155
+ && status.installedAligned === true && pair?.extensionVersion === transaction.sourceVersion
156
+ && pair?.nativeVersion === transaction.sourceVersion
157
+ && /^[0-9a-f]{64}$/.test(pair.extensionSha256 || '') && /^[0-9a-f]{64}$/.test(pair.nativeSha256 || '')
158
+ && /^[0-9a-f]{64}$/.test(pair.bootstrapSha256 || '')
159
+ && ['extensionVersion', 'nativeVersion', 'extensionSha256', 'nativeSha256', 'bootstrapSha256']
160
+ .every(key => pair[key] === rollback.restoredPair?.[key]);
161
+ }
162
+
163
+ function codedError(message) {
164
+ return Object.assign(new Error(message), { code: 'update_health_failed' });
165
+ }
166
+
167
+ function observeConfirmation(params, response) {
168
+ if (!lockedOwner || !response?.ok || response.result?.state !== 'committed'
169
+ || response.result.version !== lockedOwner.targetVersion || params?.transactionId !== lockedOwner.id
170
+ || params.extensionVersion !== lockedOwner.targetVersion || params.nativeVersion !== lockedOwner.targetVersion
171
+ || params.bootstrapRevision !== lockedOwner.revision || lockedOwner.revision !== '3.1') return;
172
+ lockedOwner = null;
173
+ setExecutionLocked(false);
174
+ }
175
+
176
+ root.CodexOverleafBootstrapMigration = Object.freeze({
177
+ init,
178
+ observeConfirmation,
179
+ ready: () => readyPromise || Promise.resolve({ continueInitialization: true })
180
+ });
181
+ })(globalThis);
@@ -0,0 +1,440 @@
1
+ (function (root, factory) {
2
+ const api = factory(typeof module === 'object' && module.exports
3
+ ? require('./shared/sharedSessionTransfer') : root.CodexOverleafSharedSessionTransfer);
4
+ if (typeof module === 'object' && module.exports) module.exports = api;
5
+ if (root) root.CodexOverleafSharedSessionsBackground = api;
6
+ })(typeof globalThis !== 'undefined' ? globalThis : this, function (Transfer) {
7
+ 'use strict';
8
+ const MESSAGE = 'codex-overleaf/shared-sessions-v1';
9
+ const LOCK_PORT = 'codex-overleaf/shared-session-lock-v1';
10
+ const REVIEW_LEASE_PREFIX = 'codex-overleaf-review-lease-v1:';
11
+ const CHANGE_KEY = 'codex-overleaf-shared-sessions-changed-v1';
12
+ const HOSTS = ['overleaf.com', 'www.overleaf.com', 'cn.overleaf.com'];
13
+ const META_PREFIX = 'codex-overleaf-scoped-persistence-v1:';
14
+ const MAX_BYTES = 8 * 1024 * 1024;
15
+ const own = (value, key) => Object.prototype.hasOwnProperty.call(value || {}, key);
16
+ const clone = value => value === undefined ? undefined : JSON.parse(JSON.stringify(value));
17
+ const equal = (a, b) => JSON.stringify(a) === JSON.stringify(b);
18
+ const failure = (code, message) => Object.assign(new Error(message), { code });
19
+ function part(value) {
20
+ if (typeof value !== 'string' || !value.trim() || value.length > 256 || /[\0\r\n]/.test(value))
21
+ throw failure('shared_store_scope_invalid', 'The shared session identity is invalid.');
22
+ return value;
23
+ }
24
+ function scope(input) {
25
+ return { accountScopeId: part(input?.accountScopeId), projectId: typeof input?.projectId === 'string' ? input.projectId : '', ...(input?.runId ? { runId: part(input.runId) } : {}) };
26
+ }
27
+ function keyFor(kind, value) {
28
+ return kind === 'review' ? 'review:' + JSON.stringify([value.accountScopeId, part(value.projectId), part(value.runId)])
29
+ : kind === 'preferences' ? 'preferences'
30
+ : 'state:' + encodeURIComponent(value.accountScopeId);
31
+ }
32
+ function metaKey(value) {
33
+ return META_PREFIX + encodeURIComponent(value.accountScopeId) + ':' + encodeURIComponent(value.projectId);
34
+ }
35
+
36
+ // Three-way merge preserves changes made by another tab to untouched fields.
37
+ // Conflicting edits fail closed; removed records are never silently revived.
38
+ function mergeValue(base, current, incoming, field = '') {
39
+ if (equal(incoming, base)) return clone(current);
40
+ if (equal(current, base) || equal(current, incoming)) return clone(incoming);
41
+ if (field === 'updatedAt' || field === 'lastActivityAt')
42
+ return (Date.parse(current) || 0) >= (Date.parse(incoming) || 0) ? current : incoming;
43
+ if (Array.isArray(base) && Array.isArray(current) && Array.isArray(incoming)) {
44
+ if (['runs', 'pendingInputs'].includes(field)
45
+ && [base, current, incoming].every(items => items.every(item => item && typeof item.id === 'string')
46
+ && new Set(items.map(item => item.id)).size === items.length)) {
47
+ const before = new Map(base.map(item => [item.id, item]));
48
+ const latest = new Map(current.map(item => [item.id, item]));
49
+ const proposed = new Map(incoming.map(item => [item.id, item]));
50
+ const ids = [...current.map(item => item.id), ...incoming.map(item => item.id).filter(id => !latest.has(id))];
51
+ return ids.map(id => mergeValue(before.get(id), latest.get(id), proposed.get(id)))
52
+ .filter(item => item !== undefined);
53
+ }
54
+ const extendsBase = items => items.length >= base.length && base.every((item, i) => equal(item, items[i]));
55
+ if (extendsBase(current) && extendsBase(incoming)) {
56
+ const result = clone(current), seen = new Set(result.map(item => JSON.stringify(item)));
57
+ for (const item of incoming.slice(base.length)) {
58
+ const key = JSON.stringify(item);
59
+ if (!seen.has(key)) { result.push(clone(item)); seen.add(key); }
60
+ }
61
+ return result;
62
+ }
63
+ }
64
+ if (base && current && incoming && !Array.isArray(base) && !Array.isArray(current) && !Array.isArray(incoming)
65
+ && [base, current, incoming].every(value => typeof value === 'object')) {
66
+ const result = {};
67
+ for (const key of new Set([...Object.keys(base), ...Object.keys(current), ...Object.keys(incoming)])) {
68
+ if (key === 'sharedRevision') continue;
69
+ const value = mergeValue(base[key], current[key], incoming[key], key);
70
+ if (value !== undefined) Object.defineProperty(result, key, { value, enumerable: true, configurable: true, writable: true });
71
+ }
72
+ return result;
73
+ }
74
+ throw failure('shared_session_conflict', 'The same session was edited in another tab. Refresh its history before retrying; the local draft was kept.');
75
+ }
76
+
77
+ function createService(options = {}) {
78
+ const chromeApi = options.chromeApi, idb = options.indexedDB, ranges = options.IDBKeyRange;
79
+ const locks = new Map(), queues = new Map();
80
+ // Account-wide writes serialize cross-project clears and shared preference saves.
81
+ // IndexedDB transactions still provide the atomic boundary for session batches.
82
+ let opening;
83
+ function openDb() {
84
+ if (!opening) opening = new Promise((resolve, reject) => {
85
+ const request = idb.open('codex-overleaf-shared-sessions', 1);
86
+ request.onupgradeneeded = () => {
87
+ const db = request.result;
88
+ const sessions = db.createObjectStore('sessions', { keyPath: ['accountScopeId', 'id'] });
89
+ sessions.createIndex('account', 'accountScopeId');
90
+ sessions.createIndex('project', ['accountScopeId', 'projectId']);
91
+ db.createObjectStore('tombstones', { keyPath: ['accountScopeId', 'id'] });
92
+ db.createObjectStore('migrations', { keyPath: ['accountScopeId', 'origin'] });
93
+ };
94
+ request.onsuccess = () => resolve(request.result);
95
+ request.onerror = () => { opening = null; reject(request.error); };
96
+ });
97
+ return opening;
98
+ }
99
+ const readRequest = request => new Promise((resolve, reject) => {
100
+ request.onsuccess = () => resolve(request.result);
101
+ request.onerror = () => reject(request.error);
102
+ });
103
+ const finished = tx => new Promise((resolve, reject) => {
104
+ tx.oncomplete = () => resolve();
105
+ tx.onabort = tx.onerror = () => reject(tx.error || failure('shared_store_transaction_failed', 'The shared session transaction failed.'));
106
+ });
107
+ async function readOne(store, key) {
108
+ const db = await openDb();
109
+ return readRequest(db.transaction(store, 'readonly').objectStore(store).get(key));
110
+ }
111
+ function senderOrigin(sender) {
112
+ const url = new URL(sender?.url || sender?.tab?.url || '');
113
+ if (sender?.id !== chromeApi.runtime.id || !sender.tab || (sender.frameId != null && sender.frameId !== 0)
114
+ || url.protocol !== 'https:' || !HOSTS.includes(url.hostname) || !/^\/project(?:\/|$)/.test(url.pathname))
115
+ throw failure('forbidden_sender', 'Shared sessions require an authorized Overleaf project page.');
116
+ return url.origin;
117
+ }
118
+ function ensureLock(message, value, sender) {
119
+ const held = locks.get(keyFor('state', value));
120
+ if (!held || held.disconnected || held.token !== message.lockToken || held.tabId !== sender.tab.id)
121
+ throw failure('storage_lock_lost', 'The shared persistence lock was lost.');
122
+ }
123
+ async function notify(value, clientId) {
124
+ // A missed refresh notification must not turn a committed write into a failure.
125
+ await chromeApi.storage.local.set({ [CHANGE_KEY]: {
126
+ accountScopeId: value.accountScopeId, projectId: value.projectId,
127
+ clientId, nonce: crypto.randomUUID(), at: Date.now()
128
+ } }).catch(() => {});
129
+ }
130
+ async function list(value, after = '') {
131
+ const db = await openDb();
132
+ return new Promise((resolve, reject) => {
133
+ const result = []; let bytes = 0, last = after;
134
+ const cursor = db.transaction('sessions', 'readonly').objectStore('sessions')
135
+ .openCursor(ranges.bound([value.accountScopeId, after], [value.accountScopeId, '\uffff'], Boolean(after), false));
136
+ cursor.onerror = () => reject(cursor.error);
137
+ cursor.onsuccess = () => {
138
+ const item = cursor.result;
139
+ if (!item) { resolve({ records: result, next: '' }); return; }
140
+ const stored = item.value;
141
+ if (value.projectId && stored.projectId !== value.projectId) { item.continue(); return; }
142
+ const record = { ...stored.record, sharedRevision: stored.revision };
143
+ const size = Transfer.byteLength(JSON.stringify(record));
144
+ if (result.length && (result.length >= 8 || bytes + size > MAX_BYTES)) {
145
+ resolve({ records: result, next: last }); return;
146
+ }
147
+ result.push(record); bytes += size; last = stored.id; item.continue();
148
+ };
149
+ });
150
+ }
151
+ async function legacyDeleted(record) {
152
+ const key = 'codexOverleafSessionTombstone:v2:' + encodeURIComponent(record.projectId) + ':' + encodeURIComponent(record.id);
153
+ const meta = metaKey(record);
154
+ const stored = await chromeApi.storage.local.get([key, meta, 'codexOverleafSessionTombstones']);
155
+ return Boolean(stored[key] || stored[meta]?.sessionTombstones?.[record.id]
156
+ || stored.codexOverleafSessionTombstones?.[record.projectId]?.includes(record.id));
157
+ }
158
+ function recoveryCopy(record, origin) {
159
+ const suffix = origin.replace(/^https:\/\//, '').replace(/\W/g, '-');
160
+ return { ...record, id: record.id.slice(0, 200) + ':recovered:' + suffix, codexThreadId: '', pendingInputs: [],
161
+ titleSource: 'manual', title: (record.title || 'Recovered session') + ' [' + suffix + ']',
162
+ runs: (record.runs || []).map(run => ({ ...run, forkSnapshot: true, codexThreadId: '',
163
+ status: run.status === 'running' ? 'interrupted' : run.status,
164
+ undoOperations: [], undoBaseFiles: [], undoExpectedFiles: [], undoTrackedChanges: [],
165
+ appliedOperations: [], trackedChangeCaptures: [], undoStatus: '' })) };
166
+ }
167
+ async function writeMany(message, value, importing, origin, sender) {
168
+ // Reject a lost owner before doing any bounded decompression work.
169
+ ensureLock(message, value, sender);
170
+ const entries = (await Transfer.decode(message)).map(entry => ({ record: clone(entry.record), base: clone(entry.base) }));
171
+ for (const { record, base } of entries) {
172
+ if (!record || record.accountScopeId !== value.accountScopeId || record.projectId !== value.projectId)
173
+ throw failure('shared_store_scope_mismatch', 'The session does not belong to the captured account and project.');
174
+ part(record.id); part(record.projectId);
175
+ delete record.sharedRevision;
176
+ if (base && (base.id !== record.id || base.accountScopeId !== value.accountScopeId || base.projectId !== value.projectId))
177
+ throw failure('shared_store_scope_mismatch', 'The session baseline belongs to a different scope.');
178
+ }
179
+ if (importing && await legacyDeleted(entries[0].record)) return [];
180
+ ensureLock(message, value, sender);
181
+ const db = await openDb();
182
+ // Recheck after opening the database; a disconnected owner cannot commit.
183
+ ensureLock(message, value, sender);
184
+ return new Promise((resolve, reject) => {
185
+ const tx = db.transaction(['sessions', 'tombstones', 'migrations'], 'readwrite');
186
+ const store = tx.objectStore('sessions'), deleted = tx.objectStore('tombstones');
187
+ const results = []; let caught;
188
+ const abort = error => { caught = error; tx.abort(); };
189
+ tx.oncomplete = () => resolve(results);
190
+ tx.onabort = tx.onerror = () => reject(caught || tx.error || failure('shared_store_write_failed', 'The session could not be saved.'));
191
+ const marker = tx.objectStore('migrations').get([value.accountScopeId, '*']);
192
+ marker.onsuccess = () => {
193
+ for (const entry of entries) {
194
+ if (marker.result?.clearedAt && (importing || (Date.parse(entry.record.createdAt) || 0) <= marker.result.clearedAt)) {
195
+ if (importing) continue;
196
+ abort(failure('shared_session_deleted', 'This history was cleared and cannot be restored by a stale tab.'));
197
+ return;
198
+ }
199
+ putAt(entry.record, entry.base);
200
+ }
201
+ };
202
+ function appendResult(record, revision) {
203
+ // Merge may grow beyond either input. Reject inside this transaction,
204
+ // before returning success or committing any sibling record.
205
+ Transfer.validateRecord(record);
206
+ const result = { ...record, sharedRevision: revision };
207
+ Transfer.validateResponse([...results, result]);
208
+ results.push(result);
209
+ }
210
+ function putAt(candidate, base, copy = false) {
211
+ const key = [value.accountScopeId, candidate.id];
212
+ const tombstone = deleted.get(key);
213
+ tombstone.onsuccess = () => {
214
+ if (tombstone.result) {
215
+ if (importing) return;
216
+ abort(failure('shared_session_deleted', 'This session was deleted in another tab.')); return;
217
+ }
218
+ const request = store.get(key);
219
+ request.onsuccess = () => {
220
+ try {
221
+ const existing = request.result;
222
+ if (existing && existing.projectId !== candidate.projectId)
223
+ throw failure('shared_store_scope_mismatch', 'Session identity conflicts with another project.');
224
+ let next = candidate;
225
+ if (importing && existing) {
226
+ if (equal(existing.record, candidate) || copy) {
227
+ appendResult(existing.record, existing.revision); return;
228
+ }
229
+ putAt(recoveryCopy(candidate, origin), null, true); return;
230
+ }
231
+ if (existing) {
232
+ if (!base) throw failure('shared_session_conflict', 'Reload the session before updating existing history.');
233
+ // Keep the established first-durable-review-decision policy.
234
+ const reviewed = options.mergeSessionReviewState?.(candidate, existing.record, message.reviewRunIds || []) || candidate;
235
+ next = mergeValue(base, existing.record, reviewed);
236
+ } else if (base && !importing) {
237
+ throw failure('shared_session_deleted', 'The session no longer exists.');
238
+ }
239
+ const revision = (existing?.revision || 0) + 1;
240
+ appendResult(next, revision);
241
+ store.put({ accountScopeId: value.accountScopeId, projectId: value.projectId,
242
+ id: next.id, record: next, revision });
243
+ } catch (error) { abort(error); }
244
+ };
245
+ };
246
+ }
247
+ });
248
+ }
249
+ async function erase(value, id, all, message, sender) {
250
+ const db = await openDb();
251
+ ensureLock(message, value, sender);
252
+ const tx = db.transaction(['sessions', 'tombstones', 'migrations'], 'readwrite');
253
+ const done = finished(tx), sessions = tx.objectStore('sessions'), tombstones = tx.objectStore('tombstones');
254
+ if (id) {
255
+ const request = sessions.get([value.accountScopeId, id]);
256
+ request.onsuccess = () => {
257
+ const existing = request.result;
258
+ if (existing && value.projectId && existing.projectId !== value.projectId) { tx.abort(); return; }
259
+ tombstones.put({ accountScopeId: value.accountScopeId, id, deletedAt: Date.now() });
260
+ sessions.delete([value.accountScopeId, id]);
261
+ };
262
+ } else {
263
+ const cursor = sessions.index('account').openCursor(ranges.only(value.accountScopeId));
264
+ cursor.onsuccess = () => {
265
+ const item = cursor.result;
266
+ if (!item) return;
267
+ if (all || item.value.projectId === value.projectId) {
268
+ tombstones.put({ accountScopeId: value.accountScopeId, id: item.value.id, deletedAt: Date.now() });
269
+ item.delete();
270
+ }
271
+ item.continue();
272
+ };
273
+ if (all) tx.objectStore('migrations').put({ accountScopeId: value.accountScopeId, origin: '*', clearedAt: Date.now() });
274
+ }
275
+ await done;
276
+ }
277
+ const reviewLeaseKey = (key, token) => REVIEW_LEASE_PREFIX + key + ':' + token;
278
+ async function activeReviewLease(key) {
279
+ const prefix = REVIEW_LEASE_PREFIX + key + ':', records = await chromeApi.storage.local.get(null);
280
+ const active = [], expired = [];
281
+ for (const [id, lease] of Object.entries(records)) {
282
+ if (!id.startsWith(prefix)) continue;
283
+ const valid = lease && typeof lease.token === 'string' && lease.token.length > 0 && lease.token.length <= 256
284
+ && id === reviewLeaseKey(key, lease.token) && Number.isSafeInteger(lease.deadlineAt) && lease.deadlineAt > 0;
285
+ if (!valid) throw failure('review_lease_invalid', 'Undo ownership storage could not be verified.');
286
+ if (lease.deadlineAt > Date.now()) active.push(lease); else expired.push(id);
287
+ }
288
+ // Immutable token rows can only be removed by their exact expired key.
289
+ await Promise.all(expired.map(id => chromeApi.storage.local.remove(id).catch(() => {})));
290
+ return active.sort((a, b) => b.deadlineAt - a.deadlineAt)[0];
291
+ }
292
+ async function handle(message, sender) {
293
+ const origin = senderOrigin(sender), value = scope(message.scope);
294
+ const method = message.method;
295
+ if (method === 'review-dispatched') {
296
+ const key = keyFor('review', { ...value, runId: part(message.runId) }), held = locks.get(key);
297
+ if (!held || held.disconnected || held.token !== message.reviewToken || held.tabId !== sender.tab.id)
298
+ throw failure('storage_lock_lost', 'The shared Undo owner was lost before dispatch.');
299
+ const deadlineAt = held.deadlineAt || (held.deadlineAt = Date.now() + 120000);
300
+ held.inFlight += 1;
301
+ try {
302
+ await chromeApi.storage.local.set({ [reviewLeaseKey(key, held.token)]: { token: held.token, deadlineAt } });
303
+ if (held.disconnected) throw failure('storage_lock_lost', 'The shared Undo owner disconnected before dispatch.');
304
+ return { deadlineAt };
305
+ } finally { held.inFlight -= 1; if (held.disconnected && !held.inFlight) held.release(); }
306
+ }
307
+ if (method === 'review-owner') {
308
+ const key = keyFor('review', { ...value, runId: part(message.runId) });
309
+ const lease = await activeReviewLease(key);
310
+ return { busy: locks.has(key) || lease?.deadlineAt > Date.now(), deadlineAt: lease?.deadlineAt || 0 };
311
+ }
312
+ if (method === 'list') return list(value, typeof message.after === 'string' ? message.after : '');
313
+ if (method === 'get') {
314
+ const record = await readOne('sessions', [value.accountScopeId, part(message.id)]);
315
+ return record && (!value.projectId || value.projectId === record.projectId)
316
+ ? { ...record.record, sharedRevision: record.revision } : null;
317
+ }
318
+ if (method === 'migration-status') {
319
+ const cleared = await readOne('migrations', [value.accountScopeId, '*']);
320
+ return cleared?.clearedAt ? { complete: true, clearedAt: cleared.clearedAt }
321
+ : await readOne('migrations', [value.accountScopeId, origin]) || { complete: false };
322
+ }
323
+ if (method === 'migration-complete') {
324
+ ensureLock(message, value, sender);
325
+ const db = await openDb(), tx = db.transaction('migrations', 'readwrite'), done = finished(tx);
326
+ tx.objectStore('migrations').put({ ...value, origin, complete: true, at: Date.now() });
327
+ await done; return { complete: true };
328
+ }
329
+ if (method === 'put' || method === 'put-compressed' || method === 'import') {
330
+ const result = await writeMany(message, value, method === 'import', origin, sender);
331
+ if (result.length) await notify(value, message.clientId);
332
+ return result;
333
+ }
334
+ if (method === 'delete' || method === 'clear-project' || method === 'clear-account') {
335
+ if (method === 'clear-project') part(value.projectId);
336
+ await erase(value, method === 'delete' ? part(message.id) : '', method === 'clear-account', message, sender);
337
+ await notify(value, message.clientId); return true;
338
+ }
339
+ if (method === 'meta-read' || method === 'meta-write') {
340
+ const key = metaKey(value);
341
+ if (method === 'meta-read') return (await chromeApi.storage.local.get(key))[key] || {};
342
+ const held = locks.get(keyFor('state', value));
343
+ if (!held || held.token !== message.lockToken || held.tabId !== sender.tab.id)
344
+ throw failure('storage_lock_lost', 'The shared persistence lock was lost.');
345
+ await chromeApi.storage.local.set({ [key]: message.meta }); return message.meta;
346
+ }
347
+ throw failure('shared_store_method_invalid', 'Unsupported shared session operation.');
348
+ }
349
+ function connect(port) {
350
+ if (port.name !== LOCK_PORT) return;
351
+ try { senderOrigin(port.sender); } catch (_error) { port.disconnect(); return; }
352
+ let heldKey = '', job = null, closed = false;
353
+ function pump(key) {
354
+ if (locks.has(key)) return;
355
+ const queue = queues.get(key);
356
+ while (queue?.length) {
357
+ const next = queue.shift();
358
+ if (next.closed()) continue;
359
+ const token = crypto.randomUUID();
360
+ const held = { token, tabId: next.tabId, port: next.port, inFlight: 0, disconnected: false,
361
+ release() {
362
+ if (locks.get(key) !== held) return;
363
+ locks.delete(key); pump(key);
364
+ }
365
+ };
366
+ locks.set(key, held);
367
+ next.grant(token); return;
368
+ }
369
+ queues.delete(key);
370
+ }
371
+ port.onMessage.addListener(message => {
372
+ if (message?.type === 'release-review') {
373
+ const held = locks.get(heldKey);
374
+ if (held?.port !== port || held.token !== message.token || !heldKey.startsWith('review:')) return;
375
+ held.inFlight += 1;
376
+ void chromeApi.storage.local.remove(reviewLeaseKey(heldKey, held.token)).then(() => {
377
+ held.inFlight -= 1; held.release(); if (!closed) port.postMessage({ type: 'released' });
378
+ }, () => { held.inFlight -= 1; port.disconnect(); if (held.disconnected && !held.inFlight) held.release(); });
379
+ return;
380
+ }
381
+ if (message?.type === 'ping') { port.postMessage({ type: 'pong' }); return; }
382
+ if (message?.type !== 'acquire' || job) return;
383
+ try {
384
+ const value = scope(message.scope), kind = message.kind === 'review' ? 'review' : message.kind === 'preferences' ? 'preferences' : 'state';
385
+ heldKey = keyFor(kind, value);
386
+ if (kind === 'review' && locks.has(heldKey)) { port.postMessage({ type: 'busy' }); return; }
387
+ job = { port, tabId: port.sender.tab.id, closed: () => closed, grant: token => {
388
+ if (kind !== 'review') { port.postMessage({ type: 'granted', token }); return; }
389
+ const held = locks.get(heldKey); held.inFlight += 1;
390
+ void (async () => {
391
+ const existing = await activeReviewLease(heldKey);
392
+ if (existing?.deadlineAt > Date.now()) { locks.get(heldKey)?.release(); if (!closed) port.postMessage({ type: 'busy' }); return; }
393
+ if (!closed) port.postMessage({ type: 'granted', token });
394
+ })().catch(() => port.disconnect()).finally(() => { held.inFlight -= 1; if (held.disconnected && !held.inFlight) held.release(); });
395
+ } };
396
+ if (!queues.has(heldKey)) queues.set(heldKey, []);
397
+ queues.get(heldKey).push(job);
398
+ pump(heldKey);
399
+ } catch (_error) { port.disconnect(); }
400
+ });
401
+ port.onDisconnect.addListener(() => {
402
+ closed = true;
403
+ const held = locks.get(heldKey);
404
+ if (held?.port === port) {
405
+ held.disconnected = true;
406
+ if (!held.inFlight) held.release();
407
+ } else if (heldKey) pump(heldKey);
408
+ });
409
+ }
410
+ function install() {
411
+ chromeApi.runtime.onConnect.addListener(connect);
412
+ chromeApi.runtime.onMessage.addListener((message, sender, respond) => {
413
+ if (message?.type !== MESSAGE) return undefined;
414
+ let held;
415
+ try {
416
+ const candidate = locks.get(keyFor('state', scope(message.scope)));
417
+ if (candidate?.token === message.lockToken && candidate.tabId === sender?.tab?.id) {
418
+ held = candidate; held.inFlight += 1;
419
+ }
420
+ } catch (_error) { /* The handler returns the scoped validation error. */ }
421
+ handle(message, sender).then(result => respond({ ok: true, result }),
422
+ error => respond({ ok: false, error: { code: error.code || 'shared_store_unavailable',
423
+ message: error.code ? error.message : 'Shared session storage is unavailable.' } }))
424
+ .finally(() => {
425
+ if (!held) return;
426
+ held.inFlight -= 1;
427
+ if (held.disconnected && !held.inFlight) held.release();
428
+ });
429
+ return true;
430
+ });
431
+ }
432
+ return { install, handle };
433
+ }
434
+ function installBackground(chromeApi) {
435
+ const service = createService({ chromeApi, indexedDB, IDBKeyRange,
436
+ mergeSessionReviewState: globalThis.CodexOverleafStorageRunActions?.mergeSessionReviewState });
437
+ service.install(); return service;
438
+ }
439
+ return { createService, installBackground, mergeValue };
440
+ });