codex-overleaf-link 2.4.0 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (327) hide show
  1. package/README.md +272 -311
  2. package/README.zh-CN.md +287 -326
  3. package/extension/bootstrap/background.js +47 -10
  4. package/extension/bootstrap/manifest.template.json +9 -4
  5. package/extension/bootstrap/popup.html +10 -16
  6. package/extension/bootstrap/update.js +25 -2
  7. package/extension/runtime-manifest.json +3 -1
  8. package/extension/src/background.js +28 -3
  9. package/extension/src/backgroundSharedSessions.js +380 -0
  10. package/extension/src/backgroundUpdateCoordinator.js +442 -379
  11. package/extension/src/content/activeTurnControl.js +8 -0
  12. package/extension/src/content/assetTransferBroker.js +186 -12
  13. package/extension/src/content/changeHistoryView.js +175 -0
  14. package/extension/src/content/composerAttachments.js +24 -22
  15. package/extension/src/content/composerPanel.js +23 -8
  16. package/extension/src/content/contentRuntime.js +572 -571
  17. package/extension/src/content/diagnosticsController.js +1 -2
  18. package/extension/src/content/diagnosticsExport.js +222 -0
  19. package/extension/src/content/diagnosticsPanel.js +48 -19
  20. package/extension/src/content/diffReviewPanel.js +8 -5
  21. package/extension/src/content/generated/content.bundle.js +8974 -1781
  22. package/extension/src/content/generated/content.bundle.meta.json +22 -3
  23. package/extension/src/content/legacyGlobalRegistry.js +19 -1
  24. package/extension/src/content/localSkillsPanel.js +42 -7
  25. package/extension/src/content/markdownDomRenderer.js +9 -4
  26. package/extension/src/content/modelPicker.js +1 -1
  27. package/extension/src/content/pageBridgeClient.js +18 -3
  28. package/extension/src/content/panelMaintenance.js +51 -120
  29. package/extension/src/content/panelRenderer.js +4 -0
  30. package/extension/src/content/pendingInputView.js +109 -76
  31. package/extension/src/content/providerSettingsCoordinator.js +17 -6
  32. package/extension/src/content/providerSettingsDialog.js +661 -108
  33. package/extension/src/content/recentProjects.js +364 -356
  34. package/extension/src/content/runActivitySummary.js +631 -0
  35. package/extension/src/content/runController.js +3 -1
  36. package/extension/src/content/runFailureNotice.js +14 -1
  37. package/extension/src/content/runGuidanceController.js +4 -3
  38. package/extension/src/content/runPresence.js +306 -0
  39. package/extension/src/content/runQueueScheduler.js +2 -1
  40. package/extension/src/content/runResultActions.js +123 -3
  41. package/extension/src/content/runTimelineView.js +194 -164
  42. package/extension/src/content/scopedPersistenceCoordinator.js +2 -1
  43. package/extension/src/content/scopedPersistencePanelState.js +45 -2
  44. package/extension/src/content/selectionContextView.js +300 -0
  45. package/extension/src/content/sessionPersistence.js +10 -2
  46. package/extension/src/content/settingsPanel.js +93 -54
  47. package/extension/src/content/settingsWorkbench.js +374 -0
  48. package/extension/src/content/sharedSessionViewSync.js +72 -0
  49. package/extension/src/content/subagentActivityView.js +195 -0
  50. package/extension/src/content/trackedChangeCaptureController.js +7 -3
  51. package/extension/src/content/updateNotice.js +121 -50
  52. package/extension/src/content/writebackController.js +257 -0
  53. package/extension/src/content/writebackOrchestrator.js +146 -141
  54. package/extension/src/content/writebackPlan.js +231 -0
  55. package/extension/src/content/writebackRecovery.js +122 -0
  56. package/extension/src/content/writingStyleSettings.js +576 -0
  57. package/extension/src/content/writtenChangesView.js +152 -0
  58. package/extension/src/page/binaryAssetUploader.js +97 -19
  59. package/extension/src/page/overleafProjectSnapshot.js +1 -0
  60. package/extension/src/page/referenceProjects.js +148 -0
  61. package/extension/src/page/saveState.js +58 -3
  62. package/extension/src/page/snapshotRouter.js +44 -13
  63. package/extension/src/page/textCoordinates.js +102 -0
  64. package/extension/src/page/textFileCreator.js +350 -59
  65. package/extension/src/page/trackedChangeCapture.js +42 -56
  66. package/extension/src/page/trackedChangeOwnership.js +198 -0
  67. package/extension/src/page/trackedChangeReplay.js +164 -0
  68. package/extension/src/page/trackedChangesLifecycle.js +139 -150
  69. package/extension/src/page/treeOperations.js +36 -29
  70. package/extension/src/page/writebackReceiptJournal.js +112 -0
  71. package/extension/src/page/writebackRouter.js +176 -136
  72. package/extension/src/pageBridge.js +59 -101
  73. package/extension/src/popup.js +203 -59
  74. package/extension/src/shared/agentTranscript.js +18 -4
  75. package/extension/src/shared/auditRecords.js +71 -0
  76. package/extension/src/shared/changeHistoryModel.js +94 -0
  77. package/extension/src/shared/compatibility.js +1 -1
  78. package/extension/src/shared/compileAdapter.js +42 -0
  79. package/extension/src/shared/failureReasons.js +20 -0
  80. package/extension/src/shared/globalPreferences.js +1 -1
  81. package/extension/src/shared/i18n.js +187 -65
  82. package/extension/src/shared/managedUpdateProjection.js +6 -3
  83. package/extension/src/shared/pageRpcContract.js +7 -1
  84. package/extension/src/shared/providerProfiles.js +109 -0
  85. package/extension/src/shared/runActivityModel.js +361 -0
  86. package/extension/src/shared/runExecutionSnapshot.js +8 -2
  87. package/extension/src/shared/runExecutionSnapshotCodec.js +16 -4
  88. package/extension/src/shared/scopedPersistenceBrowserAdapter.js +6 -3
  89. package/extension/src/shared/selectionContext.js +28 -0
  90. package/extension/src/shared/sessionState.js +97 -6
  91. package/extension/src/shared/sharedSessionBridge.js +288 -0
  92. package/extension/src/shared/storageDb.js +23 -55
  93. package/extension/src/shared/storageMigration.js +3 -0
  94. package/extension/src/shared/storageRunActions.js +54 -4
  95. package/extension/src/shared/storageValuePruning.js +40 -0
  96. package/extension/src/shared/subagentActivityModel.js +174 -0
  97. package/extension/src/shared/undoOperations.js +87 -0
  98. package/extension/src/shared/updateConsent.js +37 -8
  99. package/extension/src/shared/writebackIntent.js +62 -0
  100. package/extension/src/shared/writebackSettlement.js +29 -10
  101. package/extension/src/shared/writingStyle.js +33 -0
  102. package/extension/styles/panel.css +2136 -744
  103. package/extension/styles/popup.css +110 -0
  104. package/native-host/src/anthropicBridgeRequest.js +2 -1
  105. package/native-host/src/codexModelRecovery.js +107 -0
  106. package/native-host/src/codexPromptAssembly.js +2 -0
  107. package/native-host/src/codexProviderLaunch.js +3 -3
  108. package/native-host/src/codexRuntimeIdentity.js +1 -0
  109. package/native-host/src/codexSessionRunner.js +146 -177
  110. package/native-host/src/codexSessionTiming.js +71 -0
  111. package/native-host/src/managedInstall.js +5 -4
  112. package/native-host/src/nativeEnvironment.js +70 -0
  113. package/native-host/src/nativeQuotas.js +15 -8
  114. package/native-host/src/overleafWorkspaceRules.js +16 -0
  115. package/native-host/src/processStopBarrier.js +80 -0
  116. package/native-host/src/providerModelCatalog.js +4 -3
  117. package/native-host/src/providerProfile.js +13 -1
  118. package/native-host/src/providerReasoning.js +9 -5
  119. package/native-host/src/providerStore.js +4 -0
  120. package/native-host/src/readProgressGuard.js +84 -17
  121. package/native-host/src/releaseTransport.js +14 -5
  122. package/native-host/src/selectionScope.js +58 -0
  123. package/native-host/src/skills/parallel-subagents/SKILL.md +31 -3
  124. package/native-host/src/skills/writing-style-builder/SKILL.md +146 -0
  125. package/native-host/src/subagentBroker.js +102 -98
  126. package/native-host/src/subagentTelemetry.js +316 -0
  127. package/native-host/src/subagentWorkspace.js +103 -0
  128. package/native-host/src/subagentWorkspacePath.js +31 -0
  129. package/native-host/src/taskRunnerRuntime.js +55 -5
  130. package/native-host/src/turnAttachments.js +113 -0
  131. package/native-host/src/updateManager.js +122 -12
  132. package/native-host/src/updateNetworkControl.js +75 -0
  133. package/native-host/src/updateTrust.js +21 -2
  134. package/native-host/src/vendor/pdfjs/LICENSE +177 -0
  135. package/native-host/src/vendor/pdfjs/SOURCE.txt +3 -0
  136. package/native-host/src/vendor/pdfjs/cmaps/78-EUC-H.bcmap +0 -0
  137. package/native-host/src/vendor/pdfjs/cmaps/78-EUC-V.bcmap +0 -0
  138. package/native-host/src/vendor/pdfjs/cmaps/78-H.bcmap +0 -0
  139. package/native-host/src/vendor/pdfjs/cmaps/78-RKSJ-H.bcmap +0 -0
  140. package/native-host/src/vendor/pdfjs/cmaps/78-RKSJ-V.bcmap +0 -0
  141. package/native-host/src/vendor/pdfjs/cmaps/78-V.bcmap +0 -0
  142. package/native-host/src/vendor/pdfjs/cmaps/78ms-RKSJ-H.bcmap +0 -0
  143. package/native-host/src/vendor/pdfjs/cmaps/78ms-RKSJ-V.bcmap +0 -0
  144. package/native-host/src/vendor/pdfjs/cmaps/83pv-RKSJ-H.bcmap +0 -0
  145. package/native-host/src/vendor/pdfjs/cmaps/90ms-RKSJ-H.bcmap +0 -0
  146. package/native-host/src/vendor/pdfjs/cmaps/90ms-RKSJ-V.bcmap +0 -0
  147. package/native-host/src/vendor/pdfjs/cmaps/90msp-RKSJ-H.bcmap +0 -0
  148. package/native-host/src/vendor/pdfjs/cmaps/90msp-RKSJ-V.bcmap +0 -0
  149. package/native-host/src/vendor/pdfjs/cmaps/90pv-RKSJ-H.bcmap +0 -0
  150. package/native-host/src/vendor/pdfjs/cmaps/90pv-RKSJ-V.bcmap +0 -0
  151. package/native-host/src/vendor/pdfjs/cmaps/Add-H.bcmap +0 -0
  152. package/native-host/src/vendor/pdfjs/cmaps/Add-RKSJ-H.bcmap +0 -0
  153. package/native-host/src/vendor/pdfjs/cmaps/Add-RKSJ-V.bcmap +0 -0
  154. package/native-host/src/vendor/pdfjs/cmaps/Add-V.bcmap +0 -0
  155. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-0.bcmap +0 -0
  156. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-1.bcmap +0 -0
  157. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-2.bcmap +0 -0
  158. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-3.bcmap +0 -0
  159. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-4.bcmap +0 -0
  160. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-5.bcmap +0 -0
  161. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-6.bcmap +0 -0
  162. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
  163. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-0.bcmap +0 -0
  164. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-1.bcmap +0 -0
  165. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-2.bcmap +0 -0
  166. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-3.bcmap +0 -0
  167. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-4.bcmap +0 -0
  168. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-5.bcmap +0 -0
  169. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
  170. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-0.bcmap +0 -0
  171. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-1.bcmap +0 -0
  172. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-2.bcmap +0 -0
  173. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-3.bcmap +0 -0
  174. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-4.bcmap +0 -0
  175. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-5.bcmap +0 -0
  176. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-6.bcmap +0 -0
  177. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
  178. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-0.bcmap +0 -0
  179. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-1.bcmap +0 -0
  180. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-2.bcmap +0 -0
  181. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
  182. package/native-host/src/vendor/pdfjs/cmaps/B5-H.bcmap +0 -0
  183. package/native-host/src/vendor/pdfjs/cmaps/B5-V.bcmap +0 -0
  184. package/native-host/src/vendor/pdfjs/cmaps/B5pc-H.bcmap +0 -0
  185. package/native-host/src/vendor/pdfjs/cmaps/B5pc-V.bcmap +0 -0
  186. package/native-host/src/vendor/pdfjs/cmaps/CNS-EUC-H.bcmap +0 -0
  187. package/native-host/src/vendor/pdfjs/cmaps/CNS-EUC-V.bcmap +0 -0
  188. package/native-host/src/vendor/pdfjs/cmaps/CNS1-H.bcmap +0 -0
  189. package/native-host/src/vendor/pdfjs/cmaps/CNS1-V.bcmap +0 -0
  190. package/native-host/src/vendor/pdfjs/cmaps/CNS2-H.bcmap +0 -0
  191. package/native-host/src/vendor/pdfjs/cmaps/CNS2-V.bcmap +3 -0
  192. package/native-host/src/vendor/pdfjs/cmaps/ETHK-B5-H.bcmap +0 -0
  193. package/native-host/src/vendor/pdfjs/cmaps/ETHK-B5-V.bcmap +0 -0
  194. package/native-host/src/vendor/pdfjs/cmaps/ETen-B5-H.bcmap +0 -0
  195. package/native-host/src/vendor/pdfjs/cmaps/ETen-B5-V.bcmap +0 -0
  196. package/native-host/src/vendor/pdfjs/cmaps/ETenms-B5-H.bcmap +3 -0
  197. package/native-host/src/vendor/pdfjs/cmaps/ETenms-B5-V.bcmap +0 -0
  198. package/native-host/src/vendor/pdfjs/cmaps/EUC-H.bcmap +0 -0
  199. package/native-host/src/vendor/pdfjs/cmaps/EUC-V.bcmap +0 -0
  200. package/native-host/src/vendor/pdfjs/cmaps/Ext-H.bcmap +0 -0
  201. package/native-host/src/vendor/pdfjs/cmaps/Ext-RKSJ-H.bcmap +0 -0
  202. package/native-host/src/vendor/pdfjs/cmaps/Ext-RKSJ-V.bcmap +0 -0
  203. package/native-host/src/vendor/pdfjs/cmaps/Ext-V.bcmap +0 -0
  204. package/native-host/src/vendor/pdfjs/cmaps/GB-EUC-H.bcmap +0 -0
  205. package/native-host/src/vendor/pdfjs/cmaps/GB-EUC-V.bcmap +0 -0
  206. package/native-host/src/vendor/pdfjs/cmaps/GB-H.bcmap +4 -0
  207. package/native-host/src/vendor/pdfjs/cmaps/GB-V.bcmap +0 -0
  208. package/native-host/src/vendor/pdfjs/cmaps/GBK-EUC-H.bcmap +0 -0
  209. package/native-host/src/vendor/pdfjs/cmaps/GBK-EUC-V.bcmap +0 -0
  210. package/native-host/src/vendor/pdfjs/cmaps/GBK2K-H.bcmap +0 -0
  211. package/native-host/src/vendor/pdfjs/cmaps/GBK2K-V.bcmap +0 -0
  212. package/native-host/src/vendor/pdfjs/cmaps/GBKp-EUC-H.bcmap +0 -0
  213. package/native-host/src/vendor/pdfjs/cmaps/GBKp-EUC-V.bcmap +0 -0
  214. package/native-host/src/vendor/pdfjs/cmaps/GBT-EUC-H.bcmap +0 -0
  215. package/native-host/src/vendor/pdfjs/cmaps/GBT-EUC-V.bcmap +0 -0
  216. package/native-host/src/vendor/pdfjs/cmaps/GBT-H.bcmap +0 -0
  217. package/native-host/src/vendor/pdfjs/cmaps/GBT-V.bcmap +0 -0
  218. package/native-host/src/vendor/pdfjs/cmaps/GBTpc-EUC-H.bcmap +0 -0
  219. package/native-host/src/vendor/pdfjs/cmaps/GBTpc-EUC-V.bcmap +0 -0
  220. package/native-host/src/vendor/pdfjs/cmaps/GBpc-EUC-H.bcmap +0 -0
  221. package/native-host/src/vendor/pdfjs/cmaps/GBpc-EUC-V.bcmap +0 -0
  222. package/native-host/src/vendor/pdfjs/cmaps/H.bcmap +0 -0
  223. package/native-host/src/vendor/pdfjs/cmaps/HKdla-B5-H.bcmap +0 -0
  224. package/native-host/src/vendor/pdfjs/cmaps/HKdla-B5-V.bcmap +0 -0
  225. package/native-host/src/vendor/pdfjs/cmaps/HKdlb-B5-H.bcmap +0 -0
  226. package/native-host/src/vendor/pdfjs/cmaps/HKdlb-B5-V.bcmap +0 -0
  227. package/native-host/src/vendor/pdfjs/cmaps/HKgccs-B5-H.bcmap +0 -0
  228. package/native-host/src/vendor/pdfjs/cmaps/HKgccs-B5-V.bcmap +0 -0
  229. package/native-host/src/vendor/pdfjs/cmaps/HKm314-B5-H.bcmap +0 -0
  230. package/native-host/src/vendor/pdfjs/cmaps/HKm314-B5-V.bcmap +0 -0
  231. package/native-host/src/vendor/pdfjs/cmaps/HKm471-B5-H.bcmap +0 -0
  232. package/native-host/src/vendor/pdfjs/cmaps/HKm471-B5-V.bcmap +0 -0
  233. package/native-host/src/vendor/pdfjs/cmaps/HKscs-B5-H.bcmap +0 -0
  234. package/native-host/src/vendor/pdfjs/cmaps/HKscs-B5-V.bcmap +0 -0
  235. package/native-host/src/vendor/pdfjs/cmaps/Hankaku.bcmap +0 -0
  236. package/native-host/src/vendor/pdfjs/cmaps/Hiragana.bcmap +0 -0
  237. package/native-host/src/vendor/pdfjs/cmaps/KSC-EUC-H.bcmap +0 -0
  238. package/native-host/src/vendor/pdfjs/cmaps/KSC-EUC-V.bcmap +0 -0
  239. package/native-host/src/vendor/pdfjs/cmaps/KSC-H.bcmap +0 -0
  240. package/native-host/src/vendor/pdfjs/cmaps/KSC-Johab-H.bcmap +0 -0
  241. package/native-host/src/vendor/pdfjs/cmaps/KSC-Johab-V.bcmap +0 -0
  242. package/native-host/src/vendor/pdfjs/cmaps/KSC-V.bcmap +0 -0
  243. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-H.bcmap +0 -0
  244. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
  245. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
  246. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-V.bcmap +0 -0
  247. package/native-host/src/vendor/pdfjs/cmaps/KSCpc-EUC-H.bcmap +0 -0
  248. package/native-host/src/vendor/pdfjs/cmaps/KSCpc-EUC-V.bcmap +0 -0
  249. package/native-host/src/vendor/pdfjs/cmaps/Katakana.bcmap +0 -0
  250. package/native-host/src/vendor/pdfjs/cmaps/LICENSE +36 -0
  251. package/native-host/src/vendor/pdfjs/cmaps/NWP-H.bcmap +0 -0
  252. package/native-host/src/vendor/pdfjs/cmaps/NWP-V.bcmap +0 -0
  253. package/native-host/src/vendor/pdfjs/cmaps/RKSJ-H.bcmap +0 -0
  254. package/native-host/src/vendor/pdfjs/cmaps/RKSJ-V.bcmap +0 -0
  255. package/native-host/src/vendor/pdfjs/cmaps/Roman.bcmap +0 -0
  256. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UCS2-H.bcmap +0 -0
  257. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UCS2-V.bcmap +0 -0
  258. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF16-H.bcmap +0 -0
  259. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF16-V.bcmap +0 -0
  260. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF32-H.bcmap +0 -0
  261. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF32-V.bcmap +0 -0
  262. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF8-H.bcmap +0 -0
  263. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF8-V.bcmap +0 -0
  264. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UCS2-H.bcmap +0 -0
  265. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UCS2-V.bcmap +0 -0
  266. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF16-H.bcmap +0 -0
  267. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF16-V.bcmap +0 -0
  268. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF32-H.bcmap +0 -0
  269. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF32-V.bcmap +0 -0
  270. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF8-H.bcmap +0 -0
  271. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF8-V.bcmap +0 -0
  272. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-H.bcmap +0 -0
  273. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
  274. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
  275. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-V.bcmap +0 -0
  276. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF16-H.bcmap +0 -0
  277. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF16-V.bcmap +0 -0
  278. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF32-H.bcmap +0 -0
  279. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF32-V.bcmap +0 -0
  280. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF8-H.bcmap +0 -0
  281. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF8-V.bcmap +0 -0
  282. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
  283. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
  284. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
  285. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
  286. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
  287. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
  288. package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
  289. package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
  290. package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
  291. package/native-host/src/vendor/pdfjs/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
  292. package/native-host/src/vendor/pdfjs/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
  293. package/native-host/src/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
  294. package/native-host/src/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
  295. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UCS2-H.bcmap +0 -0
  296. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UCS2-V.bcmap +0 -0
  297. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF16-H.bcmap +0 -0
  298. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF16-V.bcmap +0 -0
  299. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF32-H.bcmap +0 -0
  300. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF32-V.bcmap +0 -0
  301. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF8-H.bcmap +0 -0
  302. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF8-V.bcmap +0 -0
  303. package/native-host/src/vendor/pdfjs/cmaps/V.bcmap +0 -0
  304. package/native-host/src/vendor/pdfjs/cmaps/WP-Symbol.bcmap +0 -0
  305. package/native-host/src/vendor/pdfjs/pdf.mjs +26740 -0
  306. package/native-host/src/vendor/pdfjs/pdf.worker.mjs +62201 -0
  307. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitDingbats.pfb +0 -0
  308. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixed.pfb +0 -0
  309. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedBold.pfb +0 -0
  310. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
  311. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedItalic.pfb +0 -0
  312. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerif.pfb +0 -0
  313. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifBold.pfb +0 -0
  314. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
  315. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifItalic.pfb +0 -0
  316. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSymbol.pfb +0 -0
  317. package/native-host/src/vendor/pdfjs/standard_fonts/LICENSE_FOXIT +27 -0
  318. package/native-host/src/vendor/pdfjs/standard_fonts/LICENSE_LIBERATION +102 -0
  319. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Bold.ttf +0 -0
  320. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
  321. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Italic.ttf +0 -0
  322. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Regular.ttf +0 -0
  323. package/native-host/src/writingStyleEvidence.js +102 -0
  324. package/native-host/src/writingStylePdfWorker.js +35 -0
  325. package/native-host/src/writingStyleProfile.js +165 -0
  326. package/native-host/src/writingStyleRuntime.js +447 -0
  327. package/package.json +1 -1
@@ -1,17 +1,14 @@
1
1
  (function initCodexOverleafRunTimelineView() {
2
2
  'use strict';
3
3
 
4
- // Run-timeline view — the timeline render pipeline carved out of
5
- // contentRuntime.js (v1.4.6 structural-debt phase 2): the scroll engine +
6
- // jump-to-latest button, the live-elapsed tick and collapsed-header summary,
7
- // run-card / stream-event / activity rendering, the completion report, and
8
- // the run-card Undo/Accept controls. Code moved verbatim (original
9
- // indentation kept); runtime collaborators are factory-injected and mutable
10
- // runtime state (panel, panel state, the live run view) is read through lazy
11
- // getters. The view-local scroll/timer state below moved here with the code
12
- // that owns it.
4
+ // Owns scroll, cards, reports and mature run actions. The optional activity
5
+ // presenter projects stored events without taking ownership of settlement.
13
6
  function create(deps = {}) {
14
7
  const {
8
+ RunActivitySummary,
9
+ RunPresence,
10
+ RunActivityModel,
11
+ SubagentActivityView,
15
12
  RunGuidanceView,
16
13
  RunResultActions,
17
14
  RunScrollLayout,
@@ -25,6 +22,7 @@
25
22
  formatEventDetail,
26
23
  formatEventTime,
27
24
  renderAttachmentPreviewList,
25
+ renderSentSelection,
28
26
  formatModeLabel,
29
27
  undoRun,
30
28
  acceptRun,
@@ -41,11 +39,15 @@
41
39
  getState,
42
40
  getCurrentRunView,
43
41
  refillComposerForRetry,
42
+ canEditRun,
43
+ retryWriteback,
44
44
  showNativeSetupGuidance,
45
45
  openProjectFileForFailure,
46
46
  openStorageSettings,
47
47
  trackedChangeInFlight,
48
- projectRunSettlement
48
+ projectRunSettlement,
49
+ getCurrentProjectId,
50
+ getProjectName
49
51
  } = deps;
50
52
 
51
53
  let logAutoFollow = true;
@@ -59,9 +61,7 @@
59
61
  let scrollLogPendingForce = false;
60
62
  let jumpToLatestButton = null;
61
63
  let unreadSinceDetach = 0;
62
- // Live-elapsed tick for the sticky run-process header. Without it the header
63
- // reads a static "Processing…" and the user can't tell a working run from a
64
- // hung one — the single highest-value streaming signal per competitor UX.
64
+ // Elapsed time belongs to the run; tool rows retain their own lifecycle.
65
65
  let runElapsedTimer = null;
66
66
  const scrollLayout = RunScrollLayout?.create({
67
67
  getScroller: getLogScrollContainer,
@@ -69,6 +69,13 @@
69
69
  onLayoutChange: scroller => logAutoFollow ? scrollLogToBottom() : updateJumpToLatestButton(scroller)
70
70
  });
71
71
  const failureNotice = RunFailureNotice?.create({ tr, projectRunSettlement, sanitizeText: sanitizeAssistantVisibleText });
72
+ const presence = RunPresence?.create({ tx, getLocale, formatElapsed });
73
+ const displayRun = run => RunFailureNotice?.projectResolvedUndo?.(run) || run;
74
+ const activitySummary = RunActivitySummary?.create({ RunActivityModel, SubagentActivityView, tx, findRunRecord: (...args) => displayRun(findRunRecord(...args)), getPanel, cssEscape,
75
+ formatEventTime, formatElapsed, renderMarkdownBlockText, renderRunEvent, formatEventDetail,
76
+ presence, classifyStatus: classifyRunPresence, getProjectId: () => getCurrentProjectId?.() || '',
77
+ summarizeCommand: RunPresence?.commandSummary,
78
+ isGuidance: event => Boolean(RunGuidanceView.getGuidanceText(event)), sanitizeAssistantVisibleText });
72
79
 
73
80
  // Re-arm auto-follow (called by the runtime when a new run starts, so the
74
81
  // log snaps back to following the live stream).
@@ -187,6 +194,7 @@
187
194
  }
188
195
 
189
196
  function scrollLogToBottom(options = {}) {
197
+ if (activitySummary?.isSubagentViewOpen?.()) return;
190
198
  const scroller = getLogScrollContainer();
191
199
  if (!scroller) {
192
200
  return;
@@ -237,6 +245,7 @@
237
245
  scroller.scrollTop = scroller.scrollHeight;
238
246
  }
239
247
  function collapseRunProcess(view, statusText) {
248
+ if (activitySummary) { activitySummary.settle(view, statusText); return; }
240
249
  const runProcess = view?.runProcess || view?.root?.querySelector('[data-run-process]');
241
250
  if (runProcess) {
242
251
  runProcess.open = false;
@@ -245,23 +254,15 @@
245
254
  if (statusEl) {
246
255
  // Append the step count to the collapsed header ("Processed 18s · 6 steps")
247
256
  // so the user sees how much work the run did without expanding it.
248
- const stepCount = countRunActivitySteps(view);
257
+ const record = view?.recordId ? findRunRecord(view.recordId, view.sessionId) : null;
258
+ const stepCount = (record?.events || []).filter(event => (event.kind || 'activity') === 'activity').length;
249
259
  statusEl.textContent = stepCount > 0
250
260
  ? `${statusText} · ${tx(`${stepCount} steps`, `${stepCount} 步`)}`
251
261
  : statusText;
252
262
  }
253
263
  }
254
264
 
255
- function countRunActivitySteps(view) {
256
- const record = view?.recordId ? findRunRecord(view.recordId, view.sessionId) : null;
257
- if (!Array.isArray(record?.events)) {
258
- return 0;
259
- }
260
- return record.events.filter(event => (event.kind || 'activity') === 'activity').length;
261
- }
262
-
263
- // The sticky run-process header shows a live "Processing… {elapsed}" while a
264
- // run is in flight so the user can distinguish a working run from a hung one.
265
+ // Keep elapsed labels live without creating new activity records.
265
266
  function startRunElapsedTick() {
266
267
  stopRunElapsedTick();
267
268
  if (typeof window.setInterval !== 'function') {
@@ -272,6 +273,7 @@
272
273
  stopRunElapsedTick();
273
274
  return;
274
275
  }
276
+ if (activitySummary?.update(getCurrentRunView()) && presence) return;
275
277
  const statusEl = getCurrentRunView().status
276
278
  || getCurrentRunView().root?.querySelector('[data-run-status]');
277
279
  if (statusEl) {
@@ -289,6 +291,13 @@
289
291
  runElapsedTimer = null;
290
292
  }
291
293
 
294
+ function classifyRunPresence(run = {}) {
295
+ if (run.retryingWriteback) return 'plain';
296
+ if (run.status === 'completed') return 'done';
297
+ if (run.status === 'cancelled' || run.status === 'rejected') return 'stopped';
298
+ return run.status === 'failed' || run.status === 'abandoned_after_navigation' ? 'failed' : 'plain';
299
+ }
300
+
292
301
  function formatProcessedSummary(status, elapsedMs) {
293
302
  const elapsed = formatElapsed(elapsedMs);
294
303
  if (status === 'failed') {
@@ -303,6 +312,7 @@
303
312
  return tr('processed', { elapsed });
304
313
  }
305
314
  function renderRunHistory(options = {}) {
315
+ activitySummary?.closeSubagentView?.();
306
316
  const log = getPanel()?.querySelector('[data-log]');
307
317
  if (!log) {
308
318
  return;
@@ -323,7 +333,12 @@
323
333
  const hint = document.createElement('div');
324
334
  hint.className = 'empty-runs-hint';
325
335
  hint.textContent = tr('emptyRunsHint');
336
+ label.className = 'empty-runs-title';
326
337
  empty.append(icon, label, hint);
338
+ if (presence) {
339
+ icon.remove();
340
+ presence.decorateEmpty(empty, { projectName: getProjectName?.() || '' });
341
+ }
327
342
  log.append(empty);
328
343
  return;
329
344
  }
@@ -342,6 +357,7 @@
342
357
  }
343
358
 
344
359
  function renderRunCard(run) {
360
+ run = displayRun(run);
345
361
  const root = document.createElement('section');
346
362
  root.className = 'transcript-turn run-card';
347
363
  root.dataset.status = run.status || 'completed';
@@ -356,11 +372,14 @@
356
372
  root.innerHTML = `
357
373
  <div class="transcript-turn-main">
358
374
  <div class="run-attachments codex-attachment-preview-list" data-run-attachments hidden></div>
375
+ <div class="run-selection" data-run-selection hidden></div>
359
376
  <div class="run-prompt" data-run-task></div>
360
377
  <div class="run-guidance-list" data-run-guidance></div>
361
378
  <div class="run-turn-meta">
362
379
  <button type="button" data-run-accept hidden title="Accept this run's tracked changes in Overleaf">Accept changes</button>
363
380
  <button type="button" data-run-undo hidden title="Undo this run's writes to Overleaf">Undo</button>
381
+ <button type="button" class="run-copy-action run-edit-action" data-run-edit hidden></button>
382
+ <button type="button" class="run-copy-action run-sync-action" data-run-sync-retry hidden></button>
364
383
  </div>
365
384
  <details class="run-process" data-run-process>
366
385
  <summary data-run-process-summary>
@@ -379,6 +398,7 @@
379
398
  `;
380
399
 
381
400
  renderAttachmentPreviewList(run.attachments, root.querySelector('[data-run-attachments]'), { readonly: true });
401
+ renderSentSelection?.(root.querySelector('[data-run-selection]'), run.executionSnapshot?.selectionContext, { document, tx });
382
402
  const runTask = root.querySelector('[data-run-task]');
383
403
  runTask.classList.add('run-user-message');
384
404
  runTask.textContent = run.task || '';
@@ -398,7 +418,7 @@
398
418
  truncated.textContent = tr('eventsTruncatedNote');
399
419
  events.append(truncated);
400
420
  }
401
- const guidanceTarget = run.status === 'running' ? events : guidance;
421
+ const guidanceTarget = guidance;
402
422
  const renderedGuidanceIds = new Set();
403
423
  const completedLegacyGuidance = new Set((run.events || [])
404
424
  .filter(event => event.kind === 'guidance' && !event.guidanceId && event.status === 'completed')
@@ -407,7 +427,7 @@
407
427
  if (event.kind === 'report') {
408
428
  report.hidden = false;
409
429
  report.replaceChildren(renderCompletionReport(event, run));
410
- } else if (event.kind === 'technical') {
430
+ } else if (activitySummary || event.kind === 'technical') {
411
431
  continue;
412
432
  } else if (RunGuidanceView.getGuidanceText(event)) {
413
433
  if (event.guidanceId && renderedGuidanceIds.has(event.guidanceId)) {
@@ -423,17 +443,21 @@
423
443
  } else if (event.kind === 'stream') {
424
444
  upsertStreamEvent({ events }, event);
425
445
  } else {
426
- events.append(renderRunEvent(event));
446
+ appendActivityDetail({ events }, renderRunEvent(event), event);
427
447
  }
428
448
  }
429
449
 
430
450
  RunResultActions.configureResultActions(root, run);
431
451
  configureAcceptButton(root, run);
432
452
  configureUndoButton(root, run);
453
+ configureEditButton(root, run);
454
+ configureWritebackButton(root, run);
455
+ activitySummary?.mount(root, run);
433
456
  return root;
434
457
  }
435
458
 
436
459
  function getRunStatusText(run = {}) {
460
+ if (run.retryingWriteback) return tx('Checking file sync', '正在检查文件同步');
437
461
  if (run.statusText) {
438
462
  return run.statusText;
439
463
  }
@@ -461,6 +485,7 @@
461
485
  if (!view?.events) {
462
486
  return;
463
487
  }
488
+ if (activitySummary?.update(view, event)) return;
464
489
  const streamKey = event.streamKey || event.streamRole || 'codex-stream';
465
490
  const selector = `[data-stream-key="${cssEscape(streamKey)}"]`;
466
491
  const existing = view.events.querySelector(selector);
@@ -477,7 +502,12 @@
477
502
  }
478
503
  return;
479
504
  }
480
- view.events.append(renderStreamEvent({ ...event, streamKey }));
505
+ appendActivityDetail(view, renderStreamEvent({ ...event, streamKey }), event);
506
+ }
507
+
508
+ function appendActivityDetail(view, row, event) {
509
+ if (activitySummary) activitySummary.appendDetail(view, row, event);
510
+ else view.events.append(row);
481
511
  }
482
512
 
483
513
  function renderStreamEvent(input) {
@@ -543,54 +573,8 @@
543
573
  return row;
544
574
  }
545
575
 
546
- function hasNonEmptyDetail(value) {
547
- if (value === undefined || value === null || value === '') {
548
- return false;
549
- }
550
- if (Array.isArray(value)) {
551
- return value.length > 0;
552
- }
553
- if (typeof value === 'object') {
554
- return Object.keys(value).length > 0;
555
- }
556
- return true;
557
- }
558
-
559
- function renderTechnicalEvent(event) {
560
- const block = document.createElement('section');
561
- block.className = 'run-technical-event';
562
- block.dataset.status = event.status || 'info';
563
-
564
- const title = document.createElement('div');
565
- title.className = 'run-technical-event-title';
566
- title.textContent = event.title || tr('technicalDetails');
567
576
 
568
- const body = document.createElement('pre');
569
- body.textContent = formatEventDetail(buildTechnicalEventDetail(event));
570
- block.append(title, body);
571
- return block;
572
- }
573
577
 
574
- function buildTechnicalEventDetail(event) {
575
- if (event?.kind === 'technical') {
576
- return event.detail || {};
577
- }
578
-
579
- const detail = {
580
- [tx('Step', '步骤')]: event?.title || '',
581
- [tx('Status', '状态')]: event?.status || ''
582
- };
583
- if (event?.timestamp) {
584
- detail[tx('Time', '时间')] = formatEventTime(event.timestamp);
585
- }
586
- if (hasNonEmptyDetail(event?.detail)) {
587
- detail[tx('Content', '内容')] = event.detail;
588
- }
589
- if (hasNonEmptyDetail(event?.technicalDetail)) {
590
- detail[tx('Raw event', '原始事件')] = event.technicalDetail;
591
- }
592
- return detail;
593
- }
594
578
 
595
579
  function buildActivityTooltip(event) {
596
580
  return [
@@ -599,71 +583,72 @@
599
583
  ].filter(Boolean).join('\n');
600
584
  }
601
585
 
602
- // The trailing status sections emitted by formatHumanReport (agentTranscript):
603
- // run metadata, not part of Codex's answer. Each entry matches the bilingual
604
- // "Label: value" line so the flat-text fallback can split them out of the
605
- // body and demote them into the same muted meta block the structured render
606
- // uses. Order mirrors the structured meta order.
607
- const FLAT_REPORT_STATUS_SECTIONS = [
608
- { key: 'unchangedReason', prefixes: ['Why nothing changed:', '未修改原因:'], en: 'Why nothing changed', zh: '未修改原因' },
609
- { key: 'writeResult', prefixes: ['Write result:', '写入结果:'], en: 'Write result', zh: '写入结果' },
610
- { key: 'undo', prefixes: ['Undo:', '可撤销:'], en: 'Undo', zh: '可撤销' },
611
- { key: 'nextStep', prefixes: ['Next:', '下一步:'], en: 'Next', zh: '下一步' }
612
- ];
613
-
614
- // Splits a flat completion-report string (formatHumanReport output) into the
615
- // answer body and the demoted meta rows. Only single-line sections whose head
616
- // matches a known status label are demoted, so a multi-paragraph conclusion
617
- // that happens to contain "Next: …" prose stays in the body.
618
- function splitFlatCompletionReport(text) {
619
- const raw = typeof text === 'string' ? text : '';
620
- if (!raw.trim()) {
621
- return { body: raw, meta: [] };
622
- }
623
- const bodySections = [];
624
- const meta = [];
625
- for (const section of raw.split(/\n{2,}/)) {
626
- const trimmed = section.trim();
627
- if (!trimmed) continue;
628
- const entry = trimmed.includes('\n')
629
- ? null
630
- : FLAT_REPORT_STATUS_SECTIONS.find(item => item.prefixes.some(prefix => trimmed.startsWith(prefix)));
631
- if (entry) {
632
- const prefix = entry.prefixes.find(p => trimmed.startsWith(p));
633
- const value = trimmed.slice(prefix.length).trim();
634
- if (value) {
635
- meta.push({ key: entry.key, label: tx(entry.en, entry.zh), value });
636
- continue;
637
- }
638
- }
639
- bodySections.push(trimmed);
640
- }
641
- return { body: bodySections.join('\n\n'), meta };
642
- }
586
+ // The result presenter owns parsing and current lifecycle metadata.
587
+ const splitFlatCompletionReport = text => RunResultActions.splitFlatCompletionReport(text, tx);
588
+ const projectCompletionMeta = (meta, run) => RunResultActions.projectCompletionMeta(meta, run, {
589
+ tx, trackedChangeInFlight, isTrackedChangeLifecycleRun, projectRunSettlement
590
+ });
643
591
 
644
- // Renders the demoted run-metadata block (Why nothing changed / Write result /
645
- // Undo / Next) beneath the answer. Shared by the structured and flat-fallback
646
- // render paths so both demote identically.
647
- function appendCompletionMetaBlock(report, meta) {
592
+ // The user's own open/closed choice per run survives card re-renders.
593
+ const metaOpenChoices = new Map();
594
+
595
+ // Renders the run-metadata rows (Why nothing changed / Write result / Undo /
596
+ // Next) behind a one-line summary beneath the answer. Shared by the
597
+ // structured and flat-fallback render paths so both demote identically.
598
+ function appendCompletionMetaBlock(report, meta, run) {
648
599
  if (!Array.isArray(meta) || !meta.length) {
649
600
  return;
650
601
  }
602
+ const rows = projectCompletionMeta(meta, run).filter(row => row?.label && row.value)
603
+ .map(row => ({ ...row, shown: failureNotice?.formatMetaValue(report, row) ?? row.value }));
604
+ if (!rows.length) return;
605
+ const summary = RunResultActions.summarizeCompletionMeta(rows, run, {
606
+ tx, failed: report.dataset.status === 'failed', unconfirmed: rows.some(row => row.shown !== row.value)
607
+ });
651
608
  const metaBlock = document.createElement('dl');
652
609
  metaBlock.className = 'run-final-answer__meta';
653
- for (const row of meta) {
654
- if (!row || !row.label || !row.value) continue;
610
+ metaBlock.id = `codex-run-meta-${String(run?.id || 'report').replace(/[^a-zA-Z0-9_-]/g, '-')}`;
611
+ for (const row of rows) {
655
612
  const dt = document.createElement('dt');
656
613
  dt.className = 'run-final-answer__meta-label';
657
614
  dt.textContent = row.label;
658
615
  if (row.key) dt.dataset.metaKey = row.key;
659
616
  const dd = document.createElement('dd');
660
617
  dd.className = 'run-final-answer__meta-value';
661
- dd.textContent = failureNotice?.formatMetaValue(report, row) ?? row.value;
618
+ dd.textContent = row.shown;
619
+ if (summary.warnKeys.has(row.key)) dt.dataset.tone = dd.dataset.tone = 'warn';
662
620
  metaBlock.append(dt, dd);
663
621
  }
664
- if (metaBlock.children.length) {
665
- report.append(metaBlock);
666
- }
622
+ const facts = document.createElement('div');
623
+ facts.className = 'run-final-answer__facts';
624
+ const toggle = document.createElement('button');
625
+ toggle.type = 'button';
626
+ toggle.className = 'run-final-answer__facts-sum';
627
+ toggle.setAttribute('aria-controls', metaBlock.id);
628
+ summary.facts.forEach((fact, index) => {
629
+ if (index) toggle.append(Object.assign(document.createElement('span'), { className: 'run-final-answer__facts-sep', textContent: '·' }));
630
+ const item = Object.assign(document.createElement('span'), { className: 'run-final-answer__fact', textContent: fact.text });
631
+ if (fact.tone) item.dataset.tone = fact.tone;
632
+ item.dataset.fact = fact.key;
633
+ toggle.append(item);
634
+ });
635
+ const more = Object.assign(document.createElement('span'), { className: 'run-final-answer__facts-more' });
636
+ toggle.append(Object.assign(document.createElement('span'), { className: 'run-final-answer__facts-sep', textContent: '·' }), more);
637
+ const setOpen = open => {
638
+ facts.dataset.open = String(open);
639
+ metaBlock.hidden = !open;
640
+ toggle.setAttribute('aria-expanded', String(open));
641
+ more.innerHTML = `${open ? tx('Hide', '收起') : tx('Details', '详情')}<svg class="codex-glyph" viewBox="0 0 16 16" aria-hidden="true" focusable="false"><path d="m6 4 4 4-4 4"/></svg>`;
642
+ };
643
+ setOpen(metaOpenChoices.get(run?.id) ?? summary.open);
644
+ toggle.addEventListener('click', event => {
645
+ event.stopPropagation();
646
+ const open = facts.dataset.open !== 'true';
647
+ if (run?.id) metaOpenChoices.set(run.id, open);
648
+ setOpen(open);
649
+ });
650
+ facts.append(toggle, metaBlock);
651
+ report.append(facts);
667
652
  }
668
653
 
669
654
  function renderCompletionReport(input, run) {
@@ -724,7 +709,7 @@
724
709
  main.className = 'run-final-answer';
725
710
  const mainSections = [];
726
711
  if (structured.conclusion) {
727
- mainSections.push(formatConclusionMarkdown(structured.conclusion));
712
+ mainSections.push(String(structured.conclusion));
728
713
  }
729
714
  if (structured.body) {
730
715
  mainSections.push(structured.body);
@@ -736,7 +721,7 @@
736
721
  }
737
722
 
738
723
  failureNotice?.append(report, event, run);
739
- appendCompletionMetaBlock(report, structured.meta);
724
+ appendCompletionMetaBlock(report, structured.meta, run);
740
725
  appendCompileFix(report);
741
726
  appendRejectedRedo(report);
742
727
  appendRecoveryActionForFailure(report, event, run);
@@ -758,24 +743,11 @@
758
743
  appendCompileFix(report);
759
744
  appendRejectedRedo(report);
760
745
  failureNotice?.append(report, event, run);
761
- appendCompletionMetaBlock(report, split.meta);
746
+ appendCompletionMetaBlock(report, split.meta, run);
762
747
  appendRecoveryActionForFailure(report, event, run);
763
748
  return report;
764
749
  }
765
750
 
766
- function formatConclusionMarkdown(value) {
767
- const conclusion = String(value || '');
768
- const label = getLocale() === 'zh' ? '结论:' : 'Conclusion:';
769
- return hasLeadingMarkdownBlock(conclusion)
770
- ? `${label}\n${conclusion}`
771
- : `${label} ${conclusion}`;
772
- }
773
-
774
- function hasLeadingMarkdownBlock(value) {
775
- const firstLine = String(value || '').trimStart().split(/\r?\n/, 1)[0];
776
- return /^(?:#{1,6}\s+\S|```|~~~|(?:[-+*]|\d+[.)])\s+\S|\*\*[^*]+\*\*:?\s*$)/.test(firstLine);
777
- }
778
-
779
751
  // For failure codes that have an actionable recovery path the user can
780
752
  // invoke directly from the run card, append a button inside the completion
781
753
  // report. Today's only consumer is codex_project_locked → "Force-release
@@ -815,20 +787,24 @@
815
787
  return button;
816
788
  }
817
789
 
790
+ function appendEditAndResend(report, run, actionKey) {
791
+ const retry = buildRecoveryButton(actionKey,
792
+ tx('Edit & resend', '编辑后重发'),
793
+ tx('Put this run\u2019s task back into the composer so you can adjust and resend it.', '把本轮任务填回输入框,修改后可直接重发。'));
794
+ retry.addEventListener('click', clickEvent => {
795
+ clickEvent.stopPropagation();
796
+ refillComposerForRetry(run || null);
797
+ });
798
+ report.append(retry);
799
+ }
800
+
818
801
  function appendRecoveryActionForFailure(report, event, run) {
819
802
  const recovery = failureNotice?.prepareRecovery(report, { openFile: openProjectFileForFailure });
803
+ const failureCode = event?.failure?.code || '';
820
804
  if (recovery?.handled) return;
821
805
  report = recovery?.target || report;
822
- const failureCode = event?.failure?.code || '';
823
806
  if (RETRYABLE_FAILURE_CODES.has(failureCode) && typeof refillComposerForRetry === 'function') {
824
- const retry = buildRecoveryButton(failureCode,
825
- tx('Edit & resend', '编辑后重发'),
826
- tx('Put this run\u2019s task back into the composer so you can adjust and resend it.', '把本轮任务填回输入框,修改后可直接重发。'));
827
- retry.addEventListener('click', clickEvent => {
828
- clickEvent.stopPropagation();
829
- refillComposerForRetry(run || null);
830
- });
831
- report.append(retry);
807
+ appendEditAndResend(report, run, failureCode);
832
808
  return;
833
809
  }
834
810
  if (NATIVE_SETUP_FAILURE_CODES.has(failureCode) && typeof showNativeSetupGuidance === 'function') {
@@ -917,6 +893,47 @@
917
893
  return Array.isArray(run.undoTrackedChanges) && run.undoTrackedChanges.length > 0;
918
894
  }
919
895
 
896
+ function configureEditButton(root, run, options = {}) {
897
+ const existing = root.querySelector('[data-run-edit]');
898
+ if (!existing) return;
899
+ const button = existing.cloneNode(true);
900
+ existing.replaceWith(button);
901
+ const available = ['cancelled', 'rejected'].includes(run?.status)
902
+ && Boolean(String(run?.task || '').trim())
903
+ && typeof canEditRun === 'function' && canEditRun(run)
904
+ && typeof refillComposerForRetry === 'function';
905
+ button.hidden = !available;
906
+ if (!available) return;
907
+ button.disabled = typeof options.running === 'boolean'
908
+ ? options.running : Boolean(getCurrentRunView?.());
909
+ button.title = tx('Edit & resend', '编辑后重发');
910
+ button.setAttribute('aria-label', button.title);
911
+ button.innerHTML = '<svg viewBox="0 0 20 20" aria-hidden="true"><path d="m12.8 3.2 4 4M3.5 16.5l4.2-.9 9-9a1.7 1.7 0 0 0 0-2.4l-.9-.9a1.7 1.7 0 0 0-2.4 0l-9 9z"/></svg>';
912
+ button.addEventListener('click', event => {
913
+ event.stopPropagation();
914
+ if (getCurrentRunView?.()) return;
915
+ refillComposerForRetry(run);
916
+ });
917
+ }
918
+
919
+ function configureWritebackButton(root, run, options = {}) {
920
+ const existing = root.querySelector('[data-run-sync-retry]');
921
+ if (!existing) return;
922
+ const button = existing.cloneNode(true);
923
+ existing.replaceWith(button);
924
+ const count = run?.retryWriteback?.operations?.length || 0;
925
+ const available = !run?.forkSnapshot && (count || run?.saveCheck?.files?.length)
926
+ && run.undoStatus !== 'applied' && run.trackedChangeStatus !== 'rejected' && typeof retryWriteback === 'function';
927
+ button.hidden = !available;
928
+ if (!available) return;
929
+ button.disabled = typeof options.running === 'boolean' ? options.running : Boolean(getCurrentRunView?.());
930
+ button.title = count ? tx('Retry sync (' + count + ' files)', '重试同步(' + count + ' 个文件)')
931
+ : tx('Check save status', '检查保存状态');
932
+ button.setAttribute('aria-label', button.title);
933
+ button.innerHTML = '<svg viewBox="0 0 20 20" aria-hidden="true"><path d="M16.5 7A7 7 0 0 0 4 5L2 7m0-4v4h4M3.5 13A7 7 0 0 0 16 15l2-2m0 4v-4h-4"/></svg>';
934
+ button.addEventListener('click', event => { event.stopPropagation(); if (!getCurrentRunView?.()) void retryWriteback(run.id); });
935
+ }
936
+
920
937
  function configureUndoButton(root, run) {
921
938
  const existing = root.querySelector('[data-run-undo]');
922
939
  const button = existing.cloneNode(true);
@@ -960,12 +977,12 @@
960
977
  // same executable state as `pending`.
961
978
  function configureLifecycleUndoButton(button, run) {
962
979
  const status = run.trackedChangeStatus || '';
980
+ const inFlight = trackedChangeInFlight.get(run.id);
963
981
  const projection = projectRunSettlement(run);
964
982
  // §7 settlement matrix: needs_review keeps BOTH controls visible AND
965
983
  // actionable. Branch placed before the terminal branches so a
966
984
  // needs_review run is never treated as terminal.
967
985
  if (status === 'needs_review') {
968
- const inFlight = trackedChangeInFlight.get(run.id);
969
986
  button.hidden = false;
970
987
  button.disabled = !projection.canUndo || inFlight === 'reject' || inFlight === 'accept';
971
988
  button.textContent = tr('undoRun');
@@ -976,14 +993,14 @@
976
993
  });
977
994
  return;
978
995
  }
979
- if (status === 'rejected') {
996
+ if (status === 'rejected' && !inFlight) {
980
997
  button.hidden = false;
981
998
  button.disabled = true;
982
999
  button.textContent = tr('undoApplied');
983
1000
  button.title = tr('undoAppliedTitle');
984
1001
  return;
985
1002
  }
986
- if (status === 'accepted') {
1003
+ if (status === 'accepted' && !inFlight) {
987
1004
  // The run was accepted — terminal. Undo stays visible but greyed so the
988
1005
  // card shows both controls disabled, never removed.
989
1006
  button.hidden = false;
@@ -992,11 +1009,10 @@
992
1009
  button.title = tr('undoRunTitle');
993
1010
  return;
994
1011
  }
995
- if (status !== 'pending') {
1012
+ if (status !== 'pending' && !inFlight) {
996
1013
  button.hidden = true;
997
1014
  return;
998
1015
  }
999
- const inFlight = trackedChangeInFlight.get(run.id);
1000
1016
  button.hidden = false;
1001
1017
  button.disabled = !projection.canUndo || inFlight === 'reject' || inFlight === 'accept';
1002
1018
  button.textContent = tr('undoRun');
@@ -1029,17 +1045,21 @@
1029
1045
  }
1030
1046
 
1031
1047
  if (!isTrackedChangeLifecycleRun(run)) {
1032
- button.hidden = true;
1048
+ const captures = run.undoStatus !== 'applied' && Array.isArray(run.trackedChangeCaptures) ? run.trackedChangeCaptures.filter(c => c && c.state !== 'observed') : [];
1049
+ button.hidden = !captures.length; button.disabled = true;
1050
+ button.textContent = tr('runAcceptTracked');
1051
+ button.title = captures.length ? tx('Tracked-change ownership is unconfirmed. Check the reasons below.', '本轮留痕归属尚未确认,请先核对下方原因。')
1052
+ + '\n' + captures.map(c => c.path + ': ' + (c.reason || c.state) + (c.diagnostics?.sourceReason ? ' / ' + c.diagnostics.sourceReason : '')).join('\n') : tr('runAcceptTrackedTitle');
1033
1053
  return;
1034
1054
  }
1035
1055
 
1036
1056
  const status = run.trackedChangeStatus || '';
1057
+ const inFlight = trackedChangeInFlight.get(run.id);
1037
1058
  const projection = projectRunSettlement(run);
1038
1059
  // §7 settlement matrix: needs_review keeps BOTH controls visible AND
1039
1060
  // actionable. It remains an internal retryable proof state, while the
1040
1061
  // primary button label stays in the same executable state as `pending`.
1041
1062
  if (status === 'needs_review') {
1042
- const inFlight = trackedChangeInFlight.get(run.id);
1043
1063
  button.hidden = false;
1044
1064
  button.disabled = !projection.canAccept || inFlight === 'accept' || inFlight === 'reject';
1045
1065
  if (inFlight === 'accept') {
@@ -1052,14 +1072,14 @@
1052
1072
  wireAcceptInlineConfirm(button, run.id);
1053
1073
  return;
1054
1074
  }
1055
- if (status === 'accepted') {
1075
+ if (status === 'accepted' && !inFlight) {
1056
1076
  button.hidden = false;
1057
1077
  button.disabled = true;
1058
1078
  button.textContent = tr('runAcceptTrackedDone');
1059
1079
  button.title = tr('runAcceptTrackedDoneTitle');
1060
1080
  return;
1061
1081
  }
1062
- if (status === 'rejected') {
1082
+ if (status === 'rejected' && !inFlight) {
1063
1083
  // The run was rejected — terminal. Accept All stays visible but greyed so
1064
1084
  // the card shows both controls disabled, never removed.
1065
1085
  button.hidden = false;
@@ -1068,12 +1088,11 @@
1068
1088
  button.title = tr('runAcceptTrackedTitle');
1069
1089
  return;
1070
1090
  }
1071
- if (status !== 'pending') {
1091
+ if (status !== 'pending' && !inFlight) {
1072
1092
  button.hidden = true;
1073
1093
  return;
1074
1094
  }
1075
1095
 
1076
- const inFlight = trackedChangeInFlight.get(run.id);
1077
1096
  button.hidden = false;
1078
1097
  button.disabled = !projection.canAccept || inFlight === 'accept' || inFlight === 'reject';
1079
1098
  if (inFlight === 'accept') {
@@ -1127,13 +1146,22 @@
1127
1146
  const log = getPanel()?.querySelector('[data-log]');
1128
1147
  const existing = log?.querySelector(`[data-run-id="${cssEscape(runId)}"]`);
1129
1148
  const run = findRunRecord(runId);
1130
- if (!log || !existing || !run) {
1131
- return;
1149
+ if (!log || !existing || !run || displayRun(run) === run) {
1150
+ return false;
1132
1151
  }
1133
- existing.replaceWith(renderRunCard(run));
1152
+ const reading = scrollLayout?.snapshot(), open = existing.querySelector('[data-run-process]')?.open;
1153
+ const next = renderRunCard(run);
1154
+ const process = next.querySelector('[data-run-process]');
1155
+ if (process && typeof open === 'boolean') process.open = open;
1156
+ existing.replaceWith(next);
1157
+ if (reading) scrollLayout?.restore(reading);
1158
+ return true;
1134
1159
  }
1135
1160
 
1136
1161
  return {
1162
+ refreshResolvedUndo: refreshRunCard,
1163
+ refreshActivitySummary: activitySummary?.update,
1164
+ appendActivityDetail,
1137
1165
  resetAutoFollow,
1138
1166
  bindLogAutoFollow,
1139
1167
  bumpUnreadIfDetached,
@@ -1149,6 +1177,8 @@
1149
1177
  upsertStreamEvent,
1150
1178
  renderCompletionReport,
1151
1179
  isTrackedChangeLifecycleRun,
1180
+ configureEditButton,
1181
+ configureWritebackButton,
1152
1182
  configureUndoButton,
1153
1183
  configureAcceptButton
1154
1184
  };