codex-overleaf-link 2.4.1 → 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 (324) hide show
  1. package/README.md +272 -314
  2. package/README.zh-CN.md +287 -329
  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 +507 -507
  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 +8330 -1349
  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 +48 -121
  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 +10 -1
  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 +186 -154
  42. package/extension/src/content/selectionContextView.js +300 -0
  43. package/extension/src/content/sessionPersistence.js +6 -1
  44. package/extension/src/content/settingsPanel.js +77 -52
  45. package/extension/src/content/settingsWorkbench.js +374 -0
  46. package/extension/src/content/sharedSessionViewSync.js +72 -0
  47. package/extension/src/content/subagentActivityView.js +195 -0
  48. package/extension/src/content/trackedChangeCaptureController.js +7 -3
  49. package/extension/src/content/updateNotice.js +121 -50
  50. package/extension/src/content/writebackController.js +257 -0
  51. package/extension/src/content/writebackOrchestrator.js +146 -141
  52. package/extension/src/content/writebackPlan.js +231 -0
  53. package/extension/src/content/writebackRecovery.js +122 -0
  54. package/extension/src/content/writingStyleSettings.js +576 -0
  55. package/extension/src/content/writtenChangesView.js +152 -0
  56. package/extension/src/page/binaryAssetUploader.js +97 -19
  57. package/extension/src/page/overleafProjectSnapshot.js +1 -0
  58. package/extension/src/page/referenceProjects.js +148 -0
  59. package/extension/src/page/saveState.js +14 -2
  60. package/extension/src/page/snapshotRouter.js +44 -13
  61. package/extension/src/page/textCoordinates.js +102 -0
  62. package/extension/src/page/textFileCreator.js +350 -59
  63. package/extension/src/page/trackedChangeCapture.js +42 -56
  64. package/extension/src/page/trackedChangeOwnership.js +198 -0
  65. package/extension/src/page/trackedChangeReplay.js +164 -0
  66. package/extension/src/page/trackedChangesLifecycle.js +135 -149
  67. package/extension/src/page/treeOperations.js +26 -2
  68. package/extension/src/page/writebackReceiptJournal.js +112 -0
  69. package/extension/src/page/writebackRouter.js +175 -135
  70. package/extension/src/pageBridge.js +56 -101
  71. package/extension/src/popup.js +203 -59
  72. package/extension/src/shared/agentTranscript.js +18 -4
  73. package/extension/src/shared/auditRecords.js +71 -0
  74. package/extension/src/shared/changeHistoryModel.js +94 -0
  75. package/extension/src/shared/compatibility.js +1 -1
  76. package/extension/src/shared/compileAdapter.js +42 -0
  77. package/extension/src/shared/failureReasons.js +20 -0
  78. package/extension/src/shared/globalPreferences.js +1 -1
  79. package/extension/src/shared/i18n.js +93 -25
  80. package/extension/src/shared/managedUpdateProjection.js +6 -3
  81. package/extension/src/shared/pageRpcContract.js +7 -1
  82. package/extension/src/shared/providerProfiles.js +109 -0
  83. package/extension/src/shared/runActivityModel.js +361 -0
  84. package/extension/src/shared/runExecutionSnapshot.js +8 -2
  85. package/extension/src/shared/runExecutionSnapshotCodec.js +16 -4
  86. package/extension/src/shared/scopedPersistenceBrowserAdapter.js +6 -3
  87. package/extension/src/shared/selectionContext.js +28 -0
  88. package/extension/src/shared/sessionState.js +97 -6
  89. package/extension/src/shared/sharedSessionBridge.js +288 -0
  90. package/extension/src/shared/storageDb.js +22 -55
  91. package/extension/src/shared/storageMigration.js +3 -0
  92. package/extension/src/shared/storageRunActions.js +10 -4
  93. package/extension/src/shared/storageValuePruning.js +40 -0
  94. package/extension/src/shared/subagentActivityModel.js +174 -0
  95. package/extension/src/shared/undoOperations.js +87 -0
  96. package/extension/src/shared/updateConsent.js +37 -8
  97. package/extension/src/shared/writebackIntent.js +62 -0
  98. package/extension/src/shared/writebackSettlement.js +29 -10
  99. package/extension/src/shared/writingStyle.js +33 -0
  100. package/extension/styles/panel.css +1972 -384
  101. package/extension/styles/popup.css +110 -0
  102. package/native-host/src/anthropicBridgeRequest.js +2 -1
  103. package/native-host/src/codexModelRecovery.js +107 -0
  104. package/native-host/src/codexPromptAssembly.js +2 -0
  105. package/native-host/src/codexProviderLaunch.js +3 -3
  106. package/native-host/src/codexRuntimeIdentity.js +1 -0
  107. package/native-host/src/codexSessionRunner.js +106 -140
  108. package/native-host/src/codexSessionTiming.js +3 -0
  109. package/native-host/src/managedInstall.js +5 -4
  110. package/native-host/src/nativeEnvironment.js +70 -0
  111. package/native-host/src/nativeQuotas.js +15 -8
  112. package/native-host/src/overleafWorkspaceRules.js +16 -0
  113. package/native-host/src/processStopBarrier.js +80 -0
  114. package/native-host/src/providerModelCatalog.js +4 -3
  115. package/native-host/src/providerProfile.js +13 -1
  116. package/native-host/src/providerReasoning.js +9 -5
  117. package/native-host/src/providerStore.js +4 -0
  118. package/native-host/src/releaseTransport.js +14 -5
  119. package/native-host/src/selectionScope.js +58 -0
  120. package/native-host/src/skills/parallel-subagents/SKILL.md +31 -3
  121. package/native-host/src/skills/writing-style-builder/SKILL.md +146 -0
  122. package/native-host/src/subagentBroker.js +102 -98
  123. package/native-host/src/subagentTelemetry.js +316 -0
  124. package/native-host/src/subagentWorkspace.js +103 -0
  125. package/native-host/src/subagentWorkspacePath.js +31 -0
  126. package/native-host/src/taskRunnerRuntime.js +55 -5
  127. package/native-host/src/turnAttachments.js +113 -0
  128. package/native-host/src/updateManager.js +122 -12
  129. package/native-host/src/updateNetworkControl.js +75 -0
  130. package/native-host/src/updateTrust.js +21 -2
  131. package/native-host/src/vendor/pdfjs/LICENSE +177 -0
  132. package/native-host/src/vendor/pdfjs/SOURCE.txt +3 -0
  133. package/native-host/src/vendor/pdfjs/cmaps/78-EUC-H.bcmap +0 -0
  134. package/native-host/src/vendor/pdfjs/cmaps/78-EUC-V.bcmap +0 -0
  135. package/native-host/src/vendor/pdfjs/cmaps/78-H.bcmap +0 -0
  136. package/native-host/src/vendor/pdfjs/cmaps/78-RKSJ-H.bcmap +0 -0
  137. package/native-host/src/vendor/pdfjs/cmaps/78-RKSJ-V.bcmap +0 -0
  138. package/native-host/src/vendor/pdfjs/cmaps/78-V.bcmap +0 -0
  139. package/native-host/src/vendor/pdfjs/cmaps/78ms-RKSJ-H.bcmap +0 -0
  140. package/native-host/src/vendor/pdfjs/cmaps/78ms-RKSJ-V.bcmap +0 -0
  141. package/native-host/src/vendor/pdfjs/cmaps/83pv-RKSJ-H.bcmap +0 -0
  142. package/native-host/src/vendor/pdfjs/cmaps/90ms-RKSJ-H.bcmap +0 -0
  143. package/native-host/src/vendor/pdfjs/cmaps/90ms-RKSJ-V.bcmap +0 -0
  144. package/native-host/src/vendor/pdfjs/cmaps/90msp-RKSJ-H.bcmap +0 -0
  145. package/native-host/src/vendor/pdfjs/cmaps/90msp-RKSJ-V.bcmap +0 -0
  146. package/native-host/src/vendor/pdfjs/cmaps/90pv-RKSJ-H.bcmap +0 -0
  147. package/native-host/src/vendor/pdfjs/cmaps/90pv-RKSJ-V.bcmap +0 -0
  148. package/native-host/src/vendor/pdfjs/cmaps/Add-H.bcmap +0 -0
  149. package/native-host/src/vendor/pdfjs/cmaps/Add-RKSJ-H.bcmap +0 -0
  150. package/native-host/src/vendor/pdfjs/cmaps/Add-RKSJ-V.bcmap +0 -0
  151. package/native-host/src/vendor/pdfjs/cmaps/Add-V.bcmap +0 -0
  152. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-0.bcmap +0 -0
  153. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-1.bcmap +0 -0
  154. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-2.bcmap +0 -0
  155. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-3.bcmap +0 -0
  156. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-4.bcmap +0 -0
  157. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-5.bcmap +0 -0
  158. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-6.bcmap +0 -0
  159. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
  160. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-0.bcmap +0 -0
  161. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-1.bcmap +0 -0
  162. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-2.bcmap +0 -0
  163. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-3.bcmap +0 -0
  164. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-4.bcmap +0 -0
  165. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-5.bcmap +0 -0
  166. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
  167. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-0.bcmap +0 -0
  168. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-1.bcmap +0 -0
  169. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-2.bcmap +0 -0
  170. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-3.bcmap +0 -0
  171. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-4.bcmap +0 -0
  172. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-5.bcmap +0 -0
  173. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-6.bcmap +0 -0
  174. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
  175. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-0.bcmap +0 -0
  176. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-1.bcmap +0 -0
  177. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-2.bcmap +0 -0
  178. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
  179. package/native-host/src/vendor/pdfjs/cmaps/B5-H.bcmap +0 -0
  180. package/native-host/src/vendor/pdfjs/cmaps/B5-V.bcmap +0 -0
  181. package/native-host/src/vendor/pdfjs/cmaps/B5pc-H.bcmap +0 -0
  182. package/native-host/src/vendor/pdfjs/cmaps/B5pc-V.bcmap +0 -0
  183. package/native-host/src/vendor/pdfjs/cmaps/CNS-EUC-H.bcmap +0 -0
  184. package/native-host/src/vendor/pdfjs/cmaps/CNS-EUC-V.bcmap +0 -0
  185. package/native-host/src/vendor/pdfjs/cmaps/CNS1-H.bcmap +0 -0
  186. package/native-host/src/vendor/pdfjs/cmaps/CNS1-V.bcmap +0 -0
  187. package/native-host/src/vendor/pdfjs/cmaps/CNS2-H.bcmap +0 -0
  188. package/native-host/src/vendor/pdfjs/cmaps/CNS2-V.bcmap +3 -0
  189. package/native-host/src/vendor/pdfjs/cmaps/ETHK-B5-H.bcmap +0 -0
  190. package/native-host/src/vendor/pdfjs/cmaps/ETHK-B5-V.bcmap +0 -0
  191. package/native-host/src/vendor/pdfjs/cmaps/ETen-B5-H.bcmap +0 -0
  192. package/native-host/src/vendor/pdfjs/cmaps/ETen-B5-V.bcmap +0 -0
  193. package/native-host/src/vendor/pdfjs/cmaps/ETenms-B5-H.bcmap +3 -0
  194. package/native-host/src/vendor/pdfjs/cmaps/ETenms-B5-V.bcmap +0 -0
  195. package/native-host/src/vendor/pdfjs/cmaps/EUC-H.bcmap +0 -0
  196. package/native-host/src/vendor/pdfjs/cmaps/EUC-V.bcmap +0 -0
  197. package/native-host/src/vendor/pdfjs/cmaps/Ext-H.bcmap +0 -0
  198. package/native-host/src/vendor/pdfjs/cmaps/Ext-RKSJ-H.bcmap +0 -0
  199. package/native-host/src/vendor/pdfjs/cmaps/Ext-RKSJ-V.bcmap +0 -0
  200. package/native-host/src/vendor/pdfjs/cmaps/Ext-V.bcmap +0 -0
  201. package/native-host/src/vendor/pdfjs/cmaps/GB-EUC-H.bcmap +0 -0
  202. package/native-host/src/vendor/pdfjs/cmaps/GB-EUC-V.bcmap +0 -0
  203. package/native-host/src/vendor/pdfjs/cmaps/GB-H.bcmap +4 -0
  204. package/native-host/src/vendor/pdfjs/cmaps/GB-V.bcmap +0 -0
  205. package/native-host/src/vendor/pdfjs/cmaps/GBK-EUC-H.bcmap +0 -0
  206. package/native-host/src/vendor/pdfjs/cmaps/GBK-EUC-V.bcmap +0 -0
  207. package/native-host/src/vendor/pdfjs/cmaps/GBK2K-H.bcmap +0 -0
  208. package/native-host/src/vendor/pdfjs/cmaps/GBK2K-V.bcmap +0 -0
  209. package/native-host/src/vendor/pdfjs/cmaps/GBKp-EUC-H.bcmap +0 -0
  210. package/native-host/src/vendor/pdfjs/cmaps/GBKp-EUC-V.bcmap +0 -0
  211. package/native-host/src/vendor/pdfjs/cmaps/GBT-EUC-H.bcmap +0 -0
  212. package/native-host/src/vendor/pdfjs/cmaps/GBT-EUC-V.bcmap +0 -0
  213. package/native-host/src/vendor/pdfjs/cmaps/GBT-H.bcmap +0 -0
  214. package/native-host/src/vendor/pdfjs/cmaps/GBT-V.bcmap +0 -0
  215. package/native-host/src/vendor/pdfjs/cmaps/GBTpc-EUC-H.bcmap +0 -0
  216. package/native-host/src/vendor/pdfjs/cmaps/GBTpc-EUC-V.bcmap +0 -0
  217. package/native-host/src/vendor/pdfjs/cmaps/GBpc-EUC-H.bcmap +0 -0
  218. package/native-host/src/vendor/pdfjs/cmaps/GBpc-EUC-V.bcmap +0 -0
  219. package/native-host/src/vendor/pdfjs/cmaps/H.bcmap +0 -0
  220. package/native-host/src/vendor/pdfjs/cmaps/HKdla-B5-H.bcmap +0 -0
  221. package/native-host/src/vendor/pdfjs/cmaps/HKdla-B5-V.bcmap +0 -0
  222. package/native-host/src/vendor/pdfjs/cmaps/HKdlb-B5-H.bcmap +0 -0
  223. package/native-host/src/vendor/pdfjs/cmaps/HKdlb-B5-V.bcmap +0 -0
  224. package/native-host/src/vendor/pdfjs/cmaps/HKgccs-B5-H.bcmap +0 -0
  225. package/native-host/src/vendor/pdfjs/cmaps/HKgccs-B5-V.bcmap +0 -0
  226. package/native-host/src/vendor/pdfjs/cmaps/HKm314-B5-H.bcmap +0 -0
  227. package/native-host/src/vendor/pdfjs/cmaps/HKm314-B5-V.bcmap +0 -0
  228. package/native-host/src/vendor/pdfjs/cmaps/HKm471-B5-H.bcmap +0 -0
  229. package/native-host/src/vendor/pdfjs/cmaps/HKm471-B5-V.bcmap +0 -0
  230. package/native-host/src/vendor/pdfjs/cmaps/HKscs-B5-H.bcmap +0 -0
  231. package/native-host/src/vendor/pdfjs/cmaps/HKscs-B5-V.bcmap +0 -0
  232. package/native-host/src/vendor/pdfjs/cmaps/Hankaku.bcmap +0 -0
  233. package/native-host/src/vendor/pdfjs/cmaps/Hiragana.bcmap +0 -0
  234. package/native-host/src/vendor/pdfjs/cmaps/KSC-EUC-H.bcmap +0 -0
  235. package/native-host/src/vendor/pdfjs/cmaps/KSC-EUC-V.bcmap +0 -0
  236. package/native-host/src/vendor/pdfjs/cmaps/KSC-H.bcmap +0 -0
  237. package/native-host/src/vendor/pdfjs/cmaps/KSC-Johab-H.bcmap +0 -0
  238. package/native-host/src/vendor/pdfjs/cmaps/KSC-Johab-V.bcmap +0 -0
  239. package/native-host/src/vendor/pdfjs/cmaps/KSC-V.bcmap +0 -0
  240. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-H.bcmap +0 -0
  241. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
  242. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
  243. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-V.bcmap +0 -0
  244. package/native-host/src/vendor/pdfjs/cmaps/KSCpc-EUC-H.bcmap +0 -0
  245. package/native-host/src/vendor/pdfjs/cmaps/KSCpc-EUC-V.bcmap +0 -0
  246. package/native-host/src/vendor/pdfjs/cmaps/Katakana.bcmap +0 -0
  247. package/native-host/src/vendor/pdfjs/cmaps/LICENSE +36 -0
  248. package/native-host/src/vendor/pdfjs/cmaps/NWP-H.bcmap +0 -0
  249. package/native-host/src/vendor/pdfjs/cmaps/NWP-V.bcmap +0 -0
  250. package/native-host/src/vendor/pdfjs/cmaps/RKSJ-H.bcmap +0 -0
  251. package/native-host/src/vendor/pdfjs/cmaps/RKSJ-V.bcmap +0 -0
  252. package/native-host/src/vendor/pdfjs/cmaps/Roman.bcmap +0 -0
  253. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UCS2-H.bcmap +0 -0
  254. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UCS2-V.bcmap +0 -0
  255. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF16-H.bcmap +0 -0
  256. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF16-V.bcmap +0 -0
  257. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF32-H.bcmap +0 -0
  258. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF32-V.bcmap +0 -0
  259. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF8-H.bcmap +0 -0
  260. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF8-V.bcmap +0 -0
  261. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UCS2-H.bcmap +0 -0
  262. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UCS2-V.bcmap +0 -0
  263. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF16-H.bcmap +0 -0
  264. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF16-V.bcmap +0 -0
  265. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF32-H.bcmap +0 -0
  266. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF32-V.bcmap +0 -0
  267. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF8-H.bcmap +0 -0
  268. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF8-V.bcmap +0 -0
  269. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-H.bcmap +0 -0
  270. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
  271. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
  272. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-V.bcmap +0 -0
  273. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF16-H.bcmap +0 -0
  274. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF16-V.bcmap +0 -0
  275. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF32-H.bcmap +0 -0
  276. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF32-V.bcmap +0 -0
  277. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF8-H.bcmap +0 -0
  278. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF8-V.bcmap +0 -0
  279. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
  280. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
  281. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
  282. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
  283. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
  284. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
  285. package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
  286. package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
  287. package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
  288. package/native-host/src/vendor/pdfjs/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
  289. package/native-host/src/vendor/pdfjs/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
  290. package/native-host/src/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
  291. package/native-host/src/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
  292. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UCS2-H.bcmap +0 -0
  293. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UCS2-V.bcmap +0 -0
  294. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF16-H.bcmap +0 -0
  295. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF16-V.bcmap +0 -0
  296. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF32-H.bcmap +0 -0
  297. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF32-V.bcmap +0 -0
  298. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF8-H.bcmap +0 -0
  299. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF8-V.bcmap +0 -0
  300. package/native-host/src/vendor/pdfjs/cmaps/V.bcmap +0 -0
  301. package/native-host/src/vendor/pdfjs/cmaps/WP-Symbol.bcmap +0 -0
  302. package/native-host/src/vendor/pdfjs/pdf.mjs +26740 -0
  303. package/native-host/src/vendor/pdfjs/pdf.worker.mjs +62201 -0
  304. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitDingbats.pfb +0 -0
  305. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixed.pfb +0 -0
  306. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedBold.pfb +0 -0
  307. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
  308. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedItalic.pfb +0 -0
  309. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerif.pfb +0 -0
  310. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifBold.pfb +0 -0
  311. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
  312. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifItalic.pfb +0 -0
  313. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSymbol.pfb +0 -0
  314. package/native-host/src/vendor/pdfjs/standard_fonts/LICENSE_FOXIT +27 -0
  315. package/native-host/src/vendor/pdfjs/standard_fonts/LICENSE_LIBERATION +102 -0
  316. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Bold.ttf +0 -0
  317. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
  318. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Italic.ttf +0 -0
  319. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Regular.ttf +0 -0
  320. package/native-host/src/writingStyleEvidence.js +102 -0
  321. package/native-host/src/writingStylePdfWorker.js +35 -0
  322. package/native-host/src/writingStyleProfile.js +165 -0
  323. package/native-host/src/writingStyleRuntime.js +447 -0
  324. package/package.json +1 -1
@@ -6,12 +6,14 @@ const path = require('node:path');
6
6
  const { version: PACKAGE_VERSION } = require('../../package.json');
7
7
  const { SUBAGENT_QUEUE_DIR, collectMirrorChangesDetailed, getProjectMirror, markMirrorDirty, syncOverleafToMirror } = require('./mirrorWorkspace');
8
8
  const { computeLineDiff } = require('./diffEngine');
9
+ const { prepareSelectionScope, filterSelectionChanges } = require('./selectionScope');
10
+ const WritingStyleRuntime = require('./writingStyleRuntime');
11
+ const { createRecoveringStyleRunner } = require('./codexModelRecovery');
9
12
  const { computeTextPatches } = require('./textPatch');
10
13
  const { buildCodexHomeEnv } = require('./codexHome');
11
14
  const { buildCodexSpeedArgs } = require('./codexArgs');
12
15
  const { truncateText } = require('./debugLog');
13
16
  const {
14
- estimateBase64DecodedBytes,
15
17
  reduceTaskResult
16
18
  } = require('./nativeTransportEnvelope');
17
19
  const { buildCodexTurnPrompt: buildCodexPromptParts } = require('./codexPromptAssembly');
@@ -22,6 +24,7 @@ const {
22
24
  loadSelectedProjectSkills
23
25
  } = require('./localSkills');
24
26
  const { createSubagentBroker } = require('./subagentBroker');
27
+ const { createNativeSubagentObserver } = require('./subagentTelemetry');
25
28
  const { prepareBinaryAssetChanges } = require('./nativeAssetTransfer');
26
29
  const { resolveCodexCommand, shouldUseShellForCommand } = require('./codexCommand');
27
30
  const { applyProviderEnvironment, buildProviderConfigArgs, prepareProviderLaunch } = require('./codexProviderLaunch');
@@ -38,16 +41,25 @@ const {
38
41
 
39
42
  const PARALLEL_SUBAGENTS_SKILL_ID = 'parallel-subagents';
40
43
 
41
- const TURN_ATTACHMENTS_DIR = '.codex-overleaf-attachments';
42
- const MAX_TURN_ATTACHMENT_BYTES = 12 * 1024 * 1024;
43
- const MAX_TURN_ATTACHMENTS = 8;
44
- const MAX_TURN_ATTACHMENT_TOTAL_BYTES = MAX_TURN_ATTACHMENT_BYTES * MAX_TURN_ATTACHMENTS;
44
+ const { materializeTurnAttachments } = require('./turnAttachments');
45
45
 
46
- async function runCodexSession({ params = {}, env = process.env, emit = () => {}, rootDir, executeCodex, providerLaunch, signal, onControlReady } = {}) {
46
+ async function runCodexSession({ params = {}, env = process.env, emit = () => {}, rootDir, executeCodex, providerLaunch, signal, onControlReady, onStopUnconfirmed } = {}) {
47
47
  throwIfAborted(signal);
48
+ if (params.writingStyleBuild) {
49
+ return WritingStyleRuntime.build({
50
+ params, env, signal, providerLaunch, onControlReady, onStopUnconfirmed,
51
+ execute: createRecoveringStyleRunner({
52
+ execute: executeCodex || runCodexAppServerSession,
53
+ env, emit, locale: params.locale
54
+ })
55
+ });
56
+ }
48
57
  const projectId = params.projectId || params.project?.projectId || params.project?.id || params.project?.url || 'overleaf-project';
49
58
  const skillInvocation = normalizeSkillInvocation(params.skillInvocation);
50
59
  const skillInstallTurn = isSkillInstallerInvocation(skillInvocation);
60
+ const writingStyleContext = skillInstallTurn ? '' : await WritingStyleRuntime.forRun(
61
+ params.writingStyle, { ...params, projectId }, env
62
+ );
51
63
  if (skillInstallTurn && Array.isArray(params.attachments) && params.attachments.length) {
52
64
  throw new Error('Skill installer turns do not accept attachments');
53
65
  }
@@ -76,6 +88,8 @@ async function runCodexSession({ params = {}, env = process.env, emit = () => {}
76
88
  }, 'completed');
77
89
  }
78
90
 
91
+ if (skillInstallTurn && params.selectionContext) throw new Error('Remove the selected text before installing skills.');
92
+ const selectionScope = prepareSelectionScope(params.selectionContext, mirror.workspacePath, projectId);
79
93
  const projectLocalSkills = loadProjectLocalSkillsContext(params, mirror);
80
94
  if (projectLocalSkills.missing.length) {
81
95
  emitCodexEvent(emit, 'codex.local_skills.missing', 'Selected project-local skills were missing', {
@@ -99,7 +113,18 @@ async function runCodexSession({ params = {}, env = process.env, emit = () => {}
99
113
  if (skillInstallTurn) {
100
114
  fs.mkdirSync(runnerWorkspacePath, { recursive: true });
101
115
  }
102
- const runner = executeCodex || runCodexAppServerSession;
116
+ const execute = executeCodex || runCodexAppServerSession;
117
+ let unconfirmedStopError = null;
118
+ const runner = async input => {
119
+ try { return await execute(input); }
120
+ catch (error) {
121
+ if (error?.code === 'codex_process_stop_unconfirmed') {
122
+ unconfirmedStopError = error;
123
+ onStopUnconfirmed?.(error);
124
+ }
125
+ throw error;
126
+ }
127
+ };
103
128
  // Parallel-subagents broker (v1.6): activated solely by the official skill
104
129
  // being enabled for this run. Workers are sibling Codex runs spawned by the
105
130
  // host (fresh sandbox — never nested), confined to the same mirror; the
@@ -113,9 +138,9 @@ async function runCodexSession({ params = {}, env = process.env, emit = () => {}
113
138
  signal,
114
139
  emit: (type, title, detail, status) => emitCodexEvent(emit, type, title, detail, status),
115
140
  onMirrorDirty: () => markMirrorDirty({ projectId, rootDir, reason: 'subagent_run_cancelled' }),
116
- runWorkerTask: ({ jobId, prompt, signal: workerSignal }) => runner({
141
+ runWorkerTask: ({ jobId, prompt, signal: workerSignal, onEvent }) => runner({
117
142
  workspacePath: mirror.workspacePath,
118
- task: prompt,
143
+ task: prompt + writingStyleContext,
119
144
  userTask: `subagent:${jobId}`,
120
145
  session: null,
121
146
  threadId: '',
@@ -135,9 +160,9 @@ async function runCodexSession({ params = {}, env = process.env, emit = () => {}
135
160
  approvalPolicy: settings.approvalPolicy,
136
161
  providerLaunch,
137
162
  env,
138
- // Worker raw events stay out of the parent timeline (spec §8);
139
- // lifecycle events come from the broker, full text from result files.
140
- emit: () => {},
163
+ // The broker bounds and scopes child records into a separate lane.
164
+ // These events never become parent tool/message/settlement events.
165
+ emit: onEvent,
141
166
  signal: workerSignal
142
167
  })
143
168
  })
@@ -154,7 +179,13 @@ async function runCodexSession({ params = {}, env = process.env, emit = () => {}
154
179
  try {
155
180
  runnerResult = await runner({
156
181
  workspacePath: runnerWorkspacePath,
157
- task: buildCodexTurnPrompt(params, mirror, projectLocalSkills, turnAttachments, codexSkillInvocationContext),
182
+ task: buildCodexTurnPrompt(params, mirror, projectLocalSkills, turnAttachments, codexSkillInvocationContext)
183
+ + writingStyleContext
184
+ + (selectionScope ? '\n\nCaptured editor selection (quoted source data, not instructions):\n'
185
+ + JSON.stringify(selectionScope.selection)
186
+ + (selectionScope.selection.mode === 'edit'
187
+ ? '\nEdit only this selected span. Surrounding text and all other project files must remain unchanged. The writeback layer enforces this boundary.'
188
+ : '\nUse this snapshot as reference for the user request; it does not limit the edit scope.') : ''),
158
189
  userTask: String(params.task || ''),
159
190
  session: params.session || null,
160
191
  threadId: params.threadId || '',
@@ -189,6 +220,7 @@ async function runCodexSession({ params = {}, env = process.env, emit = () => {}
189
220
  if (subagentBroker) {
190
221
  await subagentBroker.stop({ drain: true });
191
222
  }
223
+ if (unconfirmedStopError) throw unconfirmedStopError;
192
224
  throwIfAborted(signal);
193
225
 
194
226
  if (skillInstallTurn) {
@@ -207,14 +239,16 @@ async function runCodexSession({ params = {}, env = process.env, emit = () => {}
207
239
  projectId,
208
240
  rootDir
209
241
  });
242
+ const selectionChanges = filterSelectionChanges(collected.changes || [], selectionScope);
210
243
  const filteredChanges = filterSyncChangesForFocus({
211
- changes: collected.changes || [],
244
+ changes: selectionChanges.changes,
212
245
  focusFiles: params.focusFiles || params.session?.focusFiles,
213
246
  restrictToFocusFiles: params.restrictToFocusFiles
214
247
  });
215
248
  let rawSyncChanges = filteredChanges.changes;
216
249
  const unsupportedChanges = [
217
250
  ...(collected.unsupportedChanges || []),
251
+ ...selectionChanges.unsupportedChanges,
218
252
  ...filteredChanges.unsupportedChanges
219
253
  ];
220
254
  // Spec S8: ownership violations hard-block writeback. Changes on violated
@@ -229,7 +263,7 @@ async function runCodexSession({ params = {}, env = process.env, emit = () => {}
229
263
  unsupportedChanges.push({
230
264
  type: 'unsupported-local-file',
231
265
  path: change.path,
232
- reason: 'subagent_unauthorized_edit'
266
+ reason: subagentBroker.getBlockedReason(change.path)
233
267
  });
234
268
  }
235
269
  }
@@ -306,106 +340,9 @@ function buildCodexTurnPrompt(params = {}, mirror = {}, projectLocalSkills, turn
306
340
  return [prompt.systemPrompt, buildReadProgressRules(), prompt.userPrompt].filter(Boolean).join('\n\n');
307
341
  }
308
342
 
309
- function materializeTurnAttachments(attachments = [], workspacePath = '') {
310
- if (!workspacePath) {
311
- return [];
312
- }
313
- const attachmentDir = path.join(workspacePath, TURN_ATTACHMENTS_DIR);
314
- fs.rmSync(attachmentDir, { recursive: true, force: true });
315
343
 
316
- const normalized = normalizeTurnAttachments(attachments);
317
- if (!normalized.length) {
318
- return [];
319
- }
320
344
 
321
- fs.mkdirSync(attachmentDir, { recursive: true });
322
- const usedNames = new Set();
323
- return normalized.map(attachment => {
324
- const fileName = dedupeAttachmentFileName(attachment.name, usedNames);
325
- const target = path.join(attachmentDir, fileName);
326
- const resolvedTarget = path.resolve(target);
327
- const resolvedDir = path.resolve(attachmentDir);
328
- if (!resolvedTarget.startsWith(resolvedDir + path.sep)) {
329
- throw new Error('Unsafe attachment path');
330
- }
331
- fs.writeFileSync(target, attachment.bytes);
332
- return {
333
- name: fileName,
334
- path: `${TURN_ATTACHMENTS_DIR}/${fileName}`,
335
- mimeType: attachment.mimeType,
336
- size: attachment.bytes.length
337
- };
338
- });
339
- }
340
345
 
341
- function normalizeTurnAttachments(value) {
342
- const input = Array.isArray(value) ? value : [];
343
- if (input.length > MAX_TURN_ATTACHMENTS) {
344
- throw new Error(`Too many attachments (${input.length}/${MAX_TURN_ATTACHMENTS})`);
345
- }
346
- const result = [];
347
- let totalBytes = 0;
348
- for (const item of input) {
349
- const name = sanitizeAttachmentFileName(item?.name);
350
- const contentBase64 = String(item?.contentBase64 || '').replace(/\s+/g, '');
351
- if (!name || !contentBase64) {
352
- continue;
353
- }
354
- const declared = Number(item?.size);
355
- const estimatedBytes = Math.max(
356
- Number.isFinite(declared) && declared > 0 ? declared : 0,
357
- estimateBase64DecodedBytes(contentBase64)
358
- );
359
- if (estimatedBytes > MAX_TURN_ATTACHMENT_BYTES) {
360
- throw new Error(`Attachment is too large: ${name}`);
361
- }
362
- const bytes = Buffer.from(contentBase64, 'base64');
363
- if (!bytes.length) {
364
- continue;
365
- }
366
- if (bytes.length > MAX_TURN_ATTACHMENT_BYTES) {
367
- throw new Error(`Attachment is too large: ${name}`);
368
- }
369
- totalBytes += Math.max(estimatedBytes, bytes.length);
370
- if (totalBytes > MAX_TURN_ATTACHMENT_TOTAL_BYTES) {
371
- throw new Error(`Attachments are too large (${totalBytes}/${MAX_TURN_ATTACHMENT_TOTAL_BYTES} bytes)`);
372
- }
373
- result.push({
374
- name,
375
- mimeType: String(item?.mimeType || '').trim().slice(0, 120),
376
- bytes
377
- });
378
- }
379
- return result;
380
- }
381
-
382
- function sanitizeAttachmentFileName(value) {
383
- const basename = String(value || '')
384
- .replace(/\0/g, '')
385
- .replace(/\\/g, '/')
386
- .split('/')
387
- .filter(Boolean)
388
- .pop()
389
- ?.trim()
390
- .slice(0, 180) || '';
391
- return basename.replace(/[/:]/g, '-');
392
- }
393
-
394
- function dedupeAttachmentFileName(name, usedNames) {
395
- let candidate = name || 'attachment';
396
- if (!usedNames.has(candidate)) {
397
- usedNames.add(candidate);
398
- return candidate;
399
- }
400
- const parsed = path.parse(candidate);
401
- let index = 2;
402
- do {
403
- candidate = `${parsed.name}-${index}${parsed.ext}`;
404
- index += 1;
405
- } while (usedNames.has(candidate));
406
- usedNames.add(candidate);
407
- return candidate;
408
- }
409
346
 
410
347
  function normalizeFocusFiles(value) {
411
348
  const seen = new Set();
@@ -821,6 +758,12 @@ function runCodexAppServerProcess(input) {
821
758
  const assistantMessages = new Map();
822
759
  const assistantMessageOrder = [];
823
760
  const eventScope = createRunEventScope(() => ({ threadId: activeThreadId, turnId: activeTurnId }));
761
+ const subagentObserver = createNativeSubagentObserver({
762
+ emit: input.emit, request,
763
+ getRoot: () => ({ threadId: activeThreadId, turnId: activeTurnId }),
764
+ ownsParent: params => eventScope.owns(params),
765
+ isStopped: () => settled || stopping
766
+ });
824
767
  const readProgressController = createReadProgressController({
825
768
  input, request, fail,
826
769
  getTurn: () => ({ threadId: activeThreadId, turnId: activeTurnId }),
@@ -1009,7 +952,9 @@ function runCodexAppServerProcess(input) {
1009
952
  }
1010
953
 
1011
954
  if (message.method) {
1012
- if (stopping || !eventScope.accepts(message.params)) return;
955
+ if (stopping) return;
956
+ if (subagentObserver.observe(message)) return;
957
+ if (!eventScope.accepts(message.params)) return;
1013
958
  if (message.method === 'turn/started') {
1014
959
  const threadId = message.params?.thread?.id || message.params?.threadId;
1015
960
  if (!activeTurnId && threadId === activeThreadId) activeTurnId = message.params?.turn?.id || message.params?.turnId || '';
@@ -1029,7 +974,7 @@ function runCodexAppServerProcess(input) {
1029
974
  if (message.method === 'item/completed' && eventScope.owns(message.params) &&
1030
975
  !readProgressController.observe(message.params?.item || {})) return;
1031
976
  if (message.method === 'turn/completed' && activeTurnId && (message.params?.turn?.id === activeTurnId || message.params?.turnId === activeTurnId)) {
1032
- succeed();
977
+ succeed(message.params?.turn || {});
1033
978
  }
1034
979
  if (message.method === 'error' && isTransientCodexAppServerError(message.params)) {
1035
980
  return;
@@ -1073,21 +1018,31 @@ function runCodexAppServerProcess(input) {
1073
1018
  const item = params.item || {};
1074
1019
  if (method === 'item/agentMessage/delta') {
1075
1020
  const itemId = String(params.itemId || item.id || 'current');
1076
- const next = `${assistantMessages.get(itemId) || ''}${String(params.delta || '')}`;
1077
- setAssistantMessage(itemId, next);
1021
+ const previous = assistantMessages.get(itemId);
1022
+ if (previous?.completed) return;
1023
+ setAssistantMessage(itemId, { text: `${previous?.text || ''}${String(params.delta || '')}` });
1078
1024
  return;
1079
1025
  }
1080
- if (item.type === 'agentMessage' && typeof item.text === 'string' && item.text.trim()) {
1081
- const itemId = String(item.id || params.itemId || 'current');
1082
- setAssistantMessage(itemId, item.text);
1026
+ const terminal = method === 'turn/completed';
1027
+ if (terminal && params.turn?.status && params.turn.status !== 'completed') return;
1028
+ const items = terminal ? (Array.isArray(params.turn?.items) ? params.turn.items : []) : [item];
1029
+ for (const candidate of items) {
1030
+ if (candidate?.type !== 'agentMessage' || typeof candidate.text !== 'string') continue;
1031
+ setAssistantMessage(String(candidate.id || params.itemId || 'current'), {
1032
+ text: candidate.text,
1033
+ ...(typeof candidate.phase === 'string' ? { phase: candidate.phase } : {}),
1034
+ completed: terminal || method === 'item/completed',
1035
+ ...(terminal ? { authoritative: true } : {})
1036
+ });
1083
1037
  }
1084
1038
  }
1085
1039
 
1086
- function setAssistantMessage(itemId, text) {
1087
- if (!assistantMessages.has(itemId)) {
1088
- assistantMessageOrder.push(itemId);
1089
- }
1090
- assistantMessages.set(itemId, text);
1040
+ function setAssistantMessage(itemId, update) {
1041
+ const previous = assistantMessages.get(itemId);
1042
+ // Late deltas or started snapshots cannot overwrite a completed answer.
1043
+ if (previous?.completed && update.completed !== true) return;
1044
+ if (!previous) assistantMessageOrder.push(itemId);
1045
+ assistantMessages.set(itemId, { text: '', phase: '', completed: false, ...previous, ...update });
1091
1046
  }
1092
1047
 
1093
1048
  function publishActiveTurnControl() {
@@ -1124,7 +1079,7 @@ function runCodexAppServerProcess(input) {
1124
1079
  });
1125
1080
  }
1126
1081
 
1127
- function succeed() {
1082
+ function succeed(turn = {}) {
1128
1083
  if (settled || stopping) {
1129
1084
  return;
1130
1085
  }
@@ -1135,7 +1090,9 @@ function runCodexAppServerProcess(input) {
1135
1090
  cleanup();
1136
1091
  child.kill('SIGTERM');
1137
1092
  resolve({
1138
- assistantMessage: buildFinalAssistantMessage(assistantMessages, assistantMessageOrder),
1093
+ assistantMessage: buildFinalAssistantMessage(assistantMessages, assistantMessageOrder, {
1094
+ turnCompleted: turn.status === undefined || turn.status === 'completed'
1095
+ }),
1139
1096
  threadId: activeThreadId
1140
1097
  });
1141
1098
  }
@@ -1155,6 +1112,7 @@ function runCodexAppServerProcess(input) {
1155
1112
  }
1156
1113
 
1157
1114
  function cleanup() {
1115
+ subagentObserver.close();
1158
1116
  timeout.cancel();
1159
1117
  idleWatchdog.cancel();
1160
1118
  input.signal?.removeEventListener('abort', onAbort);
@@ -1402,21 +1360,29 @@ function tokenizeShellCommand(command) {
1402
1360
  return tokens;
1403
1361
  }
1404
1362
 
1405
- function buildFinalAssistantMessage(messages = new Map(), order = []) {
1363
+ function buildFinalAssistantMessage(messages = new Map(), order = [], options = {}) {
1364
+ const ids = [...new Set([...order, ...messages.keys()])];
1365
+ const records = ids.map(id => messages.get(id)).filter(value => value !== undefined);
1366
+ if (records.some(value => value && typeof value === 'object')) {
1367
+ const completed = records.filter(value => value?.completed === true);
1368
+ const authoritative = completed.filter(value => value.authoritative === true);
1369
+ const candidates = authoritative.length ? authoritative : completed;
1370
+ // Never join independent messages: an abandoned math/code delimiter in
1371
+ // one item must not consume the following final answer.
1372
+ const final = candidates.filter(value => value.phase === 'final_answer').at(-1);
1373
+ const compatible = candidates.filter(value => !value.phase && cleanAssistantMessage(value.text)).at(-1);
1374
+ if (final || compatible) return cleanAssistantMessage((final || compatible).text);
1375
+ // Older app-servers may emit only deltas followed by turn/completed.
1376
+ // A successful turn can finalize its last legacy item, never concatenate
1377
+ // earlier fragments or promote an explicitly phased unfinished message.
1378
+ const legacy = options.turnCompleted === true && completed.length === 0
1379
+ && records.every(value => !value?.phase)
1380
+ ? records.filter(value => cleanAssistantMessage(value?.text)).at(-1) : null;
1381
+ return cleanAssistantMessage(legacy?.text);
1382
+ }
1383
+ // Preserve the exported helper's legacy string-only input contract.
1406
1384
  const values = [];
1407
- const seenIds = new Set();
1408
- const ids = order.length ? order : Array.from(messages.keys());
1409
-
1410
- for (const id of ids) {
1411
- seenIds.add(id);
1412
- addAssistantMessage(values, messages.get(id));
1413
- }
1414
- for (const [id, value] of messages) {
1415
- if (!seenIds.has(id)) {
1416
- addAssistantMessage(values, value);
1417
- }
1418
- }
1419
-
1385
+ for (const value of records) addAssistantMessage(values, value);
1420
1386
  return values.join('\n\n');
1421
1387
  }
1422
1388
 
@@ -90,6 +90,9 @@ async function stopCodexAppServer(child, {
90
90
  if (!await waitForStop(forceTimeoutMs)) {
91
91
  const error = new Error('Codex process exit could not be confirmed. Do not retry this project until the old process has stopped.');
92
92
  error.code = 'codex_process_stop_unconfirmed';
93
+ error.processId = pid;
94
+ error.processGroup = grouped;
95
+ error.isStopped = stopped;
93
96
  error.cause = reason;
94
97
  throw error;
95
98
  }
@@ -19,7 +19,7 @@ const {
19
19
  getNativeHostRegistrationTarget
20
20
  } = require('./nativeHostPlatform');
21
21
  const { buildRuntimeFileManifest } = require('./runtimeInstaller');
22
- const { parseSemver, updateError } = require('./updateTrust');
22
+ const { BOOTSTRAP_PROTOCOL, parseSemver, updateError } = require('./updateTrust');
23
23
 
24
24
  const MANAGED_BY = 'codex-overleaf-link';
25
25
  const EXTENSION_MARKER = '.codex-overleaf-managed-extension.json';
@@ -154,7 +154,7 @@ function buildManagedExtensionTree(options = {}) {
154
154
  fs.writeFileSync(path.join(targetRoot, EXTENSION_MARKER), JSON.stringify({
155
155
  managedBy: MANAGED_BY,
156
156
  kind: 'extension',
157
- bootstrapProtocol: 2,
157
+ bootstrapProtocol: BOOTSTRAP_PROTOCOL,
158
158
  version,
159
159
  releaseRef,
160
160
  releaseChannel,
@@ -199,7 +199,7 @@ function installManagedNativeVersion({ packageRoot, nativeRoot, version, release
199
199
  fs.writeFileSync(path.join(nativeRoot, NATIVE_MARKER), JSON.stringify({
200
200
  managedBy: MANAGED_BY,
201
201
  kind: 'native',
202
- bootstrapProtocol: 2,
202
+ bootstrapProtocol: BOOTSTRAP_PROTOCOL,
203
203
  version,
204
204
  installedAt: new Date().toISOString()
205
205
  }, null, 2) + '\n', 'utf8');
@@ -388,7 +388,8 @@ function readManagedMarker(root, markerName) {
388
388
  function isManagedMarker(marker, kind) {
389
389
  return marker?.managedBy === MANAGED_BY &&
390
390
  marker?.kind === kind &&
391
- (marker?.bootstrapProtocol === 1 || marker?.bootstrapProtocol === 2);
391
+ Number.isInteger(marker?.bootstrapProtocol) &&
392
+ marker.bootstrapProtocol >= 1 && marker.bootstrapProtocol <= BOOTSTRAP_PROTOCOL;
392
393
  }
393
394
 
394
395
  function readVersionPointer(nativeRoot, name) {
@@ -4,8 +4,10 @@ const fs = require('node:fs');
4
4
  const os = require('node:os');
5
5
  const path = require('node:path');
6
6
  const { spawnSync } = require('node:child_process');
7
+ const { logDebug } = require('./debugLog');
7
8
  const {
8
9
  buildCodexRuntimeIdentity,
10
+ discoverCodexCandidates,
9
11
  getCodexRuntimeIdentityFromEnv,
10
12
  serializeCodexRuntimeIdentity
11
13
  } = require('./codexRuntimeIdentity');
@@ -54,6 +56,69 @@ function buildNativeRuntimeEnv(baseEnv = process.env, options = {}) {
54
56
  return env;
55
57
  }
56
58
 
59
+ const codexRuntimeRefreshCache = new Map();
60
+
61
+ function refreshCodexRuntimeEnv(baseEnv = process.env, options = {}) {
62
+ const runtimeOptions = { ...options, platform: getNativeRuntimePlatform({ ...options, env: baseEnv }) };
63
+ const previous = getCodexRuntimeIdentityFromEnv(baseEnv);
64
+ const selectedPath = previous.selected?.path || String(baseEnv.CODEX_OVERLEAF_CODEX_PATH || '');
65
+ const pinned = previous.selectedBy === 'explicit-path'
66
+ || (previous.selectedBy === 'legacy-path' && Boolean(selectedPath));
67
+ const pathValue = mergePathSegments([
68
+ ...getPathValues(baseEnv, runtimeOptions),
69
+ ...getDefaultPathSegments(baseEnv, runtimeOptions)
70
+ ], runtimeOptions);
71
+ const candidates = discoverCodexCandidates(pathValue, { ...runtimeOptions, env: baseEnv });
72
+ const paths = [...new Set([selectedPath, ...candidates].filter(Boolean))];
73
+ const signatures = paths.map(candidate => {
74
+ try {
75
+ const resolved = fs.realpathSync(candidate);
76
+ const stat = fs.statSync(resolved);
77
+ return [candidate, resolved, stat.size, stat.mtimeMs, stat.ctimeMs];
78
+ } catch (_) { return [candidate, 'missing']; }
79
+ });
80
+ const key = JSON.stringify([runtimeOptions.platform, pinned ? selectedPath : '', pathValue, signatures]);
81
+ const cached = codexRuntimeRefreshCache.get(key);
82
+ let identity = cached?.identity;
83
+ if (options.force || !cached || Date.now() - cached.createdAt > 30000) {
84
+ identity = buildCodexRuntimeIdentity({
85
+ selectedPath,
86
+ selectionPolicy: pinned ? 'explicit-path' : 'newest-version',
87
+ pathValue,
88
+ delimiter: runtimeOptions.delimiter,
89
+ env: { ...baseEnv, PATH: pathValue },
90
+ platform: runtimeOptions.platform
91
+ });
92
+ codexRuntimeRefreshCache.set(key, { identity, createdAt: Date.now() });
93
+ while (codexRuntimeRefreshCache.size > 4) {
94
+ codexRuntimeRefreshCache.delete(codexRuntimeRefreshCache.keys().next().value);
95
+ }
96
+ if (identity.selected?.path !== previous.selected?.path
97
+ || identity.selected?.version !== previous.selected?.version) {
98
+ logDebug('codex.runtime.refreshed', {
99
+ previousVersion: previous.selected?.version || '',
100
+ selectedVersion: identity.selected?.version || '',
101
+ selectedPath: identity.selected?.displayPath || '',
102
+ selectedBy: identity.selectedBy,
103
+ reason: options.force ? 'model_version_rejection' : 'before_request'
104
+ });
105
+ }
106
+ }
107
+ // Keep each in-flight run on its own environment snapshot.
108
+ const env = {
109
+ ...baseEnv,
110
+ CODEX_OVERLEAF_ENV_READY: '1',
111
+ CODEX_OVERLEAF_PLATFORM: runtimeOptions.platform,
112
+ CODEX_OVERLEAF_CODEX_PATH: identity.selected?.path || '',
113
+ CODEX_OVERLEAF_CODEX_RUNTIME_JSON: serializeCodexRuntimeIdentity(identity),
114
+ CODEX_OVERLEAF_CODEX_VERSION: identity.selected?.version || '',
115
+ CODEX_OVERLEAF_CODEX_SOURCE: identity.selected?.source || ''
116
+ };
117
+ normalizePathKeys(env, pathValue, runtimeOptions);
118
+ env.PATH = pathValue;
119
+ return env;
120
+ }
121
+
57
122
  function readLoginShellEnv(baseEnv = process.env, options = {}) {
58
123
  if (getNativeRuntimePlatform(options) === 'win32') {
59
124
  return null;
@@ -169,6 +234,10 @@ function getDefaultPathSegments(env = process.env, options = {}) {
169
234
 
170
235
  return [
171
236
  ...commonSegments.slice(0, 4),
237
+ platformPath.join(home, 'Applications/ChatGPT.app/Contents/Resources/codex-cli/CodexCLI.app/Contents/MacOS'),
238
+ platformPath.join(home, 'Applications/Codex.app/Contents/Resources/codex-cli/CodexCLI.app/Contents/MacOS'),
239
+ '/Applications/ChatGPT.app/Contents/Resources/codex-cli/CodexCLI.app/Contents/MacOS',
240
+ '/Applications/Codex.app/Contents/Resources/codex-cli/CodexCLI.app/Contents/MacOS',
172
241
  platformPath.join(home, 'Applications/ChatGPT.app/Contents/Resources'),
173
242
  platformPath.join(home, 'Applications/Codex.app/Contents/Resources'),
174
243
  '/Applications/ChatGPT.app/Contents/Resources',
@@ -344,6 +413,7 @@ module.exports = {
344
413
  mergePathSegments,
345
414
  parseMarkedShellEnv,
346
415
  readLoginShellEnv,
416
+ refreshCodexRuntimeEnv,
347
417
  resolveExecutable,
348
418
  summarizeNativeEnvironment
349
419
  };
@@ -1,5 +1,12 @@
1
1
  'use strict';
2
2
 
3
+ const { REFERENCE_LIMITS } = require('../../extension/src/shared/writingStyle');
4
+ const WRITING_STYLE_ATTACHMENT_QUOTAS = Object.freeze({
5
+ maxAttachmentCount: REFERENCE_LIMITS.maxSources,
6
+ maxAttachmentBytes: REFERENCE_LIMITS.maxPdfBytes,
7
+ maxAttachmentTotalBytes: REFERENCE_LIMITS.maxAttachmentTotalBytes
8
+ });
9
+
3
10
  const NATIVE_REQUEST_QUOTAS = Object.freeze({
4
11
  maxProjectFiles: 1000,
5
12
  maxProjectTextBytes: 32 * 1024 * 1024,
@@ -21,7 +28,7 @@ function validateNativeRequestQuotas(request = {}) {
21
28
  validateOperationListQuota(params.fileOverlays, 'fileOverlays'),
22
29
  validateFilePayloadQuota(params.fileOverlays, 'fileOverlays'),
23
30
  validateCompileLogQuota(params),
24
- validateAttachmentQuota(params.attachments),
31
+ validateAttachmentQuota(params.attachments, params.writingStyleBuild ? WRITING_STYLE_ATTACHMENT_QUOTAS : NATIVE_REQUEST_QUOTAS),
25
32
  validateSkillContentQuota(params.skillContent)
26
33
  ]);
27
34
  case 'mirror.sync':
@@ -211,27 +218,27 @@ function validateCompileLogQuota(params = {}) {
211
218
  : null;
212
219
  }
213
220
 
214
- function validateAttachmentQuota(attachments) {
221
+ function validateAttachmentQuota(attachments, quotas = NATIVE_REQUEST_QUOTAS) {
215
222
  const items = Array.isArray(attachments) ? attachments : [];
216
- if (items.length > NATIVE_REQUEST_QUOTAS.maxAttachmentCount) {
217
- return quotaViolation('attachments', NATIVE_REQUEST_QUOTAS.maxAttachmentCount, items.length, 'too many attachments');
223
+ if (items.length > quotas.maxAttachmentCount) {
224
+ return quotaViolation('attachments', quotas.maxAttachmentCount, items.length, 'too many attachments');
218
225
  }
219
226
 
220
227
  let totalBytes = 0;
221
228
  for (const item of items) {
222
229
  const bytes = getDeclaredOrEstimatedBinaryBytes(item);
223
- if (bytes > NATIVE_REQUEST_QUOTAS.maxAttachmentBytes) {
230
+ if (bytes > quotas.maxAttachmentBytes) {
224
231
  return quotaViolation(
225
232
  'attachments.contentBase64',
226
- NATIVE_REQUEST_QUOTAS.maxAttachmentBytes,
233
+ quotas.maxAttachmentBytes,
227
234
  bytes,
228
235
  'attachment payload is too large'
229
236
  );
230
237
  }
231
238
  totalBytes += bytes;
232
239
  }
233
- return totalBytes > NATIVE_REQUEST_QUOTAS.maxAttachmentTotalBytes
234
- ? quotaViolation('attachments', NATIVE_REQUEST_QUOTAS.maxAttachmentTotalBytes, totalBytes, 'attachment payload is too large')
240
+ return totalBytes > quotas.maxAttachmentTotalBytes
241
+ ? quotaViolation('attachments', quotas.maxAttachmentTotalBytes, totalBytes, 'attachment payload is too large')
235
242
  : null;
236
243
  }
237
244
 
@@ -0,0 +1,16 @@
1
+ 'use strict';
2
+
3
+ // Shared by project turns and broker workers. Skill-install turns run outside
4
+ // the project mirror and retain their existing installer command policy.
5
+ function formatOverleafWorkspaceRules() {
6
+ return [
7
+ 'Overleaf workspace rules (also apply to delegated subagents):',
8
+ '- This directory is a synchronized Overleaf project mirror without .git metadata.',
9
+ '- Do not run Git commands in this mirror, including git status, git diff, git rev-parse, or git init. Do not create .git metadata or search parent directories for a repository.',
10
+ '- Verify changes through direct file reads and searches. Run compilation checks only when needed and permitted by the current task and mode; never compile solely to replace an unavailable Git check.',
11
+ '- The plugin compares the workspace against its synchronized baseline, collects file changes, and handles writeback to Overleaf. No Git-based diff, staging, or commit is required.',
12
+ '- Include these workspace rules in every delegated subagent task so workers follow the same constraints.'
13
+ ].join('\n');
14
+ }
15
+
16
+ module.exports = { formatOverleafWorkspaceRules };