codex-overleaf-link 2.4.1 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +272 -314
- package/README.zh-CN.md +287 -329
- package/extension/bootstrap/background.js +47 -10
- package/extension/bootstrap/manifest.template.json +9 -4
- package/extension/bootstrap/popup.html +10 -16
- package/extension/bootstrap/update.js +25 -2
- package/extension/runtime-manifest.json +3 -1
- package/extension/src/background.js +28 -3
- package/extension/src/backgroundSharedSessions.js +380 -0
- package/extension/src/backgroundUpdateCoordinator.js +442 -379
- package/extension/src/content/activeTurnControl.js +8 -0
- package/extension/src/content/assetTransferBroker.js +186 -12
- package/extension/src/content/changeHistoryView.js +175 -0
- package/extension/src/content/composerAttachments.js +24 -22
- package/extension/src/content/composerPanel.js +23 -8
- package/extension/src/content/contentRuntime.js +507 -507
- package/extension/src/content/diagnosticsController.js +1 -2
- package/extension/src/content/diagnosticsExport.js +222 -0
- package/extension/src/content/diagnosticsPanel.js +48 -19
- package/extension/src/content/diffReviewPanel.js +8 -5
- package/extension/src/content/generated/content.bundle.js +8330 -1349
- package/extension/src/content/generated/content.bundle.meta.json +22 -3
- package/extension/src/content/legacyGlobalRegistry.js +19 -1
- package/extension/src/content/localSkillsPanel.js +42 -7
- package/extension/src/content/markdownDomRenderer.js +9 -4
- package/extension/src/content/modelPicker.js +1 -1
- package/extension/src/content/pageBridgeClient.js +18 -3
- package/extension/src/content/panelMaintenance.js +48 -121
- package/extension/src/content/panelRenderer.js +4 -0
- package/extension/src/content/pendingInputView.js +109 -76
- package/extension/src/content/providerSettingsCoordinator.js +17 -6
- package/extension/src/content/providerSettingsDialog.js +661 -108
- package/extension/src/content/recentProjects.js +10 -1
- package/extension/src/content/runActivitySummary.js +631 -0
- package/extension/src/content/runController.js +3 -1
- package/extension/src/content/runFailureNotice.js +14 -1
- package/extension/src/content/runGuidanceController.js +4 -3
- package/extension/src/content/runPresence.js +306 -0
- package/extension/src/content/runQueueScheduler.js +2 -1
- package/extension/src/content/runResultActions.js +123 -3
- package/extension/src/content/runTimelineView.js +186 -154
- package/extension/src/content/selectionContextView.js +300 -0
- package/extension/src/content/sessionPersistence.js +6 -1
- package/extension/src/content/settingsPanel.js +77 -52
- package/extension/src/content/settingsWorkbench.js +374 -0
- package/extension/src/content/sharedSessionViewSync.js +72 -0
- package/extension/src/content/subagentActivityView.js +195 -0
- package/extension/src/content/trackedChangeCaptureController.js +7 -3
- package/extension/src/content/updateNotice.js +121 -50
- package/extension/src/content/writebackController.js +257 -0
- package/extension/src/content/writebackOrchestrator.js +146 -141
- package/extension/src/content/writebackPlan.js +231 -0
- package/extension/src/content/writebackRecovery.js +122 -0
- package/extension/src/content/writingStyleSettings.js +576 -0
- package/extension/src/content/writtenChangesView.js +152 -0
- package/extension/src/page/binaryAssetUploader.js +97 -19
- package/extension/src/page/overleafProjectSnapshot.js +1 -0
- package/extension/src/page/referenceProjects.js +148 -0
- package/extension/src/page/saveState.js +14 -2
- package/extension/src/page/snapshotRouter.js +44 -13
- package/extension/src/page/textCoordinates.js +102 -0
- package/extension/src/page/textFileCreator.js +350 -59
- package/extension/src/page/trackedChangeCapture.js +42 -56
- package/extension/src/page/trackedChangeOwnership.js +198 -0
- package/extension/src/page/trackedChangeReplay.js +164 -0
- package/extension/src/page/trackedChangesLifecycle.js +135 -149
- package/extension/src/page/treeOperations.js +26 -2
- package/extension/src/page/writebackReceiptJournal.js +112 -0
- package/extension/src/page/writebackRouter.js +175 -135
- package/extension/src/pageBridge.js +56 -101
- package/extension/src/popup.js +203 -59
- package/extension/src/shared/agentTranscript.js +18 -4
- package/extension/src/shared/auditRecords.js +71 -0
- package/extension/src/shared/changeHistoryModel.js +94 -0
- package/extension/src/shared/compatibility.js +1 -1
- package/extension/src/shared/compileAdapter.js +42 -0
- package/extension/src/shared/failureReasons.js +20 -0
- package/extension/src/shared/globalPreferences.js +1 -1
- package/extension/src/shared/i18n.js +93 -25
- package/extension/src/shared/managedUpdateProjection.js +6 -3
- package/extension/src/shared/pageRpcContract.js +7 -1
- package/extension/src/shared/providerProfiles.js +109 -0
- package/extension/src/shared/runActivityModel.js +361 -0
- package/extension/src/shared/runExecutionSnapshot.js +8 -2
- package/extension/src/shared/runExecutionSnapshotCodec.js +16 -4
- package/extension/src/shared/scopedPersistenceBrowserAdapter.js +6 -3
- package/extension/src/shared/selectionContext.js +28 -0
- package/extension/src/shared/sessionState.js +97 -6
- package/extension/src/shared/sharedSessionBridge.js +288 -0
- package/extension/src/shared/storageDb.js +22 -55
- package/extension/src/shared/storageMigration.js +3 -0
- package/extension/src/shared/storageRunActions.js +10 -4
- package/extension/src/shared/storageValuePruning.js +40 -0
- package/extension/src/shared/subagentActivityModel.js +174 -0
- package/extension/src/shared/undoOperations.js +87 -0
- package/extension/src/shared/updateConsent.js +37 -8
- package/extension/src/shared/writebackIntent.js +62 -0
- package/extension/src/shared/writebackSettlement.js +29 -10
- package/extension/src/shared/writingStyle.js +33 -0
- package/extension/styles/panel.css +1972 -384
- package/extension/styles/popup.css +110 -0
- package/native-host/src/anthropicBridgeRequest.js +2 -1
- package/native-host/src/codexModelRecovery.js +107 -0
- package/native-host/src/codexPromptAssembly.js +2 -0
- package/native-host/src/codexProviderLaunch.js +3 -3
- package/native-host/src/codexRuntimeIdentity.js +1 -0
- package/native-host/src/codexSessionRunner.js +106 -140
- package/native-host/src/codexSessionTiming.js +3 -0
- package/native-host/src/managedInstall.js +5 -4
- package/native-host/src/nativeEnvironment.js +70 -0
- package/native-host/src/nativeQuotas.js +15 -8
- package/native-host/src/overleafWorkspaceRules.js +16 -0
- package/native-host/src/processStopBarrier.js +80 -0
- package/native-host/src/providerModelCatalog.js +4 -3
- package/native-host/src/providerProfile.js +13 -1
- package/native-host/src/providerReasoning.js +9 -5
- package/native-host/src/providerStore.js +4 -0
- package/native-host/src/releaseTransport.js +14 -5
- package/native-host/src/selectionScope.js +58 -0
- package/native-host/src/skills/parallel-subagents/SKILL.md +31 -3
- package/native-host/src/skills/writing-style-builder/SKILL.md +146 -0
- package/native-host/src/subagentBroker.js +102 -98
- package/native-host/src/subagentTelemetry.js +316 -0
- package/native-host/src/subagentWorkspace.js +103 -0
- package/native-host/src/subagentWorkspacePath.js +31 -0
- package/native-host/src/taskRunnerRuntime.js +55 -5
- package/native-host/src/turnAttachments.js +113 -0
- package/native-host/src/updateManager.js +122 -12
- package/native-host/src/updateNetworkControl.js +75 -0
- package/native-host/src/updateTrust.js +21 -2
- package/native-host/src/vendor/pdfjs/LICENSE +177 -0
- package/native-host/src/vendor/pdfjs/SOURCE.txt +3 -0
- package/native-host/src/vendor/pdfjs/cmaps/78-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78ms-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78ms-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/83pv-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/90ms-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/90ms-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/90msp-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/90msp-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/90pv-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/90pv-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Add-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Add-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Add-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Add-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-0.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-1.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-3.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-4.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-5.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-6.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-0.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-1.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-3.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-4.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-5.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-0.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-1.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-3.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-4.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-5.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-6.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-0.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-1.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/B5pc-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/B5pc-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/CNS-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/CNS-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/CNS1-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/CNS1-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/CNS2-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/CNS2-V.bcmap +3 -0
- package/native-host/src/vendor/pdfjs/cmaps/ETHK-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/ETHK-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/ETen-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/ETen-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/ETenms-B5-H.bcmap +3 -0
- package/native-host/src/vendor/pdfjs/cmaps/ETenms-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Ext-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Ext-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Ext-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Ext-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GB-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GB-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GB-H.bcmap +4 -0
- package/native-host/src/vendor/pdfjs/cmaps/GB-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBK-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBK-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBK2K-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBK2K-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBKp-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBKp-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBT-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBT-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBT-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBT-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBTpc-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBTpc-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBpc-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBpc-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKdla-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKdla-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKdlb-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKdlb-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKgccs-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKgccs-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKm314-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKm314-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKm471-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKm471-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKscs-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKscs-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Hankaku.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Hiragana.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSC-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSC-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSC-Johab-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSC-Johab-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSCpc-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSCpc-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Katakana.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/LICENSE +36 -0
- package/native-host/src/vendor/pdfjs/cmaps/NWP-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/NWP-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Roman.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UCS2-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UCS2-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF16-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF16-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF8-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF8-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UCS2-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UCS2-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF16-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF16-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF8-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF8-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF16-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF16-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF8-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF8-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UCS2-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UCS2-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF16-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF16-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF8-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF8-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/WP-Symbol.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/pdf.mjs +26740 -0
- package/native-host/src/vendor/pdfjs/pdf.worker.mjs +62201 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitDingbats.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixed.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedBold.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedItalic.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerif.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifBold.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifItalic.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSymbol.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/LICENSE_FOXIT +27 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/LICENSE_LIBERATION +102 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Bold.ttf +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Italic.ttf +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Regular.ttf +0 -0
- package/native-host/src/writingStyleEvidence.js +102 -0
- package/native-host/src/writingStylePdfWorker.js +35 -0
- package/native-host/src/writingStyleProfile.js +165 -0
- package/native-host/src/writingStyleRuntime.js +447 -0
- package/package.json +1 -1
|
@@ -10,8 +10,10 @@
|
|
|
10
10
|
const cancelTimer = deps.clearTimeout || clearTimeout;
|
|
11
11
|
let timer = null, busy = false, disposed = false;
|
|
12
12
|
const runs = () => deps.getRuns() || [];
|
|
13
|
+
const mergedRecovery = capture => capture?.source === 'native'
|
|
14
|
+
&& capture.state === 'needs_review' && ['capture_timeout', 'capture_expired'].includes(capture.reason);
|
|
13
15
|
const pending = run => Array.isArray(run.trackedChangeCaptures)
|
|
14
|
-
&& run.trackedChangeCaptures.some(capture => capture.state === 'pending');
|
|
16
|
+
&& run.trackedChangeCaptures.some(capture => capture.state === 'pending' || mergedRecovery(capture));
|
|
15
17
|
const terminal = run => ['accepted', 'rejected'].includes(run.trackedChangeStatus)
|
|
16
18
|
|| run.undoStatus === 'applied' || run.forkSnapshot === true;
|
|
17
19
|
function buildPostFiles(run) {
|
|
@@ -78,9 +80,10 @@
|
|
|
78
80
|
const postFiles = buildPostFiles(run);
|
|
79
81
|
for (let i = 0; i < captures.length; i++) {
|
|
80
82
|
const capture = captures[i];
|
|
81
|
-
|
|
83
|
+
const recoverMerged = mergedRecovery(capture);
|
|
84
|
+
if (capture.state !== 'pending' && !recoverMerged) continue;
|
|
82
85
|
const expected = postFiles.find(file => file.path === capture.path);
|
|
83
|
-
if (newer || !expected || now() >= capture.expiresAt || run.status === 'cancelled') {
|
|
86
|
+
if (newer || !expected || (!recoverMerged && now() >= capture.expiresAt) || run.status === 'cancelled') {
|
|
84
87
|
capture.state = 'needs_review';
|
|
85
88
|
capture.reason = newer ? 'capture_superseded' : !expected ? 'capture_baseline_missing'
|
|
86
89
|
: run.status === 'cancelled' ? 'capture_cancelled' : 'capture_expired';
|
|
@@ -129,6 +132,7 @@
|
|
|
129
132
|
if (changed) {
|
|
130
133
|
run.trackedChangeCaptures = captures;
|
|
131
134
|
await deps.persist();
|
|
135
|
+
deps.refresh?.(run);
|
|
132
136
|
if (!pending(run)) deps.notify?.(run, 'needs_review', {
|
|
133
137
|
reasons: captures.filter(capture => capture.state !== 'observed').map(capture => capture.reason)
|
|
134
138
|
});
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
let currentView = null;
|
|
12
12
|
let mountedPanel = null;
|
|
13
13
|
let actionInFlight = false;
|
|
14
|
+
let cancellationInFlight = false;
|
|
15
|
+
let actionSequence = 0;
|
|
14
16
|
let listenerInstalled = false;
|
|
15
17
|
let getLocale = () => '';
|
|
16
18
|
let settingsRoot = null;
|
|
@@ -68,42 +70,62 @@
|
|
|
68
70
|
|
|
69
71
|
async function handleClick(event) {
|
|
70
72
|
const action = event.target?.closest?.('[data-update-notice-action]')?.dataset?.updateNoticeAction;
|
|
71
|
-
if (!action
|
|
73
|
+
if (!action) return;
|
|
74
|
+
if (action === 'release-notes') {
|
|
75
|
+
const version = currentView?.state?.latestVersion || '';
|
|
76
|
+
window.open('https://github.com/Ghqqqq/codex-overleaf-link/releases/tag/v' + version, '_blank', 'noopener');
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
72
79
|
if (action === 'copy-manual') {
|
|
73
80
|
try {
|
|
74
81
|
await navigator.clipboard.writeText(manualUpdateCommand(currentView?.state));
|
|
75
82
|
manualCommandCopied = true;
|
|
76
83
|
render();
|
|
77
|
-
setTimeout(() => {
|
|
78
|
-
|
|
79
|
-
render();
|
|
80
|
-
}, 1800);
|
|
81
|
-
} catch (_error) {
|
|
82
|
-
manualCommandCopied = false;
|
|
83
|
-
}
|
|
84
|
+
setTimeout(() => { manualCommandCopied = false; render(); }, 1800);
|
|
85
|
+
} catch (_) { manualCommandCopied = false; }
|
|
84
86
|
return;
|
|
85
87
|
}
|
|
88
|
+
return runUpdateAction(action);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function runUpdateAction(action) {
|
|
92
|
+
const cancelling = action === 'cancel' || action === 'later';
|
|
93
|
+
if (cancellationInFlight || ((actionInFlight || settingsActionInFlight) && !cancelling)) return;
|
|
94
|
+
const sequence = ++actionSequence;
|
|
86
95
|
actionInFlight = true;
|
|
96
|
+
settingsActionInFlight = true;
|
|
97
|
+
cancellationInFlight = cancelling;
|
|
87
98
|
render();
|
|
88
99
|
try {
|
|
89
|
-
|
|
100
|
+
const view = await request({
|
|
101
|
+
check: 'codex-overleaf/consent-update-check',
|
|
90
102
|
install: 'codex-overleaf/consent-update-install',
|
|
91
103
|
retry: 'codex-overleaf/consent-update-check',
|
|
92
104
|
later: 'codex-overleaf/consent-update-later',
|
|
105
|
+
cancel: 'codex-overleaf/consent-update-cancel',
|
|
106
|
+
recover: 'codex-overleaf/consent-update-recover',
|
|
93
107
|
dismiss: 'codex-overleaf/consent-update-dismiss',
|
|
94
108
|
reload: 'codex-overleaf/consent-update-reload'
|
|
95
109
|
}[action]);
|
|
110
|
+
if (sequence === actionSequence) currentView = view;
|
|
96
111
|
} catch (error) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
112
|
+
if (sequence === actionSequence) {
|
|
113
|
+
const view = await reconcileAfterActionError(error, {
|
|
114
|
+
action, fallbackMessage: tx('Update action failed.', '更新操作失败。')
|
|
115
|
+
});
|
|
116
|
+
if (sequence === actionSequence) currentView = view;
|
|
117
|
+
}
|
|
101
118
|
} finally {
|
|
102
|
-
|
|
103
|
-
|
|
119
|
+
if (sequence === actionSequence) {
|
|
120
|
+
actionInFlight = false;
|
|
121
|
+
settingsActionInFlight = false;
|
|
122
|
+
cancellationInFlight = false;
|
|
123
|
+
render();
|
|
124
|
+
}
|
|
104
125
|
}
|
|
105
126
|
}
|
|
106
127
|
|
|
128
|
+
|
|
107
129
|
async function request(type) {
|
|
108
130
|
if (!type) throw new Error('Unknown update action.');
|
|
109
131
|
const response = await chrome.runtime.sendMessage({ type });
|
|
@@ -164,8 +186,9 @@
|
|
|
164
186
|
restartWatchdog = setTimeout(async () => {
|
|
165
187
|
try {
|
|
166
188
|
const view = await request('codex-overleaf/consent-update-get-state');
|
|
167
|
-
if (view?.state
|
|
189
|
+
if (view?.state) {
|
|
168
190
|
currentView = view;
|
|
191
|
+
if (ACTIVE_UPDATE_STATES.has(view.state.state)) scheduleRestartWatchdog();
|
|
169
192
|
} else {
|
|
170
193
|
currentView = buildFailedView('update_recovery_timeout', tx(
|
|
171
194
|
'The update did not finish restarting. Retry or use the manual recovery command.',
|
|
@@ -206,37 +229,18 @@
|
|
|
206
229
|
renderSettings();
|
|
207
230
|
}
|
|
208
231
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
let requestedAction = 'check';
|
|
215
|
-
try {
|
|
216
|
-
if (['reload_required', 'reload_tabs_required'].includes(stateName)) {
|
|
217
|
-
requestedAction = 'reload';
|
|
218
|
-
currentView = await request('codex-overleaf/consent-update-reload');
|
|
219
|
-
} else if (stateName === 'update_available') {
|
|
220
|
-
requestedAction = 'install';
|
|
221
|
-
currentView = await request('codex-overleaf/consent-update-install');
|
|
222
|
-
} else if (['failed', 'rolled_back'].includes(stateName)) {
|
|
223
|
-
currentView = await request('codex-overleaf/consent-update-check');
|
|
224
|
-
} else if (!ACTIVE_UPDATE_STATES.has(stateName)) {
|
|
225
|
-
currentView = await request('codex-overleaf/consent-update-check');
|
|
226
|
-
} else {
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
} catch (error) {
|
|
230
|
-
currentView = await reconcileAfterActionError(error, {
|
|
231
|
-
action: requestedAction,
|
|
232
|
-
fallbackMessage: tx('Update check failed.', '更新检查失败。')
|
|
233
|
-
});
|
|
234
|
-
} finally {
|
|
235
|
-
settingsActionInFlight = false;
|
|
236
|
-
render();
|
|
232
|
+
function handleSettingsAction() {
|
|
233
|
+
const state = currentView?.state || {};
|
|
234
|
+
if (state.recoveryPending) return runUpdateAction('recover');
|
|
235
|
+
if (state.cancelRequested || ['checking', 'downloading', 'staged', 'waiting_for_idle'].includes(state.state)) {
|
|
236
|
+
return runUpdateAction('cancel');
|
|
237
237
|
}
|
|
238
|
+
if (['reload_required', 'reload_tabs_required'].includes(state.state)) return runUpdateAction('reload');
|
|
239
|
+
if (state.state === 'update_available') return runUpdateAction('install');
|
|
240
|
+
if (!ACTIVE_UPDATE_STATES.has(state.state)) return runUpdateAction('check');
|
|
238
241
|
}
|
|
239
242
|
|
|
243
|
+
|
|
240
244
|
function render() {
|
|
241
245
|
if (!currentView) return;
|
|
242
246
|
renderSettings();
|
|
@@ -270,7 +274,24 @@
|
|
|
270
274
|
detail.textContent = copy.detail;
|
|
271
275
|
body.append(eyebrow, title, detail);
|
|
272
276
|
|
|
273
|
-
if (state.state === '
|
|
277
|
+
if (state.state === 'manual_install_required') {
|
|
278
|
+
const steps = document.createElement('ol');
|
|
279
|
+
steps.className = 'codex-update-notice-steps';
|
|
280
|
+
for (const text of [
|
|
281
|
+
tx('Run this once in a terminal:', '在终端运行一次:'),
|
|
282
|
+
tx('Reload the extension in chrome://extensions, then refresh Overleaf.', '在 chrome://extensions 里重新加载扩展,再刷新 Overleaf。')
|
|
283
|
+
]) steps.append(Object.assign(document.createElement('li'), { textContent: text }));
|
|
284
|
+
const command = document.createElement('code');
|
|
285
|
+
command.className = 'codex-update-notice-command';
|
|
286
|
+
command.textContent = manualUpdateCommand(state);
|
|
287
|
+
steps.firstElementChild.append(command);
|
|
288
|
+
const keep = document.createElement('span');
|
|
289
|
+
keep.className = 'codex-update-notice-recovery';
|
|
290
|
+
keep.textContent = tx('Sessions, settings, provider keys and project mirrors are kept.', '会话、设置、模型服务的密钥和项目镜像都会保留。');
|
|
291
|
+
body.append(steps, keep);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (state.state === 'failed' && !state.cancelRequested && !state.recoveryPending) {
|
|
274
295
|
const recovery = document.createElement('span');
|
|
275
296
|
recovery.className = 'codex-update-notice-recovery';
|
|
276
297
|
recovery.textContent = tx('Manual recovery:', '手动恢复:');
|
|
@@ -280,7 +301,7 @@
|
|
|
280
301
|
body.append(recovery, command);
|
|
281
302
|
}
|
|
282
303
|
|
|
283
|
-
if (!['update_available', 'failed', 'rolled_back', 'reload_required', 'reload_tabs_required'].includes(state.state)) {
|
|
304
|
+
if (!['update_available', 'manual_install_required', 'failed', 'rolled_back', 'reload_required', 'reload_tabs_required'].includes(state.state)) {
|
|
284
305
|
const bar = document.createElement('div');
|
|
285
306
|
bar.className = 'codex-update-notice-progress' + (progress.determinate ? '' : ' is-indeterminate');
|
|
286
307
|
bar.setAttribute('role', 'progressbar');
|
|
@@ -302,7 +323,9 @@
|
|
|
302
323
|
button.dataset.updateNoticeAction = action.id;
|
|
303
324
|
button.className = action.primary ? 'is-primary' : '';
|
|
304
325
|
button.textContent = action.label;
|
|
305
|
-
button.disabled =
|
|
326
|
+
button.disabled = action.id === 'cancel'
|
|
327
|
+
? cancellationInFlight || (state.cancelRequested && !state.code)
|
|
328
|
+
: actionInFlight || settingsActionInFlight;
|
|
306
329
|
actions.append(button);
|
|
307
330
|
}
|
|
308
331
|
notice.replaceChildren(body, actions);
|
|
@@ -343,6 +366,9 @@
|
|
|
343
366
|
summaryText = tx(`Stable v${latestVersion} is available.`, `稳定版本 v${latestVersion} 已可用。`);
|
|
344
367
|
statusText = tx('Ready to download and verify.', '已可下载并验证。');
|
|
345
368
|
buttonText = tx('Update now', '立即更新');
|
|
369
|
+
} else if (stateName === 'manual_install_required') {
|
|
370
|
+
summaryText = tx(`v${latestVersion} is available but needs a one-time reinstall.`, `v${latestVersion} 已发布,但需要重新安装一次。`);
|
|
371
|
+
statusText = manualReasonText(state) || getCopy(state).detail;
|
|
346
372
|
} else if (ACTIVE_UPDATE_STATES.has(stateName)) {
|
|
347
373
|
statusText = getCopy(state).detail;
|
|
348
374
|
buttonText = tx('Update in progress', '更新进行中');
|
|
@@ -358,11 +384,29 @@
|
|
|
358
384
|
status.textContent = statusText;
|
|
359
385
|
status.hidden = !statusText;
|
|
360
386
|
button.textContent = buttonText;
|
|
361
|
-
|
|
387
|
+
const cancellable = state.cancelRequested || ['checking', 'downloading', 'staged', 'waiting_for_idle'].includes(stateName);
|
|
388
|
+
if (state.recoveryPending) {
|
|
389
|
+
button.textContent = tx('Check recovery', '检查恢复状态');
|
|
390
|
+
button.disabled = actionInFlight || settingsActionInFlight;
|
|
391
|
+
} else if (cancellable) {
|
|
392
|
+
button.textContent = state.cancelRequested && !state.code
|
|
393
|
+
? tx('Cancelling…', '正在取消…')
|
|
394
|
+
: state.cancelRequested ? tx('Retry cancellation', '重试取消') : tx('Cancel update', '取消更新');
|
|
395
|
+
button.disabled = cancellationInFlight || (state.cancelRequested && !state.code);
|
|
396
|
+
} else {
|
|
397
|
+
button.disabled = actionInFlight || settingsActionInFlight || ACTIVE_UPDATE_STATES.has(stateName);
|
|
398
|
+
}
|
|
362
399
|
}
|
|
363
400
|
|
|
364
401
|
function visibleActions(state) {
|
|
365
|
-
|
|
402
|
+
const value = currentView?.state || {};
|
|
403
|
+
if (value.recoveryPending) return [{ id: 'recover', label: tx('Check recovery', '检查恢复状态'), primary: true }];
|
|
404
|
+
if (value.cancelRequested || ['checking', 'downloading'].includes(state)) {
|
|
405
|
+
return [{ id: 'cancel', label: value.cancelRequested
|
|
406
|
+
? value.code ? tx('Retry cancellation', '重试取消') : tx('Cancelling…', '正在取消…')
|
|
407
|
+
: tx('Cancel update', '取消更新'), primary: false }];
|
|
408
|
+
}
|
|
409
|
+
if (actionInFlight && !['staged', 'waiting_for_idle'].includes(state)) return [];
|
|
366
410
|
if (['reload_required', 'reload_tabs_required'].includes(state)) {
|
|
367
411
|
return [{ id: 'reload', label: state === 'reload_required'
|
|
368
412
|
? tx('Reload extension', '重新加载扩展') : tx('Refresh Overleaf tabs', '刷新 Overleaf 标签页'), primary: true }];
|
|
@@ -374,7 +418,14 @@
|
|
|
374
418
|
];
|
|
375
419
|
}
|
|
376
420
|
if (['staged', 'waiting_for_idle'].includes(state)) {
|
|
377
|
-
return [{ id: '
|
|
421
|
+
return [{ id: 'cancel', label: tx('Cancel update', '取消更新'), primary: false }];
|
|
422
|
+
}
|
|
423
|
+
if (state === 'manual_install_required') {
|
|
424
|
+
return [
|
|
425
|
+
{ id: 'later', label: tx('Later', '稍后'), primary: false },
|
|
426
|
+
{ id: 'release-notes', label: tx('Release notes', '发布说明'), primary: false },
|
|
427
|
+
{ id: 'copy-manual', label: manualCommandCopied ? tx('Copied', '已复制') : tx('Copy command', '复制命令'), primary: true }
|
|
428
|
+
];
|
|
378
429
|
}
|
|
379
430
|
if (['failed', 'rolled_back'].includes(state)) {
|
|
380
431
|
return [
|
|
@@ -390,8 +441,18 @@
|
|
|
390
441
|
|
|
391
442
|
function getCopy(state) {
|
|
392
443
|
const target = state.latestVersion ? 'v' + state.latestVersion : '';
|
|
444
|
+
if (state.cancelRequested) return {
|
|
445
|
+
eyebrow: tx('Cancelling update', '正在取消更新'), title: target,
|
|
446
|
+
detail: state.message || tx('Stopping this update and clearing its authorization.', '正在停止本次更新并清理更新授权。')
|
|
447
|
+
};
|
|
448
|
+
if (state.recoveryPending) return {
|
|
449
|
+
eyebrow: tx('Checking update recovery', '正在确认更新恢复状态'), title: target,
|
|
450
|
+
detail: state.message || tx('Waiting for the installed version to be confirmed.', '正在确认实际安装的版本。')
|
|
451
|
+
};
|
|
393
452
|
const blocker = blockersCopy(state.blockers?.length ? state.blockers : [state.blocker]);
|
|
394
453
|
return {
|
|
454
|
+
checking: { eyebrow: tx('Checking for updates', '正在检查更新'), title: target,
|
|
455
|
+
detail: tx('Reading the latest signed release.', '正在读取最新签名版本。') },
|
|
395
456
|
reload_required: {
|
|
396
457
|
eyebrow: tx('Installed, awaiting reload', '已安装,等待加载'), title: target,
|
|
397
458
|
detail: state.message || tx('The new files are installed. Reload the extension when Overleaf is saved and idle.', '新版文件已安装,请在 Overleaf 保存并空闲后重新加载扩展。')
|
|
@@ -400,6 +461,11 @@
|
|
|
400
461
|
eyebrow: tx('Updated runtime is ready', '新版运行组件已就绪'), title: target,
|
|
401
462
|
detail: state.message || tx('Refresh the saved, idle Overleaf tabs to load the updated panel.', '刷新已保存且空闲的 Overleaf 标签页以加载新版面板。')
|
|
402
463
|
},
|
|
464
|
+
manual_install_required: {
|
|
465
|
+
eyebrow: tx('Reinstall needed for this update', '这次更新需要重新安装'),
|
|
466
|
+
title: target,
|
|
467
|
+
detail: manualReasonText(state) || tx('This release changes what Chrome lets the extension do, so Update now cannot apply it.', '这一版改动了 Chrome 授予扩展的权限,无法通过“立即更新”完成。')
|
|
468
|
+
},
|
|
403
469
|
update_available: {
|
|
404
470
|
eyebrow: tx('Update available', '发现新版本'),
|
|
405
471
|
title: target,
|
|
@@ -488,6 +554,11 @@
|
|
|
488
554
|
);
|
|
489
555
|
}
|
|
490
556
|
|
|
557
|
+
function manualReasonText(state = {}) {
|
|
558
|
+
const reason = state.manualReason || {};
|
|
559
|
+
return tx(reason.en || reason.zh || '', reason.zh || reason.en || '');
|
|
560
|
+
}
|
|
561
|
+
|
|
491
562
|
function tx(english, chinese) {
|
|
492
563
|
const locale = String(getLocale() || document.documentElement?.lang || 'en');
|
|
493
564
|
return /^zh\b/i.test(locale) ? chinese : english;
|
|
@@ -227,6 +227,11 @@
|
|
|
227
227
|
? changeOrReason
|
|
228
228
|
: { reason: changeOrReason };
|
|
229
229
|
const reason = change.reason;
|
|
230
|
+
if (reason === 'selection_scope_violation') {
|
|
231
|
+
return isEnglish
|
|
232
|
+
? 'The local changes exceeded the captured selection. No changes from this task were written back.'
|
|
233
|
+
: '本地改动超出了已附加的选区,本轮改动未写回。';
|
|
234
|
+
}
|
|
230
235
|
if (reason === 'generated_artifact') {
|
|
231
236
|
return isEnglish
|
|
232
237
|
? 'LaTeX build artifact; not written back by default.'
|
|
@@ -240,6 +245,11 @@
|
|
|
240
245
|
if (reason === 'binary_payload_exceeds_native_message_limit') {
|
|
241
246
|
return formatBinaryPayloadLimitReason(change, locale);
|
|
242
247
|
}
|
|
248
|
+
if (reason === 'subagent_unfinished_output') {
|
|
249
|
+
return isEnglish
|
|
250
|
+
? 'The subagent did not finish; the main agent must review and adopt this file before it can sync.'
|
|
251
|
+
: '子代理未正常完成,主代理需核对并接管该文件后才能同步。';
|
|
252
|
+
}
|
|
243
253
|
if (reason === 'subagent_unauthorized_edit') {
|
|
244
254
|
return isEnglish
|
|
245
255
|
? "A subagent's change to this file was withheld from Overleaf — it either fell outside the subagent's assigned files or the subagent did not finish cleanly."
|
|
@@ -290,10 +300,257 @@
|
|
|
290
300
|
return (syncChanges || []).filter(change => appliedPaths.has(change.path));
|
|
291
301
|
}
|
|
292
302
|
|
|
303
|
+
|
|
304
|
+
// Verify the server revision independently of editor overlays. No writes or retries
|
|
305
|
+
// of writes are performed here; a missing acknowledgement never becomes success.
|
|
306
|
+
function buildSavedWritebackExpectations(applied = {}, project = {}) {
|
|
307
|
+
const expected = new Map();
|
|
308
|
+
const original = new Map((project.files || []).map(file => [file.path, file]));
|
|
309
|
+
const unsupported = [];
|
|
310
|
+
for (const entry of getAppliedEntries(applied)) {
|
|
311
|
+
const operation = entry?.operation || {};
|
|
312
|
+
const result = entry?.result || {};
|
|
313
|
+
const path = operation.path;
|
|
314
|
+
if (!path || result.ok === false) { unsupported.push(path || 'unknown'); continue; }
|
|
315
|
+
if (operation.type === 'delete') { expected.set(path, { absent: true }); continue; }
|
|
316
|
+
if (operation.type === 'rename' || operation.type === 'move') {
|
|
317
|
+
const content = typeof result.verifiedContent === 'string'
|
|
318
|
+
? result.verifiedContent : original.get(path)?.content;
|
|
319
|
+
if (!operation.to || typeof content !== 'string') { unsupported.push(path); continue; }
|
|
320
|
+
if (operation.to !== path) expected.set(path, { absent: true });
|
|
321
|
+
expected.set(operation.to, { content });
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
if (operation.type === 'binary-create' || operation.type === 'overwrite-binary') {
|
|
325
|
+
const hash = operation.sha256 || operation.assetRef?.sha256;
|
|
326
|
+
if (/^[a-f0-9]{64}$/i.test(hash || '')) expected.set(path, { sha256: hash.toLowerCase() });
|
|
327
|
+
else if (typeof operation.contentBase64 === 'string'
|
|
328
|
+
&& (operation.contentBase64 || !operation.assetRef || operation.size === 0)) {
|
|
329
|
+
expected.set(path, { contentBase64: operation.contentBase64.replace(/\s/g, '') });
|
|
330
|
+
} else unsupported.push(path);
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
const content = typeof result.verifiedContent === 'string' ? result.verifiedContent
|
|
334
|
+
: operation.type === 'create' && typeof operation.content === 'string' ? operation.content
|
|
335
|
+
: operation.type === 'edit' && typeof operation.replaceAll === 'string' ? operation.replaceAll : undefined;
|
|
336
|
+
if (typeof content === 'string') expected.set(path, { content });
|
|
337
|
+
else unsupported.push(path);
|
|
338
|
+
}
|
|
339
|
+
return { expected, unsupported };
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
async function matchSavedWritebackSnapshot(snapshot, expectations, projectId) {
|
|
343
|
+
if (snapshot?.id !== projectId || snapshot?.ok === false
|
|
344
|
+
|| snapshot?.capabilities?.method !== 'overleaf-zip'
|
|
345
|
+
|| snapshot.capabilities.fullProjectSnapshot !== true || !Array.isArray(snapshot.files)
|
|
346
|
+
|| snapshot.files.some(file => file?.source !== 'overleaf-zip')) {
|
|
347
|
+
return { matched: false, reason: 'authoritative_snapshot_unavailable' };
|
|
348
|
+
}
|
|
349
|
+
if (!expectations.expected.size || expectations.unsupported.length) {
|
|
350
|
+
return { matched: false, reason: 'expected_content_unavailable' };
|
|
351
|
+
}
|
|
352
|
+
const byPath = new Map(snapshot.files.map(file => [file.path, file]));
|
|
353
|
+
for (const [path, expected] of expectations.expected) {
|
|
354
|
+
const file = byPath.get(path);
|
|
355
|
+
if (expected.absent) {
|
|
356
|
+
if (file || snapshot.capabilities.skipped?.length) return { matched: false, reason: 'server_content_mismatch', path };
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
if (!file) return { matched: false, reason: 'server_content_mismatch', path };
|
|
360
|
+
if (typeof expected.content === 'string') {
|
|
361
|
+
if (file.content !== expected.content) return { matched: false, reason: 'server_content_mismatch', path };
|
|
362
|
+
} else {
|
|
363
|
+
if (typeof file.contentBase64 !== 'string') return { matched: false, reason: 'server_binary_unavailable', path };
|
|
364
|
+
if (expected.contentBase64 !== undefined) {
|
|
365
|
+
if (file.contentBase64.replace(/\s/g, '') !== expected.contentBase64) return { matched: false, reason: 'server_content_mismatch', path };
|
|
366
|
+
} else {
|
|
367
|
+
const hash = await binaryDigest(file.contentBase64);
|
|
368
|
+
if (!hash) return { matched: false, reason: 'binary_digest_unavailable', path };
|
|
369
|
+
if (hash !== expected.sha256) return { matched: false, reason: 'server_content_mismatch', path };
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
return { matched: true };
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
async function confirmPostWriteSave(options = {}) {
|
|
377
|
+
const { applied, project, runProjectId, assertCurrent, readSaveState, readSnapshot } = options;
|
|
378
|
+
if (!runProjectId || typeof assertCurrent !== 'function') {
|
|
379
|
+
return { verification: { ok: false, state: 'unavailable', signal: 'context_missing' } };
|
|
380
|
+
}
|
|
381
|
+
const now = options.now || Date.now;
|
|
382
|
+
const deadline = now() + 90000;
|
|
383
|
+
const attempts = [];
|
|
384
|
+
const isInterruption = error => ['codex_cancelled', 'aborted_project_changed', 'editor_project_id_unavailable'].includes(error?.code)
|
|
385
|
+
|| error?.name === 'AbortError';
|
|
386
|
+
const probe = async duration => {
|
|
387
|
+
assertCurrent();
|
|
388
|
+
try {
|
|
389
|
+
const result = await readSaveState({ deadlineMs: Math.max(0, Math.min(duration, deadline - now())), requirePositiveSignal: true });
|
|
390
|
+
assertCurrent();
|
|
391
|
+
return result || { ok: false, state: 'unavailable', signal: 'unavailable' };
|
|
392
|
+
} catch (error) {
|
|
393
|
+
if (isInterruption(error)) throw error;
|
|
394
|
+
assertCurrent();
|
|
395
|
+
return { ok: false, state: 'unavailable', signal: 'unavailable', reason: String(error?.message || error).slice(0, 800) };
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
const receiptExpectations = buildSavedWritebackExpectations(applied, project);
|
|
399
|
+
assertCurrent();
|
|
400
|
+
if (await receiptsConfirmExpectedFiles(applied, receiptExpectations, runProjectId)) {
|
|
401
|
+
assertCurrent();
|
|
402
|
+
return { verification: { ok: true, state: 'verified_saved', source: 'server-receipts' } };
|
|
403
|
+
}
|
|
404
|
+
const primary = await probe(1500);
|
|
405
|
+
if (primary.ok === true && primary.state === 'verified_saved') {
|
|
406
|
+
return { verification: { ...primary, source: 'save-indicator' } };
|
|
407
|
+
}
|
|
408
|
+
const expectations = buildSavedWritebackExpectations(applied, project);
|
|
409
|
+
let lastReason = '';
|
|
410
|
+
if (primary.signal !== 'offline' && expectations.expected.size && !expectations.unsupported.length) {
|
|
411
|
+
for (let attempt = 0; attempt < 3 && deadline - now() > 1000; attempt++) {
|
|
412
|
+
assertCurrent();
|
|
413
|
+
try {
|
|
414
|
+
const snapshot = await readSnapshot({
|
|
415
|
+
force: true, maxAgeMs: 0, zipOnly: true, serverOnly: true,
|
|
416
|
+
includeBinaryFiles: true, allowEditorNavigation: false, requireFullProject: true,
|
|
417
|
+
zipTimeoutMs: Math.max(1, Math.min(30000, deadline - now())),
|
|
418
|
+
saveCheckId: String(now()) + '-' + attempt + '-' + Math.random().toString(36).slice(2, 8)
|
|
419
|
+
});
|
|
420
|
+
assertCurrent();
|
|
421
|
+
const match = await matchSavedWritebackSnapshot(snapshot, expectations, runProjectId);
|
|
422
|
+
assertCurrent();
|
|
423
|
+
attempts.push({ attempt: attempt + 1, result: match.matched ? 'matched' : match.reason, path: match.path || '' });
|
|
424
|
+
if (match.matched) return {
|
|
425
|
+
verification: { ok: true, state: 'verified_saved', source: 'overleaf-zip', recovered: true,
|
|
426
|
+
primary: { state: primary.state, signal: primary.signal, reason: primary.reason }, attempts },
|
|
427
|
+
snapshot
|
|
428
|
+
};
|
|
429
|
+
lastReason = match.reason;
|
|
430
|
+
} catch (error) {
|
|
431
|
+
if (isInterruption(error)) throw error;
|
|
432
|
+
assertCurrent();
|
|
433
|
+
lastReason = String(error?.message || error).slice(0, 800);
|
|
434
|
+
attempts.push({ attempt: attempt + 1, result: 'snapshot_unavailable', reason: lastReason });
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
const final = primary.signal === 'offline' ? primary : await probe(2000);
|
|
439
|
+
if (final.ok === true && final.state === 'verified_saved') {
|
|
440
|
+
return { verification: { ...final, source: 'save-indicator', recovered: true, attempts } };
|
|
441
|
+
}
|
|
442
|
+
return { verification: {
|
|
443
|
+
ok: false, state: final.state === 'unavailable' ? 'unavailable' : 'unknown_timeout',
|
|
444
|
+
signal: final.signal || primary.signal || 'unavailable',
|
|
445
|
+
reason: final.reason || primary.reason || 'No positive save evidence was available.',
|
|
446
|
+
recoveryReason: lastReason || (expectations.unsupported.length ? 'expected_content_unavailable' : ''),
|
|
447
|
+
attempts
|
|
448
|
+
} };
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
async function bytesDigest(bytes) {
|
|
452
|
+
if (!globalThis.crypto?.subtle) return '';
|
|
453
|
+
const digest = await globalThis.crypto.subtle.digest('SHA-256', bytes);
|
|
454
|
+
return Array.from(new Uint8Array(digest), byte => byte.toString(16).padStart(2, '0')).join('');
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
async function textDigest(content) {
|
|
458
|
+
return typeof TextEncoder === 'function' ? bytesDigest(new TextEncoder().encode(content)) : '';
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
async function binaryDigest(contentBase64) {
|
|
462
|
+
if (typeof contentBase64 !== 'string' || typeof atob !== 'function') return '';
|
|
463
|
+
let bytes;
|
|
464
|
+
try { bytes = Uint8Array.from(atob(contentBase64.replace(/\s/g, '')), value => value.charCodeAt(0)); }
|
|
465
|
+
catch (_error) { return ''; }
|
|
466
|
+
return bytesDigest(bytes);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
async function receiptsConfirmExpectedFiles(applied, expectations, projectId) {
|
|
470
|
+
if (!expectations.expected.size || expectations.unsupported.length) return false;
|
|
471
|
+
const entries = getAppliedEntries(applied);
|
|
472
|
+
for (const [path, expected] of expectations.expected) {
|
|
473
|
+
if (typeof expected.content !== 'string') return false;
|
|
474
|
+
const receipt = [...entries].reverse().find(entry => entry.operation?.path === path)?.result?.saveReceipt;
|
|
475
|
+
if (receipt?.v !== 1 || receipt.source !== 'overleaf-zip' || receipt.projectId !== projectId
|
|
476
|
+
|| receipt.path !== path || !Number.isFinite(Date.parse(receipt.verifiedAt || ''))
|
|
477
|
+
|| !/^[a-f0-9]{64}$/.test(receipt.sha256 || '') || receipt.sha256 !== await textDigest(expected.content)) return false;
|
|
478
|
+
}
|
|
479
|
+
return true;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
async function buildSaveCheck(applied, project, owner) {
|
|
483
|
+
const expectations = buildSavedWritebackExpectations(applied, project);
|
|
484
|
+
if (expectations.unsupported.length) return null;
|
|
485
|
+
const files = [];
|
|
486
|
+
for (const [path, expected] of expectations.expected) {
|
|
487
|
+
if (expected.absent) files.push({ path, absent: true });
|
|
488
|
+
else if (typeof expected.content === 'string') {
|
|
489
|
+
const sha256 = await textDigest(expected.content);
|
|
490
|
+
if (!sha256) return null;
|
|
491
|
+
files.push({ path, sha256, kind: 'text' });
|
|
492
|
+
} else {
|
|
493
|
+
const sha256 = expected.sha256 || await binaryDigest(expected.contentBase64);
|
|
494
|
+
if (!sha256) return null;
|
|
495
|
+
files.push({ path, sha256, kind: 'binary' });
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
return files.length ? { ...owner, v: 1, files } : null;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
async function confirmSaveCheck(check, options) {
|
|
502
|
+
if (!check?.projectId || !Array.isArray(check.files) || !check.files.length
|
|
503
|
+
|| check.files.some(file => !file?.path || (file.absent !== true && !/^[a-f0-9]{64}$/i.test(file.sha256 || '')))) {
|
|
504
|
+
return { ok: false, state: 'unavailable', reason: 'expected_content_unavailable' };
|
|
505
|
+
}
|
|
506
|
+
const now = options.now || Date.now, deadline = now() + 90000;
|
|
507
|
+
let reason = 'server_snapshot_unavailable';
|
|
508
|
+
for (let attempt = 0; attempt < 3 && now() < deadline; attempt++) {
|
|
509
|
+
options.assertCurrent();
|
|
510
|
+
let snapshot;
|
|
511
|
+
try {
|
|
512
|
+
snapshot = await options.readSnapshot({ force: true, maxAgeMs: 0, zipOnly: true, serverOnly: true,
|
|
513
|
+
includeBinaryFiles: true, allowEditorNavigation: false, requireFullProject: true,
|
|
514
|
+
zipTimeoutMs: Math.min(30000, Math.max(1, deadline - now())), saveCheckId: String(now()) + '-' + attempt });
|
|
515
|
+
} catch (error) {
|
|
516
|
+
if (['codex_cancelled', 'aborted_project_changed', 'editor_project_id_unavailable'].includes(error?.code)
|
|
517
|
+
|| error?.name === 'AbortError') throw error;
|
|
518
|
+
options.assertCurrent();
|
|
519
|
+
continue;
|
|
520
|
+
}
|
|
521
|
+
options.assertCurrent();
|
|
522
|
+
if (snapshot?.ok === false || snapshot?.id !== check.projectId
|
|
523
|
+
|| snapshot.capabilities?.fullProjectSnapshot !== true
|
|
524
|
+
|| snapshot.capabilities?.method !== 'overleaf-zip' || !Array.isArray(snapshot.files)) continue;
|
|
525
|
+
const files = new Map(snapshot.files.map(file => [file.path, file]));
|
|
526
|
+
let matched = true;
|
|
527
|
+
for (const expected of check.files) {
|
|
528
|
+
const file = files.get(expected.path);
|
|
529
|
+
if (expected.absent) { if (file || snapshot.capabilities.skipped?.length) matched = false; continue; }
|
|
530
|
+
if (!file || file.source !== 'overleaf-zip') { matched = false; continue; }
|
|
531
|
+
const kind = typeof file.content === 'string' ? 'text'
|
|
532
|
+
: typeof file.contentBase64 === 'string' ? 'binary' : '';
|
|
533
|
+
if (!kind || (expected.kind && expected.kind !== kind)) { matched = false; continue; }
|
|
534
|
+
const hash = kind === 'binary' ? await binaryDigest(file.contentBase64) : await textDigest(file.content);
|
|
535
|
+
if (!hash || hash !== expected.sha256.toLowerCase()) matched = false;
|
|
536
|
+
}
|
|
537
|
+
options.assertCurrent();
|
|
538
|
+
if (matched) return { ok: true, state: 'verified_saved', source: 'overleaf-zip' };
|
|
539
|
+
reason = 'server_content_mismatch';
|
|
540
|
+
}
|
|
541
|
+
return { ok: false, state: 'unknown_timeout', reason };
|
|
542
|
+
}
|
|
543
|
+
|
|
293
544
|
return {
|
|
545
|
+
confirmPostWriteSave,
|
|
546
|
+
buildSaveCheck,
|
|
547
|
+
confirmSaveCheck,
|
|
548
|
+
buildSavedWritebackExpectations,
|
|
549
|
+
matchSavedWritebackSnapshot,
|
|
294
550
|
buildSyncApplyOperations,
|
|
295
551
|
computeSingleTextPatch,
|
|
296
552
|
formatUnsupportedLocalChangeSummary,
|
|
553
|
+
formatUnsupportedLocalChangeReason,
|
|
297
554
|
getAppliedOperationPaths,
|
|
298
555
|
getAppliedSyncChanges,
|
|
299
556
|
getSyncChangePatches,
|