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
@@ -63,6 +63,8 @@
63
63
  let writebackSettlement;
64
64
  let injectedWritebackSettlement;
65
65
  let assetTransferBroker;
66
+ let stageWritebackRecovery;
67
+ let settleWritebackRecovery;
66
68
 
67
69
  function buildSettlement(input = {}) {
68
70
  return writebackSettlement?.settle instanceof Function
@@ -98,7 +100,24 @@
98
100
  return pending;
99
101
  }
100
102
 
103
+ function selectionViolationNextStep() {
104
+ return tx('Select the intended region again and request only changes within it. Valid written parts can be undone.',
105
+ '请重新选择目标范围,仅请求修改该范围。已写入的合法部分可撤销。');
106
+ }
107
+
108
+ function buildWithheldEntry(change) {
109
+ const reason = writebackController.formatUnsupportedLocalChangeReason(change, getLocale());
110
+ const nextAction = change.reason === 'selection_scope_violation' ? selectionViolationNextStep()
111
+ : tx('The main agent must review the withheld file before syncing it.', '主代理需核对未同步文件后再写回。');
112
+ return { operation: { type: 'create', path: change.path }, result: { ok: false,
113
+ code: change.reason, reason, changedDocument: false, failure: { code: change.reason,
114
+ stage: 'preflight', severity: 'blocked', retryable: false, terminalState: 'blocked', changedDocument: false,
115
+ userMessage: reason, nextAction } } };
116
+ }
117
+
101
118
  async function applySyncChangesToOverleaf(syncChanges = [], project = {}, options = {}) {
119
+ const activeRun = getCurrentRunView?.();
120
+ const saveTarget = { runProjectId: activeRun?.runProjectId || '', recordId: activeRun?.recordId || '', sessionId: activeRun?.sessionId || '' };
102
121
  const runMode = options.mode || getState().mode;
103
122
  const runRequireReviewing = typeof options.requireReviewing === 'boolean'
104
123
  ? options.requireReviewing
@@ -106,6 +125,23 @@
106
125
  const assistantMessage = cleanFinalAnswer(options.assistantMessage || getAssistantAnswerForCurrentRun());
107
126
  const unsupportedChanges = Array.isArray(options.unsupportedChanges) ? options.unsupportedChanges : [];
108
127
  appendUnsupportedLocalChanges(unsupportedChanges);
128
+ const withheldOnly = unsupportedChanges.filter(change => ['subagent_unfinished_output', 'subagent_unauthorized_edit', 'selection_scope_violation'].includes(change.reason));
129
+ if (runMode !== 'ask' && !syncChanges.length && withheldOnly.length) {
130
+ const skipped = withheldOnly.map(buildWithheldEntry);
131
+ const hasSelectionViolation = withheldOnly.some(change => change.reason === 'selection_scope_violation');
132
+ const applied = { ok: false, applied: [], skipped };
133
+ appendCompletionReport({ conclusion: assistantMessage || tx('Some generated changes were blocked.', '部分生成的改动已被阻止。'),
134
+ status: 'failed', operations: [], applyResults: [applied], mode: runMode,
135
+ nextStep: hasSelectionViolation
136
+ ? selectionViolationNextStep()
137
+ : tx('The main agent must review and adopt the withheld files before syncing them.', '主代理需核对并接管未同步文件后再写回。') });
138
+ return { summaryLine: hasSelectionViolation
139
+ ? tx('Changes outside the selection were blocked.', '选区外改动已被阻止。')
140
+ : tx('Generated files are awaiting review.', '生成文件待核对。'), hasSkippedOperations: true,
141
+ applied, settlement: buildSettlement({ operations: [], applyResult: applied }),
142
+ audit: buildAuditSummaryFromApply({ operations: [], applyResults: [applied], resultStatus: 'completed_with_skips' }) };
143
+ }
144
+
109
145
  // Guard on the immutable submitted mode, not the mutable panel state.
110
146
  if (options.mode === 'ask' && ((syncChanges || []).length || unsupportedChanges.length)) {
111
147
  appendRunEvent({
@@ -148,7 +184,16 @@
148
184
  }
149
185
  let operations = buildSyncApplyOperations(syncChanges, project);
150
186
  let visibleSyncChanges = syncChanges || [];
151
- let additionalSkippedEntries = [];
187
+ // A previous Native build can still report inferred metadata moves.
188
+ // Forward sync never promotes them to a new file or a new capability.
189
+ let additionalSkippedEntries = operations.filter(operation => operation.type === 'move').map(operation => ({
190
+ operation,
191
+ result: { ok: false, code: 'file_tree_controls_unavailable', changedDocument: false,
192
+ reason: tx('Automatic file moves are unavailable. Handle the path change in Overleaf before retrying.',
193
+ '暂不支持自动移动文件,请先在 Overleaf 中处理路径变化后再重试。') }
194
+ }));
195
+ operations = operations.filter(operation => operation.type !== 'move');
196
+ if (additionalSkippedEntries.length) visibleSyncChanges = filterSyncChangesByOperations(syncChanges, operations);
152
197
  let skippedFilesForAudit = additionalSkippedEntries;
153
198
  let appliedFilesForAudit = [];
154
199
  const pathSafety = partitionUnsafeProjectPathOperations(operations);
@@ -173,13 +218,20 @@
173
218
  visibleSyncChanges = filterSyncChangesByOperations(syncChanges, operations);
174
219
  }
175
220
  if (!operations.length) {
221
+ const blockedSettlement = buildSettlement({
222
+ operations: buildSyncApplyOperations(syncChanges, project),
223
+ applyResult: { ok: additionalSkippedEntries.length === 0, applied: [], skipped: additionalSkippedEntries }
224
+ });
225
+ const blockedFailure = blockedSettlement
226
+ ? writebackSettlement.projectRunSettlement({ settlement: blockedSettlement.facts }).primaryFailure : undefined;
176
227
  appendRunEvent({
177
228
  title: tx('Codex did not produce file changes that need to sync back to Overleaf.', 'Codex 没有产生需要同步回 Overleaf 的文件改动。'),
178
229
  status: 'completed'
179
230
  });
180
231
  appendCompletionReport({
181
232
  conclusion: assistantMessage || tx('Codex finished locally. There are no changes to sync back to Overleaf.', 'Codex 已完成本地处理,没有需要同步回 Overleaf 的改动。'),
182
- status: runMode === 'ask' ? tr('modeAsk') : 'completed',
233
+ status: additionalSkippedEntries.length ? 'failed' : runMode === 'ask' ? tr('modeAsk') : 'completed',
234
+ failure: blockedFailure,
183
235
  operations: [],
184
236
  applyResults: additionalSkippedEntries.length ? [{ ok: false, applied: [], skipped: additionalSkippedEntries }] : [],
185
237
  unchangedReason: additionalSkippedEntries.find(item => item?.result?.reason)?.result.reason
@@ -190,14 +242,7 @@
190
242
  return {
191
243
  summaryLine: assistantMessage || tx('No changes to sync', '没有需要同步的改动'),
192
244
  hasSkippedOperations: additionalSkippedEntries.length > 0,
193
- settlement: buildSettlement({
194
- operations: buildSyncApplyOperations(syncChanges, project),
195
- applyResult: {
196
- ok: additionalSkippedEntries.length === 0,
197
- applied: [],
198
- skipped: additionalSkippedEntries
199
- }
200
- }),
245
+ settlement: blockedSettlement,
201
246
  audit: buildAuditSummaryFromApply({
202
247
  operations: buildSyncApplyOperations(syncChanges, project),
203
248
  applyResults: additionalSkippedEntries.length ? [{ ok: false, applied: [], skipped: additionalSkippedEntries }] : [],
@@ -240,13 +285,20 @@
240
285
  additionalSkippedEntries.push(...binaryDecision.skipped);
241
286
 
242
287
  if (!operations.length) {
288
+ const approvalSettlement = buildSettlement({
289
+ operations: buildSyncApplyOperations(syncChanges, project),
290
+ applyResult: { ok: additionalSkippedEntries.length === 0, applied: [], skipped: additionalSkippedEntries }
291
+ });
292
+ const approvalFailure = approvalSettlement
293
+ ? writebackSettlement.projectRunSettlement({ settlement: approvalSettlement.facts }).primaryFailure : undefined;
243
294
  appendRunEvent({
244
295
  title: tx('No approved file changes remain to sync back to Overleaf.', '没有剩余已确认的文件改动需要同步回 Overleaf。'),
245
296
  status: 'completed'
246
297
  });
247
298
  appendCompletionReport({
248
299
  conclusion: assistantMessage || tx('No approved changes were written back to Overleaf.', '没有已确认的改动写回 Overleaf。'),
249
- status: runMode === 'ask' ? tr('modeAsk') : 'completed',
300
+ status: additionalSkippedEntries.length ? 'failed' : runMode === 'ask' ? tr('modeAsk') : 'completed',
301
+ failure: approvalFailure,
250
302
  operations: [],
251
303
  applyResults: additionalSkippedEntries.length ? [{ ok: false, applied: [], skipped: additionalSkippedEntries }] : [],
252
304
  unchangedReason: additionalSkippedEntries.find(item => item?.result?.reason)?.result.reason
@@ -257,14 +309,7 @@
257
309
  return {
258
310
  summaryLine: tx('No changes applied', '没有应用改动'),
259
311
  hasSkippedOperations: additionalSkippedEntries.length > 0,
260
- settlement: buildSettlement({
261
- operations: buildSyncApplyOperations(syncChanges, project),
262
- applyResult: {
263
- ok: additionalSkippedEntries.length === 0,
264
- applied: [],
265
- skipped: additionalSkippedEntries
266
- }
267
- }),
312
+ settlement: approvalSettlement,
268
313
  audit: buildAuditSummaryFromApply({
269
314
  operations: buildSyncApplyOperations(syncChanges, project),
270
315
  applyResults: additionalSkippedEntries.length ? [{ ok: false, applied: [], skipped: additionalSkippedEntries }] : [],
@@ -312,6 +357,13 @@
312
357
  })
313
358
  };
314
359
  }
360
+ const writebackActivityId = 'overleaf-writeback:' + Date.now().toString(36);
361
+ appendRunEvent({
362
+ title: tx('Syncing approved changes to Overleaf.', '正在将已批准的改动同步到 Overleaf。'),
363
+ status: 'running',
364
+ activity: { v: 1, kind: 'sync', id: writebackActivityId, state: 'running', paths: operations.map(operation => operation.path).filter(Boolean) }
365
+ });
366
+ await stageWritebackRecovery?.(operations, saveTarget, runRequireReviewing, project);
315
367
  const applied = operations.length
316
368
  ? mergeApplyResultSkipped(await assetTransferBroker.applyOperations({
317
369
  operations,
@@ -321,10 +373,15 @@
321
373
  // Welcome-panel + write-guard:
322
374
  // immutable per-run project id, checked by the page-side guard
323
375
  // against `_ide.project._id` before any mutation.
324
- runProjectId: getCurrentRunView()?.runProjectId || ''
376
+ runProjectId: getCurrentRunView()?.runProjectId || '',
377
+ retryCreates: options.retryCreates === true
325
378
  }), additionalSkippedEntries)
326
379
  : mergeApplyResultSkipped({ ok: true, applied: [], skipped: [] }, additionalSkippedEntries);
327
380
  const hasConfirmedApplyResult = hasApplyResultEntries(applied);
381
+ for (const change of unsupportedChanges.filter(item => ['subagent_unfinished_output', 'subagent_unauthorized_edit', 'selection_scope_violation'].includes(item.reason))) {
382
+ applied.skipped.push(buildWithheldEntry(change));
383
+ applied.ok = false;
384
+ }
328
385
  // Record the apply result + undo checkpoint IMMEDIATELY, before any
329
386
  // cancellable verify/mirror awaits below. A user-cancel during the
330
387
  // post-write save-verify or mirror refresh throws codex_cancelled; if undo
@@ -333,7 +390,7 @@
333
390
  // landed in Overleaf. The manual-confirm path already records undo right
334
391
  // after its write — match that ordering here (v1.6.2).
335
392
  appendApplyResult(applied);
336
- recordUndoFromApply(project, applied);
393
+ await recordUndoFromApply(project, applied);
337
394
  const skippedEntries = getSkippedEntries(applied);
338
395
  if (skippedEntries.length) {
339
396
  appendPartialWritebackWarning(applied);
@@ -342,36 +399,37 @@
342
399
  renderReadOnlyDiffReview(getAppliedSyncChanges(syncChanges, applied));
343
400
  }
344
401
  const appliedPaths = getAppliedOperationPaths(applied);
402
+ appendRunEvent({
403
+ title: tx('Overleaf writeback returned its result.', 'Overleaf 写回已返回结果。'),
404
+ status: !hasConfirmedApplyResult || skippedEntries.length ? 'warning' : 'completed',
405
+ activity: { v: 1, kind: 'sync', id: writebackActivityId,
406
+ state: !hasConfirmedApplyResult || skippedEntries.length ? 'warning' : 'completed',
407
+ paths: operations.map(operation => operation.path).filter(Boolean),
408
+ written: appliedPaths.length, skipped: skippedEntries.length }
409
+ });
345
410
  // Only probe save-state + refresh the mirror when real writes landed. A
346
411
  // zero-write run (every operation skipped) has nothing to save-verify, so
347
412
  // skip the ~5s probe and its misleading "could not verify saved" warning
348
413
  // (v1.6.2).
349
- const saveVerification = appliedPaths.length
350
- ? await verifyPostWriteSaveState()
351
- : {
352
- ok: false,
353
- state: 'not_checked',
354
- reason: 'No applied writeback operations were returned.'
355
- };
414
+ const confirmation = appliedPaths.length
415
+ ? await verifyPostWriteSaveState(applied, project, saveTarget)
416
+ : { verification: { ok: false, state: 'not_checked', reason: 'No applied writeback operations were returned.' } };
417
+ const saveVerification = confirmation.verification;
418
+ await settleWritebackRecovery?.(applied, project, saveVerification, saveTarget);
356
419
  if (appliedPaths.length) {
357
- appendPostWriteSaveVerificationWarning(saveVerification);
420
+ appendPostWriteSaveVerificationWarning(saveVerification, saveTarget);
421
+ appendRunEvent({ kind: 'technical', title: 'Post-write save confirmation', status: 'info', detail: saveVerification });
358
422
  }
359
423
  // v1.7.5: the mirror refresh (zip snapshot + mirror.sync, often the
360
424
  // slowest post-write step) no longer blocks the completion report. The
361
425
  // pending promise is exposed so undoRun and the next runTask barrier on
362
426
  // it — a mirror.sync landing AFTER an undo would otherwise push the
363
427
  // pre-undo snapshot as the local baseline.
364
- const mirrorSettlementTarget = getCurrentRunView?.();
365
- pendingMirrorRefresh = refreshProjectMirrorAfterWriteback(project, applied, saveVerification)
366
- .catch(error => {
367
- appendRunEvent({
368
- title: tx(
369
- `Overleaf was written, but the background workspace refresh failed: ${error.message}. The next run will reread the project.`,
370
- `Overleaf 已写入,但后台刷新本地 workspace 失败:${error.message}。下一轮会重新读取项目。`
371
- ),
372
- status: 'failed'
373
- });
374
- return 'failed';
428
+ const mirrorSettlementTarget = saveTarget;
429
+ pendingMirrorRefresh = refreshProjectMirrorAfterWriteback(project, applied, saveVerification, { target: saveTarget, snapshot: confirmation.snapshot })
430
+ .catch(async error => {
431
+ appendRunRecordEvent(saveTarget.recordId, { kind: 'technical', title: 'Mirror refresh requires a fresh read', status: 'info', detail: { reason: error.message } });
432
+ return invalidateWritebackMirror(saveTarget);
375
433
  })
376
434
  .then(state => {
377
435
  if (typeof onMirrorRefreshSettled !== 'function') return;
@@ -388,7 +446,8 @@
388
446
  const compileSummary = appliedPaths.length
389
447
  ? await autoRecompileAfterWriteback(appliedPaths, saveVerification, {
390
448
  autoRecompile: options.autoRecompile,
391
- mode: runMode
449
+ mode: runMode,
450
+ runProjectId: saveTarget.runProjectId
392
451
  }).catch(error => {
393
452
  appendRunEvent({
394
453
  title: tx(`Post-write compile failed: ${error.message}`, `写后编译出错:${error.message}`),
@@ -435,6 +494,7 @@
435
494
  compileErrors: compileSummary?.status === 'failed' && Array.isArray(compileSummary.errors)
436
495
  ? compileSummary.errors
437
496
  : undefined,
497
+ saveVerification,
438
498
  // Promote the primary per-operation skip failure to the run level when
439
499
  // the writeback failed outright: target-file and write-stage codes only
440
500
  // ever exist inside applied.skipped[], and without this promotion the
@@ -475,104 +535,100 @@
475
535
  };
476
536
  }
477
537
 
478
- async function verifyPostWriteSaveState() {
479
- try {
480
- const result = await callPageBridge('waitForSaveState', {
481
- deadlineMs: 5000,
482
- requirePositiveSignal: true
483
- });
484
- if (result?.state === 'verified_saved') {
485
- return {
486
- ...result,
487
- ok: true,
488
- state: 'verified_saved'
489
- };
490
- }
491
- if (result?.ok === true && !result?.state) {
492
- return {
493
- ...result,
494
- ok: false,
495
- state: 'verified_quiet'
496
- };
497
- }
498
- if (result?.state === 'unknown_timeout' || result?.state === 'unavailable') {
499
- return {
500
- ...result,
501
- ok: false
502
- };
503
- }
504
- return {
505
- ...result,
506
- ok: false,
507
- state: 'unknown_timeout'
508
- };
509
- } catch (error) {
510
- return {
511
- ok: false,
512
- state: 'unavailable',
513
- reason: error.message
514
- };
515
- }
538
+ async function verifyPostWriteSaveState(applied, project, target = {}) {
539
+ return writebackController.confirmPostWriteSave({
540
+ applied, project, runProjectId: target.runProjectId,
541
+ assertCurrent() {
542
+ if (!target.runProjectId || getCurrentProjectId() !== target.runProjectId) {
543
+ throw Object.assign(new Error('The Overleaf project changed during save confirmation.'), { code: 'aborted_project_changed', changedDocument: true });
544
+ }
545
+ if (target.recordId && getCurrentRunView()?.recordId !== target.recordId) {
546
+ throw Object.assign(new Error('The run stopped during save confirmation.'), { code: 'codex_cancelled', changedDocument: true });
547
+ }
548
+ },
549
+ readSaveState: params => callPageBridge('waitForSaveState', { ...params, runProjectId: target.runProjectId }),
550
+ readSnapshot: params => callPageBridge('getProjectSnapshot', { ...params, runProjectId: target.runProjectId })
551
+ });
516
552
  }
517
553
 
518
- function appendPostWriteSaveVerificationWarning(saveVerification = {}) {
519
- if (saveVerification?.state === 'verified_saved') {
520
- return;
521
- }
522
- appendRunEvent({
523
- title: tx(
524
- 'Files were written or attempted in Overleaf, but Codex could not verify that Overleaf saved them. Local mirror refresh was skipped.',
525
- '文件已写入或尝试写入 Overleaf,但 Codex 未能确认 Overleaf 已保存;已跳过本地 mirror 刷新。'
526
- ),
527
- status: 'warning'
528
- });
554
+ function appendPostWriteSaveVerificationWarning(saveVerification = {}, target = {}) {
555
+ if (saveVerification.state === 'verified_saved') return;
556
+ // Missing confirmation is represented once in the report, with a check action.
557
+ if (saveVerification.signal !== 'offline') return;
558
+ const title = saveVerification.signal === 'offline'
559
+ ? tx('Overleaf is offline. Keep this page open and reconnect so the changes can be saved.',
560
+ 'Overleaf 当前离线。请保持页面开启,恢复连接后等待改动保存。')
561
+ : tx('Saving these changes is not yet confirmed. Keep this page open and check Overleaf’s save and connection status.',
562
+ '尚未确认本次改动已保存。请保持页面开启,检查 Overleaf 的保存和连接状态。');
563
+ if (target.recordId) appendRunRecordEvent(target.recordId, { title, status: 'warning' });
564
+ else appendRunEvent({ title, status: 'warning' });
529
565
  }
530
566
 
531
- // v1.8.0: text-only writebacks confirm the mirror in place. The written
532
- // content ORIGINATED in the local workspace, so after a verified writeback
533
- // the workspace already equals Overleaf; only the baseline hashes and
534
- // freshness metadata are stale. mirror.confirmWriteback re-hashes the
535
- // written files without re-downloading the project. Anything unusual —
536
- // tree ops, binary writes, dirty mirror, an older native host without the
537
- // method — falls back to the full zip resync below.
538
- const MIRROR_CONFIRMABLE_OPERATION_TYPES = new Set(['edit']);
539
-
540
- async function tryConfirmMirrorWriteback(applied) {
541
- const entries = Array.isArray(applied?.applied) ? applied.applied : [];
542
- if (!entries.length) {
543
- return false;
544
- }
545
- const paths = [];
546
- for (const entry of entries) {
547
- const operation = entry?.operation || {};
548
- if (!MIRROR_CONFIRMABLE_OPERATION_TYPES.has(operation.type) || !operation.path) {
549
- return false;
567
+ async function invalidateWritebackMirror(target = {}) {
568
+ let invalidated = false;
569
+ try {
570
+ if (target.runProjectId) {
571
+ const response = await sendBackgroundNative({ method: 'mirror.invalidate', params: { projectId: target.runProjectId } });
572
+ invalidated = response?.ok === true && response.result?.invalidated === true;
550
573
  }
551
- paths.push(operation.path);
574
+ } catch (_error) { /* An unavailable host cannot acknowledge invalidation. */ }
575
+ let pageInvalidated = getCurrentProjectId() !== target.runProjectId;
576
+ if (!pageInvalidated) {
577
+ resetContextProject();
578
+ try {
579
+ const response = await callPageBridge('invalidateProjectSnapshot', { invalidateFileList: true, runProjectId: target.runProjectId });
580
+ pageInvalidated = response?.ok === true;
581
+ } catch (_error) { /* Leave the failure visible if both caches cannot be fenced. */ }
552
582
  }
583
+ if (invalidated && pageInvalidated) return 'not-attempted';
584
+ const event = {
585
+ title: tx('The local project cache could not be reset. Check the local connection before starting another task.',
586
+ '本地项目缓存未能重置。请检查本地连接后再开始下一轮任务。'),
587
+ status: 'warning'
588
+ };
589
+ if (target.recordId) appendRunRecordEvent(target.recordId, event);
590
+ else appendRunEvent(event);
591
+ return 'failed';
592
+ }
593
+
594
+ // Text-only confirmation requires the page's verified post-image digest.
595
+ // Local files can change after writeback; Native must match those digests
596
+ // before advancing its baseline. Missing evidence and non-text/tree writes
597
+ // retain the authoritative ZIP fallback below.
598
+
599
+ async function tryConfirmMirrorWriteback(applied, runProjectId) {
553
600
  try {
601
+ if (!runProjectId || getCurrentProjectId() !== runProjectId) return false;
602
+ const proof = await writebackController.buildMirrorWritebackConfirmation?.(applied);
603
+ if (!proof || getCurrentProjectId() !== runProjectId) return false;
554
604
  const response = await sendBackgroundNative({
555
605
  method: 'mirror.confirmWriteback',
556
606
  params: {
557
- projectId: getCurrentProjectId(),
558
- paths: Array.from(new Set(paths))
607
+ projectId: runProjectId,
608
+ ...proof
559
609
  }
560
610
  });
561
- return response?.ok === true && response?.result?.ok === true;
611
+ const confirmations = Array.isArray(response?.result?.confirmed) ? response.result.confirmed : [];
612
+ const confirmed = new Map(confirmations.map(file => [file?.path, file?.hash]));
613
+ return getCurrentProjectId() === runProjectId && response?.ok === true && response?.result?.ok === true
614
+ && confirmations.length === proof.expectedFiles.length
615
+ && confirmed.size === proof.expectedFiles.length
616
+ && proof.expectedFiles.every(file => confirmed.get(file.path) === file.sha256);
562
617
  } catch (error) {
563
618
  return false;
564
619
  }
565
620
  }
566
621
 
567
- async function refreshProjectMirrorAfterWriteback(project = {}, applied = {}, saveVerification = {}) {
622
+ async function refreshProjectMirrorAfterWriteback(project = {}, applied = {}, saveVerification = {}, confirmation = {}) {
623
+ const target = confirmation.target || {};
568
624
  if (saveVerification?.state !== 'verified_saved') {
569
- return 'not-attempted';
625
+ return invalidateWritebackMirror(target);
570
626
  }
571
627
  if (!Array.isArray(applied?.applied) || !applied.applied.length) {
572
628
  return 'not-attempted';
573
629
  }
574
630
 
575
- if (await tryConfirmMirrorWriteback(applied)) {
631
+ if (!confirmation.snapshot && await tryConfirmMirrorWriteback(applied, target.runProjectId)) {
576
632
  appendRunEvent({
577
633
  title: tx(
578
634
  'Local Codex workspace confirmed in place (no project re-download needed). The next run starts from the latest content.',
@@ -588,10 +644,13 @@
588
644
  status: 'running'
589
645
  });
590
646
 
591
- await callPageBridge('invalidateProjectSnapshot', {
647
+ if (!target.runProjectId || getCurrentProjectId() !== target.runProjectId) return invalidateWritebackMirror(target);
648
+ if (!confirmation.snapshot) await callPageBridge('invalidateProjectSnapshot', {
649
+ runProjectId: target.runProjectId,
592
650
  invalidateFileList: true
593
651
  });
594
- const freshProject = sanitizeRunProjectSnapshot(await callPageBridge('getProjectSnapshot', {
652
+ const freshProject = confirmation.snapshot || sanitizeRunProjectSnapshot(await callPageBridge('getProjectSnapshot', {
653
+ runProjectId: target.runProjectId,
595
654
  force: true,
596
655
  maxAgeMs: 0,
597
656
  preferLightweight: true,
@@ -603,23 +662,18 @@
603
662
  zipTimeoutMs: RUN_SNAPSHOT_ZIP_TIMEOUT_MS,
604
663
  focusFiles: getAppliedOperationPaths(applied)
605
664
  }));
606
- if (!freshProject?.files?.length || freshProject?.capabilities?.fullProjectSnapshot === false) {
607
- appendRunEvent({
608
- title: tx(
609
- 'Overleaf was written, but the full project was not read. The local Codex workspace baseline was not refreshed; the next run will reread it.',
610
- 'Overleaf 已写入,但没有读到完整项目;暂不刷新本地 Codex workspace baseline,下一轮会重新读取。'
611
- ),
612
- status: 'failed'
613
- });
614
- return 'failed';
665
+ if (getCurrentProjectId() !== target.runProjectId || freshProject?.id !== target.runProjectId
666
+ || !freshProject?.files?.length || freshProject?.capabilities?.fullProjectSnapshot === false
667
+ || freshProject?.capabilities?.skipped?.length) {
668
+ return invalidateWritebackMirror(target);
615
669
  }
616
670
 
617
- const syncedProject = mergeVerifiedAppliedFiles(freshProject, project, applied);
671
+ const syncedProject = confirmation.snapshot || mergeVerifiedAppliedFiles(freshProject, project, applied);
618
672
  resetContextProject();
619
673
  const response = await sendBackgroundNative({
620
674
  method: 'mirror.sync',
621
675
  params: {
622
- projectId: getCurrentProjectId(),
676
+ projectId: target.runProjectId,
623
677
  project: syncedProject
624
678
  }
625
679
  });
@@ -631,15 +685,7 @@
631
685
  return 'complete';
632
686
  }
633
687
 
634
- const message = response?.error?.message || tx('native host did not respond', 'native host 没有响应');
635
- appendRunEvent({
636
- title: tx(
637
- `Overleaf was written, but refreshing the local workspace failed: ${message}`,
638
- `Overleaf 已写入,但刷新本地 workspace 失败:${message}`
639
- ),
640
- status: 'failed'
641
- });
642
- return 'failed';
688
+ return invalidateWritebackMirror(target);
643
689
  }
644
690
 
645
691
  function mergeVerifiedAppliedFiles(freshProject = {}, originalProject = {}, applied = {}) {
@@ -660,6 +706,8 @@
660
706
  return writebackController.formatUnsupportedLocalChangeSummary(changes, getLocale());
661
707
  }
662
708
 
709
+ const serverProvenSave = verification => ['overleaf-zip', 'server-receipts'].includes(verification?.source);
710
+
663
711
  async function autoRecompileAfterWriteback(writtenPaths = [], saveVerification = {}, options = {}) {
664
712
  if (options.autoRecompile === false
665
713
  || (options.autoRecompile === undefined && getState().autoRecompile === false)) return null;
@@ -671,7 +719,10 @@
671
719
  const hasCompilableFile = writtenPaths.some(filePath => CompileAdapter.isCompilableFile(filePath));
672
720
  if (!hasCompilableFile) return null;
673
721
 
722
+ const compileActivityId = 'overleaf-compile:' + Date.now().toString(36);
723
+ const activity = (state, output = '') => ({ v: 1, kind: 'compile', id: compileActivityId, state, target: 'Overleaf', output });
674
724
  appendRunEvent({
725
+ activity: activity('running'),
675
726
  title: saveVerification?.state !== 'verified_saved'
676
727
  ? tx(
677
728
  'Post-write compile: Overleaf save was not verified, but Auto Compile is on. Triggering Overleaf Recompile and letting Overleaf wait for the latest save.',
@@ -687,9 +738,10 @@
687
738
  try {
688
739
  const result = await callPageBridge('triggerCompile', {
689
740
  preferUiClick: true,
690
- waitForSaveMs: 5000,
691
- requireVerifiedSave: saveVerification?.state === 'verified_saved',
692
- runProjectId: getCurrentRunView()?.runProjectId || getCurrentProjectId()
741
+ // Server-side proof (ZIP or save receipts) already settles the save; don't also demand the UI indicator.
742
+ waitForSaveMs: serverProvenSave(saveVerification) ? 0 : 5000,
743
+ requireVerifiedSave: saveVerification?.state === 'verified_saved' && !serverProvenSave(saveVerification),
744
+ runProjectId: options.runProjectId || getCurrentRunView()?.runProjectId || getCurrentProjectId()
693
745
  });
694
746
  if (result?.ok) {
695
747
  let logResult = null;
@@ -698,79 +750,42 @@
698
750
  triggerIfStale: false,
699
751
  maxAgeMs: 30000,
700
752
  waitForSaveMs: 0,
701
- runProjectId: getCurrentRunView()?.runProjectId || getCurrentProjectId()
753
+ runProjectId: options.runProjectId || getCurrentRunView()?.runProjectId || getCurrentProjectId()
702
754
  });
703
755
  } catch (_error) {
704
756
  logResult = null;
705
757
  }
706
758
  const compile = result.compile;
707
759
  if (compile?.status === 'success') {
708
- appendRunEvent({ title: tx('Compile succeeded.', '编译成功。'), status: 'completed' });
760
+ appendRunEvent({ title: tx('Compile succeeded.', '编译成功。'), status: 'completed',
761
+ activity: activity('completed', [...(logResult?.errors || []), ...(logResult?.warnings || [])].slice(0, 5).map(CompileAdapter.formatCompileDiagnosticForSummary).join('\n')) });
709
762
  } else if (compile?.status === 'triggered') {
710
- appendRunEvent({ title: tx('Overleaf compile was triggered. The page will continue showing progress.', '已触发 Overleaf 编译;页面会继续显示编译进度。'), status: 'completed' });
763
+ appendRunEvent({ title: tx('Overleaf compile was triggered. The page will continue showing progress.', '已触发 Overleaf 编译;页面会继续显示编译进度。'), status: 'completed', activity: activity('triggered') });
711
764
  } else {
712
- appendRunEvent({ title: tx(`Compile finished with status: ${compile?.status || 'unknown'}`, `编译完成,状态:${compile?.status || '未知'}`), status: 'completed' });
765
+ appendRunEvent({ title: tx(`Compile finished with status: ${compile?.status || 'unknown'}`, `编译完成,状态:${compile?.status || '未知'}`), status: 'completed', activity: activity(compile?.status === 'failed' ? 'failed' : 'unknown') });
713
766
  }
714
767
  return buildPostWriteCompileSummary({ result, logResult });
715
768
  } else {
716
- const reason = result?.reason || tx('unknown reason', '未知原因');
717
- appendRunEvent({ title: tx(`Post-write compile did not succeed: ${reason}`, `写后编译未成功:${reason}`), status: 'failed' });
769
+ const reason = CompileAdapter.localizeCompileReason(result?.reason, getLocale()) || tx('unknown reason', '未知原因');
770
+ appendRunEvent({ title: tx(`Post-write compile did not succeed: ${reason}`, `写后编译未成功:${reason}`), status: 'failed', activity: activity('failed', reason) });
718
771
  return buildPostWriteCompileSummary({ result });
719
772
  }
720
773
  } catch (error) {
721
- appendRunEvent({ title: tx(`Post-write compile failed: ${error.message}`, `写后编译出错:${error.message}`), status: 'failed' });
774
+ const reason = CompileAdapter.localizeCompileReason(error.message, getLocale());
775
+ appendRunEvent({ title: tx(`Post-write compile failed: ${reason}`, `写后编译出错:${reason}`), status: 'failed', activity: activity('failed', reason) });
722
776
  return buildPostWriteCompileSummary({ error });
723
777
  }
724
778
  }
725
779
 
726
- function buildPostWriteCompileSummary({ result = null, logResult = null, error = null } = {}) {
727
- const logAvailable = logResult?.ok === true;
728
- const errors = logAvailable && Array.isArray(logResult.errors)
729
- ? logResult.errors.slice(0, 5).map(formatCompileDiagnosticForSummary)
730
- : [];
731
- const warnings = logAvailable && Array.isArray(logResult.warnings)
732
- ? logResult.warnings.slice(0, 5).map(formatCompileDiagnosticForSummary)
733
- : [];
734
- if (error) {
735
- return {
736
- status: 'failed',
737
- reason: error?.message || 'Post-write compile failed.',
738
- errors,
739
- warnings,
740
- logAvailable
741
- };
742
- }
743
- if (!result?.ok) {
744
- return {
745
- status: 'failed',
746
- reason: result?.reason || 'Post-write compile did not succeed.',
747
- errors,
748
- warnings,
749
- logAvailable
750
- };
751
- }
752
- return {
753
- status: result.compile?.status || 'triggered',
754
- reason: result.reason || '',
755
- errors,
756
- warnings,
757
- logAvailable
758
- };
780
+ function buildPostWriteCompileSummary(input = {}) {
781
+ return compileAdapter.buildPostWriteCompileSummary(input);
759
782
  }
760
783
 
761
- // First structured per-operation failure among the skipped writeback
762
- // entries — the run-level failure the completion report promotes.
784
+ // Use the same normalized failure selection as settlement and its UI, while
785
+ // preserving the selected producer's full evidence on the historical report.
763
786
  function promoteWritebackSkippedFailure(applied) {
764
- for (const entry of getSkippedEntries(applied)) {
765
- const failure = entry?.result?.failure || entry?.failure;
766
- if (failure?.code) {
767
- if (!failure.file && entry?.path) {
768
- return { ...failure, file: entry.path };
769
- }
770
- return failure;
771
- }
772
- }
773
- return null;
787
+ const failures = writebackSettlement.collectFailuresFromResult(applied);
788
+ return writebackSettlement.selectPrimaryFailure(failures);
774
789
  }
775
790
 
776
791
  function appendCompileSummaryToConclusion(conclusion, compileSummary) {
@@ -800,9 +815,10 @@
800
815
  )
801
816
  : tx('Post-write compile was triggered; Overleaf may still be updating the result.', '已触发写后编译;Overleaf 可能仍在更新结果。');
802
817
  } else if (compileSummary.status === 'failed') {
818
+ const reason = compileAdapter.localizeCompileReason(compileSummary.reason, getLocale());
803
819
  summary = tx(
804
- `Post-write compile check failed: ${compileSummary.reason || 'unknown reason'}`,
805
- `写后编译检查失败:${compileSummary.reason || '未知原因'}`
820
+ `Post-write compile check failed: ${reason || 'unknown reason'}`,
821
+ `写后编译检查失败:${reason || '未知原因'}`
806
822
  );
807
823
  } else {
808
824
  summary = tx(
@@ -813,10 +829,6 @@
813
829
  return [conclusion, '', summary].filter(Boolean).join('\n');
814
830
  }
815
831
 
816
- function formatCompileDiagnosticForSummary(value) {
817
- const text = String(value || '').replace(/\s+/g, ' ').trim();
818
- return text.length > 180 ? `${text.slice(0, 179)}...` : text;
819
- }
820
832
 
821
833
  async function resolveCompileLogContext() {
822
834
  try {
@@ -891,6 +903,8 @@
891
903
  getCurrentRunView,
892
904
  } = deps);
893
905
  assetTransferBroker = deps.assetTransferBroker;
906
+ stageWritebackRecovery = deps.stageWritebackRecovery;
907
+ settleWritebackRecovery = deps.settleWritebackRecovery;
894
908
  onMirrorRefreshSettled = deps.onMirrorRefreshSettled;
895
909
  writebackSettlement = deps.writebackSettlement;
896
910
  compileAdapter = deps.compileAdapter;