codex-overleaf-link 2.4.1 → 2.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (397) hide show
  1. package/README.md +275 -305
  2. package/README.zh-CN.md +290 -320
  3. package/extension/bootstrap/background.js +99 -19
  4. package/extension/bootstrap/manifest.template.json +9 -4
  5. package/extension/bootstrap/popup.html +11 -16
  6. package/extension/bootstrap/popupFallback.js +55 -0
  7. package/extension/bootstrap/update.js +25 -2
  8. package/extension/bootstrap/updateStatus.js +1 -0
  9. package/extension/runtime-manifest.json +3 -1
  10. package/extension/src/background.js +234 -56
  11. package/extension/src/backgroundBootstrapMigration.js +181 -0
  12. package/extension/src/backgroundSharedSessions.js +440 -0
  13. package/extension/src/backgroundUpdateCoordinator.js +541 -381
  14. package/extension/src/backgroundUpdateSafety.js +173 -0
  15. package/extension/src/content/activeTurnControl.js +16 -2
  16. package/extension/src/content/applyResultFormatters.js +46 -73
  17. package/extension/src/content/assetTransferBroker.js +244 -12
  18. package/extension/src/content/changeHistoryView.js +175 -0
  19. package/extension/src/content/composerAttachments.js +117 -67
  20. package/extension/src/content/composerPanel.js +41 -8
  21. package/extension/src/content/contentRuntime.js +1084 -1099
  22. package/extension/src/content/diagnosticsController.js +122 -97
  23. package/extension/src/content/diagnosticsExport.js +236 -0
  24. package/extension/src/content/diagnosticsPanel.js +78 -19
  25. package/extension/src/content/diffReviewPanel.js +8 -5
  26. package/extension/src/content/directoryCleanupRecovery.js +54 -0
  27. package/extension/src/content/generated/content.bundle.js +14680 -3606
  28. package/extension/src/content/generated/content.bundle.meta.json +30 -3
  29. package/extension/src/content/globalPreferencesController.js +1 -1
  30. package/extension/src/content/legacyGlobalRegistry.js +25 -1
  31. package/extension/src/content/localSkillsPanel.js +141 -16
  32. package/extension/src/content/markdownDomRenderer.js +9 -4
  33. package/extension/src/content/markdownText.js +5 -6
  34. package/extension/src/content/modelPicker.js +8 -5
  35. package/extension/src/content/nativeCompatibilityController.js +45 -20
  36. package/extension/src/content/otWarmMirror.js +4 -5
  37. package/extension/src/content/otWarmMirrorController.js +17 -20
  38. package/extension/src/content/pageBridgeClient.js +33 -5
  39. package/extension/src/content/panelMaintenance.js +87 -132
  40. package/extension/src/content/panelRenderer.js +10 -0
  41. package/extension/src/content/pendingInputView.js +109 -76
  42. package/extension/src/content/projectProviderSelection.js +13 -4
  43. package/extension/src/content/projectSessionCleanup.js +109 -62
  44. package/extension/src/content/projectSettingsCoordinator.js +39 -2
  45. package/extension/src/content/providerSettingsCoordinator.js +63 -14
  46. package/extension/src/content/providerSettingsDialog.js +724 -113
  47. package/extension/src/content/recentProjects.js +21 -6
  48. package/extension/src/content/runActivitySummary.js +665 -0
  49. package/extension/src/content/runCompletionMeta.js +344 -0
  50. package/extension/src/content/runController.js +40 -15
  51. package/extension/src/content/runFailureNotice.js +34 -12
  52. package/extension/src/content/runGuidanceController.js +76 -30
  53. package/extension/src/content/runGuidanceView.js +59 -10
  54. package/extension/src/content/runPresence.js +306 -0
  55. package/extension/src/content/runQueueScheduler.js +150 -43
  56. package/extension/src/content/runRecoveryActions.js +146 -0
  57. package/extension/src/content/runResultActions.js +11 -8
  58. package/extension/src/content/runReviewController.js +574 -0
  59. package/extension/src/content/runScrollLayout.js +21 -2
  60. package/extension/src/content/runTimelineView.js +315 -290
  61. package/extension/src/content/scopedPersistencePanelState.js +51 -6
  62. package/extension/src/content/selectionContextView.js +300 -0
  63. package/extension/src/content/sensitivePreflight.js +140 -0
  64. package/extension/src/content/sessionForkController.js +80 -17
  65. package/extension/src/content/sessionManager.js +1 -1
  66. package/extension/src/content/sessionPersistence.js +6 -1
  67. package/extension/src/content/settingsPanel.js +84 -55
  68. package/extension/src/content/settingsWorkbench.js +379 -0
  69. package/extension/src/content/sharedSessionViewSync.js +109 -0
  70. package/extension/src/content/subagentActivityView.js +195 -0
  71. package/extension/src/content/trackedChangeCaptureController.js +7 -3
  72. package/extension/src/content/updateIdle.js +4 -1
  73. package/extension/src/content/updateNotice.js +179 -56
  74. package/extension/src/content/updateSafetyReceiver.js +58 -0
  75. package/extension/src/content/writebackController.js +308 -2
  76. package/extension/src/content/writebackOrchestrator.js +213 -199
  77. package/extension/src/content/writebackPlan.js +231 -0
  78. package/extension/src/content/writebackRecovery.js +122 -0
  79. package/extension/src/content/writingStyleSettings.js +600 -0
  80. package/extension/src/content/writtenChangesView.js +152 -0
  81. package/extension/src/page/binaryAssetUploader.js +223 -23
  82. package/extension/src/page/fileMover.js +256 -0
  83. package/extension/src/page/overleafProjectSnapshot.js +1 -0
  84. package/extension/src/page/ownedDirectoryCleanup.js +94 -0
  85. package/extension/src/page/referenceProjects.js +149 -0
  86. package/extension/src/page/reviewContext.js +113 -0
  87. package/extension/src/page/saveState.js +20 -6
  88. package/extension/src/page/snapshotRouter.js +124 -48
  89. package/extension/src/page/textCoordinates.js +102 -0
  90. package/extension/src/page/textFileCreator.js +442 -71
  91. package/extension/src/page/trackedChangeCapture.js +53 -57
  92. package/extension/src/page/trackedChangeOwnership.js +216 -0
  93. package/extension/src/page/trackedChangeReplay.js +184 -0
  94. package/extension/src/page/trackedChangesLifecycle.js +343 -339
  95. package/extension/src/page/treeOperations.js +33 -12
  96. package/extension/src/page/updateSafetyProbe.js +41 -0
  97. package/extension/src/page/writebackReceiptJournal.js +114 -0
  98. package/extension/src/page/writebackRouter.js +242 -201
  99. package/extension/src/pageBridge.js +73 -102
  100. package/extension/src/popup.js +261 -65
  101. package/extension/src/shared/agentTranscript.js +41 -4
  102. package/extension/src/shared/auditRecords.js +73 -0
  103. package/extension/src/shared/changeHistoryModel.js +94 -0
  104. package/extension/src/shared/compatibility.js +22 -6
  105. package/extension/src/shared/compileAdapter.js +101 -37
  106. package/extension/src/shared/composerAttachmentDraft.js +151 -0
  107. package/extension/src/shared/directoryCleanupProof.js +43 -0
  108. package/extension/src/shared/failureReasons.js +329 -3
  109. package/extension/src/shared/globalPreferences.js +31 -14
  110. package/extension/src/shared/governanceRules.js +4 -37
  111. package/extension/src/shared/i18n.js +389 -25
  112. package/extension/src/shared/managedUpdateProjection.js +8 -5
  113. package/extension/src/shared/nativeRequestIdentity.js +1 -0
  114. package/extension/src/shared/pageRpcContract.js +9 -2
  115. package/extension/src/shared/projectFiles.js +21 -44
  116. package/extension/src/shared/providerProfiles.js +114 -3
  117. package/extension/src/shared/runActivityModel.js +361 -0
  118. package/extension/src/shared/runExecutionSnapshot.js +8 -2
  119. package/extension/src/shared/runExecutionSnapshotCodec.js +16 -4
  120. package/extension/src/shared/runInputQueue.js +48 -5
  121. package/extension/src/shared/scopedPersistenceBrowserAdapter.js +6 -3
  122. package/extension/src/shared/selectionContext.js +37 -0
  123. package/extension/src/shared/sessionState.js +166 -30
  124. package/extension/src/shared/settlementFacts.js +10 -2
  125. package/extension/src/shared/sharedSessionBridge.js +311 -0
  126. package/extension/src/shared/sharedSessionTransfer.js +140 -0
  127. package/extension/src/shared/staleGuard.js +118 -13
  128. package/extension/src/shared/storageDb.js +77 -78
  129. package/extension/src/shared/storageMigration.js +74 -111
  130. package/extension/src/shared/storageRunActions.js +211 -22
  131. package/extension/src/shared/storageValuePruning.js +40 -0
  132. package/extension/src/shared/subagentActivityModel.js +174 -0
  133. package/extension/src/shared/undoOperations.js +216 -6
  134. package/extension/src/shared/updateConsent.js +42 -11
  135. package/extension/src/shared/updateRuntimeIdentity.js +1 -1
  136. package/extension/src/shared/writebackIntent.js +78 -0
  137. package/extension/src/shared/writebackOperationEvidence.js +4 -15
  138. package/extension/src/shared/writebackSettlement.js +67 -48
  139. package/extension/src/shared/writingStyle.js +33 -0
  140. package/extension/styles/panel.css +1987 -385
  141. package/extension/styles/popup.css +110 -0
  142. package/native-host/src/anthropicBridgeRequest.js +6 -3
  143. package/native-host/src/anthropicBridgeResponse.js +6 -2
  144. package/native-host/src/anthropicMessagesBridge.js +24 -16
  145. package/native-host/src/bootstrapMigration.js +296 -0
  146. package/native-host/src/bootstrapMigrationContract.js +101 -0
  147. package/native-host/src/bootstrapUpdate.js +233 -0
  148. package/native-host/src/bootstrapUpdateWatchdog.js +44 -0
  149. package/native-host/src/chatBridgeResponse.js +10 -0
  150. package/native-host/src/chatCompletionsBridge.js +21 -15
  151. package/native-host/src/codexConfigPaths.js +106 -0
  152. package/native-host/src/codexHome.js +66 -73
  153. package/native-host/src/codexHomeScope.js +124 -0
  154. package/native-host/src/codexInheritedAuth.js +90 -0
  155. package/native-host/src/codexLocalSkills.js +301 -0
  156. package/native-host/src/codexModelRecovery.js +107 -0
  157. package/native-host/src/codexPromptAssembly.js +33 -12
  158. package/native-host/src/codexProviderLaunch.js +3 -3
  159. package/native-host/src/codexProviderTest.js +24 -26
  160. package/native-host/src/codexRuntimeIdentity.js +1 -0
  161. package/native-host/src/codexSessionRunner.js +211 -318
  162. package/native-host/src/codexSessionTiming.js +21 -8
  163. package/native-host/src/codexSkillIsolation.js +170 -0
  164. package/native-host/src/codexThreadFork.js +19 -3
  165. package/native-host/src/index.js +19 -7
  166. package/native-host/src/managedInstall.js +115 -39
  167. package/native-host/src/managedInstallRecovery.js +140 -0
  168. package/native-host/src/managedRuntimeEvidence.js +57 -0
  169. package/native-host/src/mirrorWorkspace.js +92 -22
  170. package/native-host/src/nativeDoctor.js +15 -0
  171. package/native-host/src/nativeEnvironment.js +70 -0
  172. package/native-host/src/nativeHelperLifecycle.js +21 -0
  173. package/native-host/src/nativeHostRegistration.js +33 -0
  174. package/native-host/src/nativeQuotas.js +15 -8
  175. package/native-host/src/nativeRunLifecycle.js +71 -0
  176. package/native-host/src/overleafWorkspaceRules.js +16 -0
  177. package/native-host/src/processStopBarrier.js +115 -0
  178. package/native-host/src/projectPathPlatform.js +30 -0
  179. package/native-host/src/providerHttp.js +80 -0
  180. package/native-host/src/providerModelCatalog.js +4 -3
  181. package/native-host/src/providerProfile.js +17 -3
  182. package/native-host/src/providerReasoning.js +10 -11
  183. package/native-host/src/providerRuntime.js +1 -0
  184. package/native-host/src/providerStore.js +76 -14
  185. package/native-host/src/releaseTransport.js +14 -5
  186. package/native-host/src/responsesPassthroughBridge.js +266 -52
  187. package/native-host/src/runtimeInstaller.js +21 -1
  188. package/native-host/src/selectionScope.js +86 -0
  189. package/native-host/src/skills/parallel-subagents/SKILL.md +31 -3
  190. package/native-host/src/skills/writing-style-builder/SKILL.md +146 -0
  191. package/native-host/src/subagentAdmission.js +26 -0
  192. package/native-host/src/subagentBroker.js +176 -159
  193. package/native-host/src/subagentTelemetry.js +325 -0
  194. package/native-host/src/subagentWorkspace.js +103 -0
  195. package/native-host/src/subagentWorkspacePath.js +34 -0
  196. package/native-host/src/taskRunnerRuntime.js +130 -57
  197. package/native-host/src/tomlStatements.js +140 -0
  198. package/native-host/src/turnAttachments.js +113 -0
  199. package/native-host/src/updateManager.js +406 -38
  200. package/native-host/src/updateNetworkControl.js +75 -0
  201. package/native-host/src/updateTrust.js +21 -2
  202. package/native-host/src/vendor/pdfjs/LICENSE +177 -0
  203. package/native-host/src/vendor/pdfjs/SOURCE.txt +3 -0
  204. package/native-host/src/vendor/pdfjs/cmaps/78-EUC-H.bcmap +0 -0
  205. package/native-host/src/vendor/pdfjs/cmaps/78-EUC-V.bcmap +0 -0
  206. package/native-host/src/vendor/pdfjs/cmaps/78-H.bcmap +0 -0
  207. package/native-host/src/vendor/pdfjs/cmaps/78-RKSJ-H.bcmap +0 -0
  208. package/native-host/src/vendor/pdfjs/cmaps/78-RKSJ-V.bcmap +0 -0
  209. package/native-host/src/vendor/pdfjs/cmaps/78-V.bcmap +0 -0
  210. package/native-host/src/vendor/pdfjs/cmaps/78ms-RKSJ-H.bcmap +0 -0
  211. package/native-host/src/vendor/pdfjs/cmaps/78ms-RKSJ-V.bcmap +0 -0
  212. package/native-host/src/vendor/pdfjs/cmaps/83pv-RKSJ-H.bcmap +0 -0
  213. package/native-host/src/vendor/pdfjs/cmaps/90ms-RKSJ-H.bcmap +0 -0
  214. package/native-host/src/vendor/pdfjs/cmaps/90ms-RKSJ-V.bcmap +0 -0
  215. package/native-host/src/vendor/pdfjs/cmaps/90msp-RKSJ-H.bcmap +0 -0
  216. package/native-host/src/vendor/pdfjs/cmaps/90msp-RKSJ-V.bcmap +0 -0
  217. package/native-host/src/vendor/pdfjs/cmaps/90pv-RKSJ-H.bcmap +0 -0
  218. package/native-host/src/vendor/pdfjs/cmaps/90pv-RKSJ-V.bcmap +0 -0
  219. package/native-host/src/vendor/pdfjs/cmaps/Add-H.bcmap +0 -0
  220. package/native-host/src/vendor/pdfjs/cmaps/Add-RKSJ-H.bcmap +0 -0
  221. package/native-host/src/vendor/pdfjs/cmaps/Add-RKSJ-V.bcmap +0 -0
  222. package/native-host/src/vendor/pdfjs/cmaps/Add-V.bcmap +0 -0
  223. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-0.bcmap +0 -0
  224. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-1.bcmap +0 -0
  225. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-2.bcmap +0 -0
  226. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-3.bcmap +0 -0
  227. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-4.bcmap +0 -0
  228. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-5.bcmap +0 -0
  229. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-6.bcmap +0 -0
  230. package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
  231. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-0.bcmap +0 -0
  232. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-1.bcmap +0 -0
  233. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-2.bcmap +0 -0
  234. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-3.bcmap +0 -0
  235. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-4.bcmap +0 -0
  236. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-5.bcmap +0 -0
  237. package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
  238. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-0.bcmap +0 -0
  239. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-1.bcmap +0 -0
  240. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-2.bcmap +0 -0
  241. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-3.bcmap +0 -0
  242. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-4.bcmap +0 -0
  243. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-5.bcmap +0 -0
  244. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-6.bcmap +0 -0
  245. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
  246. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-0.bcmap +0 -0
  247. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-1.bcmap +0 -0
  248. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-2.bcmap +0 -0
  249. package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
  250. package/native-host/src/vendor/pdfjs/cmaps/B5-H.bcmap +0 -0
  251. package/native-host/src/vendor/pdfjs/cmaps/B5-V.bcmap +0 -0
  252. package/native-host/src/vendor/pdfjs/cmaps/B5pc-H.bcmap +0 -0
  253. package/native-host/src/vendor/pdfjs/cmaps/B5pc-V.bcmap +0 -0
  254. package/native-host/src/vendor/pdfjs/cmaps/CNS-EUC-H.bcmap +0 -0
  255. package/native-host/src/vendor/pdfjs/cmaps/CNS-EUC-V.bcmap +0 -0
  256. package/native-host/src/vendor/pdfjs/cmaps/CNS1-H.bcmap +0 -0
  257. package/native-host/src/vendor/pdfjs/cmaps/CNS1-V.bcmap +0 -0
  258. package/native-host/src/vendor/pdfjs/cmaps/CNS2-H.bcmap +0 -0
  259. package/native-host/src/vendor/pdfjs/cmaps/CNS2-V.bcmap +3 -0
  260. package/native-host/src/vendor/pdfjs/cmaps/ETHK-B5-H.bcmap +0 -0
  261. package/native-host/src/vendor/pdfjs/cmaps/ETHK-B5-V.bcmap +0 -0
  262. package/native-host/src/vendor/pdfjs/cmaps/ETen-B5-H.bcmap +0 -0
  263. package/native-host/src/vendor/pdfjs/cmaps/ETen-B5-V.bcmap +0 -0
  264. package/native-host/src/vendor/pdfjs/cmaps/ETenms-B5-H.bcmap +3 -0
  265. package/native-host/src/vendor/pdfjs/cmaps/ETenms-B5-V.bcmap +0 -0
  266. package/native-host/src/vendor/pdfjs/cmaps/EUC-H.bcmap +0 -0
  267. package/native-host/src/vendor/pdfjs/cmaps/EUC-V.bcmap +0 -0
  268. package/native-host/src/vendor/pdfjs/cmaps/Ext-H.bcmap +0 -0
  269. package/native-host/src/vendor/pdfjs/cmaps/Ext-RKSJ-H.bcmap +0 -0
  270. package/native-host/src/vendor/pdfjs/cmaps/Ext-RKSJ-V.bcmap +0 -0
  271. package/native-host/src/vendor/pdfjs/cmaps/Ext-V.bcmap +0 -0
  272. package/native-host/src/vendor/pdfjs/cmaps/GB-EUC-H.bcmap +0 -0
  273. package/native-host/src/vendor/pdfjs/cmaps/GB-EUC-V.bcmap +0 -0
  274. package/native-host/src/vendor/pdfjs/cmaps/GB-H.bcmap +4 -0
  275. package/native-host/src/vendor/pdfjs/cmaps/GB-V.bcmap +0 -0
  276. package/native-host/src/vendor/pdfjs/cmaps/GBK-EUC-H.bcmap +0 -0
  277. package/native-host/src/vendor/pdfjs/cmaps/GBK-EUC-V.bcmap +0 -0
  278. package/native-host/src/vendor/pdfjs/cmaps/GBK2K-H.bcmap +0 -0
  279. package/native-host/src/vendor/pdfjs/cmaps/GBK2K-V.bcmap +0 -0
  280. package/native-host/src/vendor/pdfjs/cmaps/GBKp-EUC-H.bcmap +0 -0
  281. package/native-host/src/vendor/pdfjs/cmaps/GBKp-EUC-V.bcmap +0 -0
  282. package/native-host/src/vendor/pdfjs/cmaps/GBT-EUC-H.bcmap +0 -0
  283. package/native-host/src/vendor/pdfjs/cmaps/GBT-EUC-V.bcmap +0 -0
  284. package/native-host/src/vendor/pdfjs/cmaps/GBT-H.bcmap +0 -0
  285. package/native-host/src/vendor/pdfjs/cmaps/GBT-V.bcmap +0 -0
  286. package/native-host/src/vendor/pdfjs/cmaps/GBTpc-EUC-H.bcmap +0 -0
  287. package/native-host/src/vendor/pdfjs/cmaps/GBTpc-EUC-V.bcmap +0 -0
  288. package/native-host/src/vendor/pdfjs/cmaps/GBpc-EUC-H.bcmap +0 -0
  289. package/native-host/src/vendor/pdfjs/cmaps/GBpc-EUC-V.bcmap +0 -0
  290. package/native-host/src/vendor/pdfjs/cmaps/H.bcmap +0 -0
  291. package/native-host/src/vendor/pdfjs/cmaps/HKdla-B5-H.bcmap +0 -0
  292. package/native-host/src/vendor/pdfjs/cmaps/HKdla-B5-V.bcmap +0 -0
  293. package/native-host/src/vendor/pdfjs/cmaps/HKdlb-B5-H.bcmap +0 -0
  294. package/native-host/src/vendor/pdfjs/cmaps/HKdlb-B5-V.bcmap +0 -0
  295. package/native-host/src/vendor/pdfjs/cmaps/HKgccs-B5-H.bcmap +0 -0
  296. package/native-host/src/vendor/pdfjs/cmaps/HKgccs-B5-V.bcmap +0 -0
  297. package/native-host/src/vendor/pdfjs/cmaps/HKm314-B5-H.bcmap +0 -0
  298. package/native-host/src/vendor/pdfjs/cmaps/HKm314-B5-V.bcmap +0 -0
  299. package/native-host/src/vendor/pdfjs/cmaps/HKm471-B5-H.bcmap +0 -0
  300. package/native-host/src/vendor/pdfjs/cmaps/HKm471-B5-V.bcmap +0 -0
  301. package/native-host/src/vendor/pdfjs/cmaps/HKscs-B5-H.bcmap +0 -0
  302. package/native-host/src/vendor/pdfjs/cmaps/HKscs-B5-V.bcmap +0 -0
  303. package/native-host/src/vendor/pdfjs/cmaps/Hankaku.bcmap +0 -0
  304. package/native-host/src/vendor/pdfjs/cmaps/Hiragana.bcmap +0 -0
  305. package/native-host/src/vendor/pdfjs/cmaps/KSC-EUC-H.bcmap +0 -0
  306. package/native-host/src/vendor/pdfjs/cmaps/KSC-EUC-V.bcmap +0 -0
  307. package/native-host/src/vendor/pdfjs/cmaps/KSC-H.bcmap +0 -0
  308. package/native-host/src/vendor/pdfjs/cmaps/KSC-Johab-H.bcmap +0 -0
  309. package/native-host/src/vendor/pdfjs/cmaps/KSC-Johab-V.bcmap +0 -0
  310. package/native-host/src/vendor/pdfjs/cmaps/KSC-V.bcmap +0 -0
  311. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-H.bcmap +0 -0
  312. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
  313. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
  314. package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-V.bcmap +0 -0
  315. package/native-host/src/vendor/pdfjs/cmaps/KSCpc-EUC-H.bcmap +0 -0
  316. package/native-host/src/vendor/pdfjs/cmaps/KSCpc-EUC-V.bcmap +0 -0
  317. package/native-host/src/vendor/pdfjs/cmaps/Katakana.bcmap +0 -0
  318. package/native-host/src/vendor/pdfjs/cmaps/LICENSE +36 -0
  319. package/native-host/src/vendor/pdfjs/cmaps/NWP-H.bcmap +0 -0
  320. package/native-host/src/vendor/pdfjs/cmaps/NWP-V.bcmap +0 -0
  321. package/native-host/src/vendor/pdfjs/cmaps/RKSJ-H.bcmap +0 -0
  322. package/native-host/src/vendor/pdfjs/cmaps/RKSJ-V.bcmap +0 -0
  323. package/native-host/src/vendor/pdfjs/cmaps/Roman.bcmap +0 -0
  324. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UCS2-H.bcmap +0 -0
  325. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UCS2-V.bcmap +0 -0
  326. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF16-H.bcmap +0 -0
  327. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF16-V.bcmap +0 -0
  328. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF32-H.bcmap +0 -0
  329. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF32-V.bcmap +0 -0
  330. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF8-H.bcmap +0 -0
  331. package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF8-V.bcmap +0 -0
  332. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UCS2-H.bcmap +0 -0
  333. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UCS2-V.bcmap +0 -0
  334. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF16-H.bcmap +0 -0
  335. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF16-V.bcmap +0 -0
  336. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF32-H.bcmap +0 -0
  337. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF32-V.bcmap +0 -0
  338. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF8-H.bcmap +0 -0
  339. package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF8-V.bcmap +0 -0
  340. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-H.bcmap +0 -0
  341. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
  342. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
  343. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-V.bcmap +0 -0
  344. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF16-H.bcmap +0 -0
  345. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF16-V.bcmap +0 -0
  346. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF32-H.bcmap +0 -0
  347. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF32-V.bcmap +0 -0
  348. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF8-H.bcmap +0 -0
  349. package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF8-V.bcmap +0 -0
  350. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
  351. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
  352. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
  353. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
  354. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
  355. package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
  356. package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
  357. package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
  358. package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
  359. package/native-host/src/vendor/pdfjs/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
  360. package/native-host/src/vendor/pdfjs/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
  361. package/native-host/src/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
  362. package/native-host/src/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
  363. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UCS2-H.bcmap +0 -0
  364. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UCS2-V.bcmap +0 -0
  365. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF16-H.bcmap +0 -0
  366. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF16-V.bcmap +0 -0
  367. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF32-H.bcmap +0 -0
  368. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF32-V.bcmap +0 -0
  369. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF8-H.bcmap +0 -0
  370. package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF8-V.bcmap +0 -0
  371. package/native-host/src/vendor/pdfjs/cmaps/V.bcmap +0 -0
  372. package/native-host/src/vendor/pdfjs/cmaps/WP-Symbol.bcmap +0 -0
  373. package/native-host/src/vendor/pdfjs/pdf.mjs +26740 -0
  374. package/native-host/src/vendor/pdfjs/pdf.worker.mjs +62201 -0
  375. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitDingbats.pfb +0 -0
  376. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixed.pfb +0 -0
  377. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedBold.pfb +0 -0
  378. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
  379. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedItalic.pfb +0 -0
  380. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerif.pfb +0 -0
  381. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifBold.pfb +0 -0
  382. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
  383. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifItalic.pfb +0 -0
  384. package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSymbol.pfb +0 -0
  385. package/native-host/src/vendor/pdfjs/standard_fonts/LICENSE_FOXIT +27 -0
  386. package/native-host/src/vendor/pdfjs/standard_fonts/LICENSE_LIBERATION +102 -0
  387. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Bold.ttf +0 -0
  388. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
  389. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Italic.ttf +0 -0
  390. package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Regular.ttf +0 -0
  391. package/native-host/src/writingStyleEvidence.js +102 -0
  392. package/native-host/src/writingStylePdfWorker.js +35 -0
  393. package/native-host/src/writingStyleProfile.js +165 -0
  394. package/native-host/src/writingStyleRuntime.js +475 -0
  395. package/native-host/src/writingStyleStore.js +73 -0
  396. package/package.json +1 -1
  397. package/scripts/install-managed.mjs +1 -0
@@ -2,40 +2,85 @@
2
2
  'use strict';
3
3
 
4
4
  function create(deps = {}) {
5
+ // Unacknowledged input is a page-local projection. Only confirmed delivery
6
+ // joins record.events; the durable queue owns refresh/recovery before that.
7
+ const pending = new Map();
8
+ let lastTimestamp = 0;
9
+ const keyOf = target => JSON.stringify([target.sessionId, target.recordId, target.guidanceId]);
10
+ const sameScope = scope => !scope || ['accountScopeId', 'projectId', 'generation'].every(key => scope[key] === deps.getScope?.()?.[key]);
11
+ function ownedRecord(target) {
12
+ if (!target.sessionId || !target.recordId) return null;
13
+ if (target.sessionCreatedAt !== undefined && deps.getSessionCreatedAt
14
+ && deps.getSessionCreatedAt(target.sessionId) !== target.sessionCreatedAt) return null;
15
+ return deps.findRunRecord?.(target.recordId, target.sessionId) || null;
16
+ }
17
+ function nextTimestamp() {
18
+ lastTimestamp = Math.max(Date.now(), lastTimestamp + 1);
19
+ return new Date(lastTimestamp).toISOString();
20
+ }
21
+ function getPending(run) {
22
+ return [...pending.values()].filter(token => token.target.recordId === run?.id
23
+ && (!deps.getActiveSessionId || token.target.sessionId === deps.getActiveSessionId())
24
+ && sameScope(token.scope) && ownedRecord(token.target)).map(token => token.event);
25
+ }
26
+ function refresh(target) {
27
+ const record = ownedRecord(target);
28
+ if (!record) return null;
29
+ const view = deps.getCurrentRunView?.();
30
+ const root = deps.getRunRoot?.(target) || (view?.recordId === target.recordId
31
+ && view?.sessionId === target.sessionId ? view.root : null);
32
+ const container = root?.querySelector('[data-run-guidance]');
33
+ deps.RunGuidanceView?.reconcileGuidance(container,
34
+ (record.events || []).concat(getPending(record)), deps.tx, { active: record.status === 'running' });
35
+ return container;
36
+ }
37
+ function refreshSettled(target) {
38
+ try { refresh(target); } catch (error) { deps.onPresentationError?.(error); }
39
+ }
40
+ function preview(text, target = {}) {
41
+ const title = String(text || '').trim();
42
+ if (!title || !target.guidanceId || !ownedRecord(target)) return null;
43
+ const token = { target: { ...target }, scope: deps.getScope?.(), event: { title, status: 'steering', kind: 'guidance',
44
+ guidanceId: target.guidanceId, timestamp: nextTimestamp(), guidancePending: true } };
45
+ pending.set(keyOf(target), token);
46
+ try {
47
+ const container = refresh(target);
48
+ const row = container?.querySelector?.(`[data-guidance-id="${deps.cssEscape?.(target.guidanceId) || target.guidanceId}"]`);
49
+ if (row) deps.revealGuidance?.(row);
50
+ deps.bumpUnreadIfDetached?.();
51
+ } catch (error) {
52
+ if (pending.get(keyOf(target)) === token) pending.delete(keyOf(target));
53
+ try { refresh(target); } catch { /* preserve the original presentation error */ }
54
+ throw error;
55
+ }
56
+ return token;
57
+ }
58
+ function clearPreview(token) {
59
+ if (!token || pending.get(keyOf(token.target)) !== token) return;
60
+ pending.delete(keyOf(token.target));
61
+ if (sameScope(token.scope)) refreshSettled(token.target);
62
+ }
5
63
  function upsert(text, target = {}) {
6
- const record = deps.findRunRecord?.(target.recordId, target.sessionId);
64
+ const record = ownedRecord(target);
7
65
  const guidanceId = String(target.guidanceId || '').trim();
8
66
  if (!record || !guidanceId) return null;
9
- const event = {
10
- title: String(text || '').trim(),
11
- status: target.status || 'queued',
12
- kind: 'guidance',
13
- guidanceId,
14
- timestamp: new Date().toISOString()
15
- };
16
- const existing = (record.events || []).find(entry => entry.guidanceId === guidanceId);
17
- if (!existing) {
18
- deps.appendRunEvent?.(event, record);
19
- return event;
20
- }
21
- Object.assign(existing, event, { timestamp: existing.timestamp || event.timestamp });
22
- const view = deps.getCurrentRunView?.();
23
- if (view?.recordId === target.recordId) {
24
- view.root?.querySelector(`[data-guidance-id="${deps.cssEscape(guidanceId)}"]`)
25
- ?.replaceWith(deps.renderRunEvent(existing));
26
- }
27
- return existing;
67
+ const existing = (record.events || []).find(entry => entry.kind === 'guidance' && entry.guidanceId === guidanceId);
68
+ const event = { title: String(text || '').trim(), status: target.status || 'completed', kind: 'guidance', guidanceId,
69
+ timestamp: existing?.timestamp || target.timestamp || pending.get(keyOf(target))?.event.timestamp || nextTimestamp() };
70
+ if (existing) Object.assign(existing, event);
71
+ else record.events = [...(record.events || []), event].slice(-(deps.maxRunEvents || 300));
72
+ // A late ACK still belongs to the captured run, even if another run is
73
+ // now active. The coordinator saves it together with queue removal.
74
+ deps.onRecordChanged?.(target);
75
+ refreshSettled(target);
76
+ return existing || event;
28
77
  }
29
-
30
78
  function remove(guidanceId, target = {}) {
31
- const record = deps.findRunRecord?.(target.recordId, target.sessionId);
79
+ const record = ownedRecord(target);
32
80
  if (!record || !guidanceId) return false;
33
81
  const before = (record.events || []).length;
34
82
  record.events = (record.events || []).filter(event => event.guidanceId !== guidanceId);
35
- const view = deps.getCurrentRunView?.();
36
- if (view?.recordId === target.recordId) {
37
- view.root?.querySelector(`[data-guidance-id="${deps.cssEscape(guidanceId)}"]`)?.remove();
38
- }
83
+ refreshSettled(target);
39
84
  return record.events.length !== before;
40
85
  }
41
86
 
@@ -49,13 +94,14 @@
49
94
  function appendToView(event, view) {
50
95
  const text = deps.RunGuidanceView?.getGuidanceText(event);
51
96
  if (!text) return false;
52
- const guidance = view.guidance || view.root?.querySelector('[data-run-guidance]');
53
- const target = view.terminalStatus ? guidance : view.events;
97
+ const root = view.root || view.events?.closest('[data-run-id]');
98
+ const guidance = view.guidance || root?.querySelector('[data-run-guidance]');
99
+ const target = guidance || view.events;
54
100
  if (!target) return false;
55
101
  view.guidance = guidance;
56
102
  const rendered = deps.renderRunEvent(event);
57
103
  const existing = event.guidanceId
58
- ? view.root?.querySelector(`[data-guidance-id="${deps.cssEscape(event.guidanceId)}"]`)
104
+ ? root?.querySelector(`[data-guidance-id="${deps.cssEscape(event.guidanceId)}"]`)
59
105
  : null;
60
106
  if (existing) existing.replaceWith(rendered);
61
107
  else target.append(rendered);
@@ -63,7 +109,7 @@
63
109
  return true;
64
110
  }
65
111
 
66
- return { upsert, remove, settleView, appendToView };
112
+ return { preview, clearPreview, getPending, upsert, remove, settleView, appendToView };
67
113
  }
68
114
 
69
115
  window.CodexOverleafRunGuidanceController = { create };
@@ -26,23 +26,72 @@
26
26
  const row = document.createElement('div');
27
27
  row.className = 'run-guidance-message run-user-message';
28
28
  row.dataset.kind = 'guidance';
29
- row.dataset.status = event.status || 'completed';
30
- if (event.guidanceId) {
31
- row.dataset.guidanceId = event.guidanceId;
32
- }
33
29
  row.setAttribute('role', 'group');
34
- row.setAttribute('aria-label', tx('Follow-up guidance', '\u540e\u7eed\u5f15\u5bfc'));
35
-
36
30
  const text = document.createElement('div');
37
31
  text.className = 'run-guidance-text';
38
- text.textContent = guidanceText;
39
-
40
- row.append(text);
32
+ const label = document.createElement('div');
33
+ label.className = 'run-guidance-label';
34
+ row.append(text, label);
35
+ updateGuidanceMessage(row, event, guidanceText, tx);
41
36
  return row;
42
37
  }
43
38
 
39
+ function updateGuidanceMessage(row, event, guidanceText, tx, { active = true } = {}) {
40
+ row.dataset.status = event.status || 'completed';
41
+ if (event.guidanceId) row.dataset.guidanceId = event.guidanceId;
42
+ row.dataset.guidanceTimestamp = event.timestamp || '';
43
+ const label = tx('Follow-up guidance', '补充指令');
44
+ const sending = (active || event.guidancePending === true) && ['queued', 'steering'].includes(event.status);
45
+ const text = row.querySelector('.run-guidance-text');
46
+ if (text.textContent !== guidanceText) text.textContent = guidanceText;
47
+ const status = row.querySelector('.run-guidance-label');
48
+ const statusText = label + (sending ? tx(' · Sending…', ' · 发送中…') : '');
49
+ if (status.textContent !== statusText) status.textContent = statusText;
50
+ row.setAttribute('aria-label', statusText);
51
+ }
52
+
53
+ // Stored events and the controller's in-flight projection share a container.
54
+ // Confirmation updates the same row; removed previews leave no stale bubble.
55
+ function reconcileGuidance(container, events, tx, options = {}) {
56
+ if (!container) return;
57
+ const completedLegacy = new Set(events.filter(event => !event.guidanceId && event.status === 'completed')
58
+ .map(getGuidanceText).filter(Boolean));
59
+ const entries = new Map();
60
+ for (const [index, event] of events.entries()) {
61
+ const text = getGuidanceText(event);
62
+ if (!text || (!event.guidanceId && event.status === 'queued' && completedLegacy.has(text))) continue;
63
+ const key = event.guidanceId ? 'id:' + event.guidanceId : 'legacy:' + index;
64
+ const previous = entries.get(key);
65
+ if (previous && event.guidancePending === true && previous.event.guidancePending !== true) continue;
66
+ entries.set(key, { key, event: previous ? { ...event, timestamp: previous.event.timestamp || event.timestamp } : event, text });
67
+ }
68
+ const existing = new Map();
69
+ for (const row of [...container.children]) {
70
+ const key = row.dataset.guidanceId ? 'id:' + row.dataset.guidanceId : row.dataset.guidanceKey;
71
+ if (!key || existing.has(key)) { row.remove(); continue; }
72
+ existing.set(key, row);
73
+ }
74
+ for (const [key, row] of existing) if (!entries.has(key)) row.remove();
75
+ const known = [...entries.values()].filter(entry => Number.isFinite(Date.parse(entry.event.timestamp)))
76
+ .sort((a, b) => Date.parse(a.event.timestamp) - Date.parse(b.event.timestamp));
77
+ let datedIndex = 0;
78
+ // Keep legacy rows without timestamps in their event-order slots.
79
+ const ordered = [...entries.values()].map(entry => Number.isFinite(Date.parse(entry.event.timestamp)) ? known[datedIndex++] : entry);
80
+ let cursor = container.firstChild;
81
+ for (const entry of ordered) {
82
+ const row = existing.get(entry.key) || renderGuidanceMessage(entry.event, entry.text, tx);
83
+ row.dataset.guidanceKey = entry.key;
84
+ if (entry.event.guidancePending === true) row.dataset.guidancePending = 'true';
85
+ else delete row.dataset.guidancePending;
86
+ updateGuidanceMessage(row, entry.event, entry.text, tx, options);
87
+ if (row !== cursor) container.insertBefore(row, cursor);
88
+ cursor = row.nextSibling;
89
+ }
90
+ }
91
+
44
92
  window.CodexOverleafRunGuidanceView = {
45
93
  getGuidanceText,
46
- renderGuidanceMessage
94
+ renderGuidanceMessage,
95
+ reconcileGuidance
47
96
  };
48
97
  })();
@@ -0,0 +1,306 @@
1
+ (function initRunPresence(root, factory) {
2
+ if (typeof module === 'object' && module.exports) {
3
+ module.exports = factory();
4
+ } else {
5
+ root.CodexOverleafModuleRegistry.define('RunPresence', [], factory);
6
+ }
7
+ })(typeof window !== 'undefined' ? window : globalThis, function runPresenceFactory() {
8
+ 'use strict';
9
+
10
+ // Presentation-only run header: the animated brand mark, the live label and
11
+ // the settled summary. It never reads or writes run records.
12
+ const VERBS = {
13
+ en: ['Vibe writing', 'Typesetting', 'Kerning', 'Footnoting', 'Citing sources', 'Peer-reviewing',
14
+ 'Polishing prose', 'Balancing braces', 'Chasing references', 'Proofreading', 'Untangling macros',
15
+ 'Hunting overfull hboxes'],
16
+ zh: ['推敲中', '斟酌措辞', '排版中', '查文献', '对齐公式', '润色中', '翻稿纸', '补脚注', '配平括号',
17
+ '追引用', '校对中', '抓 overfull hbox']
18
+ };
19
+ const TIPS = {
20
+ en: ['Type @ to add a file as context, e.g. @sections/intro.tex.',
21
+ 'Ask for an edit, not a rewrite: “tighten §2, keep every citation”.',
22
+ 'Compile errors can go straight back to Codex from the log.',
23
+ '\\label everything. Cross-references are cheaper than prose.',
24
+ 'Reviewer 2 is not here. Yet.',
25
+ 'Overfull \\hbox? Ask Codex to rephrase the line, not shrink the font.'],
26
+ zh: ['输入 @ 把文件加入上下文,比如 @sections/intro.tex。',
27
+ '让它“改”而不是“重写”:“精简 §2,保留所有引用”。',
28
+ '编译报错可以直接从日志发回给 Codex。',
29
+ '多打 \\label。交叉引用比文字描述省事。',
30
+ 'Reviewer 2 还没来,趁现在。',
31
+ 'Overfull \\hbox?让 Codex 改写这一行,而不是缩字号。']
32
+ };
33
+ // The header word changes rarely: at 1, 3, 7 and 15 minutes, so even a long run shows only a few words.
34
+ const WORD_AT_MS = [0, 60000, 180000, 420000, 900000];
35
+ const LONG_RUN_MS = 120000;
36
+ // Layers (inlined in panel.css) are pixel-exact slices of assets/icons/codex-overleaf-icon.png;
37
+ // the origins (percent of the square crop) are the leaf stem and cloud centre.
38
+ const MARK_LAYERS = ['cloud', 'cursor', 'leaf'];
39
+ const MARK_STYLE = '--mark-leaf-origin:70.6% 41.6%;--mark-cloud-origin:44.3% 55%';
40
+ const ICONS = {
41
+ alert: '<circle cx="8" cy="8" r="6"/><path d="M8 4.5v4 M8 11h.01"/>',
42
+ check: '<path d="m3.5 8 3 3 6-6"/>',
43
+ file: '<path d="M9 2H4v12h8V5L9 2Z M9 2v4h3 M6 9h4 M6 11h3"/>',
44
+ refresh: '<path d="M4.2 5.3A5 5 0 1 1 3.6 10"/><path d="M4.2 2.2v3.1H1.1"/>'
45
+ };
46
+
47
+ const escapeHtml = value => String(value ?? '').replace(/[&<>"']/g, char => ({
48
+ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;'
49
+ })[char]);
50
+
51
+ function icon(name, className = 'codex-glyph') {
52
+ return '<svg class="' + className + '" viewBox="0 0 16 16" aria-hidden="true" focusable="false">'
53
+ + (ICONS[name] || ICONS.check) + '</svg>';
54
+ }
55
+
56
+ function qed(className = '') {
57
+ return '<span class="run-qed' + (className ? ' ' + className : '') + '" aria-hidden="true">'
58
+ + '<svg viewBox="0 0 11 11" focusable="false"><rect x="1" y="1" width="9" height="9" rx=".6"/></svg></span>';
59
+ }
60
+
61
+ function pickDifferent(list, previous, random) {
62
+ if (list.length < 2) return list[0] || '';
63
+ const index = Math.min(list.length - 1, Math.floor(random() * list.length));
64
+ // Step past a repeat instead of re-rolling, so a fixed random source can never spin.
65
+ return list[index] === previous ? list[(index + 1) % list.length] : list[index];
66
+ }
67
+
68
+ // Tool rows win over playful verbs; the label names the real action.
69
+ function activityVerb(item, tx) {
70
+ const meta = item?.meta || {};
71
+ if (item?.kind === 'explore') {
72
+ return ({ read: tx('Reading', '读取'), search: tx('Searching', '搜索'), list: tx('Listing', '查看') })[meta.action]
73
+ || tx('Exploring', '查阅');
74
+ }
75
+ if (item?.kind === 'edit') {
76
+ return ({ add: tx('Creating', '新建'), delete: tx('Deleting', '删除'), move: tx('Moving', '移动') })[item.file?.operation]
77
+ || tx('Editing', '修改');
78
+ }
79
+ return ({ command: tx('Running', '执行'), compile: tx('Compiling', '编译'), sync: tx('Syncing to Overleaf', '同步到 Overleaf'),
80
+ tool: tx('Using', '调用'), agent: tx('Delegating', '委派子代理'), plan: tx('Planning', '规划') })[item?.kind]
81
+ || tx('Working', '处理中');
82
+ }
83
+
84
+ // Header-only command label: drop the shell wrapper and the leading `cd …&&`, keep the first command.
85
+ function commandSummary(command) {
86
+ let text = String(command || '').trim().replace(/^(?:\/usr)?\/bin\/(?:ba|z)?sh\s+-l?c\s+/, '');
87
+ if (/^(["']).*\1$/s.test(text)) text = text.slice(1, -1);
88
+ text = text.replace(/^cd\s+.*?&&\s*/, '').split(/\s*(?:&&|\|\||[|;])\s*/)[0].replace(/\s+/g, ' ').trim();
89
+ return text.length > 48 ? text.slice(0, 47) + '…' : text;
90
+ }
91
+
92
+ // Settled header: ∎ (end of proof) followed by what the run actually did.
93
+ function settledHtml(facts = {}, tx, formatElapsed) {
94
+ const hasElapsed = Number.isFinite(facts.elapsedMs);
95
+ const elapsed = hasElapsed ? '<span>' + escapeHtml(formatElapsed(facts.elapsedMs)) + '</span>' : '';
96
+ const sep = '<span class="run-summary-sep">·</span>';
97
+ if (facts.kind === 'stopped') {
98
+ return qed('is-open' + (facts.animate ? ' is-settling' : '')) + '<span class="run-summary-stopped">\\end{draft}</span>'
99
+ + (hasElapsed ? sep + '<span>' + escapeHtml(tx('stopped at ', '停在 ') + formatElapsed(facts.elapsedMs)) + '</span>' : '');
100
+ }
101
+ const parts = elapsed ? [elapsed] : [];
102
+ if (facts.files > 0) {
103
+ const files = tx(facts.files + (facts.files === 1 ? ' file' : ' files'), facts.files + ' 个文件');
104
+ // A clipped history only proves the files it recorded.
105
+ parts.push('<span>' + escapeHtml(facts.filesClipped ? tx(files + ' recorded', '已记录 ' + files) : files) + '</span>');
106
+ if (facts.added || facts.removed) {
107
+ parts.push('<span><span class="run-summary-add">+' + Number(facts.added || 0) + '</span> <span class="run-summary-del">−'
108
+ + Number(facts.removed || 0) + '</span></span>');
109
+ }
110
+ } else if (facts.steps > 0) {
111
+ parts.push('<span>' + escapeHtml(tx(facts.steps + ' steps', facts.steps + ' 步')) + '</span>');
112
+ }
113
+ if (facts.compiled) parts.push('<span>' + escapeHtml(tx('compiled', '已编译')) + '</span>');
114
+ if (facts.firstCompile) {
115
+ parts.push('<span class="run-summary-qed">' + escapeHtml(tx('Q.E.D. — first clean compile', 'Q.E.D. · 首次编译通过')) + '</span>');
116
+ }
117
+ const mark = qed(facts.animate ? 'is-settling' + (facts.firstCompile ? ' is-first' : '') : '');
118
+ return '<span class="codex-sr-only">' + escapeHtml(tx('Done', '已完成')) + '</span>' + mark + parts.join(sep);
119
+ }
120
+
121
+ function create(deps = {}) {
122
+ const tx = deps.tx || ((en) => en);
123
+ const locale = () => (deps.getLocale?.() === 'zh' ? 'zh' : 'en');
124
+ const formatElapsed = deps.formatElapsed || (ms => Math.round(ms / 1000) + 's');
125
+ const now = deps.now || Date.now;
126
+ const random = deps.random || Math.random;
127
+ const storage = deps.storage === undefined ? safeStorage() : deps.storage;
128
+ // Wrapped, never stored bare: browser timers throw "Illegal invocation" when called as methods of another object.
129
+ const timers = { later: (fn, ms) => (deps.setTimeout || globalThis.setTimeout)(fn, ms) };
130
+ const doc = () => deps.document || globalThis.document;
131
+ const live = new WeakMap();
132
+ const longRunsShown = new Set();
133
+ let tipIndex = Math.floor(random() * TIPS.en.length);
134
+
135
+ function safeStorage() {
136
+ try { return globalThis.localStorage || null; } catch { return null; }
137
+ }
138
+ function once(key) {
139
+ try {
140
+ if (!storage || storage.getItem(key)) return false;
141
+ storage.setItem(key, '1');
142
+ return true;
143
+ } catch { return false; }
144
+ }
145
+ function isLateNight() {
146
+ const hour = new Date(now()).getHours();
147
+ return hour >= 23 || hour < 5;
148
+ }
149
+ function lateNightEgg() {
150
+ if (!isLateNight()) return '';
151
+ // One "night" runs until 05:00, so a 01:00 run belongs to the previous date.
152
+ const night = new Date(now() - 5 * 3600000).toDateString();
153
+ return once('codex-overleaf:egg:late-night:' + night) ? tx('Burning the midnight oil', '挑灯夜战') : '';
154
+ }
155
+
156
+ function markHtml(className = '') {
157
+ return '<span class="run-mark' + (className ? ' ' + className : '') + '" aria-hidden="true" style="' + MARK_STYLE + '">'
158
+ + MARK_LAYERS.map(layer => '<span class="run-mark-' + layer + '"></span>').join('') + '</span>';
159
+ }
160
+
161
+ function stop(el) {
162
+ live.delete(el);
163
+ }
164
+
165
+ function swapLabel(state, html, egg = false) {
166
+ const box = state.label;
167
+ const next = doc().createElement('span');
168
+ next.className = 'is-in';
169
+ next.innerHTML = '<span class="run-shimmer' + (egg ? ' is-egg' : '') + '">' + html + '…</span>';
170
+ // Drop anything still fading out, so a slow timer can never leave the label blank.
171
+ for (const stale of [...(box.children || [])]) if (stale.className === 'is-out') stale.remove();
172
+ const old = box.lastElementChild;
173
+ box.append(next);
174
+ if (old) {
175
+ old.className = 'is-out';
176
+ timers.later(() => old.remove(), 280);
177
+ }
178
+ }
179
+
180
+ function nextIdle(state) {
181
+ const egg = state.eggs.shift();
182
+ if (egg) { swapLabel(state, escapeHtml(egg), true); return; }
183
+ state.verb = pickDifferent(VERBS[locale()], state.verb, random);
184
+ swapLabel(state, escapeHtml(state.verb));
185
+ }
186
+
187
+ function wordSlot(elapsedMs) {
188
+ let slot = 0;
189
+ for (let index = 0; index < WORD_AT_MS.length; index += 1) if (elapsedMs >= WORD_AT_MS[index]) slot = index;
190
+ return slot;
191
+ }
192
+
193
+ function ensureRunning(el, runId) {
194
+ let state = live.get(el);
195
+ if (state && state.runId === runId) return state;
196
+ stop(el);
197
+ el.dataset.presence = 'running';
198
+ el.innerHTML = markHtml() + '<span class="codex-sr-only">' + escapeHtml(tx('Running', '运行中')) + '</span>'
199
+ + '<span class="run-presence-label"></span><span class="run-presence-timer"></span>';
200
+ state = { runId, key: '', verb: '', slot: -1, elapsedMs: 0, eggs: [], label: el.querySelector('.run-presence-label'),
201
+ timer: el.querySelector('.run-presence-timer') };
202
+ const late = lateNightEgg();
203
+ if (late) state.eggs.push(late);
204
+ live.set(el, state);
205
+ return state;
206
+ }
207
+
208
+ // label: { kind: 'stage', text } | { kind: 'idle' }. Tool steps live in the round list, not the header.
209
+ function paintRunning(el, { runId = '', label = { kind: 'idle' }, elapsedMs } = {}) {
210
+ if (!el) return;
211
+ const state = ensureRunning(el, runId);
212
+ state.idle = label.kind !== 'stage';
213
+ if (elapsedMs !== undefined) tick(el, elapsedMs);
214
+ if (!state.idle) {
215
+ const key = 's:' + label.text;
216
+ if (key !== state.key) { state.key = key; swapLabel(state, escapeHtml(label.text)); }
217
+ return;
218
+ }
219
+ refreshWord(state);
220
+ }
221
+
222
+ function refreshWord(state) {
223
+ const slot = wordSlot(state.elapsedMs);
224
+ if (state.key === 'idle' && slot === state.slot) return;
225
+ state.key = 'idle';
226
+ state.slot = slot;
227
+ nextIdle(state);
228
+ }
229
+
230
+ function tick(el, elapsedMs) {
231
+ const state = live.get(el);
232
+ if (!state) return;
233
+ const value = formatElapsed(elapsedMs);
234
+ if (state.timer.textContent !== value) state.timer.textContent = value;
235
+ state.elapsedMs = elapsedMs;
236
+ if (elapsedMs > LONG_RUN_MS && state.runId && !longRunsShown.has(state.runId)) {
237
+ longRunsShown.add(state.runId);
238
+ state.eggs.push(tx('This is a long proof', '这是个长证明'));
239
+ }
240
+ if (state.idle) refreshWord(state);
241
+ }
242
+
243
+ // facts: { kind: 'done' | 'stopped' | 'failed' | 'plain', text, elapsedMs, files, added, removed,
244
+ // steps, compiled, projectId, animate }
245
+ function paintSettled(el, facts = {}) {
246
+ if (!el) return;
247
+ stop(el);
248
+ const firstCompile = facts.kind === 'done' && facts.animate && facts.compiled && facts.projectId
249
+ ? once('codex-overleaf:egg:first-compile:' + facts.projectId) : false;
250
+ const stamp = JSON.stringify({ ...facts, animate: false });
251
+ if (el.dataset.presenceStamp === stamp && !facts.animate) return;
252
+ el.dataset.presenceStamp = stamp;
253
+ el.dataset.presence = facts.kind || 'plain';
254
+ if (facts.kind === 'done' || facts.kind === 'stopped') {
255
+ el.innerHTML = settledHtml({ ...facts, firstCompile }, tx, formatElapsed);
256
+ } else if (facts.kind === 'failed') {
257
+ el.innerHTML = icon('alert') + '<span>' + escapeHtml(facts.text) + '</span>';
258
+ } else {
259
+ el.textContent = facts.text || '';
260
+ }
261
+ }
262
+
263
+ function emptyTitle() {
264
+ return isLateNight() ? tx("Still up? Let's finish this section.", '还没睡?把这一节写完吧。')
265
+ : tx('What are we writing today?', '今天写点什么?');
266
+ }
267
+
268
+ // Decorates the existing empty-state element with the mark, project chip and a tip.
269
+ function decorateEmpty(empty, { projectName = '' } = {}) {
270
+ const mark = doc().createElement('div');
271
+ mark.className = 'run-empty-mark';
272
+ mark.innerHTML = markHtml('is-large');
273
+ empty.prepend(mark);
274
+ const title = empty.querySelector('.empty-runs-title');
275
+ if (title) title.textContent = emptyTitle();
276
+ if (projectName) {
277
+ const chip = doc().createElement('span');
278
+ chip.className = 'run-empty-project';
279
+ chip.innerHTML = icon('file') + '<span></span>';
280
+ chip.lastElementChild.textContent = projectName;
281
+ title?.after(chip);
282
+ }
283
+ const tip = doc().createElement('div');
284
+ tip.className = 'run-empty-tip';
285
+ tip.innerHTML = '<span class="run-empty-pilcrow" aria-hidden="true">¶</span><span class="run-empty-tip-text"></span>'
286
+ + '<button type="button" class="run-empty-tip-next">' + icon('refresh') + '</button>';
287
+ const next = tip.querySelector('button');
288
+ next.title = tx('Next tip', '换一条');
289
+ next.setAttribute('aria-label', next.title);
290
+ const show = () => {
291
+ const old = tip.querySelector('.run-empty-tip-text');
292
+ const fresh = old.cloneNode(false);
293
+ fresh.textContent = TIPS[locale()][tipIndex % TIPS.en.length];
294
+ old.replaceWith(fresh);
295
+ };
296
+ next.addEventListener('click', () => { tipIndex += 1; show(); });
297
+ show();
298
+ empty.append(tip);
299
+ return empty;
300
+ }
301
+
302
+ return { markHtml, paintRunning, tick, paintSettled, decorateEmpty, stop };
303
+ }
304
+
305
+ return { create, VERBS, TIPS, activityVerb, commandSummary, settledHtml, icon };
306
+ });