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
@@ -57,6 +57,11 @@
57
57
  fallbackUserMessage: 'Codex could not resolve the requested selection or context.',
58
58
  fallbackNextAction: 'Select the target again or specify the file/section explicitly.'
59
59
  },
60
+ selection_scope_violation: {
61
+ stage: 'preflight', severity: 'blocked', defaultRetryable: false,
62
+ fallbackUserMessage: 'A generated change exceeded the attached selection and was blocked.',
63
+ fallbackNextAction: 'Select the intended region again and request only changes within it. Valid written parts can be undone.'
64
+ },
60
65
  base_file_missing_at_start: {
61
66
  stage: 'context', severity: 'error', defaultRetryable: true,
62
67
  fallbackUserMessage: 'A file needed for this task was missing during the initial project read.',
@@ -101,6 +106,21 @@
101
106
  },
102
107
 
103
108
  // 9.2 Preflight
109
+ governance_blocked: {
110
+ stage: 'preflight', severity: 'blocked', defaultRetryable: false,
111
+ fallbackUserMessage: 'Project file rules blocked this write. Codex did not write the affected path.',
112
+ fallbackNextAction: 'Review the project file rules in Settings > Protection & privacy, then request changes within the allowed paths.'
113
+ },
114
+ governance_readonly: {
115
+ stage: 'preflight', severity: 'blocked', defaultRetryable: false,
116
+ fallbackUserMessage: 'Project file rules marked a path in this operation read-only. Codex did not apply this operation.',
117
+ fallbackNextAction: 'Review the read-only paths in Settings > Protection & privacy, then request changes within the allowed paths.'
118
+ },
119
+ governance_writable_allowlist: {
120
+ stage: 'preflight', severity: 'blocked', defaultRetryable: false,
121
+ fallbackUserMessage: 'A path in this operation is outside the configured writable paths. Codex did not apply this operation.',
122
+ fallbackNextAction: 'Review the writable paths in Settings > Protection & privacy, then request changes within those paths.'
123
+ },
104
124
  missing_base_file: {
105
125
  stage: 'preflight', severity: 'blocked', defaultRetryable: true,
106
126
  fallbackUserMessage: 'A write safety check needed a base file that is missing from the run snapshot.',
@@ -121,11 +141,26 @@
121
141
  fallbackUserMessage: 'The edit anchor matches multiple locations.',
122
142
  fallbackNextAction: 'Narrow the request or select a smaller region.'
123
143
  },
144
+ file_plan_confirmation_rejected: {
145
+ stage: 'preflight', severity: 'blocked', defaultRetryable: false,
146
+ fallbackUserMessage: 'The complete file plan was cancelled; no part was applied.',
147
+ fallbackNextAction: 'Review the intended changes and start a new run if you want to apply them.'
148
+ },
149
+ file_tree_controls_unavailable: {
150
+ stage: 'preflight', severity: 'blocked', defaultRetryable: false,
151
+ fallbackUserMessage: 'Codex could not safely perform this file operation with the available Overleaf controls.',
152
+ fallbackNextAction: 'Check the file operation in Overleaf before starting a new task.'
153
+ },
124
154
  delete_confirmation_missing: {
125
155
  stage: 'preflight', severity: 'blocked', defaultRetryable: true,
126
156
  fallbackUserMessage: 'A destructive delete was not confirmed.',
127
157
  fallbackNextAction: 'Confirm the delete explicitly if intended.'
128
158
  },
159
+ delete_confirmation_rejected: {
160
+ stage: 'preflight', severity: 'blocked', defaultRetryable: false,
161
+ fallbackUserMessage: 'The deletion was cancelled and was not applied. Other allowed changes in this run may still proceed.',
162
+ fallbackNextAction: 'Review the other changes. If deletion is still intended, request it in a new task.'
163
+ },
129
164
  binary_write_blocked: {
130
165
  stage: 'preflight', severity: 'blocked', defaultRetryable: false,
131
166
  fallbackUserMessage: 'Codex tried to write unsupported binary content.',
@@ -158,6 +193,26 @@
158
193
  fallbackUserMessage: 'Create/delete/rename/move did not appear in the file tree as expected.',
159
194
  fallbackNextAction: 'Inspect the file tree and retry if needed.'
160
195
  },
196
+ source_zip_unavailable: {
197
+ stage: 'preflight', severity: 'blocked', defaultRetryable: true,
198
+ fallbackUserMessage: 'The project could not be checked before uploading this file.',
199
+ fallbackNextAction: 'Retry sync; only missing files will be uploaded.'
200
+ },
201
+ file_upload_unconfirmed: {
202
+ stage: 'verify', severity: 'warning', defaultRetryable: true,
203
+ fallbackUserMessage: 'The file was submitted, but its saved content is not yet confirmed.',
204
+ fallbackNextAction: 'Check the file before retrying; matching content will not be uploaded twice.'
205
+ },
206
+ subagent_unfinished_output: {
207
+ stage: 'preflight', severity: 'blocked', defaultRetryable: false,
208
+ fallbackUserMessage: 'A subagent stopped before finishing this file; the main agent must review and adopt it.',
209
+ fallbackNextAction: 'Have the main agent complete and adopt the pending file.'
210
+ },
211
+ subagent_unauthorized_edit: {
212
+ stage: 'preflight', severity: 'blocked', defaultRetryable: false,
213
+ fallbackUserMessage: 'A file changed outside the subagent ownership boundary and was not synced.',
214
+ fallbackNextAction: 'Review the ownership violation; it cannot be cleared through output adoption.'
215
+ },
161
216
  partial_write_needs_review: {
162
217
  stage: 'verify', severity: 'warning', defaultRetryable: false,
163
218
  fallbackUserMessage: 'Some operations wrote, some were skipped.',
@@ -214,6 +269,21 @@
214
269
  },
215
270
 
216
271
  // 9.5 Undo
272
+ snapshot_undo_current_mismatch: {
273
+ stage: 'undo', severity: 'blocked', defaultRetryable: false,
274
+ fallbackUserMessage: 'The current content or document identity does not match this run\'s undo checkpoint. Codex stopped Undo and kept the recovery data.',
275
+ fallbackNextAction: 'Inspect the file and any later edits before trying Undo again.'
276
+ },
277
+ snapshot_undo_open_failed: {
278
+ stage: 'undo', severity: 'blocked', defaultRetryable: true,
279
+ fallbackUserMessage: 'Codex could not open the file to restore its saved checkpoint.',
280
+ fallbackNextAction: 'Open the file in Overleaf, wait for it to load, then retry Undo.'
281
+ },
282
+ snapshot_undo_unavailable: {
283
+ stage: 'undo', severity: 'blocked', defaultRetryable: false,
284
+ fallbackUserMessage: 'The saved checkpoint is unavailable for this Undo. Codex kept the remaining recovery data.',
285
+ fallbackNextAction: 'Inspect the file and the run details before continuing.'
286
+ },
217
287
  undo_preflight_content_drift: {
218
288
  stage: 'undo', severity: 'blocked', defaultRetryable: false,
219
289
  fallbackUserMessage: "Current content no longer matches this run's written content.",
@@ -283,6 +353,16 @@
283
353
  fallbackUserMessage: 'Native host version or capabilities do not match the extension.',
284
354
  fallbackNextAction: 'Update the native host.'
285
355
  },
356
+ codex_local_skill_unavailable: {
357
+ stage: 'preflight', severity: 'blocked', defaultRetryable: true,
358
+ fallbackUserMessage: 'The selected local Codex skill is unavailable or disabled. This run did not start.',
359
+ fallbackNextAction: 'Open Skills, select an available enabled skill, and submit again.'
360
+ },
361
+ codex_local_skills_failed: {
362
+ stage: 'preflight', severity: 'blocked', defaultRetryable: true,
363
+ fallbackUserMessage: 'Local Codex skills could not be loaded. This run did not start.',
364
+ fallbackNextAction: 'Open Skills to reload the local catalog, then submit again.'
365
+ },
286
366
  codex_no_usable_result: {
287
367
  stage: 'codex', severity: 'error', defaultRetryable: true,
288
368
  fallbackUserMessage: 'Local Codex returned no usable final report or operations.',
@@ -425,6 +505,8 @@
425
505
  * @type {Record<string, string | ((result: any) => string)>}
426
506
  */
427
507
  const LEGACY_CODE_MAP = {
508
+ governance_blocked: result => result.reasonKey === 'readonly' ? 'governance_readonly'
509
+ : result.reasonKey === 'writable_allowlist' ? 'governance_writable_allowlist' : 'governance_blocked',
428
510
  path_not_found: 'target_file_not_found',
429
511
  file_open_failed: 'target_file_open_failed',
430
512
  editor_not_ready: 'target_editor_not_ready',
@@ -560,6 +642,240 @@
560
642
  return out;
561
643
  }
562
644
 
645
+ // Display projection only: these aliases and exact historical templates do
646
+ // not enter the canonical catalog, persistence, retry or recovery decisions.
647
+ const REVIEW_DISPLAY_CODES = new Set([
648
+ 'missing_tracked_changes', 'tracked_change_file_open_failed', 'tracked_change_reject_control_not_found',
649
+ 'tracked_change_reject_not_confirmed', 'tracked_change_accept_control_not_found', 'tracked_change_accept_not_confirmed',
650
+ 'tracked_change_editor_undo_open_failed', 'tracked_change_editor_undo_current_mismatch', 'editor_undo_control_not_found',
651
+ 'editor_undo_no_progress', 'editor_undo_max_iterations', 'tracked_change_undo_max_iterations',
652
+ 'tracked_change_undo_verify_open_failed', 'tracked_change_undo_verify_failed', 'accept_missing_run_content',
653
+ 'accept_editor_undo_unavailable', 'accept_editing_not_confirmed', 'accept_editing_not_stable',
654
+ 'accept_replay_rollback_missing_content', 'review_scope_unavailable', 'review_request_unverified',
655
+ 'review_owner_disconnected', 'review_deadline_exceeded', 'review_cancelled',
656
+ 'review_project_changed', 'tracked_change_not_found', 'snapshot_undo_current_mismatch',
657
+ 'snapshot_undo_open_failed', 'snapshot_undo_unavailable', 'file_tree_controls_unavailable',
658
+ 'native_untracked_undo_pending_changes'
659
+ ]);
660
+ const REVIEW_DISPLAY_TEMPLATES = [
661
+ ['governance_readonly', 'Project governance marked this path read-only, so Codex did not write it.'],
662
+ ['governance_readonly', '项目治理规则将此路径标记为只读,因此 Codex 没有写入。'],
663
+ ['governance_readonly', '项目文件规则将此操作涉及的路径标记为只读。Codex 未执行此操作。'],
664
+ ['governance_writable_allowlist', 'Project governance allows writes only to configured writable patterns, and this path is outside that allowlist.'],
665
+ ['governance_writable_allowlist', '项目治理规则只允许写入配置的可写路径,此路径不在允许范围内。'],
666
+ ['governance_writable_allowlist', '此操作涉及的路径不在配置的可写路径范围内。Codex 未执行此操作。'],
667
+ ['governance_blocked', 'Project governance blocked this write.'],
668
+ ['governance_blocked', '项目治理规则阻止了此写入。'],
669
+ ['governance_blocked', '项目文件规则阻止了此次写入。Codex 未写入受影响的路径。'],
670
+ ["missing_tracked_changes", "这轮写入没有可识别的 Overleaf 留痕记录;为避免制造新的红线,Codex 没有执行文本补丁撤销。"],
671
+ ["missing_tracked_changes", "No matching Overleaf tracked-change records were found for this run, so Codex did not undo with text patches."],
672
+ ["missing_tracked_changes", "No matching Overleaf tracked-change records were found for this run. Codex did not undo with text patches."],
673
+ ["missing_tracked_changes", "这轮写入没有可识别的 Overleaf 留痕记录;Codex 没有执行文本补丁撤销。"],
674
+ ["tracked_change_file_open_failed", "无法打开 {file} 来查找这轮写入的留痕记录;Codex 没有用文本补丁伪撤销。"],
675
+ ["tracked_change_file_open_failed", "无法打开 {file} 来继续拒绝这轮留痕记录;请在 Overleaf 审阅面板手动处理。"],
676
+ ["tracked_change_file_open_failed", "Could not open {file} to find this run's tracked changes. Handle them manually in the Overleaf review tools."],
677
+ ["tracked_change_file_open_failed", "Could not open the file to find this run's tracked changes. Handle them manually in the Overleaf review tools."],
678
+ ["tracked_change_file_open_failed", "Could not open the file to find this run's tracked changes. Check it in the Overleaf review panel."],
679
+ ["tracked_change_file_open_failed", "无法打开文件来查找这轮写入的留痕记录;请在 Overleaf 审阅面板检查。"],
680
+ ["tracked_change_reject_control_not_found", "找到了这轮写入的留痕记录,但没有找到对应的 Reject/拒绝按钮;Codex 没有用文本补丁伪撤销。"],
681
+ ["tracked_change_reject_control_not_found", "还有 {file} 的留痕记录未处理,但没有找到对应的 Reject/拒绝按钮;请在 Overleaf 审阅面板手动拒绝。"],
682
+ ["tracked_change_reject_control_not_found", "Some tracked changes in {file} remain, but the matching Reject button was not found. Reject them manually in Overleaf."],
683
+ ["tracked_change_reject_control_not_found", "Some tracked changes remain, but the matching Reject button was not found. Reject them manually in Overleaf."],
684
+ ["tracked_change_reject_control_not_found", "Some tracked changes remain, but the matching Reject button was not found. Check them in the Overleaf review panel."],
685
+ ["tracked_change_reject_control_not_found", "仍有留痕记录未处理,但未找到对应的拒绝按钮;请在 Overleaf 审阅面板检查。"],
686
+ ["tracked_change_reject_not_confirmed", "Codex 点击了 Reject/拒绝,但 Overleaf 页面仍显示这条留痕记录;请在 Overleaf 审阅面板手动拒绝。"],
687
+ ["tracked_change_reject_not_confirmed", "Codex clicked Reject, but Overleaf still shows this tracked change. Reject it manually in the Overleaf review panel."],
688
+ ["tracked_change_reject_not_confirmed", "Codex clicked Reject, but Overleaf still shows this tracked change. Check it in the Overleaf review panel."],
689
+ ["tracked_change_reject_not_confirmed", "Codex 已点击拒绝,但 Overleaf 仍显示该留痕记录;请在审阅面板检查。"],
690
+ ["tracked_change_accept_control_not_found", "Some tracked changes in {file} remain, but the matching Accept button was not found. Accept them manually in Overleaf."],
691
+ ["tracked_change_accept_control_not_found", "Some tracked changes remain, but the matching Accept button was not found. Accept them manually in Overleaf."],
692
+ ["tracked_change_accept_control_not_found", "Some tracked changes remain, but the matching Accept button was not found. Check them in the Overleaf review panel."],
693
+ ["tracked_change_accept_control_not_found", "仍有留痕记录未处理,但未找到对应的接受按钮;请在 Overleaf 审阅面板检查。"],
694
+ ["tracked_change_accept_not_confirmed", "Codex clicked Accept, but Overleaf still shows this tracked change. Accept it manually in the Overleaf review panel."],
695
+ ["tracked_change_accept_not_confirmed", "Codex clicked Accept, but Overleaf still shows this tracked change. Check it in the Overleaf review panel."],
696
+ ["tracked_change_accept_not_confirmed", "Codex 已点击接受,但 Overleaf 仍显示该留痕记录;请在审阅面板检查。"],
697
+ ["tracked_change_editor_undo_open_failed", "无法打开 {file} 来执行 Overleaf 原生撤销。"],
698
+ ["tracked_change_editor_undo_open_failed", "Could not open {file} for Overleaf native undo."],
699
+ ["tracked_change_editor_undo_open_failed", "Could not open the file for Overleaf native undo."],
700
+ ["tracked_change_editor_undo_open_failed", "Could not open the file for Overleaf native Undo."],
701
+ ["tracked_change_editor_undo_open_failed", "无法打开文件来执行 Overleaf 原生撤销。"],
702
+ ["tracked_change_editor_undo_current_mismatch", "{file} 当前内容已经不是本轮写入后的内容;为避免撤掉你的后续修改,Codex 不使用 Overleaf 原生撤销。"],
703
+ ["tracked_change_editor_undo_current_mismatch", "{file} no longer matches this run's written content, so Codex did not use Overleaf native undo."],
704
+ ["tracked_change_editor_undo_current_mismatch", "The current content no longer matches this run's written content, so Codex did not use Overleaf native undo."],
705
+ ["tracked_change_editor_undo_current_mismatch", "The current content no longer matches this run's written content. Codex stopped native Undo to preserve later edits."],
706
+ ["tracked_change_editor_undo_current_mismatch", "当前内容与本轮写入后的内容不一致;Codex 已停止原生撤销,以保留后续编辑。"],
707
+ ["editor_undo_control_not_found", "没有找到 Overleaf 编辑器自己的 Undo/撤销按钮,无法一次性撤销 {file} 的本轮留痕。"],
708
+ ["editor_undo_control_not_found", "Could not find Overleaf's editor Undo button to undo this run in {file}."],
709
+ ["editor_undo_control_not_found", "Could not find Overleaf's editor Undo button to undo this run."],
710
+ ["editor_undo_control_not_found", "未找到 Overleaf 编辑器的撤销按钮,无法撤销本轮改动。"],
711
+ ["editor_undo_no_progress", "Codex 点击了 Overleaf Undo/撤销,但 {file} 内容没有变化。"],
712
+ ["editor_undo_no_progress", "Codex clicked Overleaf Undo, but {file} did not change."],
713
+ ["editor_undo_no_progress", "Codex clicked Overleaf Undo, but the file did not change."],
714
+ ["editor_undo_no_progress", "Codex 已点击 Overleaf 撤销,但文件内容没有变化。"],
715
+ ["editor_undo_max_iterations", "{file} 经过多次 Overleaf 原生撤销后仍未回到本轮写入前内容,已停止以避免撤销其它修改。"],
716
+ ["editor_undo_max_iterations", "{file} did not return to its pre-run content after repeated Overleaf native undo steps. Codex stopped to avoid undoing other edits."],
717
+ ["editor_undo_max_iterations", "The file did not return to its pre-run content after repeated Overleaf native undo steps. Codex stopped to avoid undoing other edits."],
718
+ ["editor_undo_max_iterations", "The file did not return to its pre-run content after repeated native Undo steps. Codex stopped to avoid undoing other edits."],
719
+ ["editor_undo_max_iterations", "经过多次原生撤销后,文件仍未恢复到本轮写入前的内容;Codex 已停止,以免撤销其他编辑。"],
720
+ ["tracked_change_undo_max_iterations", "{file} 仍有未完成的留痕记录;Codex 已停止以避免误拒绝其它改动。"],
721
+ ["tracked_change_undo_max_iterations", "{file} still has tracked changes after the reject sweep, so Codex stopped to avoid mis-rejecting other edits."],
722
+ ["tracked_change_undo_max_iterations", "{file} still has tracked changes after the per-expected-file reject sweep, so Codex stopped to avoid mis-rejecting other edits."],
723
+ ["tracked_change_undo_max_iterations", "{file} still has tracked changes left. Codex stopped to avoid rejecting unrelated edits."],
724
+ ["tracked_change_undo_max_iterations", "Tracked changes are still left. Codex stopped to avoid rejecting unrelated edits."],
725
+ ["tracked_change_undo_max_iterations", "仍有未处理的留痕记录;Codex 已停止,以免误拒绝其他编辑。"],
726
+ ["tracked_change_undo_verify_open_failed", "撤销后无法打开 {file} 验证内容;请刷新 Overleaf 后检查。"],
727
+ ["tracked_change_undo_verify_open_failed", "Could not open {file} after undo to verify content. Reload Overleaf and check manually."],
728
+ ["tracked_change_undo_verify_open_failed", "Could not open the file after undo to verify content. Reload Overleaf and check manually."],
729
+ ["tracked_change_undo_verify_open_failed", "Could not open the file after Undo to verify its content. Reload Overleaf and check it."],
730
+ ["tracked_change_undo_verify_open_failed", "撤销后无法打开文件验证内容;请刷新 Overleaf 后检查。"],
731
+ ["tracked_change_undo_verify_failed", "{file} 拒绝留痕后内容没有回到写入前状态;请在 Overleaf 审阅面板检查这轮修改。"],
732
+ ["tracked_change_undo_verify_failed", "{file} did not return to its pre-run content after rejecting tracked changes. Check this run's changes in the Overleaf review panel."],
733
+ ["tracked_change_undo_verify_failed", "The file did not return to its pre-run content after rejecting tracked changes. Check this run's changes in the Overleaf review panel."],
734
+ ["tracked_change_undo_verify_failed", "拒绝留痕后,文件内容仍未恢复到写入前状态;请在 Overleaf 审阅面板检查本轮修改。"],
735
+ ["accept_missing_run_content", "这轮写入没有可识别的写入前/写入后内容;Codex 没有把留痕改动接受为永久文本。"],
736
+ ["accept_missing_run_content", "{file} 缺少写入前/写入后内容;Codex 没有重放本轮改动。"],
737
+ ["accept_missing_run_content", "The pre-write or post-write content is unavailable. Codex did not replay or accept the tracked changes."],
738
+ ["accept_missing_run_content", "缺少写入前或写入后的内容;Codex 未重放或接受留痕改动。"],
739
+ ["accept_editor_undo_unavailable", "没有可执行的 Overleaf 原生撤销或安全快照回滚来清掉本轮留痕;Codex 没有接受这轮改动。"],
740
+ ["accept_editor_undo_unavailable", "Native Undo and a safe checkpoint rollback are unavailable. Codex did not accept this run."],
741
+ ["accept_editor_undo_unavailable", "原生撤销及安全的检查点回滚均不可用;Codex 未接受本轮改动。"],
742
+ ["accept_editing_not_confirmed", "无法确认 Overleaf 已切换到 Editing 模式;Codex 没有把本轮改动重写为永久文本。"],
743
+ ["accept_editing_not_confirmed", "切换后仍未能确认 Overleaf 处于 Editing 模式;为避免重写又留下留痕,Codex 没有重放本轮改动。"],
744
+ ["accept_editing_not_confirmed", "本次操作前未能确认 Overleaf 处于 Editing 模式;为避免重写又留下留痕,Codex 没有继续重放本轮剩余改动。"],
745
+ ["accept_editing_not_confirmed", "Codex could not re-confirm Editing mode before replaying {file}; Codex stopped to avoid landing a tracked write."],
746
+ ["accept_editing_not_confirmed", "Codex could not confirm Editing mode for the untracked Accept replay, so the run was not finalized."],
747
+ ["accept_editing_not_confirmed", "Codex could not switch Overleaf to Editing mode for the untracked Accept replay, so the run was not finalized."],
748
+ ["accept_editing_not_confirmed", "Codex toggled Overleaf to Editing, but the post-toggle state did not positively confirm Editing — Codex did not replay the run."],
749
+ ["accept_editing_not_confirmed", "Codex could not confirm Overleaf Editing mode. It stopped replaying this run to avoid creating new tracked changes."],
750
+ ["accept_editing_not_confirmed", "无法确认 Overleaf 已进入编辑模式;Codex 已停止重放本轮改动,以免产生新的留痕。"],
751
+ ["accept_editing_not_stable", "Overleaf Editing mode did not remain stable long enough for an untracked Accept All replay; Codex did not replay this write."],
752
+ ["accept_editing_not_stable", "Overleaf Editing mode did not remain stable long enough for an untracked Accept replay. Codex did not replay this write."],
753
+ ["accept_editing_not_stable", "Overleaf 编辑模式未保持稳定,无法无留痕地重放接受的改动;Codex 未重放此次写入。"],
754
+ ["accept_replay_rollback_missing_content", "Accept All detected fresh tracked changes, but could not roll back because the pre/post content was unavailable."],
755
+ ["accept_replay_rollback_missing_content", "Accept created fresh tracked changes, but rollback could not run because the pre-write or post-write content was unavailable."],
756
+ ["accept_replay_rollback_missing_content", "接受改动时产生了新的留痕,但缺少写入前或写入后的内容,无法回滚。"],
757
+ ["review_scope_unavailable", "The native tracked-change scope could not be safely isolated. No review mutation was attempted. Use Overleaf Review to handle the changes individually."],
758
+ ["review_scope_unavailable", "The native tracked-change scope could not be safely isolated. No review mutation was attempted. Check the changes individually in Overleaf Review."],
759
+ ["review_scope_unavailable", "无法安全确认本轮原生留痕的范围;尚未尝试审阅写入。请在 Overleaf 审阅面板逐项检查。"],
760
+ ["review_request_unverified", "The native review request could not be fully verified; some target changes may already be accepted. No text replay was attempted. Check Overleaf Review before retrying."],
761
+ ["review_request_unverified", "原生审阅请求未能完全核实,部分目标改动可能已接受;未尝试文本重放。请先在 Overleaf 审阅面板检查,再决定是否重试。"],
762
+ ["review_owner_disconnected", "The Undo owner disconnected; no further review writes were started."],
763
+ ["review_owner_disconnected", "撤销操作的连接已断开;未再启动后续审阅写入。"],
764
+ ["review_deadline_exceeded", "The review time budget expired; no further review writes were started."],
765
+ ["review_deadline_exceeded", "The review time budget expired."],
766
+ ["review_deadline_exceeded", "审阅操作已超时;未再启动后续审阅写入。"],
767
+ ["review_cancelled", "The review was cancelled; no further review writes were started."],
768
+ ["review_cancelled", "审阅操作已取消;未再启动后续审阅写入。"],
769
+ ["review_project_changed", "The original review project is no longer active."],
770
+ ["review_project_changed", "原审阅项目已不再处于活动状态。"],
771
+ ["tracked_change_not_found", "没有在 Overleaf 页面里找到这轮写入对应的留痕记录;Codex 没有用文本补丁伪撤销。"],
772
+ ["tracked_change_not_found", "No matching tracked changes were found on the Overleaf page for this run."],
773
+ ["tracked_change_not_found", "No matching tracked changes were found on the Overleaf page for this run. Codex did not undo with text patches."],
774
+ ["snapshot_undo_current_mismatch", "{file} 当前内容或文档身份与本轮撤销检查点不一致;Codex 保留恢复材料并停止撤销。"],
775
+ ["snapshot_undo_current_mismatch", "{file} 当前内容已经不是本轮写入后的内容;为避免覆盖你的后续修改,Codex 不执行快照撤销。"],
776
+ ["snapshot_undo_current_mismatch", "The current content or document identity does not match this run's undo checkpoint. Codex stopped Undo and kept the recovery data."],
777
+ ["snapshot_undo_current_mismatch", "当前内容或文档身份与本轮撤销检查点不一致;Codex 已停止撤销并保留恢复材料。"],
778
+ ["snapshot_undo_open_failed", "无法打开 {file} 来执行快照撤销。"],
779
+ ["snapshot_undo_open_failed", "Codex could not open the file to restore its saved checkpoint."],
780
+ ["snapshot_undo_open_failed", "Codex 无法打开文件来恢复已保存的检查点。"],
781
+ ["snapshot_undo_unavailable", "The saved checkpoint is unavailable for this undo."],
782
+ ["snapshot_undo_unavailable", "The saved checkpoint is unavailable for this Undo. Codex kept the remaining recovery data."],
783
+ ["snapshot_undo_unavailable", "本次撤销所需的检查点不可用;Codex 已保留剩余恢复材料。"]
784
+ ].sort((a, b) => Number(a[1].includes('{file}')) - Number(b[1].includes('{file}')))
785
+ .map(([code, template]) => ({ code, template,
786
+ pattern: new RegExp('^' + template.split('{file}').map(part => part.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('(.+)') + '$') }));
787
+
788
+ function safeDisplayProjectPath(value) {
789
+ if (typeof value !== 'string' || !value || value.length > 300 || /[\r\n]/.test(value)) return '';
790
+ const path = value.replace(/\\/g, '/');
791
+ return !path.startsWith('/') && !/^[A-Za-z]:/.test(path) && !path.split('/').includes('..') ? path : '';
792
+ }
793
+
794
+ function recoverDisplayFailure(failure, allowFilePrefix = true) {
795
+ if (!failure || typeof failure !== 'object') return failure;
796
+ const originalCode = failure.evidence?.originalCode;
797
+ const displayCodeAllowed = code => REVIEW_DISPLAY_CODES.has(code)
798
+ && (code !== 'native_untracked_undo_pending_changes'
799
+ || (failure.changedDocument !== true && failure.mayHaveMutated !== true && failure.evidence?.writeStarted !== true));
800
+ const explicitCode = displayCodeAllowed(originalCode) ? originalCode
801
+ : displayCodeAllowed(failure.code) ? failure.code : '';
802
+ const message = String(failure.userMessage || '');
803
+ for (const { code, pattern } of REVIEW_DISPLAY_TEMPLATES) {
804
+ if (explicitCode && code !== explicitCode) continue;
805
+ const match = pattern.exec(message);
806
+ if (!match) continue;
807
+ const captured = ['当前文件', 'The target file', 'the next file'].includes(match[1]) ? '' : match[1];
808
+ if (captured && safeDisplayProjectPath(captured) !== captured) continue;
809
+ return { ...failure, code, file: failure.file || captured || '' };
810
+ }
811
+ // Catalog defaults are also product-owned exact messages in older compact
812
+ // records. Recover only a display code; their old retry semantics stay put.
813
+ const catalogCode = Object.keys(FAILURE_CODE_CATALOG).find(code => code !== 'unknown_legacy_failure'
814
+ && FAILURE_CODE_CATALOG[code].fallbackUserMessage === message);
815
+ if (!explicitCode && catalogCode) return { ...failure, code: catalogCode };
816
+ // Earlier formatters persisted "file: message". Only accept one safe file
817
+ // prefix whose complete remaining body resolves to a known product message.
818
+ const prefixed = allowFilePrefix && /^([^:\r\n]+): (.+)$/.exec(message);
819
+ if (prefixed && safeDisplayProjectPath(prefixed[1]) === prefixed[1]) {
820
+ const body = { ...failure, userMessage: prefixed[2], file: failure.file || prefixed[1] };
821
+ const recovered = recoverDisplayFailure(body, false);
822
+ if (recovered !== body && recovered.code !== 'unknown_legacy_failure') return recovered;
823
+ }
824
+ return explicitCode ? { ...failure, code: explicitCode } : failure;
825
+ }
826
+
827
+ // A single renderer prevents the Notice and expanded results from using
828
+ // different code lists or emitting a dynamic filename twice.
829
+ function formatFailureReasonForDisplay(failure, locale, i18nLookup) {
830
+ const display = recoverDisplayFailure(failure);
831
+ const lookup = typeof i18nLookup === 'function' ? i18nLookup : () => undefined;
832
+ const key = display?.code ? 'failureReason_' + display.code + '_user' : '';
833
+ const template = key ? lookup(key) : '';
834
+ const file = safeDisplayProjectPath(display?.file);
835
+ const localized = localizeFailureReason(display ? { ...display, file } : display, locale, lookup);
836
+ const message = template?.includes('{file}') ? localized.userMessage
837
+ : [file, localized.userMessage].filter(Boolean).join(': ');
838
+ return { ...localized, code: display?.code, message, file, localized: Boolean(template && template !== key) };
839
+ }
840
+
841
+ function localizeFailureMessage(message, locale, i18nLookup) {
842
+ return formatFailureReasonForDisplay({ code: 'unknown_legacy_failure', userMessage: message }, locale, i18nLookup).message;
843
+ }
844
+
845
+ // Writeback consumers share catalog normalization, including file context,
846
+ // while retaining the mutation evidence carried by older result envelopes.
847
+ function normalizeWritebackFailure(result, operation) {
848
+ if (!result || typeof result !== 'object' || (!result.failure && !result.code && result.ok !== false)) return null;
849
+ const failure = normalizeFailureReason(result, operation);
850
+ const explicit = result.failure && typeof result.failure === 'object' ? result.failure : {};
851
+ const changedDocument = typeof explicit.changedDocument === 'boolean' ? explicit.changedDocument : result.changedDocument;
852
+ if (typeof changedDocument === 'boolean') failure.changedDocument = changedDocument;
853
+ if (explicit.mayHaveMutated === true || result.mayHaveMutated === true) failure.mayHaveMutated = true;
854
+ const terminalState = explicit.terminalState || result.terminalState;
855
+ if (ALLOWED_SEVERITY_PER_TERMINAL[terminalState]?.has(failure.severity)) failure.terminalState = terminalState;
856
+ // An unrecognized transport code can still carry a valid write-stage hint.
857
+ if (failure.code === 'unknown_legacy_failure') {
858
+ const stage = explicit.stage || result.stage;
859
+ if (FAILURE_STAGES.has(stage)) failure.stage = stage;
860
+ }
861
+ return failure;
862
+ }
863
+
864
+ function isUnconfirmedWriteFailure(failure) {
865
+ if (!failure || typeof failure !== 'object') return false;
866
+ return failure.terminalState === 'needs_review' || failure.mayHaveMutated === true
867
+ || ['write_timeout', 'partial_write_needs_review', 'writeback_result_unconfirmed', 'write_result_missing'].includes(failure.code)
868
+ || (failure.changedDocument === true && ['write', 'verify', 'undo', 'accept'].includes(failure.stage));
869
+ }
870
+
871
+ // A potentially changed document needs review before unrelated blockers can
872
+ // offer a retry. Keep the generic severity/stage order within each group.
873
+ function selectPrimaryWritebackFailure(failures) {
874
+ if (!Array.isArray(failures)) return null;
875
+ const review = failures.filter(isUnconfirmedWriteFailure);
876
+ return selectPrimaryFailure(review.length ? review : failures);
877
+ }
878
+
563
879
  function buildFallbackFailureReason(code, op) {
564
880
  const catalog = FAILURE_CODE_CATALOG[code] || FAILURE_CODE_CATALOG.unknown_legacy_failure;
565
881
  return augmentWithOperation({
@@ -628,10 +944,15 @@
628
944
  */
629
945
  function localizeFailureReason(failure, locale, i18nLookup) {
630
946
  void locale;
631
- const lookup = i18nLookup instanceof Function ? i18nLookup : function noopLookup() { return undefined; };
947
+ failure = recoverDisplayFailure(failure);
948
+ const lookup = key => {
949
+ const value = typeof i18nLookup === 'function' ? i18nLookup(key) : undefined;
950
+ return value && value !== key ? value : undefined;
951
+ };
632
952
  const code = failure && typeof failure.code === 'string' ? failure.code : '';
633
953
  const userTemplate = code ? lookup('failureReason_' + code + '_user') : undefined;
634
- const nextTemplate = code ? lookup('failureReason_' + code + '_next') : undefined;
954
+ const nextTemplate = (code ? lookup('failureReason_' + code + '_next') : undefined)
955
+ || (REVIEW_DISPLAY_CODES.has(code) ? lookup('failureReason_review_detail_next') : undefined);
635
956
  const userMessage = userTemplate
636
957
  ? interpolateFailureTemplate(userTemplate, failure)
637
958
  : (failure && failure.userMessage) || '';
@@ -662,7 +983,12 @@
662
983
  STAGE_TIE_BREAKER_ORDER,
663
984
  validateFailureReason,
664
985
  normalizeFailureReason,
986
+ normalizeWritebackFailure,
987
+ isUnconfirmedWriteFailure,
988
+ selectPrimaryWritebackFailure,
665
989
  selectPrimaryFailure,
666
- localizeFailureReason
990
+ localizeFailureReason,
991
+ formatFailureReasonForDisplay,
992
+ localizeFailureMessage
667
993
  };
668
994
  });
@@ -11,17 +11,29 @@
11
11
  const PATCH_MESSAGE = 'codex-overleaf/global-preferences/patch';
12
12
  const DEFAULTS = Object.freeze({ theme: 'dark', locale: 'en', preloadProjectContext: true,
13
13
  loadCodexLocalSkills: true, loadCodexOverleafSkills: true });
14
- const FIELDS = Object.freeze([...Object.keys(DEFAULTS), 'codexOverleafSkillEnabled']);
14
+ const SKILL_MAP_FIELDS = Object.freeze(['codexOverleafSkillEnabled', 'codexLocalSkillEnabled']);
15
+ const FIELDS = Object.freeze([...Object.keys(DEFAULTS), ...SKILL_MAP_FIELDS]);
16
+ const MAX_SKILL_PREFERENCES = 200;
15
17
 
16
18
  function validSkillId(id) {
17
19
  return /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$/.test(id)
18
20
  && !['__proto__', 'prototype', 'constructor'].includes(id) && !id.includes('..');
19
21
  }
20
22
 
23
+ function normalizeSkillEnabledMap(value) {
24
+ const result = {};
25
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return result;
26
+ for (const [id, enabled] of Object.entries(value)) {
27
+ if (validSkillId(id) && typeof enabled === 'boolean') result[id] = enabled;
28
+ }
29
+ if (Object.keys(result).length > MAX_SKILL_PREFERENCES) throw new Error('Too many skill preferences.');
30
+ return result;
31
+ }
32
+
21
33
  function pick(value = {}) {
22
- const skills = {};
23
- for (const [id, enabled] of Object.entries(value.codexOverleafSkillEnabled || {}).slice(0, 200)) {
24
- if (validSkillId(id) && typeof enabled === 'boolean') skills[id] = enabled;
34
+ const overleafSkills = {};
35
+ for (const [id, enabled] of Object.entries(value.codexOverleafSkillEnabled || {}).slice(0, MAX_SKILL_PREFERENCES)) {
36
+ if (validSkillId(id) && typeof enabled === 'boolean') overleafSkills[id] = enabled;
25
37
  }
26
38
  return {
27
39
  theme: ['dark', 'light', 'auto'].includes(value.theme) ? value.theme : 'dark',
@@ -29,7 +41,8 @@
29
41
  preloadProjectContext: value.preloadProjectContext !== false,
30
42
  loadCodexLocalSkills: value.loadCodexLocalSkills !== false,
31
43
  loadCodexOverleafSkills: value.loadCodexOverleafSkills !== false,
32
- codexOverleafSkillEnabled: skills
44
+ codexOverleafSkillEnabled: overleafSkills,
45
+ codexLocalSkillEnabled: normalizeSkillEnabledMap(value.codexLocalSkillEnabled)
33
46
  };
34
47
  }
35
48
 
@@ -43,8 +56,8 @@
43
56
  || typeof DEFAULTS[key] === 'boolean' && typeof item !== 'boolean') {
44
57
  throw new Error('Invalid global preference: ' + key);
45
58
  }
46
- if (key === 'codexOverleafSkillEnabled') {
47
- if (!item || typeof item !== 'object' || Array.isArray(item) || Object.keys(item).length > 200) {
59
+ if (SKILL_MAP_FIELDS.includes(key)) {
60
+ if (!item || typeof item !== 'object' || Array.isArray(item) || Object.keys(item).length > MAX_SKILL_PREFERENCES) {
48
61
  throw new Error('Invalid skill preference map.');
49
62
  }
50
63
  for (const [id, enabled] of Object.entries(item)) {
@@ -57,9 +70,12 @@
57
70
  }
58
71
 
59
72
  function applyPatch(values, patch) {
60
- return { ...pick(values), ...patch, codexOverleafSkillEnabled: {
61
- ...pick(values).codexOverleafSkillEnabled, ...(patch.codexOverleafSkillEnabled || {})
62
- } };
73
+ const previous = pick(values);
74
+ const result = { ...previous, ...patch };
75
+ for (const field of SKILL_MAP_FIELDS) {
76
+ result[field] = normalizeSkillEnabledMap({ ...previous[field], ...(patch[field] || {}) });
77
+ }
78
+ return result;
63
79
  }
64
80
 
65
81
  function changedKeys(left, right) {
@@ -71,7 +87,9 @@
71
87
  throw new Error('Invalid global preference revision.');
72
88
  }
73
89
  validatePatch(value.values);
74
- if (!FIELDS.every(key => Object.hasOwn(value.values, key))) throw new Error('Incomplete global preferences.');
90
+ // The local-skill map was added within v1; existing complete v1 snapshots
91
+ // inherit their source defaults until an explicit preference is saved.
92
+ if (!FIELDS.filter(key => key !== 'codexLocalSkillEnabled').every(key => Object.hasOwn(value.values, key))) throw new Error('Incomplete global preferences.');
75
93
  return { schemaVersion: 1, revision: value.revision, values: pick(value.values) };
76
94
  }
77
95
 
@@ -95,7 +113,6 @@
95
113
  const patch = validatePatch(input);
96
114
  const previous = await read();
97
115
  const values = applyPatch(previous.values, patch);
98
- if (Object.keys(values.codexOverleafSkillEnabled).length > 200) throw new Error('Too many skill preferences.');
99
116
  if (!changedKeys(previous.values, values).length) return previous;
100
117
  const snapshot = { schemaVersion: 1, revision: previous.revision + 1, values };
101
118
  await storage.set({ [STORAGE_KEY]: snapshot });
@@ -112,7 +129,7 @@
112
129
  try {
113
130
  const url = new URL(sender?.tab?.url || '');
114
131
  allowed = sender.id === chromeApi.runtime.id && url.protocol === 'https:'
115
- && ['overleaf.com', 'www.overleaf.com'].includes(url.hostname)
132
+ && ['overleaf.com', 'www.overleaf.com', 'cn.overleaf.com'].includes(url.hostname)
116
133
  && /^\/project(?:\/|$)/.test(url.pathname);
117
134
  } catch (_error) { /* reject unrelated contexts */ }
118
135
  if (!allowed) {
@@ -127,5 +144,5 @@
127
144
  }
128
145
 
129
146
  return Object.freeze({ STORAGE_KEY, LEGACY_KEY, READ_MESSAGE, PATCH_MESSAGE, FIELDS,
130
- pick, validatePatch, validateSnapshot, applyPatch, changedKeys, createStore, installBackground });
147
+ normalizeSkillEnabledMap, pick, validatePatch, validateSnapshot, applyPatch, changedKeys, createStore, installBackground });
131
148
  });
@@ -203,43 +203,10 @@
203
203
  }
204
204
 
205
205
  function normalizeSafeProjectPathFallback(value) {
206
- if (typeof value !== 'string' || /[\u0000-\u001f\u007f]/.test(value)) {
207
- return '';
208
- }
209
- const trimmed = value.trim();
210
- if (!trimmed || trimmed.startsWith('/') || trimmed.includes('\\') || /^[A-Za-z]:/.test(trimmed)) {
211
- return '';
212
- }
213
- let decoded = trimmed;
214
- for (let index = 0; index < 3; index += 1) {
215
- if (/%(?:2f|5c)/i.test(decoded)) {
216
- return '';
217
- }
218
- let next;
219
- try {
220
- next = decodeURIComponent(decoded);
221
- } catch (_error) {
222
- return '';
223
- }
224
- if (next === decoded) {
225
- break;
226
- }
227
- decoded = next;
228
- }
229
- if (/[\u0000-\u001f\u007f]/.test(decoded)
230
- || decoded.startsWith('/')
231
- || decoded.includes('\\')
232
- || /^[A-Za-z]:/.test(decoded)) {
233
- return '';
234
- }
235
- const normalized = decoded.replace(/\/+/g, '/').trim();
236
- if (!normalized) {
237
- return '';
238
- }
239
- const segments = normalized.split('/');
240
- return segments.some(segment => !segment || segment === '.' || segment === '..')
241
- ? ''
242
- : normalized;
206
+ if (typeof value !== 'string' || !value || value.length > 2048 || value.trim() !== value
207
+ || /[\u0000-\u001f\u007f]/.test(value) || value.startsWith('/')
208
+ || value.includes('\\') || /^[A-Za-z]:/.test(value)) return '';
209
+ return value.split('/').some(segment => !segment || segment === '.' || segment === '..') ? '' : value;
243
210
  }
244
211
 
245
212
  return {