codex-overleaf-link 2.4.0 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (327) hide show
  1. package/README.md +272 -311
  2. package/README.zh-CN.md +287 -326
  3. package/extension/bootstrap/background.js +47 -10
  4. package/extension/bootstrap/manifest.template.json +9 -4
  5. package/extension/bootstrap/popup.html +10 -16
  6. package/extension/bootstrap/update.js +25 -2
  7. package/extension/runtime-manifest.json +3 -1
  8. package/extension/src/background.js +28 -3
  9. package/extension/src/backgroundSharedSessions.js +380 -0
  10. package/extension/src/backgroundUpdateCoordinator.js +442 -379
  11. package/extension/src/content/activeTurnControl.js +8 -0
  12. package/extension/src/content/assetTransferBroker.js +186 -12
  13. package/extension/src/content/changeHistoryView.js +175 -0
  14. package/extension/src/content/composerAttachments.js +24 -22
  15. package/extension/src/content/composerPanel.js +23 -8
  16. package/extension/src/content/contentRuntime.js +572 -571
  17. package/extension/src/content/diagnosticsController.js +1 -2
  18. package/extension/src/content/diagnosticsExport.js +222 -0
  19. package/extension/src/content/diagnosticsPanel.js +48 -19
  20. package/extension/src/content/diffReviewPanel.js +8 -5
  21. package/extension/src/content/generated/content.bundle.js +8974 -1781
  22. package/extension/src/content/generated/content.bundle.meta.json +22 -3
  23. package/extension/src/content/legacyGlobalRegistry.js +19 -1
  24. package/extension/src/content/localSkillsPanel.js +42 -7
  25. package/extension/src/content/markdownDomRenderer.js +9 -4
  26. package/extension/src/content/modelPicker.js +1 -1
  27. package/extension/src/content/pageBridgeClient.js +18 -3
  28. package/extension/src/content/panelMaintenance.js +51 -120
  29. package/extension/src/content/panelRenderer.js +4 -0
  30. package/extension/src/content/pendingInputView.js +109 -76
  31. package/extension/src/content/providerSettingsCoordinator.js +17 -6
  32. package/extension/src/content/providerSettingsDialog.js +661 -108
  33. package/extension/src/content/recentProjects.js +364 -356
  34. package/extension/src/content/runActivitySummary.js +631 -0
  35. package/extension/src/content/runController.js +3 -1
  36. package/extension/src/content/runFailureNotice.js +14 -1
  37. package/extension/src/content/runGuidanceController.js +4 -3
  38. package/extension/src/content/runPresence.js +306 -0
  39. package/extension/src/content/runQueueScheduler.js +2 -1
  40. package/extension/src/content/runResultActions.js +123 -3
  41. package/extension/src/content/runTimelineView.js +194 -164
  42. package/extension/src/content/scopedPersistenceCoordinator.js +2 -1
  43. package/extension/src/content/scopedPersistencePanelState.js +45 -2
  44. package/extension/src/content/selectionContextView.js +300 -0
  45. package/extension/src/content/sessionPersistence.js +10 -2
  46. package/extension/src/content/settingsPanel.js +93 -54
  47. package/extension/src/content/settingsWorkbench.js +374 -0
  48. package/extension/src/content/sharedSessionViewSync.js +72 -0
  49. package/extension/src/content/subagentActivityView.js +195 -0
  50. package/extension/src/content/trackedChangeCaptureController.js +7 -3
  51. package/extension/src/content/updateNotice.js +121 -50
  52. package/extension/src/content/writebackController.js +257 -0
  53. package/extension/src/content/writebackOrchestrator.js +146 -141
  54. package/extension/src/content/writebackPlan.js +231 -0
  55. package/extension/src/content/writebackRecovery.js +122 -0
  56. package/extension/src/content/writingStyleSettings.js +576 -0
  57. package/extension/src/content/writtenChangesView.js +152 -0
  58. package/extension/src/page/binaryAssetUploader.js +97 -19
  59. package/extension/src/page/overleafProjectSnapshot.js +1 -0
  60. package/extension/src/page/referenceProjects.js +148 -0
  61. package/extension/src/page/saveState.js +58 -3
  62. package/extension/src/page/snapshotRouter.js +44 -13
  63. package/extension/src/page/textCoordinates.js +102 -0
  64. package/extension/src/page/textFileCreator.js +350 -59
  65. package/extension/src/page/trackedChangeCapture.js +42 -56
  66. package/extension/src/page/trackedChangeOwnership.js +198 -0
  67. package/extension/src/page/trackedChangeReplay.js +164 -0
  68. package/extension/src/page/trackedChangesLifecycle.js +139 -150
  69. package/extension/src/page/treeOperations.js +36 -29
  70. package/extension/src/page/writebackReceiptJournal.js +112 -0
  71. package/extension/src/page/writebackRouter.js +176 -136
  72. package/extension/src/pageBridge.js +59 -101
  73. package/extension/src/popup.js +203 -59
  74. package/extension/src/shared/agentTranscript.js +18 -4
  75. package/extension/src/shared/auditRecords.js +71 -0
  76. package/extension/src/shared/changeHistoryModel.js +94 -0
  77. package/extension/src/shared/compatibility.js +1 -1
  78. package/extension/src/shared/compileAdapter.js +42 -0
  79. package/extension/src/shared/failureReasons.js +20 -0
  80. package/extension/src/shared/globalPreferences.js +1 -1
  81. package/extension/src/shared/i18n.js +187 -65
  82. package/extension/src/shared/managedUpdateProjection.js +6 -3
  83. package/extension/src/shared/pageRpcContract.js +7 -1
  84. package/extension/src/shared/providerProfiles.js +109 -0
  85. package/extension/src/shared/runActivityModel.js +361 -0
  86. package/extension/src/shared/runExecutionSnapshot.js +8 -2
  87. package/extension/src/shared/runExecutionSnapshotCodec.js +16 -4
  88. package/extension/src/shared/scopedPersistenceBrowserAdapter.js +6 -3
  89. package/extension/src/shared/selectionContext.js +28 -0
  90. package/extension/src/shared/sessionState.js +97 -6
  91. package/extension/src/shared/sharedSessionBridge.js +288 -0
  92. package/extension/src/shared/storageDb.js +23 -55
  93. package/extension/src/shared/storageMigration.js +3 -0
  94. package/extension/src/shared/storageRunActions.js +54 -4
  95. package/extension/src/shared/storageValuePruning.js +40 -0
  96. package/extension/src/shared/subagentActivityModel.js +174 -0
  97. package/extension/src/shared/undoOperations.js +87 -0
  98. package/extension/src/shared/updateConsent.js +37 -8
  99. package/extension/src/shared/writebackIntent.js +62 -0
  100. package/extension/src/shared/writebackSettlement.js +29 -10
  101. package/extension/src/shared/writingStyle.js +33 -0
  102. package/extension/styles/panel.css +2136 -744
  103. package/extension/styles/popup.css +110 -0
  104. package/native-host/src/anthropicBridgeRequest.js +2 -1
  105. package/native-host/src/codexModelRecovery.js +107 -0
  106. package/native-host/src/codexPromptAssembly.js +2 -0
  107. package/native-host/src/codexProviderLaunch.js +3 -3
  108. package/native-host/src/codexRuntimeIdentity.js +1 -0
  109. package/native-host/src/codexSessionRunner.js +146 -177
  110. package/native-host/src/codexSessionTiming.js +71 -0
  111. package/native-host/src/managedInstall.js +5 -4
  112. package/native-host/src/nativeEnvironment.js +70 -0
  113. package/native-host/src/nativeQuotas.js +15 -8
  114. package/native-host/src/overleafWorkspaceRules.js +16 -0
  115. package/native-host/src/processStopBarrier.js +80 -0
  116. package/native-host/src/providerModelCatalog.js +4 -3
  117. package/native-host/src/providerProfile.js +13 -1
  118. package/native-host/src/providerReasoning.js +9 -5
  119. package/native-host/src/providerStore.js +4 -0
  120. package/native-host/src/readProgressGuard.js +84 -17
  121. package/native-host/src/releaseTransport.js +14 -5
  122. package/native-host/src/selectionScope.js +58 -0
  123. package/native-host/src/skills/parallel-subagents/SKILL.md +31 -3
  124. package/native-host/src/skills/writing-style-builder/SKILL.md +146 -0
  125. package/native-host/src/subagentBroker.js +102 -98
  126. package/native-host/src/subagentTelemetry.js +316 -0
  127. package/native-host/src/subagentWorkspace.js +103 -0
  128. package/native-host/src/subagentWorkspacePath.js +31 -0
  129. package/native-host/src/taskRunnerRuntime.js +55 -5
  130. package/native-host/src/turnAttachments.js +113 -0
  131. package/native-host/src/updateManager.js +122 -12
  132. package/native-host/src/updateNetworkControl.js +75 -0
  133. package/native-host/src/updateTrust.js +21 -2
  134. package/native-host/src/vendor/pdfjs/LICENSE +177 -0
  135. package/native-host/src/vendor/pdfjs/SOURCE.txt +3 -0
  136. package/native-host/src/vendor/pdfjs/cmaps/78-EUC-H.bcmap +0 -0
  137. package/native-host/src/vendor/pdfjs/cmaps/78-EUC-V.bcmap +0 -0
  138. package/native-host/src/vendor/pdfjs/cmaps/78-H.bcmap +0 -0
  139. package/native-host/src/vendor/pdfjs/cmaps/78-RKSJ-H.bcmap +0 -0
  140. package/native-host/src/vendor/pdfjs/cmaps/78-RKSJ-V.bcmap +0 -0
  141. package/native-host/src/vendor/pdfjs/cmaps/78-V.bcmap +0 -0
  142. package/native-host/src/vendor/pdfjs/cmaps/78ms-RKSJ-H.bcmap +0 -0
  143. package/native-host/src/vendor/pdfjs/cmaps/78ms-RKSJ-V.bcmap +0 -0
  144. package/native-host/src/vendor/pdfjs/cmaps/83pv-RKSJ-H.bcmap +0 -0
  145. package/native-host/src/vendor/pdfjs/cmaps/90ms-RKSJ-H.bcmap +0 -0
  146. package/native-host/src/vendor/pdfjs/cmaps/90ms-RKSJ-V.bcmap +0 -0
  147. package/native-host/src/vendor/pdfjs/cmaps/90msp-RKSJ-H.bcmap +0 -0
  148. package/native-host/src/vendor/pdfjs/cmaps/90msp-RKSJ-V.bcmap +0 -0
  149. package/native-host/src/vendor/pdfjs/cmaps/90pv-RKSJ-H.bcmap +0 -0
  150. package/native-host/src/vendor/pdfjs/cmaps/90pv-RKSJ-V.bcmap +0 -0
  151. package/native-host/src/vendor/pdfjs/cmaps/Add-H.bcmap +0 -0
  152. package/native-host/src/vendor/pdfjs/cmaps/Add-RKSJ-H.bcmap +0 -0
  153. package/native-host/src/vendor/pdfjs/cmaps/Add-RKSJ-V.bcmap +0 -0
  154. package/native-host/src/vendor/pdfjs/cmaps/Add-V.bcmap +0 -0
  155. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-0.bcmap +0 -0
  156. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-1.bcmap +0 -0
  157. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-2.bcmap +0 -0
  158. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-3.bcmap +0 -0
  159. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-4.bcmap +0 -0
  160. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-5.bcmap +0 -0
  161. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-6.bcmap +0 -0
  162. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
  163. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-0.bcmap +0 -0
  164. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-1.bcmap +0 -0
  165. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-2.bcmap +0 -0
  166. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-3.bcmap +0 -0
  167. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-4.bcmap +0 -0
  168. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-5.bcmap +0 -0
  169. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
  170. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-0.bcmap +0 -0
  171. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-1.bcmap +0 -0
  172. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-2.bcmap +0 -0
  173. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-3.bcmap +0 -0
  174. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-4.bcmap +0 -0
  175. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-5.bcmap +0 -0
  176. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-6.bcmap +0 -0
  177. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
  178. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-0.bcmap +0 -0
  179. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-1.bcmap +0 -0
  180. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-2.bcmap +0 -0
  181. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
  182. package/native-host/src/vendor/pdfjs/cmaps/B5-H.bcmap +0 -0
  183. package/native-host/src/vendor/pdfjs/cmaps/B5-V.bcmap +0 -0
  184. package/native-host/src/vendor/pdfjs/cmaps/B5pc-H.bcmap +0 -0
  185. package/native-host/src/vendor/pdfjs/cmaps/B5pc-V.bcmap +0 -0
  186. package/native-host/src/vendor/pdfjs/cmaps/CNS-EUC-H.bcmap +0 -0
  187. package/native-host/src/vendor/pdfjs/cmaps/CNS-EUC-V.bcmap +0 -0
  188. package/native-host/src/vendor/pdfjs/cmaps/CNS1-H.bcmap +0 -0
  189. package/native-host/src/vendor/pdfjs/cmaps/CNS1-V.bcmap +0 -0
  190. package/native-host/src/vendor/pdfjs/cmaps/CNS2-H.bcmap +0 -0
  191. package/native-host/src/vendor/pdfjs/cmaps/CNS2-V.bcmap +3 -0
  192. package/native-host/src/vendor/pdfjs/cmaps/ETHK-B5-H.bcmap +0 -0
  193. package/native-host/src/vendor/pdfjs/cmaps/ETHK-B5-V.bcmap +0 -0
  194. package/native-host/src/vendor/pdfjs/cmaps/ETen-B5-H.bcmap +0 -0
  195. package/native-host/src/vendor/pdfjs/cmaps/ETen-B5-V.bcmap +0 -0
  196. package/native-host/src/vendor/pdfjs/cmaps/ETenms-B5-H.bcmap +3 -0
  197. package/native-host/src/vendor/pdfjs/cmaps/ETenms-B5-V.bcmap +0 -0
  198. package/native-host/src/vendor/pdfjs/cmaps/EUC-H.bcmap +0 -0
  199. package/native-host/src/vendor/pdfjs/cmaps/EUC-V.bcmap +0 -0
  200. package/native-host/src/vendor/pdfjs/cmaps/Ext-H.bcmap +0 -0
  201. package/native-host/src/vendor/pdfjs/cmaps/Ext-RKSJ-H.bcmap +0 -0
  202. package/native-host/src/vendor/pdfjs/cmaps/Ext-RKSJ-V.bcmap +0 -0
  203. package/native-host/src/vendor/pdfjs/cmaps/Ext-V.bcmap +0 -0
  204. package/native-host/src/vendor/pdfjs/cmaps/GB-EUC-H.bcmap +0 -0
  205. package/native-host/src/vendor/pdfjs/cmaps/GB-EUC-V.bcmap +0 -0
  206. package/native-host/src/vendor/pdfjs/cmaps/GB-H.bcmap +4 -0
  207. package/native-host/src/vendor/pdfjs/cmaps/GB-V.bcmap +0 -0
  208. package/native-host/src/vendor/pdfjs/cmaps/GBK-EUC-H.bcmap +0 -0
  209. package/native-host/src/vendor/pdfjs/cmaps/GBK-EUC-V.bcmap +0 -0
  210. package/native-host/src/vendor/pdfjs/cmaps/GBK2K-H.bcmap +0 -0
  211. package/native-host/src/vendor/pdfjs/cmaps/GBK2K-V.bcmap +0 -0
  212. package/native-host/src/vendor/pdfjs/cmaps/GBKp-EUC-H.bcmap +0 -0
  213. package/native-host/src/vendor/pdfjs/cmaps/GBKp-EUC-V.bcmap +0 -0
  214. package/native-host/src/vendor/pdfjs/cmaps/GBT-EUC-H.bcmap +0 -0
  215. package/native-host/src/vendor/pdfjs/cmaps/GBT-EUC-V.bcmap +0 -0
  216. package/native-host/src/vendor/pdfjs/cmaps/GBT-H.bcmap +0 -0
  217. package/native-host/src/vendor/pdfjs/cmaps/GBT-V.bcmap +0 -0
  218. package/native-host/src/vendor/pdfjs/cmaps/GBTpc-EUC-H.bcmap +0 -0
  219. package/native-host/src/vendor/pdfjs/cmaps/GBTpc-EUC-V.bcmap +0 -0
  220. package/native-host/src/vendor/pdfjs/cmaps/GBpc-EUC-H.bcmap +0 -0
  221. package/native-host/src/vendor/pdfjs/cmaps/GBpc-EUC-V.bcmap +0 -0
  222. package/native-host/src/vendor/pdfjs/cmaps/H.bcmap +0 -0
  223. package/native-host/src/vendor/pdfjs/cmaps/HKdla-B5-H.bcmap +0 -0
  224. package/native-host/src/vendor/pdfjs/cmaps/HKdla-B5-V.bcmap +0 -0
  225. package/native-host/src/vendor/pdfjs/cmaps/HKdlb-B5-H.bcmap +0 -0
  226. package/native-host/src/vendor/pdfjs/cmaps/HKdlb-B5-V.bcmap +0 -0
  227. package/native-host/src/vendor/pdfjs/cmaps/HKgccs-B5-H.bcmap +0 -0
  228. package/native-host/src/vendor/pdfjs/cmaps/HKgccs-B5-V.bcmap +0 -0
  229. package/native-host/src/vendor/pdfjs/cmaps/HKm314-B5-H.bcmap +0 -0
  230. package/native-host/src/vendor/pdfjs/cmaps/HKm314-B5-V.bcmap +0 -0
  231. package/native-host/src/vendor/pdfjs/cmaps/HKm471-B5-H.bcmap +0 -0
  232. package/native-host/src/vendor/pdfjs/cmaps/HKm471-B5-V.bcmap +0 -0
  233. package/native-host/src/vendor/pdfjs/cmaps/HKscs-B5-H.bcmap +0 -0
  234. package/native-host/src/vendor/pdfjs/cmaps/HKscs-B5-V.bcmap +0 -0
  235. package/native-host/src/vendor/pdfjs/cmaps/Hankaku.bcmap +0 -0
  236. package/native-host/src/vendor/pdfjs/cmaps/Hiragana.bcmap +0 -0
  237. package/native-host/src/vendor/pdfjs/cmaps/KSC-EUC-H.bcmap +0 -0
  238. package/native-host/src/vendor/pdfjs/cmaps/KSC-EUC-V.bcmap +0 -0
  239. package/native-host/src/vendor/pdfjs/cmaps/KSC-H.bcmap +0 -0
  240. package/native-host/src/vendor/pdfjs/cmaps/KSC-Johab-H.bcmap +0 -0
  241. package/native-host/src/vendor/pdfjs/cmaps/KSC-Johab-V.bcmap +0 -0
  242. package/native-host/src/vendor/pdfjs/cmaps/KSC-V.bcmap +0 -0
  243. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-H.bcmap +0 -0
  244. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
  245. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
  246. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-V.bcmap +0 -0
  247. package/native-host/src/vendor/pdfjs/cmaps/KSCpc-EUC-H.bcmap +0 -0
  248. package/native-host/src/vendor/pdfjs/cmaps/KSCpc-EUC-V.bcmap +0 -0
  249. package/native-host/src/vendor/pdfjs/cmaps/Katakana.bcmap +0 -0
  250. package/native-host/src/vendor/pdfjs/cmaps/LICENSE +36 -0
  251. package/native-host/src/vendor/pdfjs/cmaps/NWP-H.bcmap +0 -0
  252. package/native-host/src/vendor/pdfjs/cmaps/NWP-V.bcmap +0 -0
  253. package/native-host/src/vendor/pdfjs/cmaps/RKSJ-H.bcmap +0 -0
  254. package/native-host/src/vendor/pdfjs/cmaps/RKSJ-V.bcmap +0 -0
  255. package/native-host/src/vendor/pdfjs/cmaps/Roman.bcmap +0 -0
  256. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UCS2-H.bcmap +0 -0
  257. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UCS2-V.bcmap +0 -0
  258. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF16-H.bcmap +0 -0
  259. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF16-V.bcmap +0 -0
  260. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF32-H.bcmap +0 -0
  261. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF32-V.bcmap +0 -0
  262. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF8-H.bcmap +0 -0
  263. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF8-V.bcmap +0 -0
  264. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UCS2-H.bcmap +0 -0
  265. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UCS2-V.bcmap +0 -0
  266. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF16-H.bcmap +0 -0
  267. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF16-V.bcmap +0 -0
  268. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF32-H.bcmap +0 -0
  269. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF32-V.bcmap +0 -0
  270. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF8-H.bcmap +0 -0
  271. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF8-V.bcmap +0 -0
  272. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-H.bcmap +0 -0
  273. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
  274. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
  275. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-V.bcmap +0 -0
  276. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF16-H.bcmap +0 -0
  277. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF16-V.bcmap +0 -0
  278. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF32-H.bcmap +0 -0
  279. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF32-V.bcmap +0 -0
  280. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF8-H.bcmap +0 -0
  281. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF8-V.bcmap +0 -0
  282. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
  283. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
  284. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
  285. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
  286. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
  287. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
  288. package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
  289. package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
  290. package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
  291. package/native-host/src/vendor/pdfjs/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
  292. package/native-host/src/vendor/pdfjs/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
  293. package/native-host/src/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
  294. package/native-host/src/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
  295. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UCS2-H.bcmap +0 -0
  296. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UCS2-V.bcmap +0 -0
  297. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF16-H.bcmap +0 -0
  298. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF16-V.bcmap +0 -0
  299. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF32-H.bcmap +0 -0
  300. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF32-V.bcmap +0 -0
  301. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF8-H.bcmap +0 -0
  302. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF8-V.bcmap +0 -0
  303. package/native-host/src/vendor/pdfjs/cmaps/V.bcmap +0 -0
  304. package/native-host/src/vendor/pdfjs/cmaps/WP-Symbol.bcmap +0 -0
  305. package/native-host/src/vendor/pdfjs/pdf.mjs +26740 -0
  306. package/native-host/src/vendor/pdfjs/pdf.worker.mjs +62201 -0
  307. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitDingbats.pfb +0 -0
  308. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixed.pfb +0 -0
  309. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedBold.pfb +0 -0
  310. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
  311. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedItalic.pfb +0 -0
  312. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerif.pfb +0 -0
  313. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifBold.pfb +0 -0
  314. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
  315. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifItalic.pfb +0 -0
  316. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSymbol.pfb +0 -0
  317. package/native-host/src/vendor/pdfjs/standard_fonts/LICENSE_FOXIT +27 -0
  318. package/native-host/src/vendor/pdfjs/standard_fonts/LICENSE_LIBERATION +102 -0
  319. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Bold.ttf +0 -0
  320. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
  321. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Italic.ttf +0 -0
  322. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Regular.ttf +0 -0
  323. package/native-host/src/writingStyleEvidence.js +102 -0
  324. package/native-host/src/writingStylePdfWorker.js +35 -0
  325. package/native-host/src/writingStyleProfile.js +165 -0
  326. package/native-host/src/writingStyleRuntime.js +447 -0
  327. package/package.json +1 -1
@@ -15,6 +15,7 @@
15
15
  window.__codexOverleafPageBridgeInstalledVersion = PAGE_BRIDGE_INSTALL_VERSION;
16
16
  window.__codexOverleafPageBridgeInstalledRevision = PAGE_BRIDGE_INSTALL_REVISION;
17
17
 
18
+ const textCoordinates = requirePageModule('CodexOverleafTextCoordinates').create();
18
19
  const PAGE_BRIDGE_CAPABILITY_METHOD = 'initializeCapability';
19
20
  const pageBridgeCapabilityGuard = window.CodexOverleafPageBridgeCapability.create();
20
21
  let treeOperations = null;
@@ -67,6 +68,7 @@
67
68
  treeOperations,
68
69
  window
69
70
  });
71
+ const referenceProjects = requirePageModule('CodexOverleafReferenceProjects').create({ window, snapshotRouter });
70
72
  const textFileCreator = requirePageModule('CodexOverleafTextFileCreator').create({
71
73
  window, document, treeOperations, snapshotRouter,
72
74
  collectElements, ensureEditing, ensureReviewing, readActiveEditorText, readWriteCancellationSequence,
@@ -93,7 +95,12 @@
93
95
  window
94
96
  });
95
97
  writebackRouter = requirePageModule('CodexOverleafWritebackRouter').create({
98
+ confirmReviewWriteback: (params, result) => requirePageModule('CodexOverleafSaveState').confirmReviewWriteback({
99
+ params, result, getProjectId, delay, readSnapshot: options => snapshotRouter.fetchProjectZipSnapshot(options)
100
+ }),
96
101
  createTextFile: textFileCreator.createFile,
102
+ beginTextCreateBatch: textFileCreator.beginCreateBatch,
103
+ finishTextCreateBatch: textFileCreator.finishCreateBatch,
97
104
  deleteTextFile: textFileCreator.deleteFile,
98
105
  activeEditorIdentityChanged,
99
106
  clickNode,
@@ -157,6 +164,10 @@
157
164
  }
158
165
  }
159
166
 
167
+ const writebackReceipts = requirePageModule('CodexOverleafWritebackReceiptJournal').create({
168
+ getProjectId: expectedRunProjectId => writeGuard.getEditorProjectIdPageSide(expectedRunProjectId),
169
+ prepareEditor: params => textFileCreator.prepareEditor(params), applyOperations
170
+ });
160
171
  const pageBridgeMessageHandler = async event => {
161
172
  if (event.source !== window
162
173
  || event.origin !== window.location.origin
@@ -172,7 +183,8 @@
172
183
  } else if (!pageBridgeCapabilityGuard.hasValidPageBridgeCapability(capability)) {
173
184
  result = window.CodexOverleafPageBridgeCapability.buildUnauthorizedBridgeResult();
174
185
  } else {
175
- result = await dispatch(method, params || {});
186
+ result = await dispatch(method, method === 'applyOperations'
187
+ ? { ...(params || {}), writebackRequestId: id } : params || {});
176
188
  }
177
189
  } catch (error) {
178
190
  result = pageRpcContract.normalizeFailure(method, error);
@@ -211,10 +223,15 @@
211
223
  probe,
212
224
  cancelActiveWrite() {
213
225
  const sequence = bumpWriteCancellationSequence();
226
+ textFileCreator.cancelVerifications();
227
+ snapshotRouter.cancelWritebackReads();
214
228
  return { ok: true, cancelled: true, sequence };
215
229
  },
216
230
  getProjectSnapshot: params => projectSnapshotBridge.getProjectSnapshot(withSnapshotCacheIdentity(params)),
217
231
  getProjectFileList: params => projectSnapshotBridge.getProjectFileList(params),
232
+ listReferenceProjects: () => referenceProjects.listProjects(),
233
+ getReferenceProjectSnapshot: params => referenceProjects.readProject(params),
234
+ cancelReferenceRead: params => referenceProjects.cancelRead(params),
218
235
  invalidateProjectSnapshot(params) {
219
236
  projectSnapshotBridge.invalidateProjectSnapshot(params);
220
237
  return { ok: true };
@@ -222,23 +239,13 @@
222
239
  createCheckpoint: params => createCheckpoint(params.label),
223
240
  ensureReviewing: params => textFileCreator.ensureWriteMode(true, params),
224
241
  ensureEditing: params => textFileCreator.ensureWriteMode(false, params),
225
- applyOperations: async params => {
226
- if (params.reviewingPolicy === 'no-trace-undo') {
227
- const prepared = await textFileCreator.prepareEditor(params);
228
- if (prepared.ok !== true) return { applied: [], changedDocument: false,
229
- skipped: (params.operations || []).map(operation => ({ operation, result: prepared })) };
230
- }
231
- return applyOperations(params.operations || [], {
232
- baseFiles: params.baseFiles || null,
233
- reviewingPolicy: params.reviewingPolicy || '',
234
- requireReviewing: params.requireReviewing === true,
235
- requireEditing: params.requireEditing === true,
236
- runProjectId: typeof params.runProjectId === 'string' ? params.runProjectId : ''
237
- });
238
- },
242
+ applyOperations: writebackReceipts.apply,
243
+ getWritebackReceipt: writebackReceipts.get,
244
+ getSelectionContext,
239
245
  binaryUploadBegin: params => binaryAssetUploader.begin(params),
240
246
  binaryUploadAppend: params => binaryAssetUploader.append(params),
241
247
  binaryUploadCommit: params => binaryAssetUploader.commit(params),
248
+ binaryUploadStatus: params => binaryAssetUploader.status(params),
242
249
  binaryUploadAbort: params => binaryAssetUploader.abort(params),
243
250
  jumpToPosition,
244
251
  reconcileTrackedChangeCapture: params => writebackRouter.reconcileTrackedChangeCapture(params),
@@ -669,97 +676,48 @@
669
676
  };
670
677
  }
671
678
 
672
- function resolveJumpToPositionRange(params, text, filePath) {
673
- if (params.line === undefined && params.column === undefined) {
674
- return {
675
- ok: true,
676
- from: params.from,
677
- to: params.to
678
- };
679
- }
680
-
681
- const lines = collectTextLineRanges(String(text || ''));
682
- const lineCount = lines.length;
683
- const lineNumber = Number(params.line);
684
- const lineMetadata = { lineCount };
685
- if (params.line !== undefined) {
686
- lineMetadata.line = Number.isInteger(lineNumber) ? lineNumber : params.line;
687
- }
688
- if (!Number.isInteger(lineNumber) || lineNumber < 1) {
689
- return jumpPositionOutOfRange('line_out_of_range', filePath, lineMetadata);
690
- }
691
-
692
- const line = lines[lineNumber - 1];
693
- if (!line) {
694
- return jumpPositionOutOfRange('line_out_of_range', filePath, {
695
- line: lineNumber,
696
- lineCount
697
- });
698
- }
699
-
700
- const lineLength = line.end - line.start;
701
- if (params.selectLine === true) {
702
- return {
703
- ok: true,
704
- from: line.start,
705
- to: line.end
706
- };
707
- }
708
-
709
- if (params.column !== undefined) {
710
- const columnNumber = Number(params.column);
711
- const maxColumn = lineLength + 1;
712
- if (!Number.isInteger(columnNumber) || columnNumber < 1 || columnNumber > maxColumn) {
713
- return jumpPositionOutOfRange('column_out_of_range', filePath, {
714
- line: lineNumber,
715
- column: Number.isInteger(columnNumber) ? columnNumber : params.column,
716
- lineLength
717
- });
718
- }
719
- const offset = line.start + columnNumber - 1;
720
- return {
721
- ok: true,
722
- from: offset,
723
- to: offset
724
- };
725
- }
726
-
727
- return {
728
- ok: true,
729
- from: line.start,
730
- to: line.start
731
- };
679
+ async function getSelectionContext(params = {}) {
680
+ const projectId = getProjectId();
681
+ const view = getCodeMirrorEditorView();
682
+ const editorState = view?.state;
683
+ const selection = editorState?.selection?.main;
684
+ const path = getActiveFilePath();
685
+ if (!projectId || params.runProjectId !== projectId || !path || !selection
686
+ || !editorState.doc || editorState.selection.ranges?.length !== 1 || selection.empty) {
687
+ return { ok: false, code: 'selection_unavailable' };
688
+ }
689
+ const from = selection.from, to = selection.to;
690
+ if (to - from > 20000) return { ok: false, code: 'selection_too_large' };
691
+ const source = editorState.doc.toString();
692
+ const text = source.slice(from, to);
693
+ const digest = await window.crypto.subtle.digest('SHA-256', new TextEncoder().encode(source));
694
+ if (getProjectId() !== projectId || getActiveFilePath() !== path || getCodeMirrorEditorView() !== view
695
+ || view.state.doc !== editorState.doc || view.state.selection.main.from !== from || view.state.selection.main.to !== to) {
696
+ return { ok: false, code: 'selection_changed' };
697
+ }
698
+ const captured = { projectId, path, from, to, text,
699
+ lineStart: editorState.doc.lineAt(from).number,
700
+ lineEnd: editorState.doc.lineAt(Math.max(from, to - 1)).number,
701
+ documentHash: Array.from(new Uint8Array(digest), byte => byte.toString(16).padStart(2, '0')).join(''),
702
+ capturedAt: new Date().toISOString() };
703
+ let anchor = null;
704
+ try {
705
+ const bounds = view.dom.getBoundingClientRect();
706
+ const head = view.coordsAtPos(selection.head);
707
+ const start = view.coordsAtPos(from);
708
+ const visible = value => value && value.bottom >= Math.max(0, bounds.top)
709
+ && value.top <= Math.min(window.innerHeight, bounds.bottom);
710
+ const point = visible(start) ? start : visible(head) ? head : null;
711
+ if (point) anchor = { left: point.left, right: point.right, top: point.top, bottom: point.bottom };
712
+ } catch (_) { /* Off-screen selections remain valid context without a floating anchor. */ }
713
+ return { ok: true, ...captured, selection: captured, anchor };
732
714
  }
733
715
 
734
- function jumpPositionOutOfRange(code, filePath, metadata = {}) {
735
- return {
736
- ok: false,
737
- code,
738
- reason: 'Requested jumpToPosition location is out of range',
739
- path: filePath,
740
- ...metadata
741
- };
742
- }
743
716
 
744
- function collectTextLineRanges(text) {
745
- const lines = [];
746
- let start = 0;
747
717
 
748
- for (let index = 0; index < text.length; index += 1) {
749
- if (text[index] === '\r') {
750
- lines.push({ start, end: index });
751
- if (text[index + 1] === '\n') {
752
- index += 1;
753
- }
754
- start = index + 1;
755
- } else if (text[index] === '\n') {
756
- lines.push({ start, end: index });
757
- start = index + 1;
758
- }
759
- }
760
718
 
761
- lines.push({ start, end: text.length });
762
- return lines;
719
+ function resolveJumpToPositionRange(params, text, filePath) {
720
+ return textCoordinates.resolveJumpToPositionRange(params, text, filePath);
763
721
  }
764
722
 
765
723
  async function waitForActiveEditorAfterNavigation(filePath, previousEditorIdentity, timeoutMs) {
@@ -1,75 +1,209 @@
1
1
  (function initPopup() {
2
2
  'use strict';
3
3
 
4
+ const popupScriptUrl = document.currentScript?.src || chrome.runtime.getURL('src/popup.js');
5
+ ensureMinimalPopupShell();
4
6
  const CodexOverleafCompatibility = window.CodexOverleafCompatibility;
5
7
  const DEFAULT_INSTALL_COMMAND = CodexOverleafCompatibility?.buildInstallCommand?.(
6
8
  undefined,
7
9
  undefined,
8
10
  getCurrentExtensionId()
9
11
  ) || 'curl -fsSL https://raw.githubusercontent.com/Ghqqqq/codex-overleaf-link/main/install.sh | bash -s -- --extension-id <chrome-extension-id>';
10
- const button = document.getElementById('open-panel');
12
+ const launcherToggle = document.getElementById('launcher-toggle');
11
13
  const status = document.getElementById('status');
14
+ const connectionToggle = document.getElementById('connection-toggle');
15
+ const connectionDetails = document.getElementById('connection-details');
16
+ const connectionLabel = document.getElementById('connection-label');
12
17
  const compatStatusIcon = document.getElementById('compat-status-icon');
13
- const versionPair = document.getElementById('version-pair');
18
+ const extensionVersionLabel = document.getElementById('extension-version');
19
+ const nativeVersionLabel = document.getElementById('native-version');
14
20
  const nativeInstall = document.getElementById('native-install');
21
+ const nativeStatusMessage = document.getElementById('native-status-message');
15
22
  const installCommand = document.getElementById('install-command');
16
23
  const copyInstallCommand = document.getElementById('copy-install-command');
24
+ const copyFeedback = document.getElementById('copy-feedback');
17
25
  let activeOverleafTab = null;
18
26
  let currentInstallCommand = DEFAULT_INSTALL_COMMAND;
27
+ let lastCompatibility = null;
28
+ let launcherVisible = false;
29
+ let launcherReady = false;
19
30
 
20
31
  installCommand.textContent = currentInstallCommand;
21
- button.textContent = 'Show Codex button in Overleaf';
22
- setVersionStatus({
23
- status: 'native_missing',
24
- classification: 'incompatible',
25
- extensionVersion: getExtensionCompatibilityMetadata().version
32
+ setVersionStatus({ status: 'checking', extensionVersion: getExtensionCompatibilityMetadata().version });
33
+
34
+ connectionToggle.addEventListener('click', () => {
35
+ connectionDetails.hidden = !connectionDetails.hidden;
36
+ connectionToggle.setAttribute('aria-expanded', String(!connectionDetails.hidden));
26
37
  });
27
38
 
28
- button.addEventListener('click', async () => {
29
- const tab = activeOverleafTab || await getActiveOverleafProjectTab();
30
- if (!tab?.id) {
31
- status.textContent = 'Open an Overleaf project tab first.';
32
- return;
39
+ launcherToggle.addEventListener('change', async () => {
40
+ const desired = launcherToggle.checked;
41
+ launcherToggle.disabled = true;
42
+ setLauncherStatus('');
43
+ try {
44
+ const tab = await getActiveOverleafProjectTab();
45
+ if (!tab?.id) throw new Error(utx('Open an Overleaf project tab first.', '请先打开 Overleaf 项目页。'));
46
+ activeOverleafTab = tab;
47
+ const before = await chrome.tabs.sendMessage(tab.id, { type: 'codex-overleaf/get-panel-state' });
48
+ if (typeof before?.launcherVisible !== 'boolean') {
49
+ throw new Error(utx('Refresh the Overleaf tab, then reopen this popup.', '请刷新 Overleaf 页面,再打开此弹窗。'));
50
+ }
51
+ // Keep the existing visibility contract. Do not open or close the panel.
52
+ if (before.launcherVisible !== desired) {
53
+ const response = await chrome.tabs.sendMessage(tab.id, { type: 'codex-overleaf/toggle-launcher' });
54
+ if (response?.ok === false) throw new Error(response.error?.message || response.error
55
+ || utx('The side button could not be changed.', '侧边入口设置未能修改。'));
56
+ }
57
+ const after = await chrome.tabs.sendMessage(tab.id, { type: 'codex-overleaf/get-panel-state' });
58
+ if (typeof after?.launcherVisible !== 'boolean' || after.launcherVisible !== desired) {
59
+ throw new Error(utx('The side button state could not be confirmed. Reopen this popup to retry.',
60
+ '未能确认侧边入口状态,请重新打开此弹窗后重试。'));
61
+ }
62
+ launcherVisible = after.launcherVisible;
63
+ launcherReady = true;
64
+ } catch (error) {
65
+ launcherReady = false;
66
+ setLauncherStatus(error?.message || utx('Refresh the Overleaf tab and try again.', '请刷新 Overleaf 页面后重试。'), true);
67
+ } finally {
68
+ launcherToggle.checked = launcherVisible;
69
+ launcherToggle.disabled = !launcherReady;
33
70
  }
34
-
35
- await chrome.tabs.sendMessage(tab.id, { type: 'codex-overleaf/toggle-launcher' });
36
- window.close();
37
71
  });
38
72
 
39
73
  copyInstallCommand.addEventListener('click', async () => {
40
- await navigator.clipboard.writeText(currentInstallCommand);
41
- copyInstallCommand.textContent = 'Copied';
42
- setTimeout(() => {
43
- copyInstallCommand.textContent = 'Copy install command';
44
- }, 1400);
74
+ copyInstallCommand.disabled = true;
75
+ copyFeedback.hidden = true;
76
+ try {
77
+ await navigator.clipboard.writeText(currentInstallCommand);
78
+ copyInstallCommand.textContent = utx('Copied', '已复制');
79
+ setTimeout(() => { copyInstallCommand.textContent = utx('Copy install command', '复制安装命令'); }, 1400);
80
+ } catch (_error) {
81
+ copyFeedback.textContent = utx('Copy failed. Select the command above to copy it.', '复制失败,可选中上方命令复制。');
82
+ copyFeedback.hidden = false;
83
+ } finally {
84
+ copyInstallCommand.disabled = false;
85
+ }
45
86
  });
46
87
 
47
88
  initPopupState();
48
89
  scheduleConsentUpdateUi();
49
90
 
91
+ // Older managed installations keep their bootstrap HTML across runtime
92
+ // updates. Upgrade only this popup's shell, leaving runtime behavior shared.
93
+ function ensureMinimalPopupShell() {
94
+ document.documentElement.classList.add('popup-minimal-root');
95
+ document.body.classList.add('popup-minimal');
96
+ if (!document.getElementById('launcher-toggle')) {
97
+ const shell = document.createElement('div');
98
+ shell.innerHTML = "<main id=\"popup-shell\">\n <header class=\"popup-header\">\n <img id=\"brand-icon\" class=\"popup-icon\" src=\"assets/icons/icon128.png\" width=\"32\" height=\"32\" alt=\"\">\n <div class=\"popup-brand\">\n <h1>Codex Overleaf Link</h1>\n <button id=\"connection-toggle\" class=\"connection-toggle\" type=\"button\" aria-expanded=\"false\" aria-controls=\"connection-details\">\n <span id=\"compat-status-icon\" class=\"status-icon pending\" aria-hidden=\"true\"></span>\n <span id=\"connection-label\">Checking connection...</span>\n <span class=\"connection-chevron\" aria-hidden=\"true\"></span>\n </button>\n </div>\n </header>\n <section id=\"connection-details\" class=\"connection-details\" aria-label=\"Version details\" hidden>\n <dl id=\"version-pair\">\n <div><dt id=\"extension-version-label\">Extension</dt><dd id=\"extension-version\">Unknown</dd></div>\n <div><dt>Native Host</dt><dd id=\"native-version\">Checking...</dd></div>\n </dl>\n </section>\n <label class=\"launcher-setting\" for=\"launcher-toggle\">\n <span class=\"launcher-copy\">\n <strong id=\"launcher-label\">Show Codex side button</strong>\n <small id=\"launcher-description\">When the panel is closed</small>\n </span>\n <input id=\"launcher-toggle\" class=\"launcher-toggle\" type=\"checkbox\" aria-describedby=\"launcher-description\" disabled>\n </label>\n <p id=\"status\" class=\"popup-note\" role=\"status\" aria-live=\"polite\" hidden></p>\n <section id=\"native-install\" class=\"install\" aria-labelledby=\"native-install-title\" hidden>\n <strong id=\"native-install-title\">Native host attention required</strong>\n <p id=\"native-status-message\"></p>\n <code id=\"install-command\"></code>\n <button id=\"copy-install-command\" class=\"copy-command\" type=\"button\">Copy install command</button>\n <p id=\"copy-feedback\" class=\"copy-feedback\" role=\"status\" hidden></p>\n </section>\n</main>";
99
+ for (const element of Array.from(document.body.children)) {
100
+ if (element.tagName !== 'SCRIPT') element.remove();
101
+ }
102
+ document.body.prepend(shell.firstElementChild);
103
+ }
104
+ document.getElementById('brand-icon').src = chrome.runtime.getURL('assets/icons/icon128.png');
105
+ let stylesheet = document.getElementById('popup-styles');
106
+ if (!stylesheet) {
107
+ stylesheet = document.createElement('link');
108
+ stylesheet.id = 'popup-styles';
109
+ stylesheet.rel = 'stylesheet';
110
+ document.head.append(stylesheet);
111
+ }
112
+ stylesheet.href = new URL('../styles/popup.css', popupScriptUrl).href;
113
+ }
114
+
50
115
  async function initPopupState() {
51
- await checkNativeHost();
52
- await refreshPanelButtonState();
116
+ try {
117
+ const stored = await chrome.storage.local.get(['codexOverleafGlobalPrefsV1', 'codexOverleafPrefs']);
118
+ applyPopupPreferences(stored.codexOverleafGlobalPrefsV1?.values || stored.codexOverleafPrefs || {});
119
+ } catch (_error) { applyPopupPreferences({}); }
120
+ chrome.storage.onChanged?.addListener((changes, area) => {
121
+ if (area === 'local' && changes.codexOverleafGlobalPrefsV1?.newValue?.values) {
122
+ applyPopupPreferences(changes.codexOverleafGlobalPrefsV1.newValue.values);
123
+ }
124
+ });
125
+ await Promise.all([checkNativeHost(), refreshPanelButtonState(), offerNewSites()]);
53
126
  }
54
127
 
55
- async function refreshPanelButtonState() {
56
- const tab = await getActiveOverleafProjectTab();
57
- activeOverleafTab = tab;
58
- if (!tab?.id) {
59
- button.textContent = 'Show Codex button in Overleaf';
60
- return;
128
+ // A runtime update can list an Overleaf site the install did not grant.
129
+ // Chrome only grants it from a click here; nothing changes until then.
130
+ async function offerNewSites() {
131
+ if (!chrome.permissions?.contains || !chrome.permissions?.request) return;
132
+ let matches = [];
133
+ try {
134
+ const url = new URL('../runtime-manifest.json', popupScriptUrl).href;
135
+ matches = (await (await fetch(url, { cache: 'no-store' })).json()).matches || [];
136
+ } catch (_error) { return; }
137
+ const missing = [];
138
+ for (const value of matches) {
139
+ if (!/^https:\/\/(?:[a-z0-9-]+\.)*overleaf\.com\/project(?:\/\*)?$/.test(value)) continue;
140
+ if (!(await chrome.permissions.contains({ origins: [value] }).catch(() => true))) missing.push(value);
141
+ }
142
+ if (!missing.length) return;
143
+ const hosts = [...new Set(missing.map(value => new URL(value.replace(/\*$/, '')).host))];
144
+ const section = document.createElement('section');
145
+ section.className = 'install';
146
+ section.dataset.newSites = '';
147
+ const title = document.createElement('strong');
148
+ title.textContent = utx('This version supports another Overleaf site', '这一版支持新的 Overleaf 站点');
149
+ const detail = document.createElement('p');
150
+ detail.textContent = utx(`Allow access to ${hosts.join(', ')} to use Codex there. Chrome will ask you to confirm.`,
151
+ `允许访问 ${hosts.join('、')} 后即可在那里使用 Codex,Chrome 会请你确认。`);
152
+ const button = document.createElement('button');
153
+ button.type = 'button';
154
+ button.className = 'copy-command';
155
+ button.textContent = utx('Allow', '允许');
156
+ button.addEventListener('click', async () => {
157
+ const granted = await chrome.permissions.request({ origins: missing }).catch(() => false);
158
+ if (granted) section.remove();
159
+ });
160
+ section.append(title, detail, button);
161
+ document.getElementById('popup-shell')?.append(section);
162
+ }
163
+
164
+ function applyPopupPreferences(preferences) {
165
+ document.documentElement.lang = preferences.locale === 'zh' ? 'zh-CN' : 'en';
166
+ document.documentElement.dataset.popupTheme = ['light', 'dark', 'auto'].includes(preferences.theme)
167
+ ? preferences.theme : 'dark';
168
+ document.getElementById('launcher-label').textContent = utx('Show Codex side button', '显示 Codex 侧边入口');
169
+ document.getElementById('launcher-description').textContent = utx('When the panel is closed', '面板关闭时显示');
170
+ document.getElementById('extension-version-label').textContent = utx('Extension', '扩展');
171
+ document.getElementById('native-install-title').textContent = utx('Local connection needs attention', '本地连接需要处理');
172
+ connectionDetails.setAttribute('aria-label', utx('Version details', '版本信息'));
173
+ connectionToggle.title = utx('Show or hide version details', '展开或收起版本信息');
174
+ copyInstallCommand.textContent = utx('Copy install command', '复制安装命令');
175
+ if (lastCompatibility) {
176
+ setVersionStatus(lastCompatibility);
177
+ if (!nativeInstall.hidden) nativeStatusMessage.textContent = getNativeStatusMessage(
178
+ lastCompatibility.status, getCompatibilityClassification(lastCompatibility));
61
179
  }
180
+ }
181
+
182
+ function setLauncherStatus(message, failed = false) {
183
+ status.textContent = message;
184
+ status.hidden = !message;
185
+ status.setAttribute('role', failed ? 'alert' : 'status');
186
+ }
62
187
 
188
+ async function refreshPanelButtonState() {
189
+ launcherReady = false;
190
+ launcherToggle.disabled = true;
63
191
  try {
192
+ const tab = await getActiveOverleafProjectTab();
193
+ activeOverleafTab = tab;
194
+ if (!tab?.id) {
195
+ setLauncherStatus(utx('Open an Overleaf project to change this preference.', '打开 Overleaf 项目页后可设置侧边入口。'));
196
+ return;
197
+ }
64
198
  const response = await chrome.tabs.sendMessage(tab.id, { type: 'codex-overleaf/get-panel-state' });
65
- const visible = response?.launcherVisible !== false;
66
- button.textContent = visible ? 'Hide Codex edge button' : 'Show Codex edge button';
67
- status.textContent = visible
68
- ? 'The edge button appears whenever the Codex panel is closed.'
69
- : 'The Codex edge button is hidden in Overleaf.';
199
+ if (typeof response?.launcherVisible !== 'boolean') throw new Error('Panel state unavailable');
200
+ launcherVisible = response.launcherVisible;
201
+ launcherReady = true;
202
+ launcherToggle.checked = launcherVisible;
203
+ launcherToggle.disabled = false;
204
+ setLauncherStatus('');
70
205
  } catch (_error) {
71
- button.textContent = 'Show Codex button in Overleaf';
72
- status.textContent = 'Refresh the Overleaf tab, then show the Codex button.';
206
+ setLauncherStatus(utx('Refresh the Overleaf tab, then reopen this popup.', '请刷新 Overleaf 页面,再打开此弹窗。'));
73
207
  }
74
208
  }
75
209
 
@@ -79,7 +213,7 @@
79
213
  }
80
214
 
81
215
  function isOverleafProjectUrl(url) {
82
- return /^https:\/\/(www\.)?overleaf\.com\/project\//.test(String(url || ''));
216
+ return /^https:\/\/(?:(?:www|cn)\.)?overleaf\.com\/project\//.test(String(url || ''));
83
217
  }
84
218
 
85
219
  async function checkNativeHost() {
@@ -96,16 +230,13 @@
96
230
  setVersionStatus(compatibility);
97
231
  if (getCompatibilityClassification(compatibility) === 'compatible') {
98
232
  nativeInstall.hidden = true;
99
- status.textContent = 'Native host connected. Open an Overleaf project tab to use Codex.';
100
233
  return;
101
234
  }
102
235
  showNativeInstallGuide(compatibility);
103
236
  } catch (_error) {
104
237
  const compatibility = {
105
- status: 'native_missing',
106
- classification: 'incompatible',
107
- installCommand: DEFAULT_INSTALL_COMMAND,
108
- updateCommand: DEFAULT_INSTALL_COMMAND,
238
+ status: 'native_missing', classification: 'incompatible',
239
+ installCommand: DEFAULT_INSTALL_COMMAND, updateCommand: DEFAULT_INSTALL_COMMAND,
109
240
  extensionVersion: getExtensionCompatibilityMetadata().version
110
241
  };
111
242
  setVersionStatus(compatibility);
@@ -117,7 +248,7 @@
117
248
  nativeInstall.hidden = false;
118
249
  currentInstallCommand = getCompatibilityUpdateCommand(compatibility);
119
250
  installCommand.textContent = currentInstallCommand;
120
- status.textContent = getNativeStatusMessage(compatibility.status, getCompatibilityClassification(compatibility));
251
+ nativeStatusMessage.textContent = getNativeStatusMessage(compatibility.status, getCompatibilityClassification(compatibility));
121
252
  }
122
253
 
123
254
  function evaluateNativeCompatibility(response) {
@@ -146,17 +277,25 @@
146
277
  }
147
278
 
148
279
  function setVersionStatus(compatibility = {}) {
149
- const classification = getCompatibilityClassification(compatibility);
280
+ lastCompatibility = compatibility;
281
+ const pending = compatibility.status === 'checking';
282
+ const classification = pending ? 'pending' : getCompatibilityClassification(compatibility);
150
283
  const extensionVersion = compatibility.extensionVersion || getExtensionCompatibilityMetadata().version;
151
284
  const nativeVersion = compatibility.currentNativeVersion || compatibility.nativeVersion || compatibility.native?.version;
152
- versionPair.textContent = `Extension ${formatVersion(extensionVersion)} / Native ${formatVersion(nativeVersion)}`;
153
- compatStatusIcon.textContent = getStatusIconText(classification);
154
- compatStatusIcon.className = `status-icon ${classification}`;
155
- compatStatusIcon.title = getCompatibilityStatusTitle(classification);
156
- if (compatStatusIcon.dataset) {
157
- compatStatusIcon.dataset.status = classification;
158
- }
159
- compatStatusIcon.setAttribute?.('aria-label', compatStatusIcon.title);
285
+ extensionVersionLabel.textContent = formatVersion(extensionVersion);
286
+ nativeVersionLabel.textContent = pending ? utx('Checking...', '正在检查...') : formatVersion(nativeVersion);
287
+ let label = utx('Update required', '需要更新');
288
+ if (pending) label = utx('Checking connection...', '正在检查连接...');
289
+ else if (classification === 'compatible') label = utx('Connected', '已连接');
290
+ else if (classification === 'update-available') label = utx('Update available', '有可用更新');
291
+ else if (compatibility.status === 'native_missing') label = utx('Not connected', '未连接');
292
+ else if (compatibility.status === 'native_unhealthy') label = utx('Needs attention', '需要处理');
293
+ connectionLabel.textContent = label;
294
+ connectionToggle.setAttribute('aria-label', label + '. ' + utx('Version details', '版本信息'));
295
+ compatStatusIcon.textContent = '';
296
+ compatStatusIcon.className = 'status-icon ' + classification;
297
+ compatStatusIcon.title = label;
298
+ compatStatusIcon.dataset.status = classification;
160
299
  }
161
300
 
162
301
  function getExtensionCompatibilityMetadata() {
@@ -221,28 +360,33 @@
221
360
  function formatVersion(version) {
222
361
  const value = String(version || '').trim();
223
362
  if (!value) {
224
- return 'unknown';
363
+ return utx('Unknown', '未知');
225
364
  }
226
365
  return value.startsWith('v') ? value : `v${value}`;
227
366
  }
228
367
 
229
368
  function getNativeStatusMessage(statusValue, classification) {
230
369
  if (classification === 'update-available') {
231
- return 'Native host update available. Run the update command, then reload the extension.';
370
+ return utx('An update is available for the local bridge. Run the command below, then reload the extension.',
371
+ '本地桥接程序有可用更新。运行下方命令后重新加载扩展。');
232
372
  }
233
373
  switch (statusValue) {
234
374
  case 'native_too_old':
235
- return 'Native host update required. Run the install command, then reload the extension.';
375
+ return utx('Update the local bridge with the command below, then reload the extension.',
376
+ '运行下方命令更新本地桥接程序,然后重新加载扩展。');
236
377
  case 'protocol_unsupported':
237
- return 'Native host protocol mismatch. Update the native host and extension together.';
378
+ return utx('The extension and local bridge use different protocols. Update both components together.',
379
+ '扩展与本地桥接程序的协议不匹配,请一并更新。');
238
380
  case 'extension_too_old':
239
- return 'Extension update required. Update the Chrome extension before running Codex.';
381
+ return utx('Update the Chrome extension before running Codex.', '运行 Codex 前需要更新 Chrome 扩展。');
240
382
  case 'native_unhealthy':
241
- return 'Native host connected, but local Codex is not ready. Check the panel diagnostics.';
383
+ return utx('The local bridge is connected, but Codex needs attention. Check diagnostics in the side panel.',
384
+ '本地桥接已连接,Codex 状态需要处理。请查看侧边栏中的诊断。');
242
385
  case 'native_missing':
243
- return 'Install the local native host before running Codex.';
386
+ return utx('Run this command in Terminal, then reload the extension.', '在终端运行下方命令,然后重新加载扩展。');
244
387
  default:
245
- return 'Native host is not compatible. Update the native host, then reload the extension.';
388
+ return utx('Update the local bridge with the command below, then reload the extension.',
389
+ '运行下方命令更新本地桥接程序,然后重新加载扩展。');
246
390
  }
247
391
  }
248
392