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
@@ -0,0 +1,316 @@
1
+ 'use strict';
2
+
3
+ // Observation only: never resumes a thread, starts a turn or settles a run.
4
+ const CHILD_ID = /^[a-zA-Z0-9][a-zA-Z0-9_.:-]{0,159}$/;
5
+ const MAX_CHILDREN = 16;
6
+ const TERMINAL = new Set(['completed', 'failed', 'cancelled']);
7
+ const EVIDENCE = { history: 1, agent: 2, turn: 3 };
8
+
9
+ function publicText(value, limit = 4096) {
10
+ return String(value ?? '')
11
+ .replace(/\bsk-(?:ant-|proj-)?[A-Za-z0-9_-]{12,}/g, '[REDACTED_SECRET]')
12
+ .replace(/\bBearer\s+[A-Za-z0-9._~+/-]+=*/gi, 'Bearer [REDACTED_SECRET]')
13
+ .replace(/((?:api[_-]?key|access[_-]?token|secret|password|authorization)\s*[:=]\s*["']?)[^\s"',;]+/gi, '$1[REDACTED_SECRET]')
14
+ .slice(0, limit);
15
+ }
16
+
17
+ function fields(value, names, limit = 4096) {
18
+ const result = {};
19
+ for (const name of names) {
20
+ const item = value?.[name];
21
+ if (typeof item === 'string') result[name] = publicText(item, limit);
22
+ else if (typeof item === 'number' && Number.isFinite(item) || typeof item === 'boolean') result[name] = item;
23
+ }
24
+ return result;
25
+ }
26
+
27
+ function compactEvent(event) {
28
+ if (!event || !['codex.session.event', 'codex.command.started', 'codex.command.completed',
29
+ 'codex.agent.message', 'codex.agent.result', 'codex.turn.bound'].includes(event.type)) return null;
30
+ const source = event.detail || {};
31
+ const detail = fields(source, ['method', 'threadId', 'turnId', 'itemId', 'phase', 'code', 'exitCode', 'durationMs']);
32
+ Object.assign(detail, fields(source, ['command', 'output', 'text'], 12000));
33
+ if (Array.isArray(source.commandActions)) detail.commandActions = source.commandActions.slice(0, 12)
34
+ .map(action => fields(action, ['type', 'path', 'query', 'name'], 400));
35
+ if (source.params) {
36
+ const p = source.params;
37
+ // Private reasoning and raw server request payloads never enter this lane.
38
+ if (/reasoning|textDelta|outputDelta/.test(source.method || '') && source.method !== 'item/agentMessage/delta') return null;
39
+ const params = fields(p, ['threadId', 'turnId', 'itemId', 'phase', 'message', 'warning'], 1000);
40
+ if (typeof p.delta === 'string') params.delta = publicText(p.delta, 12000);
41
+ if (p.thread) params.thread = fields(p.thread, ['id', 'model'], 160);
42
+ if (p.turn) {
43
+ params.turn = fields(p.turn, ['id', 'status'], 160);
44
+ if (p.turn.error) params.turn.error = fields(p.turn.error, ['message'], 1200);
45
+ }
46
+ if (p.error) params.error = fields(p.error, ['message'], 1200);
47
+ if (Array.isArray(p.plan)) params.plan = p.plan.slice(0, 16).map(step => fields(step, ['step', 'status'], 600));
48
+ const changes = input => (Array.isArray(input) ? input : []).slice(0, 12).map(change => ({
49
+ ...fields(change, ['path'], 320),
50
+ kind: publicText(typeof change?.kind === 'object' ? change.kind.type : change?.kind, 32),
51
+ diff: publicText(change?.diff, 1800)
52
+ }));
53
+ if (Array.isArray(p.changes)) params.changes = changes(p.changes);
54
+ if (p.item) {
55
+ const item = p.item;
56
+ if (item.type === 'reasoning') return null;
57
+ params.item = {
58
+ ...fields(item, ['id', 'type', 'status', 'phase', 'tool', 'server', 'exitCode', 'durationMs', 'success'], 400),
59
+ ...fields(item, ['command'], 1000),
60
+ ...fields(item, ['text'], 24000),
61
+ ...fields(item, ['aggregatedOutput'], 1600)
62
+ };
63
+ if (Array.isArray(item.commandActions)) params.item.commandActions = item.commandActions.slice(0, 12)
64
+ .map(action => fields(action, ['type', 'path', 'query', 'name'], 400));
65
+ if (Array.isArray(item.changes)) params.item.changes = changes(item.changes);
66
+ if (item.error) params.item.error = fields(item.error, ['message'], 1200);
67
+ }
68
+ detail.params = params;
69
+ }
70
+ return {
71
+ type: event.type, title: publicText(event.title, 24000),
72
+ status: publicText(event.status, 32),
73
+ timestamp: publicText(event.timestamp || new Date().toISOString(), 64), detail
74
+ };
75
+ }
76
+
77
+ // Metadata has a narrower exposure policy than already-compacted tool events.
78
+ function metadataText(value, limit) {
79
+ if (typeof value !== 'string') return '';
80
+ return publicText(value, 16384)
81
+ .replace(/(["'\x60])(?:file:\/\/|~\/|\/(?!\/)|[a-zA-Z]:[\\/]|\\\\)[\s\S]*?\1/g, '$1[local path]$1')
82
+ .replace(/\bfile:\/\/[^\s<>"'\x60]+/gi, '[local path]')
83
+ .replace(/(^|[\s([{"'=,:])(?:[a-zA-Z]:[\\/]|\\\\)[^\s<>"'\x60)\]}]+/g, '$1[local path]')
84
+ .replace(/(^|[\s([{"'=,:])(?:~\/|\/(?!\/))[^\s<>"'\x60)\]}]*/g, '$1[local path]')
85
+ .slice(0, limit);
86
+ }
87
+
88
+ function agentTitle(id, item) {
89
+ // agentPath is a logical namespace only for this exact, single-name shape.
90
+ // Never turn an arbitrary filesystem path into a display name.
91
+ const match = typeof item.agentPath === 'string'
92
+ && /^\/root\/([a-zA-Z0-9][a-zA-Z0-9_-]{0,79})$/.exec(item.agentPath);
93
+ if (match) {
94
+ const name = match[1].replace(/[_-]+/g, ' ').trim();
95
+ return name.charAt(0).toUpperCase() + name.slice(1);
96
+ }
97
+ const role = metadataText(item.agentRole, 120).trim();
98
+ return role && !role.includes('[local path]') ? role : 'Agent ' + id.slice(0, 8);
99
+ }
100
+
101
+ function taskText(value) {
102
+ if (typeof value !== 'string') return '';
103
+ const text = value.trim();
104
+ if (!text || /^gAAAA[A-Za-z0-9_-]{20,}={0,2}$/.test(text)
105
+ || /^<(?:environment_context|user_instructions|developer_instructions|system_instructions|permissions|collaboration_mode)\b/i.test(text)
106
+ || /^Same Codex Overleaf session context:/.test(text)
107
+ || /^Message Type:\s*NEW_TASK\b/.test(text)) return '';
108
+ return metadataText(text, 4096);
109
+ }
110
+
111
+ function taskFromItems(items) {
112
+ for (const item of items.slice(0, 100)) {
113
+ if (item?.type !== 'userMessage' || !Array.isArray(item.content)
114
+ || item.content.some(part => part?.type === 'encrypted_content')) continue;
115
+ const text = item.content.filter(part => part?.type === 'text')
116
+ .map(part => taskText(part.text)).filter(Boolean).join('\n').slice(0, 4096);
117
+ if (text) return text;
118
+ }
119
+ return '';
120
+ }
121
+
122
+ function createNativeSubagentObserver({ emit, request, getRoot, ownsParent, isStopped }) {
123
+ const children = new Map();
124
+ let closed = false;
125
+ const active = () => !closed && !isStopped();
126
+ function publish(child, event, extra = {}) {
127
+ if (!active()) return;
128
+ emit({
129
+ type: event ? 'codex.subagent.event' : 'codex.subagent.observed',
130
+ title: child.title, timestamp: new Date().toISOString(), status: child.status,
131
+ detail: {
132
+ source: 'codex', threadId: child.id, parentThreadId: child.parentThreadId,
133
+ title: child.title, task: child.task, status: child.status,
134
+ sequence: ++child.sequence, ...extra,
135
+ ...(event ? { event: compactEvent(event) } : {})
136
+ }
137
+ });
138
+ }
139
+ function status(value) {
140
+ return ({ pendingInit: 'pending', running: 'running', completed: 'completed',
141
+ errored: 'failed', interrupted: 'cancelled', notFound: 'unknown' })[value];
142
+ }
143
+ function setStatus(child, next, evidence) {
144
+ if (!next) return false;
145
+ if (TERMINAL.has(child.status)) {
146
+ if (!TERMINAL.has(next) || evidence < child.statusEvidence
147
+ || next !== child.status && evidence === child.statusEvidence) return false;
148
+ }
149
+ const changed = child.status !== next;
150
+ child.status = next;
151
+ if (TERMINAL.has(next)) child.statusEvidence = evidence;
152
+ return changed;
153
+ }
154
+ function rememberTask(child, items) {
155
+ if (child.task) return false;
156
+ const text = taskFromItems(items);
157
+ if (!text) return false;
158
+ child.task = text;
159
+ return true;
160
+ }
161
+ function register(id, item) {
162
+ if (typeof id !== 'string' || !CHILD_ID.test(id) || id === getRoot().threadId) return null;
163
+ let child = children.get(id);
164
+ if (!child) {
165
+ if (children.size >= MAX_CHILDREN) return null;
166
+ child = { id, title: agentTitle(id, item),
167
+ task: taskText(item.prompt), parentThreadId: getRoot().threadId,
168
+ status: 'pending', statusEvidence: 0, turnId: '', generation: 0, retiredTurns: new Set(),
169
+ interruptionObserved: false, sequence: 0, items: new Map(), activities: new Set(), lastRead: -Infinity };
170
+ children.set(id, child);
171
+ } else {
172
+ if (child.title === 'Agent ' + id.slice(0, 8)) child.title = agentTitle(id, item);
173
+ if (!child.task) child.task = taskText(item.prompt);
174
+ }
175
+ return child;
176
+ }
177
+ function duplicateActivity(child, item) {
178
+ if (typeof item.id !== 'string' || !item.id) return false;
179
+ // The same lifecycle item can arrive as both item/started and item/completed.
180
+ // Its kind, not the outer notification method, identifies the child activity.
181
+ const key = JSON.stringify([item.id.slice(0, 160), item.kind]);
182
+ if (child.activities.has(key)) return true;
183
+ child.activities.add(key);
184
+ if (child.activities.size > 100) child.activities.delete(child.activities.values().next().value);
185
+ return false;
186
+ }
187
+ function snapshot(child, terminal = false) {
188
+ if (!active() || child.readDisabled) return;
189
+ if (child.reading) { child.readAgain ||= terminal; return; }
190
+ if (!terminal && Date.now() - child.lastRead < 2000) return;
191
+ child.reading = true; child.lastRead = Date.now();
192
+ const generation = child.generation, interruptionObserved = child.interruptionObserved;
193
+ // Read only on real lifecycle/activity notifications. Polling would keep
194
+ // the parent's idle watchdog alive and change execution semantics.
195
+ Promise.resolve().then(() => active()
196
+ ? request('thread/read', { threadId: child.id, includeTurns: true }) : null)
197
+ .then(result => {
198
+ if (!active() || child.generation !== generation || result?.thread?.id !== child.id
199
+ || result.thread.parentThreadId && result.thread.parentThreadId !== child.parentThreadId) return;
200
+ const turns = Array.isArray(result.thread.turns) ? result.thread.turns : [];
201
+ const turn = turns.at(-1);
202
+ // A fork can include its parent's context; do not replay that as work
203
+ // produced by this child.
204
+ if (!turn?.id || turn.id === getRoot().turnId
205
+ || child.turnId && child.turnId !== turn.id) return;
206
+ child.historyTurnId = turn.id;
207
+ const items = Array.isArray(turn.items) ? turn.items : [];
208
+ // Recover real child input before compactEvent drops user content.
209
+ // A fork's parent context and encrypted delegation are not task text.
210
+ if (rememberTask(child, items)) publish(child, null);
211
+ for (const item of items.slice(-100)) {
212
+ const event = compactEvent({
213
+ type: 'codex.session.event', status: item.status === 'inProgress' ? 'running' : 'completed',
214
+ detail: {
215
+ method: item.status === 'inProgress' ? 'item/started' : 'item/completed',
216
+ params: { threadId: child.id, turnId: turn.id, item }
217
+ }
218
+ });
219
+ if (!event) continue;
220
+ const signature = JSON.stringify(event.detail);
221
+ const key = turn.id + ':' + item.id;
222
+ if (child.items.get(key) === signature) continue;
223
+ child.items.set(key, signature);
224
+ if (child.items.size > 100) child.items.delete(child.items.keys().next().value);
225
+ publish(child, event, { historyClipped: items.length > 100 });
226
+ }
227
+ if (['completed', 'failed', 'interrupted'].includes(turn.status)) {
228
+ // A persisted, still-active turn can look interrupted. Require an
229
+ // explicit interruption observation before trusting that snapshot.
230
+ const next = turn.status === 'interrupted'
231
+ ? (interruptionObserved ? 'cancelled' : undefined) : turn.status;
232
+ if (setStatus(child, next, EVIDENCE.history)) publish(child, null);
233
+ }
234
+ }).catch(() => {
235
+ if (!active() || child.generation !== generation) return;
236
+ // Older app servers may lack this capability. Keep observed records;
237
+ // reading history must never interrupt or resume the parent or child.
238
+ child.readDisabled = true;
239
+ publish(child, null, { historyUnavailable: true });
240
+ }).finally(() => {
241
+ child.reading = false;
242
+ if (child.readAgain) { child.readAgain = false; snapshot(child, true); }
243
+ });
244
+ }
245
+ function observe(message) {
246
+ if (!active()) return false;
247
+ const p = message.params || {};
248
+ const threadId = p.threadId || p.thread?.id;
249
+ const known = children.get(threadId);
250
+ if (known) {
251
+ const turnId = p.turnId || p.turn?.id || '';
252
+ if (message.method === 'turn/started') {
253
+ if (!turnId || known.retiredTurns.has(turnId)
254
+ || (known.turnId === turnId || !known.turnId && known.historyTurnId === turnId)
255
+ && TERMINAL.has(known.status)) return true;
256
+ if (known.turnId !== turnId) {
257
+ if (known.turnId) known.retiredTurns.add(known.turnId);
258
+ if (known.retiredTurns.size > 100) known.retiredTurns.delete(known.retiredTurns.values().next().value);
259
+ known.turnId = turnId;
260
+ known.generation += 1;
261
+ known.statusEvidence = 0;
262
+ known.interruptionObserved = false;
263
+ }
264
+ known.status = 'running';
265
+ } else if (turnId && known.turnId && turnId !== known.turnId) {
266
+ return true;
267
+ } else if (turnId) {
268
+ known.turnId = turnId;
269
+ }
270
+ if (message.method === 'turn/completed') {
271
+ const next = p.turn?.status === 'interrupted' ? 'cancelled'
272
+ : ['completed', 'failed'].includes(p.turn?.status) ? p.turn.status : undefined;
273
+ const changed = setStatus(known, next, EVIDENCE.turn);
274
+ // Do not forward rejected terminal evidence: the frontend also reads
275
+ // params.turn.status and must not reapply a weaker/conflicting outcome.
276
+ if (next && !changed && next !== known.status) return true;
277
+ }
278
+ if (turnId && turnId !== getRoot().turnId && rememberTask(known, [p.item])) publish(known, null);
279
+ const event = compactEvent({ type: 'codex.session.event', title: message.method,
280
+ detail: { method: message.method, params: p }, status: /completed/.test(message.method) ? 'completed' : 'running' });
281
+ if (event) publish(known, event);
282
+ return true; // Child errors/completions cannot settle the parent.
283
+ }
284
+ if (!ownsParent(p)) return false;
285
+ const item = p.item || {};
286
+ if (item.type === 'subAgentActivity') {
287
+ if (!['started', 'interacted', 'interrupted', 'completed'].includes(item.kind)) return false;
288
+ const child = register(item.agentThreadId, item);
289
+ if (!child || duplicateActivity(child, item)) return false;
290
+ if (item.kind === 'started' && ['pending', 'unknown'].includes(child.status)) child.status = 'running';
291
+ if (item.kind === 'interrupted') child.interruptionObserved = true;
292
+ publish(child, null);
293
+ // A lifecycle completion wakes the final read; it does not establish
294
+ // success. Only the child's own turn/status evidence can do that.
295
+ snapshot(child, item.kind === 'completed' || item.kind === 'interrupted');
296
+ return false;
297
+ }
298
+ if (item.type !== 'collabAgentToolCall') return false;
299
+ const states = item.agentsStates && typeof item.agentsStates === 'object' ? item.agentsStates : {};
300
+ const ids = [...new Set([...(Array.isArray(item.receiverThreadIds) ? item.receiverThreadIds : []), ...Object.keys(states)])];
301
+ for (const id of ids.slice(0, MAX_CHILDREN)) {
302
+ const child = register(id, item);
303
+ if (!child) continue;
304
+ const next = status(states[id]?.status);
305
+ setStatus(child, next, EVIDENCE.agent);
306
+ const terminal = ['completed', 'failed', 'cancelled'].includes(child.status);
307
+ publish(child, null, { summary: next === child.status && TERMINAL.has(next)
308
+ ? publicText(states[id]?.message, 24000) : '' });
309
+ snapshot(child, terminal);
310
+ }
311
+ return false;
312
+ }
313
+ return { observe, close() { closed = true; children.clear(); } };
314
+ }
315
+
316
+ module.exports = { publicText, compactEvent, createNativeSubagentObserver };
@@ -0,0 +1,103 @@
1
+ 'use strict';
2
+
3
+ const crypto = require('node:crypto');
4
+ const fs = require('node:fs');
5
+ const path = require('node:path');
6
+ const { SUBAGENT_QUEUE_DIR } = require('./mirrorWorkspace');
7
+ const { safeWorkspaceRelativePath } = require('./subagentWorkspacePath');
8
+ const { formatOverleafWorkspaceRules } = require('./overleafWorkspaceRules');
9
+
10
+ // Filesystem evidence and worker context are separate from scheduling policy.
11
+ function createSubagentWorkspace({ workspacePath, logsDir }) {
12
+ function atomicWrite(target, text) {
13
+ const tmp = path.join(path.dirname(target), `.tmp-${crypto.randomUUID()}`);
14
+ fs.writeFileSync(tmp, text);
15
+ fs.renameSync(tmp, target);
16
+ }
17
+
18
+ function appendLog(jobId, text) {
19
+ try {
20
+ fs.appendFileSync(path.join(logsDir, `${jobId}.log`), `${new Date().toISOString()} ${text}\n`);
21
+ } catch (_error) { /* logs are best-effort */ }
22
+ }
23
+
24
+ function adoptionHash(file) {
25
+ try {
26
+ const safe = safeWorkspaceRelativePath(file);
27
+ if (!safe) return '';
28
+ const absolute = path.join(workspacePath, safe);
29
+ const stat = fs.lstatSync(absolute);
30
+ const relative = path.relative(fs.realpathSync(workspacePath), fs.realpathSync(absolute));
31
+ if (!stat.isFile() || stat.size > 32 * 1024 * 1024 || path.isAbsolute(relative)
32
+ || relative === '..' || relative.startsWith('..' + path.sep)) return '';
33
+ return crypto.createHash('sha256').update(fs.readFileSync(absolute)).digest('hex');
34
+ } catch (_error) { return ''; }
35
+ }
36
+
37
+ function hashWorkspace() {
38
+ const hashes = new Map();
39
+ walk(workspacePath, '');
40
+ return hashes;
41
+
42
+ function walk(dir, prefix) {
43
+ let entries;
44
+ try {
45
+ entries = fs.readdirSync(dir, { withFileTypes: true });
46
+ } catch (_error) {
47
+ return;
48
+ }
49
+ for (const entry of entries) {
50
+ // The whole queue zone (incl. the work/ slice scratch) stays out of
51
+ // wave hashing: scratch can never reach Overleaf, same-wave slices
52
+ // are all in the owned union anyway, and a lead staggering slice
53
+ // creation mid-wave must not read as a violation (v1.6.1).
54
+ if (entry.name === '.DS_Store' || entry.name === SUBAGENT_QUEUE_DIR || entry.name === '.codex-overleaf-attachments') {
55
+ continue;
56
+ }
57
+ const relative = prefix ? `${prefix}/${entry.name}` : entry.name;
58
+ const absolute = path.join(dir, entry.name);
59
+ if (entry.isDirectory()) {
60
+ walk(absolute, relative);
61
+ } else if (entry.isFile()) {
62
+ hashes.set(relative, hashFile(absolute));
63
+ }
64
+ }
65
+ }
66
+ }
67
+
68
+ function hashPaths(files) {
69
+ const hashes = new Map();
70
+ for (const file of files) {
71
+ hashes.set(file, hashFile(path.join(workspacePath, file)));
72
+ }
73
+ return hashes;
74
+ }
75
+
76
+ function hashFile(absolute) {
77
+ try {
78
+ return crypto.createHash('sha1').update(fs.readFileSync(absolute)).digest('hex');
79
+ } catch (_error) {
80
+ return 'missing';
81
+ }
82
+ }
83
+
84
+ function buildWorkerPrompt(job) {
85
+ const readOnly = job.readOnlyContext.length
86
+ ? `- You may read these for context but must not modify them: ${job.readOnlyContext.join(', ')}.\n`
87
+ : '';
88
+ return [
89
+ 'You are a subagent working on one slice of a larger task.',
90
+ formatOverleafWorkspaceRules(),
91
+ 'HARD CONSTRAINTS:',
92
+ `- You may modify ONLY these files: ${job.files.join(', ')}.`,
93
+ readOnly + '- Do not modify, create, or delete any other file. Inside .codex-overleaf-subagents/ you may touch ONLY the slice files listed above (if any).',
94
+ '- Work fully autonomously; nobody can answer questions.',
95
+ '',
96
+ job.task
97
+ ].join('\n');
98
+ }
99
+
100
+
101
+ return { atomicWrite, appendLog, adoptionHash, hashWorkspace, hashPaths, hashFile, buildWorkerPrompt };
102
+ }
103
+ module.exports = { createSubagentWorkspace };
@@ -0,0 +1,31 @@
1
+ 'use strict';
2
+
3
+ const path = require('node:path');
4
+ const { SUBAGENT_QUEUE_DIR } = require('./mirrorWorkspace');
5
+
6
+ function safeWorkspaceRelativePath(value) {
7
+ if (typeof value !== 'string' || !value.trim()) {
8
+ return null;
9
+ }
10
+ const normalized = value.trim().replace(/\\/g, '/').replace(/^\.\//, '');
11
+ if (!normalized || path.isAbsolute(normalized)) {
12
+ return null;
13
+ }
14
+ const segments = normalized.split('/');
15
+ if (segments.some(segment => segment === '..' || segment === '')) {
16
+ return null;
17
+ }
18
+ if (segments[0] === SUBAGENT_QUEUE_DIR) {
19
+ // The queue control plane (jobs/results/logs/broker.json) is never
20
+ // ownable — but the work/ scratch zone IS: single-file fan-out slices
21
+ // live there (v1.6.1 scatter-gather), excluded from writeback by the
22
+ // mirror-scan rule yet fully owned/hashed like any other job file.
23
+ if (segments[1] === 'work' && segments.length >= 3) {
24
+ return segments.join('/');
25
+ }
26
+ return null;
27
+ }
28
+ return segments.join('/');
29
+ }
30
+
31
+ module.exports = { safeWorkspaceRelativePath };
@@ -10,6 +10,7 @@ const {
10
10
  SUPPORTED_NATIVE_PROTOCOL
11
11
  } = require('../../extension/src/shared/compatibility');
12
12
  const { runCodexSession } = require('./codexSessionRunner');
13
+ const WritingStyleRuntime = require('./writingStyleRuntime');
13
14
  const { resolveCodexModels } = require('./codexModels');
14
15
  const {
15
16
  handleProviderRequest,
@@ -23,7 +24,8 @@ const { forkCodexThread } = require('./codexThreadFork');
23
24
  const { readAssetChunk, releaseAsset } = require('./nativeAssetTransfer');
24
25
  const { logDebug, truncateText } = require('./debugLog');
25
26
  const { HOST_NAME } = require('./manifest');
26
- const { getNativeRuntimePlatform, summarizeNativeEnvironment } = require('./nativeEnvironment');
27
+ const { getNativeRuntimePlatform, summarizeNativeEnvironment, refreshCodexRuntimeEnv } = require('./nativeEnvironment');
28
+ const { formatModelUpgradeError } = require('./codexModelRecovery');
27
29
  const {
28
30
  NATIVE_REQUEST_QUOTAS,
29
31
  firstQuotaViolation,
@@ -33,6 +35,7 @@ const {
33
35
  } = require('./nativeTransportEnvelope');
34
36
  const { version: PACKAGE_VERSION } = require('../../package.json');
35
37
 
38
+ const processStopBarrier = require('./processStopBarrier');
36
39
  const activeProjectLocks = new Map();
37
40
  const activeRunControllers = new Map();
38
41
  const activeRunEntries = new Map();
@@ -41,7 +44,7 @@ const activeRunEntries = new Map();
41
44
  // Overleaf tab was reloaded — the requestId lived in content-side JS state
42
45
  // and is gone, but the native-host-side controller is still running).
43
46
  const activeRunByProject = new Map();
44
- const CODEX_RUN_PASSTHROUGH_ERROR_CODES = new Set(['thread_resume_failed', 'codex_no_usable_result']);
47
+ const CODEX_RUN_PASSTHROUGH_ERROR_CODES = new Set(['thread_resume_failed', 'codex_no_usable_result', 'codex_process_stop_unconfirmed', 'selected_context_unresolved']);
45
48
 
46
49
  async function handleRequest(request, env = process.env, emit = () => {}) {
47
50
  if (!request || typeof request !== 'object') {
@@ -53,6 +56,10 @@ async function handleRequest(request, env = process.env, emit = () => {}) {
53
56
  return quotaErrorResponse(request.id, quotaError);
54
57
  }
55
58
 
59
+ if (['bridge.ping', 'codex.run', 'codex.models', 'codex.thread.fork'].includes(request.method)) {
60
+ env = refreshCodexRuntimeEnv(env);
61
+ }
62
+
56
63
  if (request.method === 'bridge.ping') {
57
64
  return okResponse(request.id, {
58
65
  host: HOST_NAME,
@@ -66,6 +73,12 @@ async function handleRequest(request, env = process.env, emit = () => {}) {
66
73
  });
67
74
  }
68
75
 
76
+ if (['codex.run', 'mirror.sync', 'mirror.patchFiles', 'mirror.confirmWriteback'].includes(request.method)
77
+ && processStopBarrier.isBlocked(resolveProjectKey(request.params || {}), env.CODEX_OVERLEAF_MIRROR_ROOT)) {
78
+ return errorResponse(request.id, 'codex_process_stop_unconfirmed',
79
+ 'The previous Codex process has not exited. This project remains isolated until exit is confirmed.');
80
+ }
81
+
69
82
  if (request.method === 'mirror.sync') {
70
83
  return handleMirrorSync(request, env);
71
84
  }
@@ -115,7 +128,7 @@ async function handleRequest(request, env = process.env, emit = () => {}) {
115
128
  }
116
129
 
117
130
  if (request.method === 'codex.cancel') {
118
- return handleCodexCancel(request);
131
+ return handleCodexCancel(request, env);
119
132
  }
120
133
 
121
134
  if (request.method === 'codex.history.clearPlugin') {
@@ -142,6 +155,18 @@ async function handleRequest(request, env = process.env, emit = () => {}) {
142
155
  return okResponse(request.id, releaseAsset(request.params || {}));
143
156
  }
144
157
 
158
+ if (request.method === 'writing-style.get' || request.method === 'writing-style.set') {
159
+ try {
160
+ const params = request.params || {};
161
+ const result = request.method === 'writing-style.get'
162
+ ? await WritingStyleRuntime.get(params, env, id => activeRunEntries.has(id))
163
+ : await WritingStyleRuntime.set(params, env);
164
+ return okResponse(request.id, result);
165
+ } catch (error) {
166
+ return errorResponse(request.id, error.code || 'writing_style_failed', error.message);
167
+ }
168
+ }
169
+
145
170
  if (request.method === 'skills.list') {
146
171
  return handleSkillsList(request, env);
147
172
  }
@@ -180,6 +205,19 @@ function quotaErrorResponse(id, violation) {
180
205
 
181
206
  async function handleCodexRun(request, env, emit) {
182
207
  let params = request.params || {};
208
+ if (params.writingStyleBuild != null) {
209
+ if (typeof params.writingStyleBuild !== 'object' || Array.isArray(params.writingStyleBuild)) {
210
+ return errorResponse(request.id, 'writing_style_invalid_build', 'Writing style build settings must be an object.');
211
+ }
212
+ params = {
213
+ ...params,
214
+ mode: 'ask',
215
+ useExistingMirror: false,
216
+ fileOverlays: [],
217
+ writingStyle: null,
218
+ writingStyleBuild: { ...params.writingStyleBuild, requestId: String(request.id || '') }
219
+ };
220
+ }
183
221
  if (isCodexMissing(env)) {
184
222
  return errorResponse(
185
223
  request.id,
@@ -253,7 +291,7 @@ async function handleCodexRun(request, env, emit) {
253
291
  if (Array.isArray(params.fileOverlays) && params.fileOverlays.length) {
254
292
  await applyFileOverlays({ projectId: projectKey, overlays: params.fileOverlays, rootDir });
255
293
  }
256
- } else if (!isSnapshotlessSkillInstallerRun(params) && !hasRunnableProjectSnapshotEvidence(params)) {
294
+ } else if (!params.writingStyleBuild && !isSnapshotlessSkillInstallerRun(params) && !hasRunnableProjectSnapshotEvidence(params)) {
257
295
  return errorResponse(
258
296
  request.id,
259
297
  'codex_run_requires_snapshot_evidence',
@@ -267,6 +305,7 @@ async function handleCodexRun(request, env, emit) {
267
305
  emit,
268
306
  rootDir: env.CODEX_OVERLEAF_MIRROR_ROOT,
269
307
  providerLaunch: providerResolution.providerLaunch,
308
+ onStopUnconfirmed: error => processStopBarrier.record(projectKey, env.CODEX_OVERLEAF_MIRROR_ROOT, error),
270
309
  onControlReady: control => {
271
310
  activeEntry.control = control;
272
311
  },
@@ -285,6 +324,13 @@ async function handleCodexRun(request, env, emit) {
285
324
  });
286
325
  return errorResponse(request.id, 'codex_cancelled', 'Codex run was cancelled by the user');
287
326
  }
327
+ const modelUpgradeError = formatModelUpgradeError(error, env, {
328
+ model: params.model, locale: params.locale
329
+ });
330
+ if (modelUpgradeError) {
331
+ logDebug('codex.run.model_version_rejected', modelUpgradeError.details);
332
+ return errorResponse(request.id, modelUpgradeError.code, modelUpgradeError.message, modelUpgradeError.details);
333
+ }
288
334
  if (shouldPassthroughCodexRunError(error)) {
289
335
  logDebug('codex.run.passthrough_failed', {
290
336
  code: error.code,
@@ -372,7 +418,7 @@ function findActiveRunEntry(params = {}) {
372
418
  // the user otherwise has no way to recover short of restarting Chrome.
373
419
  // Only fires when `force: true` is explicitly set so accidental calls
374
420
  // can't punch through a real live run.
375
- function handleCodexCancel(request) {
421
+ function handleCodexCancel(request, env = process.env) {
376
422
  const params = request.params || {};
377
423
  const targetId = params.requestId || params.id;
378
424
  const projectKey = typeof params.projectKey === 'string' ? params.projectKey : '';
@@ -396,6 +442,10 @@ function handleCodexCancel(request) {
396
442
  requestId: entry.id || ''
397
443
  });
398
444
  }
445
+ if (processStopBarrier.isBlocked(projectKey, env.CODEX_OVERLEAF_MIRROR_ROOT)) {
446
+ return errorResponse(request.id, 'codex_process_stop_unconfirmed',
447
+ 'Cancellation was requested, but process exit is not yet confirmed.');
448
+ }
399
449
  if (force && activeProjectLocks.has(projectKey)) {
400
450
  activeProjectLocks.delete(projectKey);
401
451
  activeRunByProject.delete(projectKey);