codex-overleaf-link 2.4.1 → 2.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (397) hide show
  1. package/README.md +275 -305
  2. package/README.zh-CN.md +290 -320
  3. package/extension/bootstrap/background.js +99 -19
  4. package/extension/bootstrap/manifest.template.json +9 -4
  5. package/extension/bootstrap/popup.html +11 -16
  6. package/extension/bootstrap/popupFallback.js +55 -0
  7. package/extension/bootstrap/update.js +25 -2
  8. package/extension/bootstrap/updateStatus.js +1 -0
  9. package/extension/runtime-manifest.json +3 -1
  10. package/extension/src/background.js +234 -56
  11. package/extension/src/backgroundBootstrapMigration.js +181 -0
  12. package/extension/src/backgroundSharedSessions.js +440 -0
  13. package/extension/src/backgroundUpdateCoordinator.js +541 -381
  14. package/extension/src/backgroundUpdateSafety.js +173 -0
  15. package/extension/src/content/activeTurnControl.js +16 -2
  16. package/extension/src/content/applyResultFormatters.js +46 -73
  17. package/extension/src/content/assetTransferBroker.js +244 -12
  18. package/extension/src/content/changeHistoryView.js +175 -0
  19. package/extension/src/content/composerAttachments.js +117 -67
  20. package/extension/src/content/composerPanel.js +41 -8
  21. package/extension/src/content/contentRuntime.js +1084 -1099
  22. package/extension/src/content/diagnosticsController.js +122 -97
  23. package/extension/src/content/diagnosticsExport.js +236 -0
  24. package/extension/src/content/diagnosticsPanel.js +78 -19
  25. package/extension/src/content/diffReviewPanel.js +8 -5
  26. package/extension/src/content/directoryCleanupRecovery.js +54 -0
  27. package/extension/src/content/generated/content.bundle.js +14680 -3606
  28. package/extension/src/content/generated/content.bundle.meta.json +30 -3
  29. package/extension/src/content/globalPreferencesController.js +1 -1
  30. package/extension/src/content/legacyGlobalRegistry.js +25 -1
  31. package/extension/src/content/localSkillsPanel.js +141 -16
  32. package/extension/src/content/markdownDomRenderer.js +9 -4
  33. package/extension/src/content/markdownText.js +5 -6
  34. package/extension/src/content/modelPicker.js +8 -5
  35. package/extension/src/content/nativeCompatibilityController.js +45 -20
  36. package/extension/src/content/otWarmMirror.js +4 -5
  37. package/extension/src/content/otWarmMirrorController.js +17 -20
  38. package/extension/src/content/pageBridgeClient.js +33 -5
  39. package/extension/src/content/panelMaintenance.js +87 -132
  40. package/extension/src/content/panelRenderer.js +10 -0
  41. package/extension/src/content/pendingInputView.js +109 -76
  42. package/extension/src/content/projectProviderSelection.js +13 -4
  43. package/extension/src/content/projectSessionCleanup.js +109 -62
  44. package/extension/src/content/projectSettingsCoordinator.js +39 -2
  45. package/extension/src/content/providerSettingsCoordinator.js +63 -14
  46. package/extension/src/content/providerSettingsDialog.js +724 -113
  47. package/extension/src/content/recentProjects.js +21 -6
  48. package/extension/src/content/runActivitySummary.js +665 -0
  49. package/extension/src/content/runCompletionMeta.js +344 -0
  50. package/extension/src/content/runController.js +40 -15
  51. package/extension/src/content/runFailureNotice.js +34 -12
  52. package/extension/src/content/runGuidanceController.js +76 -30
  53. package/extension/src/content/runGuidanceView.js +59 -10
  54. package/extension/src/content/runPresence.js +306 -0
  55. package/extension/src/content/runQueueScheduler.js +150 -43
  56. package/extension/src/content/runRecoveryActions.js +146 -0
  57. package/extension/src/content/runResultActions.js +11 -8
  58. package/extension/src/content/runReviewController.js +574 -0
  59. package/extension/src/content/runScrollLayout.js +21 -2
  60. package/extension/src/content/runTimelineView.js +315 -290
  61. package/extension/src/content/scopedPersistencePanelState.js +51 -6
  62. package/extension/src/content/selectionContextView.js +300 -0
  63. package/extension/src/content/sensitivePreflight.js +140 -0
  64. package/extension/src/content/sessionForkController.js +80 -17
  65. package/extension/src/content/sessionManager.js +1 -1
  66. package/extension/src/content/sessionPersistence.js +6 -1
  67. package/extension/src/content/settingsPanel.js +84 -55
  68. package/extension/src/content/settingsWorkbench.js +379 -0
  69. package/extension/src/content/sharedSessionViewSync.js +109 -0
  70. package/extension/src/content/subagentActivityView.js +195 -0
  71. package/extension/src/content/trackedChangeCaptureController.js +7 -3
  72. package/extension/src/content/updateIdle.js +4 -1
  73. package/extension/src/content/updateNotice.js +179 -56
  74. package/extension/src/content/updateSafetyReceiver.js +58 -0
  75. package/extension/src/content/writebackController.js +308 -2
  76. package/extension/src/content/writebackOrchestrator.js +213 -199
  77. package/extension/src/content/writebackPlan.js +231 -0
  78. package/extension/src/content/writebackRecovery.js +122 -0
  79. package/extension/src/content/writingStyleSettings.js +600 -0
  80. package/extension/src/content/writtenChangesView.js +152 -0
  81. package/extension/src/page/binaryAssetUploader.js +223 -23
  82. package/extension/src/page/fileMover.js +256 -0
  83. package/extension/src/page/overleafProjectSnapshot.js +1 -0
  84. package/extension/src/page/ownedDirectoryCleanup.js +94 -0
  85. package/extension/src/page/referenceProjects.js +149 -0
  86. package/extension/src/page/reviewContext.js +113 -0
  87. package/extension/src/page/saveState.js +20 -6
  88. package/extension/src/page/snapshotRouter.js +124 -48
  89. package/extension/src/page/textCoordinates.js +102 -0
  90. package/extension/src/page/textFileCreator.js +442 -71
  91. package/extension/src/page/trackedChangeCapture.js +53 -57
  92. package/extension/src/page/trackedChangeOwnership.js +216 -0
  93. package/extension/src/page/trackedChangeReplay.js +184 -0
  94. package/extension/src/page/trackedChangesLifecycle.js +343 -339
  95. package/extension/src/page/treeOperations.js +33 -12
  96. package/extension/src/page/updateSafetyProbe.js +41 -0
  97. package/extension/src/page/writebackReceiptJournal.js +114 -0
  98. package/extension/src/page/writebackRouter.js +242 -201
  99. package/extension/src/pageBridge.js +73 -102
  100. package/extension/src/popup.js +261 -65
  101. package/extension/src/shared/agentTranscript.js +41 -4
  102. package/extension/src/shared/auditRecords.js +73 -0
  103. package/extension/src/shared/changeHistoryModel.js +94 -0
  104. package/extension/src/shared/compatibility.js +22 -6
  105. package/extension/src/shared/compileAdapter.js +101 -37
  106. package/extension/src/shared/composerAttachmentDraft.js +151 -0
  107. package/extension/src/shared/directoryCleanupProof.js +43 -0
  108. package/extension/src/shared/failureReasons.js +329 -3
  109. package/extension/src/shared/globalPreferences.js +31 -14
  110. package/extension/src/shared/governanceRules.js +4 -37
  111. package/extension/src/shared/i18n.js +389 -25
  112. package/extension/src/shared/managedUpdateProjection.js +8 -5
  113. package/extension/src/shared/nativeRequestIdentity.js +1 -0
  114. package/extension/src/shared/pageRpcContract.js +9 -2
  115. package/extension/src/shared/projectFiles.js +21 -44
  116. package/extension/src/shared/providerProfiles.js +114 -3
  117. package/extension/src/shared/runActivityModel.js +361 -0
  118. package/extension/src/shared/runExecutionSnapshot.js +8 -2
  119. package/extension/src/shared/runExecutionSnapshotCodec.js +16 -4
  120. package/extension/src/shared/runInputQueue.js +48 -5
  121. package/extension/src/shared/scopedPersistenceBrowserAdapter.js +6 -3
  122. package/extension/src/shared/selectionContext.js +37 -0
  123. package/extension/src/shared/sessionState.js +166 -30
  124. package/extension/src/shared/settlementFacts.js +10 -2
  125. package/extension/src/shared/sharedSessionBridge.js +311 -0
  126. package/extension/src/shared/sharedSessionTransfer.js +140 -0
  127. package/extension/src/shared/staleGuard.js +118 -13
  128. package/extension/src/shared/storageDb.js +77 -78
  129. package/extension/src/shared/storageMigration.js +74 -111
  130. package/extension/src/shared/storageRunActions.js +211 -22
  131. package/extension/src/shared/storageValuePruning.js +40 -0
  132. package/extension/src/shared/subagentActivityModel.js +174 -0
  133. package/extension/src/shared/undoOperations.js +216 -6
  134. package/extension/src/shared/updateConsent.js +42 -11
  135. package/extension/src/shared/updateRuntimeIdentity.js +1 -1
  136. package/extension/src/shared/writebackIntent.js +78 -0
  137. package/extension/src/shared/writebackOperationEvidence.js +4 -15
  138. package/extension/src/shared/writebackSettlement.js +67 -48
  139. package/extension/src/shared/writingStyle.js +33 -0
  140. package/extension/styles/panel.css +1987 -385
  141. package/extension/styles/popup.css +110 -0
  142. package/native-host/src/anthropicBridgeRequest.js +6 -3
  143. package/native-host/src/anthropicBridgeResponse.js +6 -2
  144. package/native-host/src/anthropicMessagesBridge.js +24 -16
  145. package/native-host/src/bootstrapMigration.js +296 -0
  146. package/native-host/src/bootstrapMigrationContract.js +101 -0
  147. package/native-host/src/bootstrapUpdate.js +233 -0
  148. package/native-host/src/bootstrapUpdateWatchdog.js +44 -0
  149. package/native-host/src/chatBridgeResponse.js +10 -0
  150. package/native-host/src/chatCompletionsBridge.js +21 -15
  151. package/native-host/src/codexConfigPaths.js +106 -0
  152. package/native-host/src/codexHome.js +66 -73
  153. package/native-host/src/codexHomeScope.js +124 -0
  154. package/native-host/src/codexInheritedAuth.js +90 -0
  155. package/native-host/src/codexLocalSkills.js +301 -0
  156. package/native-host/src/codexModelRecovery.js +107 -0
  157. package/native-host/src/codexPromptAssembly.js +33 -12
  158. package/native-host/src/codexProviderLaunch.js +3 -3
  159. package/native-host/src/codexProviderTest.js +24 -26
  160. package/native-host/src/codexRuntimeIdentity.js +1 -0
  161. package/native-host/src/codexSessionRunner.js +211 -318
  162. package/native-host/src/codexSessionTiming.js +21 -8
  163. package/native-host/src/codexSkillIsolation.js +170 -0
  164. package/native-host/src/codexThreadFork.js +19 -3
  165. package/native-host/src/index.js +19 -7
  166. package/native-host/src/managedInstall.js +115 -39
  167. package/native-host/src/managedInstallRecovery.js +140 -0
  168. package/native-host/src/managedRuntimeEvidence.js +57 -0
  169. package/native-host/src/mirrorWorkspace.js +92 -22
  170. package/native-host/src/nativeDoctor.js +15 -0
  171. package/native-host/src/nativeEnvironment.js +70 -0
  172. package/native-host/src/nativeHelperLifecycle.js +21 -0
  173. package/native-host/src/nativeHostRegistration.js +33 -0
  174. package/native-host/src/nativeQuotas.js +15 -8
  175. package/native-host/src/nativeRunLifecycle.js +71 -0
  176. package/native-host/src/overleafWorkspaceRules.js +16 -0
  177. package/native-host/src/processStopBarrier.js +115 -0
  178. package/native-host/src/projectPathPlatform.js +30 -0
  179. package/native-host/src/providerHttp.js +80 -0
  180. package/native-host/src/providerModelCatalog.js +4 -3
  181. package/native-host/src/providerProfile.js +17 -3
  182. package/native-host/src/providerReasoning.js +10 -11
  183. package/native-host/src/providerRuntime.js +1 -0
  184. package/native-host/src/providerStore.js +76 -14
  185. package/native-host/src/releaseTransport.js +14 -5
  186. package/native-host/src/responsesPassthroughBridge.js +266 -52
  187. package/native-host/src/runtimeInstaller.js +21 -1
  188. package/native-host/src/selectionScope.js +86 -0
  189. package/native-host/src/skills/parallel-subagents/SKILL.md +31 -3
  190. package/native-host/src/skills/writing-style-builder/SKILL.md +146 -0
  191. package/native-host/src/subagentAdmission.js +26 -0
  192. package/native-host/src/subagentBroker.js +176 -159
  193. package/native-host/src/subagentTelemetry.js +325 -0
  194. package/native-host/src/subagentWorkspace.js +103 -0
  195. package/native-host/src/subagentWorkspacePath.js +34 -0
  196. package/native-host/src/taskRunnerRuntime.js +130 -57
  197. package/native-host/src/tomlStatements.js +140 -0
  198. package/native-host/src/turnAttachments.js +113 -0
  199. package/native-host/src/updateManager.js +406 -38
  200. package/native-host/src/updateNetworkControl.js +75 -0
  201. package/native-host/src/updateTrust.js +21 -2
  202. package/native-host/src/vendor/pdfjs/LICENSE +177 -0
  203. package/native-host/src/vendor/pdfjs/SOURCE.txt +3 -0
  204. package/native-host/src/vendor/pdfjs/cmaps/78-EUC-H.bcmap +0 -0
  205. package/native-host/src/vendor/pdfjs/cmaps/78-EUC-V.bcmap +0 -0
  206. package/native-host/src/vendor/pdfjs/cmaps/78-H.bcmap +0 -0
  207. package/native-host/src/vendor/pdfjs/cmaps/78-RKSJ-H.bcmap +0 -0
  208. package/native-host/src/vendor/pdfjs/cmaps/78-RKSJ-V.bcmap +0 -0
  209. package/native-host/src/vendor/pdfjs/cmaps/78-V.bcmap +0 -0
  210. package/native-host/src/vendor/pdfjs/cmaps/78ms-RKSJ-H.bcmap +0 -0
  211. package/native-host/src/vendor/pdfjs/cmaps/78ms-RKSJ-V.bcmap +0 -0
  212. package/native-host/src/vendor/pdfjs/cmaps/83pv-RKSJ-H.bcmap +0 -0
  213. package/native-host/src/vendor/pdfjs/cmaps/90ms-RKSJ-H.bcmap +0 -0
  214. package/native-host/src/vendor/pdfjs/cmaps/90ms-RKSJ-V.bcmap +0 -0
  215. package/native-host/src/vendor/pdfjs/cmaps/90msp-RKSJ-H.bcmap +0 -0
  216. package/native-host/src/vendor/pdfjs/cmaps/90msp-RKSJ-V.bcmap +0 -0
  217. package/native-host/src/vendor/pdfjs/cmaps/90pv-RKSJ-H.bcmap +0 -0
  218. package/native-host/src/vendor/pdfjs/cmaps/90pv-RKSJ-V.bcmap +0 -0
  219. package/native-host/src/vendor/pdfjs/cmaps/Add-H.bcmap +0 -0
  220. package/native-host/src/vendor/pdfjs/cmaps/Add-RKSJ-H.bcmap +0 -0
  221. package/native-host/src/vendor/pdfjs/cmaps/Add-RKSJ-V.bcmap +0 -0
  222. package/native-host/src/vendor/pdfjs/cmaps/Add-V.bcmap +0 -0
  223. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-0.bcmap +0 -0
  224. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-1.bcmap +0 -0
  225. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-2.bcmap +0 -0
  226. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-3.bcmap +0 -0
  227. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-4.bcmap +0 -0
  228. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-5.bcmap +0 -0
  229. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-6.bcmap +0 -0
  230. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
  231. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-0.bcmap +0 -0
  232. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-1.bcmap +0 -0
  233. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-2.bcmap +0 -0
  234. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-3.bcmap +0 -0
  235. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-4.bcmap +0 -0
  236. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-5.bcmap +0 -0
  237. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
  238. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-0.bcmap +0 -0
  239. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-1.bcmap +0 -0
  240. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-2.bcmap +0 -0
  241. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-3.bcmap +0 -0
  242. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-4.bcmap +0 -0
  243. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-5.bcmap +0 -0
  244. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-6.bcmap +0 -0
  245. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
  246. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-0.bcmap +0 -0
  247. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-1.bcmap +0 -0
  248. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-2.bcmap +0 -0
  249. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
  250. package/native-host/src/vendor/pdfjs/cmaps/B5-H.bcmap +0 -0
  251. package/native-host/src/vendor/pdfjs/cmaps/B5-V.bcmap +0 -0
  252. package/native-host/src/vendor/pdfjs/cmaps/B5pc-H.bcmap +0 -0
  253. package/native-host/src/vendor/pdfjs/cmaps/B5pc-V.bcmap +0 -0
  254. package/native-host/src/vendor/pdfjs/cmaps/CNS-EUC-H.bcmap +0 -0
  255. package/native-host/src/vendor/pdfjs/cmaps/CNS-EUC-V.bcmap +0 -0
  256. package/native-host/src/vendor/pdfjs/cmaps/CNS1-H.bcmap +0 -0
  257. package/native-host/src/vendor/pdfjs/cmaps/CNS1-V.bcmap +0 -0
  258. package/native-host/src/vendor/pdfjs/cmaps/CNS2-H.bcmap +0 -0
  259. package/native-host/src/vendor/pdfjs/cmaps/CNS2-V.bcmap +3 -0
  260. package/native-host/src/vendor/pdfjs/cmaps/ETHK-B5-H.bcmap +0 -0
  261. package/native-host/src/vendor/pdfjs/cmaps/ETHK-B5-V.bcmap +0 -0
  262. package/native-host/src/vendor/pdfjs/cmaps/ETen-B5-H.bcmap +0 -0
  263. package/native-host/src/vendor/pdfjs/cmaps/ETen-B5-V.bcmap +0 -0
  264. package/native-host/src/vendor/pdfjs/cmaps/ETenms-B5-H.bcmap +3 -0
  265. package/native-host/src/vendor/pdfjs/cmaps/ETenms-B5-V.bcmap +0 -0
  266. package/native-host/src/vendor/pdfjs/cmaps/EUC-H.bcmap +0 -0
  267. package/native-host/src/vendor/pdfjs/cmaps/EUC-V.bcmap +0 -0
  268. package/native-host/src/vendor/pdfjs/cmaps/Ext-H.bcmap +0 -0
  269. package/native-host/src/vendor/pdfjs/cmaps/Ext-RKSJ-H.bcmap +0 -0
  270. package/native-host/src/vendor/pdfjs/cmaps/Ext-RKSJ-V.bcmap +0 -0
  271. package/native-host/src/vendor/pdfjs/cmaps/Ext-V.bcmap +0 -0
  272. package/native-host/src/vendor/pdfjs/cmaps/GB-EUC-H.bcmap +0 -0
  273. package/native-host/src/vendor/pdfjs/cmaps/GB-EUC-V.bcmap +0 -0
  274. package/native-host/src/vendor/pdfjs/cmaps/GB-H.bcmap +4 -0
  275. package/native-host/src/vendor/pdfjs/cmaps/GB-V.bcmap +0 -0
  276. package/native-host/src/vendor/pdfjs/cmaps/GBK-EUC-H.bcmap +0 -0
  277. package/native-host/src/vendor/pdfjs/cmaps/GBK-EUC-V.bcmap +0 -0
  278. package/native-host/src/vendor/pdfjs/cmaps/GBK2K-H.bcmap +0 -0
  279. package/native-host/src/vendor/pdfjs/cmaps/GBK2K-V.bcmap +0 -0
  280. package/native-host/src/vendor/pdfjs/cmaps/GBKp-EUC-H.bcmap +0 -0
  281. package/native-host/src/vendor/pdfjs/cmaps/GBKp-EUC-V.bcmap +0 -0
  282. package/native-host/src/vendor/pdfjs/cmaps/GBT-EUC-H.bcmap +0 -0
  283. package/native-host/src/vendor/pdfjs/cmaps/GBT-EUC-V.bcmap +0 -0
  284. package/native-host/src/vendor/pdfjs/cmaps/GBT-H.bcmap +0 -0
  285. package/native-host/src/vendor/pdfjs/cmaps/GBT-V.bcmap +0 -0
  286. package/native-host/src/vendor/pdfjs/cmaps/GBTpc-EUC-H.bcmap +0 -0
  287. package/native-host/src/vendor/pdfjs/cmaps/GBTpc-EUC-V.bcmap +0 -0
  288. package/native-host/src/vendor/pdfjs/cmaps/GBpc-EUC-H.bcmap +0 -0
  289. package/native-host/src/vendor/pdfjs/cmaps/GBpc-EUC-V.bcmap +0 -0
  290. package/native-host/src/vendor/pdfjs/cmaps/H.bcmap +0 -0
  291. package/native-host/src/vendor/pdfjs/cmaps/HKdla-B5-H.bcmap +0 -0
  292. package/native-host/src/vendor/pdfjs/cmaps/HKdla-B5-V.bcmap +0 -0
  293. package/native-host/src/vendor/pdfjs/cmaps/HKdlb-B5-H.bcmap +0 -0
  294. package/native-host/src/vendor/pdfjs/cmaps/HKdlb-B5-V.bcmap +0 -0
  295. package/native-host/src/vendor/pdfjs/cmaps/HKgccs-B5-H.bcmap +0 -0
  296. package/native-host/src/vendor/pdfjs/cmaps/HKgccs-B5-V.bcmap +0 -0
  297. package/native-host/src/vendor/pdfjs/cmaps/HKm314-B5-H.bcmap +0 -0
  298. package/native-host/src/vendor/pdfjs/cmaps/HKm314-B5-V.bcmap +0 -0
  299. package/native-host/src/vendor/pdfjs/cmaps/HKm471-B5-H.bcmap +0 -0
  300. package/native-host/src/vendor/pdfjs/cmaps/HKm471-B5-V.bcmap +0 -0
  301. package/native-host/src/vendor/pdfjs/cmaps/HKscs-B5-H.bcmap +0 -0
  302. package/native-host/src/vendor/pdfjs/cmaps/HKscs-B5-V.bcmap +0 -0
  303. package/native-host/src/vendor/pdfjs/cmaps/Hankaku.bcmap +0 -0
  304. package/native-host/src/vendor/pdfjs/cmaps/Hiragana.bcmap +0 -0
  305. package/native-host/src/vendor/pdfjs/cmaps/KSC-EUC-H.bcmap +0 -0
  306. package/native-host/src/vendor/pdfjs/cmaps/KSC-EUC-V.bcmap +0 -0
  307. package/native-host/src/vendor/pdfjs/cmaps/KSC-H.bcmap +0 -0
  308. package/native-host/src/vendor/pdfjs/cmaps/KSC-Johab-H.bcmap +0 -0
  309. package/native-host/src/vendor/pdfjs/cmaps/KSC-Johab-V.bcmap +0 -0
  310. package/native-host/src/vendor/pdfjs/cmaps/KSC-V.bcmap +0 -0
  311. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-H.bcmap +0 -0
  312. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
  313. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
  314. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-V.bcmap +0 -0
  315. package/native-host/src/vendor/pdfjs/cmaps/KSCpc-EUC-H.bcmap +0 -0
  316. package/native-host/src/vendor/pdfjs/cmaps/KSCpc-EUC-V.bcmap +0 -0
  317. package/native-host/src/vendor/pdfjs/cmaps/Katakana.bcmap +0 -0
  318. package/native-host/src/vendor/pdfjs/cmaps/LICENSE +36 -0
  319. package/native-host/src/vendor/pdfjs/cmaps/NWP-H.bcmap +0 -0
  320. package/native-host/src/vendor/pdfjs/cmaps/NWP-V.bcmap +0 -0
  321. package/native-host/src/vendor/pdfjs/cmaps/RKSJ-H.bcmap +0 -0
  322. package/native-host/src/vendor/pdfjs/cmaps/RKSJ-V.bcmap +0 -0
  323. package/native-host/src/vendor/pdfjs/cmaps/Roman.bcmap +0 -0
  324. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UCS2-H.bcmap +0 -0
  325. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UCS2-V.bcmap +0 -0
  326. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF16-H.bcmap +0 -0
  327. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF16-V.bcmap +0 -0
  328. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF32-H.bcmap +0 -0
  329. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF32-V.bcmap +0 -0
  330. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF8-H.bcmap +0 -0
  331. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF8-V.bcmap +0 -0
  332. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UCS2-H.bcmap +0 -0
  333. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UCS2-V.bcmap +0 -0
  334. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF16-H.bcmap +0 -0
  335. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF16-V.bcmap +0 -0
  336. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF32-H.bcmap +0 -0
  337. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF32-V.bcmap +0 -0
  338. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF8-H.bcmap +0 -0
  339. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF8-V.bcmap +0 -0
  340. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-H.bcmap +0 -0
  341. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
  342. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
  343. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-V.bcmap +0 -0
  344. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF16-H.bcmap +0 -0
  345. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF16-V.bcmap +0 -0
  346. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF32-H.bcmap +0 -0
  347. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF32-V.bcmap +0 -0
  348. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF8-H.bcmap +0 -0
  349. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF8-V.bcmap +0 -0
  350. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
  351. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
  352. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
  353. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
  354. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
  355. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
  356. package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
  357. package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
  358. package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
  359. package/native-host/src/vendor/pdfjs/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
  360. package/native-host/src/vendor/pdfjs/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
  361. package/native-host/src/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
  362. package/native-host/src/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
  363. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UCS2-H.bcmap +0 -0
  364. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UCS2-V.bcmap +0 -0
  365. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF16-H.bcmap +0 -0
  366. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF16-V.bcmap +0 -0
  367. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF32-H.bcmap +0 -0
  368. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF32-V.bcmap +0 -0
  369. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF8-H.bcmap +0 -0
  370. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF8-V.bcmap +0 -0
  371. package/native-host/src/vendor/pdfjs/cmaps/V.bcmap +0 -0
  372. package/native-host/src/vendor/pdfjs/cmaps/WP-Symbol.bcmap +0 -0
  373. package/native-host/src/vendor/pdfjs/pdf.mjs +26740 -0
  374. package/native-host/src/vendor/pdfjs/pdf.worker.mjs +62201 -0
  375. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitDingbats.pfb +0 -0
  376. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixed.pfb +0 -0
  377. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedBold.pfb +0 -0
  378. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
  379. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedItalic.pfb +0 -0
  380. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerif.pfb +0 -0
  381. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifBold.pfb +0 -0
  382. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
  383. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifItalic.pfb +0 -0
  384. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSymbol.pfb +0 -0
  385. package/native-host/src/vendor/pdfjs/standard_fonts/LICENSE_FOXIT +27 -0
  386. package/native-host/src/vendor/pdfjs/standard_fonts/LICENSE_LIBERATION +102 -0
  387. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Bold.ttf +0 -0
  388. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
  389. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Italic.ttf +0 -0
  390. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Regular.ttf +0 -0
  391. package/native-host/src/writingStyleEvidence.js +102 -0
  392. package/native-host/src/writingStylePdfWorker.js +35 -0
  393. package/native-host/src/writingStyleProfile.js +165 -0
  394. package/native-host/src/writingStyleRuntime.js +475 -0
  395. package/native-host/src/writingStyleStore.js +73 -0
  396. package/package.json +1 -1
  397. package/scripts/install-managed.mjs +1 -0
@@ -0,0 +1,344 @@
1
+ (function (root, factory) {
2
+ if (typeof module === 'object' && module.exports) module.exports = factory(require('../shared/failureReasons'), require('../shared/i18n'), require('../shared/agentTranscript'));
3
+ else root.CodexOverleafModuleRegistry.define('RunCompletionMeta', ['FailureReasons', 'I18n', 'AgentTranscript'], factory);
4
+ })(typeof window !== 'undefined' ? window : globalThis, function (FailureReasons, I18n, AgentTranscript) {
5
+ 'use strict';
6
+
7
+ const FLAT_REPORT_STATUS_SECTIONS = [
8
+ { key: 'saveState', prefixes: ['Save:', '保存:'], en: 'Save', zh: '保存' },
9
+ { key: 'unchangedReason', prefixes: ['Why nothing changed:', '未修改原因:'], en: 'Why nothing changed', zh: '未修改原因' },
10
+ { key: 'writeResult', prefixes: ['Write result:', '写入结果:'], en: 'Write result', zh: '写入结果' },
11
+ { key: 'undo', prefixes: ['Undo:', '可撤销:'], en: 'Undo', zh: '可撤销' },
12
+ { key: 'nextStep', prefixes: ['Next:', '下一步:'], en: 'Next', zh: '下一步' }
13
+ ];
14
+
15
+ // Reports persist the language used when the run finished. Re-project only
16
+ // product-owned metadata; model conclusions and custom reasons stay intact.
17
+ const META_COPY = {
18
+ unchangedReason: [
19
+ ['This run was Ask mode.', '这轮是只问不改。'],
20
+ ['You cancelled this change.', '你取消了这轮修改。'],
21
+ ['No file changes need to sync back to Overleaf.', '没有产生需要同步回 Overleaf 的文件改动。'],
22
+ ['No approved file changes remain to sync back to Overleaf.', '没有剩余已确认的文件改动需要同步回 Overleaf。']
23
+ ],
24
+ undo: [['this run has no reversible writes', '本轮没有可撤销的写入']],
25
+ saveState: [['Saved', '已确认保存'],
26
+ ['Pending confirmation; check save status', '待确认,可检查保存状态']],
27
+ nextStep: [
28
+ ['Review the skipped items in this report, then retry after resolving them.', '请查看本轮报告中的跳过项,处理后可以重试。'],
29
+ ['Nothing was written in this run. Review the skipped reasons, fix them, and retry.', '这轮没有任何内容写入。请查看跳过原因,处理后重试。'],
30
+ ['Review the skipped reasons. You can use "Undo written parts" to roll back what already reached Overleaf, then fix conflicts and retry.', '请查看跳过原因。已写入的部分可以点击“撤销已写入部分”回退,处理冲突后再重试。'],
31
+ ['Resolve the issue above, then retry.', '请处理上面的原因后重试。'],
32
+ ['You can continue asking, or add more @context and run another check.', '可以继续追问,或加入更多 @context 后再检查。'],
33
+ ['Review these tracked changes in Overleaf.', '请在 Overleaf 中查看这些文件的留痕修改。'],
34
+ ['You can continue the conversation, or adjust @context and run again.', '可以继续追问,或调整 @context 后重新运行。'],
35
+ ['The first queued follow-up will start next.', '接下来会自动启动队首的后续任务。'],
36
+ ['Edit the task and run again.', '可以修改任务后重新运行。'],
37
+ ['Continue the conversation, or switch to Auto to let Codex edit files.', '可以继续追问,或切换到自动写入后让 Codex 修改文件。'],
38
+ ['Switch to Auto only when you want Codex to edit files.', '只有希望 Codex 修改文件时,才需要切换到自动写入。'],
39
+ ['Review the synced file in Overleaf.', '请在 Overleaf 中查看同步后的文件。'],
40
+ ['Check Overleaf manually before running again. Local mirror refresh and auto compile were skipped.', '再次运行前请先手动检查 Overleaf。本地 mirror 刷新和自动编译已跳过。'],
41
+ ['Switch Overleaf to Reviewing/Track Changes manually and rerun, or turn off Track before writing.', '请在 Overleaf 手动切到 Reviewing/Track Changes 后重新运行,或关闭“留痕”再写入。'],
42
+ ['The main agent must review and adopt the withheld files before syncing them.', '主代理需核对并接管未同步文件后再写回。'],
43
+ ['Select the intended region again and request only changes within it. Valid written parts can be undone.', '请重新选择目标范围,仅请求修改该范围。已写入的合法部分可撤销。'],
44
+ ['Reload the Overleaf project or reopen the .tex file you want to process, then retry.', '请刷新 Overleaf 项目或重新打开要处理的 .tex 文件后再试。'],
45
+ ['Retry with an explicit target such as @file:main.tex and the exact section to edit; if this repeats, open Technical Details.', '请带上明确目标重试,例如 @file:main.tex 和具体要修改的小节;如果重复出现,请打开 Technical Details。'],
46
+ ['Restart Codex Overleaf or start a new run if the installed skill is not visible immediately.', '如果新安装的 skill 没有立刻出现,请重启 Codex Overleaf 或开始新一轮运行。'],
47
+ ['If files still need to be deleted, rerun and confirm deletion separately.', '如果仍需要删除文件,请重新运行并单独确认删除。'],
48
+ ['Expand the write result, review the skipped reasons, then retry after fixing them.', '请展开写入结果查看跳过原因,处理后可以重试。'],
49
+ ['Adjust the task description and run again.', '可以调整任务描述后重新运行。'],
50
+ ['Continue the conversation or run the next task.', '可以继续追问,或运行下一项任务。']
51
+ ]
52
+ };
53
+
54
+ let errorNextSteps;
55
+ const errorNextStepTemplates = [];
56
+ function localizeErrorNextStep(value, tx) {
57
+ if (!errorNextSteps) {
58
+ errorNextSteps = new Map();
59
+ const add = pair => {
60
+ if (!pair.every(text => typeof text === 'string' && text)) return;
61
+ if (pair.every(text => text.includes('{file}'))) {
62
+ for (const template of pair) {
63
+ const parts = template.split('{file}');
64
+ if (parts.length === 2) errorNextStepTemplates.push({ pair,
65
+ pattern: new RegExp('^' + parts.map(part => part.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('([^\\r\\n]*?)') + '$') });
66
+ }
67
+ }
68
+ for (const text of pair) if (!errorNextSteps.has(text)) errorNextSteps.set(text, pair);
69
+ };
70
+ // Reuse the producer's own bilingual copy rather than maintain another
71
+ // translation catalog. Only exact, known next-step prose is accepted.
72
+ for (const key of Object.keys(I18n?.MESSAGES?.en || {})) {
73
+ if (/^failureReason_.+_next$/.test(key)) add([I18n.MESSAGES.en[key], I18n.MESSAGES.zh[key]]);
74
+ }
75
+ const catalog = FailureReasons?.FAILURE_CODE_CATALOG || {};
76
+ for (const [code, entry] of Object.entries(catalog)) {
77
+ const key = `failureReason_${code}_next`;
78
+ const pair = [I18n?.MESSAGES?.en?.[key], I18n?.MESSAGES?.zh?.[key]];
79
+ if (entry.fallbackNextAction && pair.every(Boolean)) errorNextSteps.set(entry.fallbackNextAction, pair);
80
+ }
81
+ const legacyInputs = ['Mode must be "ask" or "auto"', 'Agent returned invalid JSON',
82
+ 'Could not parse Codex output', 'timed out', 'output limit exceeded',
83
+ 'unsupported_parameter reasoning.summary', 'quota', 'checkpoint', 'changed while Codex was working'];
84
+ if (AgentTranscript?.translateRawError) {
85
+ for (const message of [...Object.keys(catalog), ...legacyInputs]) {
86
+ add(['en', 'zh'].map(locale => AgentTranscript.translateRawError(message, { locale }).nextStep));
87
+ }
88
+ add(['en', 'zh'].map(locale => AgentTranscript.translateRawError('', { locale, codexReturned: true }).nextStep));
89
+ }
90
+ }
91
+ const pair = errorNextSteps.get(value);
92
+ if (pair) return tx(...pair);
93
+ for (const entry of errorNextStepTemplates) {
94
+ const match = entry.pattern.exec(String(value || ''));
95
+ if (match) return tx(...entry.pair).replace('{file}', () => match[1]);
96
+ }
97
+ return value;
98
+ }
99
+
100
+ function localizeMetaRow(row, options) {
101
+ if (!row || typeof row !== 'object') return row;
102
+ const entry = FLAT_REPORT_STATUS_SECTIONS.find(item => item.key === row.key);
103
+ if (!entry) return row;
104
+ const { tx } = options;
105
+ let value = row.value;
106
+ const pair = (META_COPY[row.key] || []).find(values => values.includes(value));
107
+ if (pair) value = tx(...pair);
108
+ if (row.key === 'nextStep') value = localizeErrorNextStep(value, tx);
109
+ if (row.key === 'writeResult') {
110
+ const counts = /^(?:已写入 (\d+) 项,跳过 (\d+) 项|wrote (\d+) items?, skipped (\d+) items?)$/.exec(String(value || ''));
111
+ if (counts) {
112
+ const written = Number(counts[1] ?? counts[3]), skipped = Number(counts[2] ?? counts[4]);
113
+ value = tx(`wrote ${written} item${written === 1 ? '' : 's'}, skipped ${skipped} item${skipped === 1 ? '' : 's'}`,
114
+ `已写入 ${written} 项,跳过 ${skipped} 项`);
115
+ }
116
+ }
117
+ if (row.key === 'undo') {
118
+ const count = /^(?:可撤销本轮 (\d+) 项写入|this run has (\d+) reversible writes?)$/.exec(String(value || ''));
119
+ if (count) {
120
+ const n = Number(count[1] ?? count[2]);
121
+ value = tx(`this run has ${n} reversible write${n === 1 ? '' : 's'}`, `可撤销本轮 ${n} 项写入`);
122
+ }
123
+ }
124
+ if (['nextStep', 'unchangedReason'].includes(row.key) && options.getLocale && options.tr) {
125
+ value = FailureReasons?.localizeFailureMessage?.(value, options.getLocale(), key => {
126
+ const translated = options.tr(key);
127
+ return translated === key ? undefined : translated;
128
+ }) ?? value;
129
+ }
130
+ return { ...row, label: tx(entry.en, entry.zh), value };
131
+ }
132
+
133
+ function splitFlatCompletionReport(text, tx = value => value) {
134
+ const raw = typeof text === 'string' ? text : '';
135
+ if (!raw.trim()) return { body: raw, meta: [] };
136
+ const bodySections = [], meta = [];
137
+ for (const section of raw.split(/\n{2,}/)) {
138
+ const trimmed = section.trim();
139
+ if (!trimmed) continue;
140
+ const entry = trimmed.includes('\n') ? null
141
+ : FLAT_REPORT_STATUS_SECTIONS.find(item => item.prefixes.some(prefix => trimmed.startsWith(prefix)));
142
+ if (entry) {
143
+ const prefix = entry.prefixes.find(value => trimmed.startsWith(value));
144
+ const value = trimmed.slice(prefix.length).trim();
145
+ if (value) {
146
+ meta.push({ key: entry.key, label: tx(entry.en, entry.zh), value });
147
+ continue;
148
+ }
149
+ }
150
+ bodySections.push(trimmed);
151
+ }
152
+ return { body: bodySections.join('\n\n'), meta };
153
+ }
154
+
155
+ function projectCompletionBody(body, tx = value => value) {
156
+ if (typeof body !== 'string' || !body) return body;
157
+ const sections = [['Checked', '检查范围'], ['Findings', '发现'], ['Planned changes', '计划修改'],
158
+ ['Changes', '修改'], ['Skipped', '跳过原因']];
159
+ let rest = body, previous = -1, language;
160
+ const projected = [];
161
+ while (rest) {
162
+ let found;
163
+ for (let index = previous + 1; index < sections.length && !found; index++) {
164
+ for (const locale of [0, 1]) {
165
+ const prefix = sections[index][locale] + (locale ? ':\n' : ':\n');
166
+ if ((language === undefined || locale === language) && rest.startsWith(prefix)) {
167
+ found = { index, locale, prefix }; break;
168
+ }
169
+ }
170
+ }
171
+ if (!found) return body;
172
+ language = found.locale;
173
+ previous = found.index;
174
+ rest = rest.slice(found.prefix.length);
175
+ const heading = tx(sections[previous][0] + ':', sections[previous][1] + ':');
176
+ // Skipped may contain arbitrary model/error prose. Only a complete,
177
+ // exact product-owned governance block can be re-projected.
178
+ if (previous === sections.length - 1) {
179
+ if (!/^- [^\r\n]+/.test(rest)) return body;
180
+ projected.push(heading + '\n' + projectGovernanceSkippedBody(rest, tx));
181
+ return projected.join('\n\n');
182
+ }
183
+ const boundary = rest.indexOf('\n\n');
184
+ const items = boundary < 0 ? rest : rest.slice(0, boundary);
185
+ if (!/^- [^\r\n]+(?:\n- [^\r\n]+)*$/.test(items)) return body;
186
+ projected.push(heading + '\n' + items);
187
+ if (boundary < 0) return projected.join('\n\n');
188
+ rest = rest.slice(boundary + 2);
189
+ if (!rest) return body;
190
+ }
191
+ return body;
192
+ }
193
+
194
+ function projectGovernanceSkippedBody(body, tx) {
195
+ const locale = tx('en', 'zh');
196
+ const lookup = key => I18n.t(locale, key);
197
+ const operationLabels = { edit: '编辑', create: '新建', delete: '删除', move: '移动', rename: '重命名' };
198
+ const pattern = /(^|\n)- ([^\r\n]+?)(?:: (edit|create|delete|move|rename|binary-create|overwrite-binary) was not written|:(编辑|新建|删除|移动|重命名|binary-create|overwrite-binary)没有写入)\n([ \t]*)(?:Reason|原因): ([^\r\n]+)\n\5(?:Stage|阶段): (?:unknown|preflight)\n\5(?:Code|代码): (unknown_legacy_failure|governance_blocked|governance_readonly|governance_writable_allowlist)\n\5(?:Next|下一步): ([^\r\n]+)(?=\n- |$)/g;
199
+ return body.replace(pattern, (block, prefix, file, enOperation, zhOperation, indent, message, code, next) => {
200
+ const display = FailureReasons.formatFailureReasonForDisplay({ code: 'unknown_legacy_failure', userMessage: message }, locale, lookup);
201
+ if (!['governance_blocked', 'governance_readonly', 'governance_writable_allowlist'].includes(display.code)) return block;
202
+ if (code !== 'unknown_legacy_failure' && code !== 'governance_blocked' && code !== display.code) return block;
203
+ const nextKeys = [display.code, 'unknown_legacy_failure'].flatMap(value => [
204
+ FailureReasons.FAILURE_CODE_CATALOG[value]?.fallbackNextAction,
205
+ I18n.t('en', `failureReason_${value}_next`), I18n.t('zh', `failureReason_${value}_next`)
206
+ ]);
207
+ if (!nextKeys.includes(next)) return block;
208
+ const operation = enOperation || Object.keys(operationLabels).find(key => operationLabels[key] === zhOperation) || zhOperation;
209
+ const header = tx(`${file}: ${operation} was not written`, `${file}:${operationLabels[operation] || operation}没有写入`);
210
+ const failure = { code: display.code, stage: 'preflight', userMessage: display.userMessage, nextAction: display.nextAction };
211
+ return `${prefix}- ${header}\n${AgentTranscript.formatFailureBlock(failure, locale, indent)}`;
212
+ });
213
+ }
214
+
215
+ function projectCompletionMeta(meta, run, options) {
216
+ const { tx, trackedChangeInFlight, isTrackedChangeLifecycleRun, projectRunSettlement } = options;
217
+ if (!Array.isArray(meta) || !run) return meta;
218
+ const undone = run.undoStatus === 'applied' || run.trackedChangeStatus === 'rejected';
219
+ const rows = (undone ? meta.filter(row => row?.key !== 'saveState') : meta).map(row => localizeMetaRow(row, options))
220
+ .filter(row => row?.key !== 'recoveryRetention' && row?.key !== 'directoryObservation');
221
+ const pending = run.pendingDirectoryCleanup;
222
+ if (!run.forkSnapshot && pending?.v === 1 && pending.runId === run.id
223
+ && pending.projectId === run.runProjectId && pending.projectId === options.projectId
224
+ && pending.accountScopeId && pending.accountScopeId === options.accountScopeId) {
225
+ const paths = [...new Set((Array.isArray(pending.directories) ? pending.directories : []).filter(item => item?.projectId === pending.projectId
226
+ && typeof item.path === 'string' && item.path && !/^[\\/]|^[A-Za-z]:|[\u0000-\u001f\u007f]/.test(item.path)
227
+ && !item.path.replace(/\\/g, '/').split('/').some(part => !part || part === '.' || part === '..')).map(item => item.path))];
228
+ if (paths.length) rows.push({ key: 'directoryObservation', label: tx('Folders', '文件夹'),
229
+ value: tx('The run recorded these folders at completion; their current status has not been rechecked: ',
230
+ '本轮结束时记录了以下文件夹,当前状态尚未重新核验:') + paths.join(', ') });
231
+ }
232
+ const retentionOmitted = hasOmittedRecoveryRetention(run);
233
+ const inFlight = trackedChangeInFlight?.get(run.id);
234
+ const tracked = isTrackedChangeLifecycleRun(run);
235
+ const pendingFileUndo = tracked && run.trackedChangeStatus === 'needs_review' && run.undoOperations?.some(operation => operation?.undoCreatedFile?.v === 1 || operation?.type === 'create');
236
+ let undo;
237
+ if (run.undoStatus === 'running' || inFlight === 'reject') {
238
+ undo = tx('Undoing changes...', '正在撤销修改…');
239
+ } else if (run.undoStatus === 'applied' || (tracked && run.trackedChangeStatus === 'rejected')) {
240
+ undo = tx('This run\'s changes have been undone.', '本轮修改已撤销。');
241
+ } else if (tracked && run.trackedChangeStatus === 'accepted') {
242
+ undo = tx('Changes accepted; undo is no longer available.', '修改已接受,无法再撤销。');
243
+ } else if (run.undoStatus === 'partial' || pendingFileUndo) {
244
+ undo = hasUndoProgress(run)
245
+ ? projectRunSettlement(run).canUndo
246
+ ? tx(pendingFileUndo ? 'Some changes were undone; retry the remaining files.' : 'Some changes were undone; remaining changes can still be undone.', pendingFileUndo ? '已撤销部分修改,可重试剩余文件。' : '已撤销部分修改,剩余修改仍可撤销。')
247
+ : tx('Some changes were undone.', '已撤销部分修改。')
248
+ : projectRunSettlement(run).canUndo
249
+ ? tx(pendingFileUndo ? 'Undo is incomplete; retry the remaining files.' : 'Undo is incomplete; remaining changes can still be undone.', pendingFileUndo ? '撤销未完成,可重试剩余文件。' : '撤销未完成,剩余修改仍可撤销。')
250
+ : tx('Undo is incomplete.', '撤销未完成。');
251
+ }
252
+ if (!undo && !run.saveCheck && !run.saveConfirmedAt && !retentionOmitted) return rows;
253
+ const projected = rows.map(row => row?.key === 'undo' && undo
254
+ ? { ...row, label: tx('Undo', '撤销'), value: undo }
255
+ : row?.key === 'saveState' && (run.saveCheck || run.saveConfirmedAt)
256
+ ? { ...row, label: tx('Save', '保存'), value: run.saveCheck
257
+ ? tx('Pending confirmation', '待确认') : tx('Saved', '已确认保存') }
258
+ : row);
259
+ if (retentionOmitted) {
260
+ const budget = ['run-budget', 'session-budget'].includes(run.recoveryRetention.reason);
261
+ const directory = run.recoveryRetention.directoryCleanup === true ? tx(
262
+ 'Recorded folder observations were not retained; their current status is unknown.',
263
+ '文件夹历史观测记录未保留,当前状态未核验。') : '';
264
+ const recovery = budget
265
+ ? tx('Persistent recovery data was not retained: local recovery budget exceeded. After reload, use Overleaf history to recover.',
266
+ '持久恢复材料未保留:超过本地恢复预算,刷新后请使用 Overleaf 历史恢复。')
267
+ : tx('Persistent recovery data was not retained. After reload, use Overleaf history to recover.',
268
+ '持久恢复材料未保留,刷新后请使用 Overleaf 历史恢复。');
269
+ projected.push({ key: 'recoveryRetention', label: tx('Recovery data', '恢复材料'),
270
+ value: directory && (run.recoveryRetention.coreRetained === true || undone || run.trackedChangeStatus === 'accepted')
271
+ ? directory : [recovery, directory].filter(Boolean).join(' ') });
272
+ }
273
+ return projected;
274
+ }
275
+
276
+ function hasOmittedRecoveryRetention(run) {
277
+ return run?.recoveryRetention?.state === 'omitted' && (run.recoveryRetention.directoryCleanup === true
278
+ || (run.undoStatus !== 'applied' && !['accepted', 'rejected'].includes(run.trackedChangeStatus)));
279
+ }
280
+
281
+ function hasUndoProgress(run) {
282
+ const failures = run?.settlement?.failures || run?.settlementFacts?.failures || [];
283
+ return (Array.isArray(run?.events) ? run.events : []).some(event => {
284
+ if (!['completed', 'failed'].includes(event?.status) || event.streamRole || ['report', 'guidance', 'stream'].includes(event.kind)) return false;
285
+ const count = String(event.title || '').match(/^(?:Undo result: (?:undone|rejected) (\d+) (?:item\(s\)|file\(s\)|tracked change\(s\)), skipped \d+(?: item\(s\))?|撤销结果:已(?:撤销|拒绝) (\d+) (?:项|条留痕|个文件),跳过 \d+ (?:项|条))$/);
286
+ if (!(Number(count?.[1] || count?.[2]) > 0)) return false;
287
+ const detail = event.detail || {}, applied = detail.Undone || detail.Rejected || detail['已撤销'] || detail['已拒绝'];
288
+ const skipped = detail.Skipped || detail['跳过'], path = item => item?.File || item?.['文件'];
289
+ return Array.isArray(applied) && Array.isArray(skipped) && applied.some(item =>
290
+ typeof path(item) === 'string' && path(item).trim() && !skipped.some(other => path(other) === path(item))
291
+ && !(Array.isArray(failures) && failures.some(failure => failure?.code === 'undo_not_verified'
292
+ && (!failure.file || failure.file === path(item)))));
293
+ });
294
+ }
295
+
296
+ // Generic reasons say nothing beyond "no files were written", so they stay in
297
+ // the details. Both locales match because a report keeps its original locale.
298
+ const GENERIC_UNCHANGED_REASONS = new Set([
299
+ 'No file changes need to sync back to Overleaf.', '没有产生需要同步回 Overleaf 的文件改动。',
300
+ 'No approved file changes remain to sync back to Overleaf.', '没有剩余已确认的文件改动需要同步回 Overleaf。',
301
+ 'This run was Ask mode.', '这轮是只问不改。'
302
+ ]);
303
+
304
+ // One summary line for the meta rows: what was written, whether it can be
305
+ // undone, and a pending save. The rows themselves stay behind the disclosure,
306
+ // which opens by itself only when something needs the user's attention.
307
+ function summarizeCompletionMeta(rows, run, { tx, failed = false, unconfirmed = false } = {}) {
308
+ const find = key => String(rows.find(row => row?.key === key)?.value || '').trim();
309
+ const counts = find('writeResult').match(/wrote (\d+) items?, skipped (\d+)|已写入 (\d+) 项,跳过 (\d+) 项/);
310
+ const wrote = Number(counts?.[1] ?? counts?.[3] ?? 0), skipped = Number(counts?.[2] ?? counts?.[4] ?? 0);
311
+ const reason = find('unchangedReason');
312
+ const undone = run?.undoStatus === 'applied' || run?.trackedChangeStatus === 'rejected';
313
+ const retentionOmitted = hasOmittedRecoveryRetention(run);
314
+ const savePending = !undone && (Boolean(run?.saveCheck) || (!run?.saveConfirmedAt && /^(?:Pending|待确认)/.test(find('saveState'))));
315
+ const pendingFileUndo = run?.trackedChangeStatus === 'needs_review'
316
+ && run.undoOperations?.some(operation => operation?.undoCreatedFile?.v === 1 || operation?.type === 'create');
317
+ const facts = [];
318
+ if (failed) facts.push({ key: 'write', tone: 'fail', text: unconfirmed ? tx('Write not confirmed', '写入结果未确认') : tx('Write incomplete', '写入未完成') });
319
+ else if (wrote) facts.push({ key: 'write', text: tx(`Wrote ${wrote} item${wrote === 1 ? '' : 's'}`, `已写入 ${wrote} 项`) });
320
+ else if (reason && !GENERIC_UNCHANGED_REASONS.has(reason)) facts.push({ key: 'write', text: tx('Not written: ', '未写入:') + reason.replace(/[.。]$/, '') });
321
+ else facts.push({ key: 'write', text: tx('No files written', '未写入文件') });
322
+ if (skipped) facts.push({ key: 'skip', tone: 'warn', text: tx(`${skipped} skipped`, `跳过 ${skipped} 项`) });
323
+ const undoable = Number(find('undo').match(/(\d+)/)?.[1] || 0);
324
+ const undo = run?.undoStatus === 'running' || /^(?:Undoing changes\.\.\.|正在撤销修改…)$/.test(find('undo')) ? tx('Undoing…', '正在撤销…')
325
+ : run?.undoStatus === 'applied' || run?.trackedChangeStatus === 'rejected' ? tx('Changes undone', '已撤销本轮修改')
326
+ : run?.trackedChangeStatus === 'accepted' ? tx('Changes accepted', '修改已接受')
327
+ : pendingFileUndo || run?.undoStatus === 'partial'
328
+ ? (hasUndoProgress(run) ? tx('Partly undone', '已撤销部分修改') : tx('Undo incomplete', '撤销未完成'))
329
+ : undoable ? tx(`${undoable} undoable`, `可撤销 ${undoable} 项`)
330
+ : failed || retentionOmitted ? '' : tx('Nothing to undo', '无可撤销写入');
331
+ if (undo) facts.push({ key: 'undo', text: undo });
332
+ if (retentionOmitted) facts.push({ key: 'recoveryRetention', tone: 'warn',
333
+ text: run.recoveryRetention.coreRetained === true
334
+ ? tx('Folder observations not retained after reload', '刷新后文件夹观测记录未保留')
335
+ : tx('Recovery data not retained after reload', '刷新后恢复材料未保留') });
336
+ if (savePending) facts.push({ key: 'save', tone: 'warn', text: tx('Save pending', '保存待确认') });
337
+ const attention = failed || skipped > 0 || retentionOmitted;
338
+ const warnKeys = new Set([...(failed || skipped > 0 ? ['writeResult', 'nextStep'] : []),
339
+ ...(retentionOmitted ? ['recoveryRetention'] : []), ...(savePending ? ['saveState'] : [])]);
340
+ return { facts, open: attention, warnKeys };
341
+ }
342
+
343
+ return { splitFlatCompletionReport, projectCompletionBody, projectCompletionMeta, summarizeCompletionMeta };
344
+ });
@@ -1,14 +1,25 @@
1
1
  (function initCodexOverleafRunController(root, factory) {
2
2
  if (typeof module === 'object' && module.exports) {
3
- module.exports = factory();
3
+ module.exports = factory(require('../shared/projectFiles'));
4
4
  } else {
5
- root.CodexOverleafRunController = factory();
5
+ root.CodexOverleafRunController = factory(root.CodexOverleafProjectFiles);
6
6
  }
7
- })(typeof window !== 'undefined' ? window : globalThis, function runControllerFactory() {
7
+ })(typeof window !== 'undefined' ? window : globalThis, function runControllerFactory(ProjectFiles) {
8
8
  'use strict';
9
9
 
10
10
  const DEFAULT_EXPECTED_MIRROR_FRESHNESS_MS = 5 * 60 * 1000;
11
11
 
12
+ function captureSessionContext(state = {}) {
13
+ // This is the prompt projection, not the mutable visible-session alias.
14
+ const session = state.session;
15
+ return session ? JSON.parse(JSON.stringify(session)) : null;
16
+ }
17
+
18
+ function isSubmittedComposerUnchanged(submitted, current) {
19
+ return ['task', 'attachments', 'skillInvocation', 'selectionContext'].every(key =>
20
+ JSON.stringify(submitted[key] ?? null) === JSON.stringify(current[key] ?? null));
21
+ }
22
+
12
23
  function buildCodexRunParams({
13
24
  currentProjectId,
14
25
  state = {},
@@ -22,6 +33,7 @@
22
33
  customInstructions,
23
34
  skillLoadingSettings,
24
35
  enabledCodexOverleafSkillIds,
36
+ enabledCodexLocalSkillIds,
25
37
  attachments,
26
38
  skillInvocation,
27
39
  compileLogContext,
@@ -45,6 +57,7 @@
45
57
  otWarmStart: useExistingMirror && otWarmStart ? true : undefined,
46
58
  warmStartStrategy: useExistingMirror && otWarmStart ? 'ot-warm-mirror' : undefined,
47
59
  focusFiles,
60
+ focusFilesAreLiteral: true,
48
61
  restrictToFocusFiles: restrictToFocusFiles || undefined,
49
62
  model: state.model,
50
63
  reasoningEffort: state.reasoningEffort,
@@ -56,6 +69,9 @@
56
69
  loadCodexLocalSkills: skillLoadingSettings?.loadCodexLocalSkills !== false,
57
70
  loadCodexOverleafSkills: skillLoadingSettings?.loadCodexOverleafSkills !== false,
58
71
  enabledCodexOverleafSkillIds: normalizedEnabledSkillIds,
72
+ enabledCodexLocalSkillIds: Array.isArray(enabledCodexLocalSkillIds)
73
+ ? [...new Set(enabledCodexLocalSkillIds.filter(id => typeof id === 'string' && isSafeSkillId(id)))]
74
+ : undefined,
59
75
  skillInvocation: normalizedSkillInvocation || undefined,
60
76
  attachments: normalizedAttachments.length ? normalizedAttachments : undefined
61
77
  };
@@ -106,13 +122,14 @@
106
122
  project = {},
107
123
  snapshotWarnings = {},
108
124
  focusFiles = [],
125
+ focusFilesAreLiteral = false,
109
126
  isUsableProjectFileContent = defaultIsUsableProjectFileContent
110
127
  } = {}) {
111
128
  const blocking = Array.isArray(snapshotWarnings.blocking) ? snapshotWarnings.blocking : [];
112
129
  if (!blocking.length || !blocking.some(isFullSnapshotWarning)) {
113
130
  return false;
114
131
  }
115
- const normalizedFocusFiles = normalizeFocusFiles(focusFiles);
132
+ const normalizedFocusFiles = normalizeFocusFiles(focusFiles, focusFilesAreLiteral === true);
116
133
  if (!normalizedFocusFiles.length) {
117
134
  return false;
118
135
  }
@@ -122,10 +139,10 @@
122
139
 
123
140
  const textFilesByPath = new Map((project.files || [])
124
141
  .filter(file => file && typeof file.path === 'string' && typeof file.content === 'string')
125
- .map(file => [normalizeFocusPath(file.path), file]));
142
+ .map(file => [normalizeFocusPath(file.path, true), file]));
126
143
 
127
144
  return normalizedFocusFiles.every(filePath => {
128
- const file = textFilesByPath.get(normalizeFocusPath(filePath));
145
+ const file = textFilesByPath.get(filePath);
129
146
  return file && isUsableProjectFileContent(file.content);
130
147
  });
131
148
  }
@@ -138,11 +155,11 @@
138
155
  return /Full project snapshot was not captured/i.test(String(warning || ''));
139
156
  }
140
157
 
141
- function normalizeFocusFiles(value) {
158
+ function normalizeFocusFiles(value, literal = false) {
142
159
  const seen = new Set();
143
160
  const files = [];
144
161
  for (const item of Array.isArray(value) ? value : []) {
145
- const filePath = normalizeFocusPath(item);
162
+ const filePath = normalizeFocusPath(item, literal);
146
163
  if (!filePath || seen.has(filePath)) {
147
164
  continue;
148
165
  }
@@ -152,7 +169,8 @@
152
169
  return files;
153
170
  }
154
171
 
155
- function normalizeFocusPath(value) {
172
+ function normalizeFocusPath(value, literal = false) {
173
+ if (literal) return ProjectFiles.normalizeSafeProjectPath(value);
156
174
  return String(value || '')
157
175
  .replace(/^@file:/i, '')
158
176
  .replace(/\\/g, '/')
@@ -187,19 +205,22 @@
187
205
  if (!isSafeSkillId(id)) {
188
206
  return null;
189
207
  }
190
- const title = String(value?.title || 'Skill Installer').trim().slice(0, 80) || 'Skill Installer';
191
- if (id === 'skill-installer') {
208
+ const installer = id === 'skill-installer' && (value?.scope == null || value.scope === 'builtin');
209
+ const fallbackTitle = installer ? 'Skill Installer' : id;
210
+ const title = String(value?.title || fallbackTitle).trim().slice(0, 80) || fallbackTitle;
211
+ if (installer) {
192
212
  return { id, title };
193
213
  }
194
- if (value?.scope !== 'codex-overleaf') {
214
+ if (!['codex-overleaf', 'codex-local'].includes(value?.scope)) {
195
215
  return null;
196
216
  }
197
- return { id, title, scope: 'codex-overleaf' };
217
+ return { id, title, scope: value.scope };
198
218
  }
199
219
 
200
220
  function isSafeSkillId(id) {
201
221
  return /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$/.test(String(id || ''))
202
- && !String(id || '').includes('..');
222
+ && !String(id || '').includes('..')
223
+ && !['__proto__', 'prototype', 'constructor'].includes(id);
203
224
  }
204
225
 
205
226
  function normalizeAttachmentName(value) {
@@ -232,7 +253,9 @@
232
253
  }
233
254
 
234
255
  function isRetryReplacementEligible(run = {}, projection = {}) {
235
- if (!run.id || !['failed', 'interrupted'].includes(run.status)) return false;
256
+ if (run.retryWriteback || run.saveCheck) return false;
257
+ if (!run.id || run.forkSnapshot === true
258
+ || !['failed', 'interrupted', 'cancelled', 'rejected'].includes(run.status)) return false;
236
259
  if (run.trackedChangeStatus || run.undoStatus) return false;
237
260
  if (['undoOperations', 'undoTrackedChanges', 'undoExpectedFiles', 'undoBaseFiles', 'appliedOperations']
238
261
  .some(field => Array.isArray(run[field]) && run[field].length)) return false;
@@ -264,6 +287,8 @@
264
287
  }
265
288
 
266
289
  return {
290
+ captureSessionContext,
291
+ isSubmittedComposerUnchanged,
267
292
  buildCodexRunParams,
268
293
  canUseFocusedPartialSnapshot,
269
294
  shouldRestrictWritebackToFocus,
@@ -1,14 +1,26 @@
1
1
  (function initRunFailureNotice(root, factory) {
2
2
  if (typeof module === 'object' && module.exports) {
3
- module.exports = factory();
3
+ module.exports = factory(require('../shared/failureReasons'));
4
4
  } else {
5
- root.CodexOverleafModuleRegistry.define('RunFailureNotice', [], factory);
5
+ root.CodexOverleafModuleRegistry.define('RunFailureNotice', ['FailureReasons'], factory);
6
6
  }
7
- })(typeof window !== 'undefined' ? window : globalThis, function runFailureNoticeFactory() {
7
+ })(typeof window !== 'undefined' ? window : globalThis, function runFailureNoticeFactory(FailureReasons) {
8
8
  'use strict';
9
9
 
10
10
  const REVIEW_CODES = new Set(['write_timeout', 'partial_write_needs_review']);
11
11
  const CANCEL_CODES = new Set(['cancelled', 'user_cancelled', 'codex_cancelled']);
12
+ // Old attempts remain in the stored audit trail; a resolved undo must not
13
+ // advertise them as a current failure in the transcript or its summary.
14
+ function projectResolvedUndo(run) {
15
+ if (!run || (run.undoStatus !== 'applied' && run.trackedChangeStatus !== 'rejected')
16
+ || !Array.isArray(run.events)) return run;
17
+ const events = run.events.filter(event => {
18
+ if (event?.status !== 'failed' || event.streamRole
19
+ || ['report', 'guidance', 'stream'].includes(event.kind)) return true;
20
+ return !/^(?:Undo result:\s*(?:undone|rejected)\s+\d+\s+(?:item\(s\)|file\(s\)|tracked change\(s\)),\s*skipped\s+\d+(?:\s+item\(s\))?|撤销结果[::]\s*已(?:撤销|拒绝)\s*\d+\s*(?:项|条留痕|个文件),\s*跳过\s*\d+\s*(?:项|条))$/.test(String(event.title || '').trim());
21
+ });
22
+ return events.length === run.events.length ? run : { ...run, events };
23
+ }
12
24
 
13
25
  function create({ tr, projectRunSettlement, sanitizeText = value => value,
14
26
  document: documentRef = globalThis.document } = {}) {
@@ -20,7 +32,7 @@
20
32
  const failure = projection?.primaryFailure || event.failure;
21
33
  if (report.dataset.status === 'cancelled' || CANCEL_CODES.has(failure?.code)) return;
22
34
  const facts = run?.settlement || run?.settlementFacts || {};
23
- const unconfirmed = REVIEW_CODES.has(failure?.code)
35
+ const unconfirmed = projection?.requiresWriteReview === true || REVIEW_CODES.has(failure?.code)
24
36
  || facts.documentEffect === 'possibly-changed'
25
37
  || (facts.evidence?.applied === 'unknown' && facts.evidence?.settled === 'needs-review');
26
38
  const partial = facts.evidence?.applied === 'partial' || run?.partialWriteback === true;
@@ -36,9 +48,14 @@
36
48
  heading.textContent = tr(unconfirmed ? 'runFeedbackUnconfirmedTitle'
37
49
  : partial ? 'runFeedbackPartialTitle' : 'runFeedbackFailedTitle');
38
50
  const message = documentRef.createElement('p');
39
- const detail = typeof failure?.userMessage === 'string' ? failure.userMessage : '';
40
51
  const file = safeProjectPath(failure?.file);
41
- message.textContent = sanitizeText([file, detail].filter(Boolean).join(': ').slice(0, 1000))
52
+ // Localization is a display projection. Recovery keeps the original
53
+ // failure and its trusted file, even when historical text yields a path.
54
+ const display = FailureReasons?.formatFailureReasonForDisplay?.(failure, undefined, key => {
55
+ const value = tr(key);
56
+ return value && value !== key ? value : undefined;
57
+ });
58
+ message.textContent = sanitizeText((display?.message || [file, failure?.userMessage].filter(Boolean).join(': ')).slice(0, 1000))
42
59
  || tr('runFeedbackGeneric');
43
60
  notice.append(heading, message);
44
61
  if (unconfirmed) {
@@ -61,10 +78,15 @@
61
78
  return row.value;
62
79
  }
63
80
 
64
- function prepareRecovery(report, { openFile } = {}) {
81
+ function getRecoveryContext(report) {
65
82
  const info = notices.get(report);
66
- const target = info?.notice || report;
67
- if (!info?.unconfirmed) return { target, handled: false };
83
+ return { target: info?.notice || report, failure: info?.failure, unconfirmed: info?.unconfirmed === true, file: info?.file || '' };
84
+ }
85
+
86
+ function prepareRecovery(report, { openFile } = {}) {
87
+ const info = getRecoveryContext(report);
88
+ const target = info.target;
89
+ if (!info.unconfirmed) return { target, handled: false, failure: info.failure };
68
90
  const canOpen = Boolean(info.file && typeof openFile === 'function');
69
91
  const button = documentRef.createElement('button');
70
92
  button.type = 'button';
@@ -87,10 +109,10 @@
87
109
  }
88
110
  });
89
111
  target.append(button);
90
- return { target, handled: true };
112
+ return { target, handled: true, failure: info.failure };
91
113
  }
92
114
 
93
- return Object.freeze({ append, formatMetaValue, prepareRecovery });
115
+ return Object.freeze({ append, formatMetaValue, getRecoveryContext, prepareRecovery });
94
116
  }
95
117
 
96
118
  function safeProjectPath(value) {
@@ -100,5 +122,5 @@
100
122
  && !path.split('/').includes('..') ? path.slice(0, 300) : '';
101
123
  }
102
124
 
103
- return Object.freeze({ create });
125
+ return Object.freeze({ create, projectResolvedUndo });
104
126
  });