codex-overleaf-link 2.4.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +272 -311
- package/README.zh-CN.md +287 -326
- 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 +572 -571
- 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 +8974 -1781
- 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 +51 -120
- 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 +364 -356
- 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 +194 -164
- package/extension/src/content/scopedPersistenceCoordinator.js +2 -1
- package/extension/src/content/scopedPersistencePanelState.js +45 -2
- package/extension/src/content/selectionContextView.js +300 -0
- package/extension/src/content/sessionPersistence.js +10 -2
- package/extension/src/content/settingsPanel.js +93 -54
- 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 +58 -3
- 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 +139 -150
- package/extension/src/page/treeOperations.js +36 -29
- package/extension/src/page/writebackReceiptJournal.js +112 -0
- package/extension/src/page/writebackRouter.js +176 -136
- package/extension/src/pageBridge.js +59 -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 +187 -65
- 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 +23 -55
- package/extension/src/shared/storageMigration.js +3 -0
- package/extension/src/shared/storageRunActions.js +54 -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 +2136 -744
- 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 +146 -177
- package/native-host/src/codexSessionTiming.js +71 -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/readProgressGuard.js +84 -17
- 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
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
(function initCodexOverleafTrackedChangesLifecycle(root, factory) {
|
|
2
2
|
if (typeof module === 'object' && module.exports) {
|
|
3
|
-
module.exports = factory();
|
|
3
|
+
module.exports = factory(require('./trackedChangeReplay'));
|
|
4
4
|
} else {
|
|
5
|
-
root.CodexOverleafTrackedChangesLifecycle = factory();
|
|
5
|
+
root.CodexOverleafTrackedChangesLifecycle = factory(root.CodexOverleafTrackedChangeReplay);
|
|
6
6
|
}
|
|
7
|
-
})(typeof window !== 'undefined' ? window : globalThis, function trackedChangesLifecycleFactory() {
|
|
7
|
+
})(typeof window !== 'undefined' ? window : globalThis, function trackedChangesLifecycleFactory(Replay) {
|
|
8
8
|
'use strict';
|
|
9
9
|
|
|
10
10
|
// Tracked-changes lifecycle — carved out of writebackRouter.js in v1.8.0
|
|
@@ -49,6 +49,9 @@
|
|
|
49
49
|
verifyActiveEditorText,
|
|
50
50
|
collectElements,
|
|
51
51
|
} = deps;
|
|
52
|
+
const { buildAcceptReplayOperations, rebaseCheckpointPair } = Replay.create({
|
|
53
|
+
normalizeSafeProjectPath, applyTextPatches
|
|
54
|
+
});
|
|
52
55
|
|
|
53
56
|
function nativeReviewBlocked(path, code, applied = [], requestStarted = false) {
|
|
54
57
|
const reason = requestStarted
|
|
@@ -104,11 +107,118 @@
|
|
|
104
107
|
return nativeReviewBlocked(path, 'native_review_file_unavailable');
|
|
105
108
|
const scope = await waitForNativeReview(path, refs, untracked);
|
|
106
109
|
if (!scope.ok) return nativeReviewBlocked(path, scope.reason || 'native_review_unavailable');
|
|
110
|
+
if (scope.merged) {
|
|
111
|
+
const before = (params.expectedFiles || []).filter(file => file.path === path);
|
|
112
|
+
const post = (params.postFiles || []).filter(file => file.path === path);
|
|
113
|
+
if (scope.merged.runProjectId !== params.runProjectId || before.length !== 1 || post.length !== 1
|
|
114
|
+
|| before[0].content !== scope.merged.preContent || post[0].content !== scope.merged.postContent)
|
|
115
|
+
return nativeReviewBlocked(path, 'native_merged_review_checkpoint_mismatch');
|
|
116
|
+
}
|
|
107
117
|
files.push({ path, nativeDocId: scope.nativeDocId, scope });
|
|
108
118
|
}
|
|
109
119
|
return { ok: true, files, refs, deadline };
|
|
110
120
|
}
|
|
111
121
|
|
|
122
|
+
function mergedReviewContextMatches(params, file, content) {
|
|
123
|
+
const projectId = typeof deps.getProjectId === 'function' ? deps.getProjectId()
|
|
124
|
+
: /\/project\/([^/?#]+)/.exec(window?.location?.pathname || '')?.[1];
|
|
125
|
+
return Boolean(params.runProjectId && projectId === params.runProjectId
|
|
126
|
+
&& !checkWritebackRunProjectId(params) && getActiveFilePath() === file.path
|
|
127
|
+
&& readActiveEditorText() === content);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async function reviewMergedInsertion(params, file, action) {
|
|
131
|
+
const path = file.path, accepting = action === 'accept';
|
|
132
|
+
let scope = prepareTrackedChangeReview(path, file.scope.targets);
|
|
133
|
+
if (!scope.ok || !scope.merged || scope.nativeDocId !== file.nativeDocId
|
|
134
|
+
|| !mergedReviewContextMatches(params, file, scope.merged.postContent))
|
|
135
|
+
return nativeReviewBlocked(path, 'native_merged_review_scope_changed');
|
|
136
|
+
const before = (params.expectedFiles || []).filter(item => item.path === path);
|
|
137
|
+
const post = (params.postFiles || []).filter(item => item.path === path);
|
|
138
|
+
if (before.length !== 1 || post.length !== 1
|
|
139
|
+
|| before[0].content !== scope.merged.preContent || post[0].content !== scope.merged.postContent)
|
|
140
|
+
return nativeReviewBlocked(path, 'native_merged_review_checkpoint_mismatch');
|
|
141
|
+
const view = deps.getCodeMirrorEditorView?.();
|
|
142
|
+
if (typeof view?.dispatch !== 'function' || view.state?.doc?.toString() !== post[0].content)
|
|
143
|
+
return nativeReviewBlocked(path, 'native_merged_review_editor_unavailable');
|
|
144
|
+
|
|
145
|
+
const editing = await forceEditingForAcceptReplay();
|
|
146
|
+
if (!editing.ok) return nativeReviewBlocked(path, 'native_merged_review_editing_unavailable');
|
|
147
|
+
let attempted = false;
|
|
148
|
+
try {
|
|
149
|
+
const stable = await waitForStableEditingForAcceptReplay({ waitMs: 1400, intervalMs: 160 });
|
|
150
|
+
scope = prepareTrackedChangeReview(path, file.scope.targets);
|
|
151
|
+
if (!stable.ok || !scope.ok || !scope.merged || scope.nativeDocId !== file.nativeDocId
|
|
152
|
+
|| !mergedReviewContextMatches(params, file, post[0].content)
|
|
153
|
+
|| deps.getCodeMirrorEditorView?.() !== view || view.state.doc.toString() !== post[0].content)
|
|
154
|
+
return nativeReviewBlocked(path, 'native_merged_review_scope_changed');
|
|
155
|
+
|
|
156
|
+
// A same-text replacement is deliberate: plain Editing removes tracking
|
|
157
|
+
// only from these exact inserted slices, without a transient text rollback.
|
|
158
|
+
// Never send a merged parent's ID to the whole-change Accept endpoint.
|
|
159
|
+
const changes = scope.merged.ranges.map(range => ({
|
|
160
|
+
from: range.start, to: range.end,
|
|
161
|
+
insert: accepting ? post[0].content.slice(range.start, range.end) : ''
|
|
162
|
+
}));
|
|
163
|
+
const expectedText = accepting ? post[0].content : before[0].content;
|
|
164
|
+
const expectedKeys = accepting ? scope.merged.preservedKeys : scope.merged.beforeKeys;
|
|
165
|
+
attempted = true;
|
|
166
|
+
view.dispatch({ changes });
|
|
167
|
+
compileBridge.markSourceEdited();
|
|
168
|
+
|
|
169
|
+
const until = Math.min(file.deadline || Date.now() + 8000, Date.now() + 8000);
|
|
170
|
+
let matchingSince = null;
|
|
171
|
+
while (Date.now() <= until) {
|
|
172
|
+
if (!mergedReviewContextMatches(params, file, expectedText))
|
|
173
|
+
return nativeReviewBlocked(path, 'native_merged_review_content_or_context_changed', [], true);
|
|
174
|
+
const after = prepareTrackedChangeCapture(path);
|
|
175
|
+
const matches = after.ready && after.source === 'native' && after.nativeDocId === file.nativeDocId
|
|
176
|
+
&& JSON.stringify(after.refs.map(ref => ref.key).sort()) === JSON.stringify(expectedKeys);
|
|
177
|
+
if (matches) {
|
|
178
|
+
if (matchingSince === null) matchingSince = Date.now();
|
|
179
|
+
if (Date.now() - matchingSince >= 500) {
|
|
180
|
+
return { ok: true, verified: true, applied: scope.targets.map(trackedChange => ({
|
|
181
|
+
trackedChange, result: { ok: true, verified: true, verifiedContent: expectedText,
|
|
182
|
+
method: accepting ? 'overleaf-accept-untracked-replay' : 'overleaf-merged-insertion-undo',
|
|
183
|
+
preservedTrackedChanges: true }
|
|
184
|
+
})), skipped: [] };
|
|
185
|
+
}
|
|
186
|
+
} else matchingSince = null;
|
|
187
|
+
await delay(150);
|
|
188
|
+
}
|
|
189
|
+
return nativeReviewBlocked(path, 'native_merged_review_not_verified', [], true);
|
|
190
|
+
} catch (_error) {
|
|
191
|
+
return nativeReviewBlocked(path, 'native_merged_review_interrupted', [], attempted);
|
|
192
|
+
} finally {
|
|
193
|
+
// Match the existing no-trace Accept policy: do not re-enable tracking
|
|
194
|
+
// while an untracked operation can still be awaiting its server flush.
|
|
195
|
+
if (!attempted && editing.activated) await setReviewingEnabled(true, { waitMs: 1800 });
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
async function rejectPlanWithMergedInsertions(params, plan) {
|
|
200
|
+
const mixed = plan.files.find(file => !file.scope.merged && file.scope.unrelated.length);
|
|
201
|
+
if (mixed) return nativeReviewBlocked(mixed.path, 'native_reject_mixed_changes');
|
|
202
|
+
const applied = [];
|
|
203
|
+
for (const file of plan.files) {
|
|
204
|
+
if (Date.now() >= plan.deadline || checkWritebackRunProjectId(params))
|
|
205
|
+
return nativeReviewBlocked(file.path, 'native_review_context_changed', applied, applied.length > 0);
|
|
206
|
+
if (getActiveFilePath() !== file.path && !(await openFileByPath(file.path)).ok)
|
|
207
|
+
return nativeReviewBlocked(file.path, 'native_review_file_unavailable', applied, applied.length > 0);
|
|
208
|
+
const scoped = { ...params,
|
|
209
|
+
trackedChanges: plan.refs.filter(ref => ref.path === file.path),
|
|
210
|
+
expectedFiles: (params.expectedFiles || []).filter(item => item.path === file.path),
|
|
211
|
+
postFiles: (params.postFiles || []).filter(item => item.path === file.path)
|
|
212
|
+
};
|
|
213
|
+
const result = file.scope.merged
|
|
214
|
+
? await reviewMergedInsertion(scoped, { ...file, deadline: plan.deadline }, 'reject')
|
|
215
|
+
: await rejectTrackedChanges(scoped);
|
|
216
|
+
applied.push(...(result.applied || []));
|
|
217
|
+
if (!result.ok) return { ...result, applied };
|
|
218
|
+
}
|
|
219
|
+
return { ok: true, applied, skipped: [] };
|
|
220
|
+
}
|
|
221
|
+
|
|
112
222
|
async function acceptNativeReview(params, plan) {
|
|
113
223
|
const applied = [];
|
|
114
224
|
let token = window?.document?.querySelector?.('meta[name="ol-csrfToken"]')?.getAttribute('content');
|
|
@@ -126,6 +236,12 @@
|
|
|
126
236
|
return nativeReviewBlocked(path, 'native_review_context_changed', applied, applied.length > 0);
|
|
127
237
|
if (getActiveFilePath() !== path && !(await openFileByPath(path)).ok)
|
|
128
238
|
return nativeReviewBlocked(path, 'native_review_file_unavailable', applied, applied.length > 0);
|
|
239
|
+
if (file.scope.merged) {
|
|
240
|
+
const result = await reviewMergedInsertion(params, { ...file, deadline: plan.deadline }, 'accept');
|
|
241
|
+
applied.push(...(result.applied || []));
|
|
242
|
+
if (!result.ok) return { ...result, applied };
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
129
245
|
await waitForNativeReview(path, plan.refs);
|
|
130
246
|
const scope = prepareTrackedChangeReview(path, plan.refs), text = readActiveEditorText();
|
|
131
247
|
if (!scope.ok || !scope.acceptByIdSupported || scope.nativeDocId !== file.nativeDocId
|
|
@@ -195,8 +311,24 @@
|
|
|
195
311
|
|
|
196
312
|
const nativeReview = await prepareNativeReview(params, true);
|
|
197
313
|
if (nativeReview && !nativeReview.ok) return nativeReview;
|
|
314
|
+
if (nativeReview?.files.some(file => file.scope.merged))
|
|
315
|
+
return rejectPlanWithMergedInsertions(params, nativeReview);
|
|
198
316
|
const mixedFile = nativeReview?.files.find(file => file.scope.unrelated.length);
|
|
199
317
|
if (mixedFile) return nativeReviewBlocked(mixedFile.path, 'native_reject_mixed_changes');
|
|
318
|
+
if (params.untrackedUndo === true && !trackedChanges.length) {
|
|
319
|
+
if (!nativeReview) return nativeReviewBlocked('', 'native_review_unavailable');
|
|
320
|
+
// An ordinary write has no owned editor-history entry. Restore its
|
|
321
|
+
// checkpoint directly; global Undo may belong to an earlier user edit.
|
|
322
|
+
const restored = await restoreExpectedFilesWithNoTraceUndo(expectedFiles, postFiles, {
|
|
323
|
+
runProjectId: params.runProjectId
|
|
324
|
+
});
|
|
325
|
+
if (restored.applied.length) compileBridge.markSourceEdited();
|
|
326
|
+
return { ...restored, ok: restored.attempted && restored.ok,
|
|
327
|
+
skipped: restored.attempted ? restored.skipped : [{ trackedChange: null, result: {
|
|
328
|
+
ok: false, code: restored.code || 'snapshot_undo_unavailable',
|
|
329
|
+
reason: restored.reason || 'The saved checkpoint is unavailable for this undo.'
|
|
330
|
+
} }] };
|
|
331
|
+
}
|
|
200
332
|
const editorUndo = await rejectTrackedChangesViaEditorUndo(expectedFiles, postFiles, applied);
|
|
201
333
|
if (editorUndo.ok) {
|
|
202
334
|
if (applied.length > 0) {
|
|
@@ -933,125 +1065,9 @@
|
|
|
933
1065
|
return { ok: true, activated: true };
|
|
934
1066
|
}
|
|
935
1067
|
|
|
936
|
-
// Builds the minimal replay operations for Accept All. The replay must write
|
|
937
|
-
// only the changed fragments, never a whole-file replaceAll.
|
|
938
|
-
//
|
|
939
|
-
// Preferred source: the run's own original forward writeback operations
|
|
940
|
-
// (carrying their `patches`). After the editor-undo the document is back at
|
|
941
|
-
// the pre-write content, so those patches' `expected` slices match and
|
|
942
|
-
// re-apply cleanly.
|
|
943
|
-
//
|
|
944
|
-
// Fallback: when a path has no usable original patch operation, compute a
|
|
945
|
-
// minimal pre->post diff (trim the common prefix/suffix to a single targeted
|
|
946
|
-
// {from,to,insert} patch).
|
|
947
|
-
function buildAcceptReplayOperations(paths, expectedByPath, postByPath, appliedOperations) {
|
|
948
|
-
const patchesByPath = collectAppliedEditPatchesByPath(appliedOperations);
|
|
949
|
-
const operations = [];
|
|
950
|
-
for (const path of paths) {
|
|
951
|
-
const preContent = expectedByPath.get(path);
|
|
952
|
-
const postContent = postByPath.get(path);
|
|
953
|
-
if (typeof preContent !== 'string' || typeof postContent !== 'string') {
|
|
954
|
-
return {
|
|
955
|
-
ok: false,
|
|
956
|
-
code: 'accept_missing_run_content',
|
|
957
|
-
reason: `${path} 缺少写入前/写入后内容;Codex 没有重放本轮改动。`
|
|
958
|
-
};
|
|
959
|
-
}
|
|
960
|
-
|
|
961
|
-
// Preferred: re-apply the run's original forward patches verbatim.
|
|
962
|
-
const originalPatches = patchesByPath.get(path);
|
|
963
|
-
if (originalPatches && originalPatches.length && patchesApplyCleanly(preContent, originalPatches)) {
|
|
964
|
-
operations.push({
|
|
965
|
-
type: 'edit',
|
|
966
|
-
path,
|
|
967
|
-
patches: originalPatches,
|
|
968
|
-
reason: 'Accept tracked edit (replay untracked)'
|
|
969
|
-
});
|
|
970
|
-
continue;
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
// Fallback: minimal pre->post diff trimmed to a single targeted patch.
|
|
974
|
-
const diffPatch = buildMinimalDiffPatch(preContent, postContent);
|
|
975
|
-
if (!diffPatch) {
|
|
976
|
-
// pre === post: nothing to replay for this file.
|
|
977
|
-
continue;
|
|
978
|
-
}
|
|
979
|
-
operations.push({
|
|
980
|
-
type: 'edit',
|
|
981
|
-
path,
|
|
982
|
-
patches: [diffPatch],
|
|
983
|
-
reason: 'Accept tracked edit (replay untracked)'
|
|
984
|
-
});
|
|
985
|
-
}
|
|
986
|
-
return { ok: true, operations };
|
|
987
|
-
}
|
|
988
1068
|
|
|
989
|
-
// Collects the per-path `patches` arrays from the run's applied edit
|
|
990
|
-
// operations. Only edit operations that actually carried `patches` are
|
|
991
|
-
// usable; whole-file replaceAll / verifiedContent operations are skipped so
|
|
992
|
-
// the replay never falls back to a whole-file write.
|
|
993
|
-
function collectAppliedEditPatchesByPath(appliedOperations) {
|
|
994
|
-
const patchesByPath = new Map();
|
|
995
|
-
for (const rawOperation of Array.isArray(appliedOperations) ? appliedOperations : []) {
|
|
996
|
-
if (!rawOperation || rawOperation.type !== 'edit') {
|
|
997
|
-
continue;
|
|
998
|
-
}
|
|
999
|
-
const path = typeof rawOperation.path === 'string'
|
|
1000
|
-
? normalizeSafeProjectPath(rawOperation.path)
|
|
1001
|
-
: '';
|
|
1002
|
-
if (!path || !Array.isArray(rawOperation.patches) || !rawOperation.patches.length) {
|
|
1003
|
-
continue;
|
|
1004
|
-
}
|
|
1005
|
-
const normalized = rawOperation.patches.map(patch => ({
|
|
1006
|
-
from: Number(patch?.from),
|
|
1007
|
-
to: Number(patch?.to),
|
|
1008
|
-
expected: String(patch?.expected ?? ''),
|
|
1009
|
-
insert: String(patch?.insert ?? '')
|
|
1010
|
-
}));
|
|
1011
|
-
const existing = patchesByPath.get(path) || [];
|
|
1012
|
-
patchesByPath.set(path, existing.concat(normalized));
|
|
1013
|
-
}
|
|
1014
|
-
return patchesByPath;
|
|
1015
|
-
}
|
|
1016
1069
|
|
|
1017
|
-
// Confirms a patch set re-applies cleanly against the given (pre-write) text:
|
|
1018
|
-
// every patch range is valid and its `expected` slice matches.
|
|
1019
|
-
function patchesApplyCleanly(text, patches) {
|
|
1020
|
-
const applied = applyTextPatches(text, patches);
|
|
1021
|
-
return applied.ok === true;
|
|
1022
|
-
}
|
|
1023
1070
|
|
|
1024
|
-
// Computes a single targeted {from,to,insert} patch describing the pre->post
|
|
1025
|
-
// change by trimming the common prefix and suffix. Returns null when the two
|
|
1026
|
-
// strings are identical.
|
|
1027
|
-
function buildMinimalDiffPatch(preContent, postContent) {
|
|
1028
|
-
if (preContent === postContent) {
|
|
1029
|
-
return null;
|
|
1030
|
-
}
|
|
1031
|
-
const preLen = preContent.length;
|
|
1032
|
-
const postLen = postContent.length;
|
|
1033
|
-
let prefix = 0;
|
|
1034
|
-
const maxPrefix = Math.min(preLen, postLen);
|
|
1035
|
-
while (prefix < maxPrefix && preContent[prefix] === postContent[prefix]) {
|
|
1036
|
-
prefix += 1;
|
|
1037
|
-
}
|
|
1038
|
-
let suffix = 0;
|
|
1039
|
-
const maxSuffix = Math.min(preLen, postLen) - prefix;
|
|
1040
|
-
while (
|
|
1041
|
-
suffix < maxSuffix
|
|
1042
|
-
&& preContent[preLen - 1 - suffix] === postContent[postLen - 1 - suffix]
|
|
1043
|
-
) {
|
|
1044
|
-
suffix += 1;
|
|
1045
|
-
}
|
|
1046
|
-
const from = prefix;
|
|
1047
|
-
const to = preLen - suffix;
|
|
1048
|
-
return {
|
|
1049
|
-
from,
|
|
1050
|
-
to,
|
|
1051
|
-
expected: preContent.slice(from, to),
|
|
1052
|
-
insert: postContent.slice(from, postLen - suffix)
|
|
1053
|
-
};
|
|
1054
|
-
}
|
|
1055
1071
|
|
|
1056
1072
|
async function rejectTrackedChangesViaEditorUndo(expectedFiles, postFiles, applied) {
|
|
1057
1073
|
const expectedByPath = new Map((expectedFiles || [])
|
|
@@ -1249,36 +1265,6 @@
|
|
|
1249
1265
|
};
|
|
1250
1266
|
}
|
|
1251
1267
|
|
|
1252
|
-
function rebaseCheckpointPair(actualContent, expectedContent, postContent) {
|
|
1253
|
-
const actual = String(actualContent ?? '');
|
|
1254
|
-
const expected = String(expectedContent ?? '');
|
|
1255
|
-
const post = String(postContent ?? '');
|
|
1256
|
-
if (actual === post) {
|
|
1257
|
-
return {
|
|
1258
|
-
ok: true,
|
|
1259
|
-
expectedContent: expected,
|
|
1260
|
-
postContent: post,
|
|
1261
|
-
prefixLength: 0,
|
|
1262
|
-
suffixLength: 0
|
|
1263
|
-
};
|
|
1264
|
-
}
|
|
1265
|
-
if (!post) {
|
|
1266
|
-
return { ok: false };
|
|
1267
|
-
}
|
|
1268
|
-
const matchIndex = actual.indexOf(post);
|
|
1269
|
-
if (matchIndex < 0 || actual.indexOf(post, matchIndex + 1) >= 0) {
|
|
1270
|
-
return { ok: false };
|
|
1271
|
-
}
|
|
1272
|
-
const prefix = actual.slice(0, matchIndex);
|
|
1273
|
-
const suffix = actual.slice(matchIndex + post.length);
|
|
1274
|
-
return {
|
|
1275
|
-
ok: true,
|
|
1276
|
-
expectedContent: prefix + expected + suffix,
|
|
1277
|
-
postContent: actual,
|
|
1278
|
-
prefixLength: prefix.length,
|
|
1279
|
-
suffixLength: suffix.length
|
|
1280
|
-
};
|
|
1281
|
-
}
|
|
1282
1268
|
|
|
1283
1269
|
async function waitForActiveEditorExpectedText(filePath, expectedContent, timeoutMs) {
|
|
1284
1270
|
const deadline = Date.now() + Math.max(0, Number(timeoutMs) || 0);
|
|
@@ -1630,7 +1616,10 @@
|
|
|
1630
1616
|
}
|
|
1631
1617
|
return {
|
|
1632
1618
|
acceptTrackedChanges,
|
|
1633
|
-
rejectTrackedChanges
|
|
1619
|
+
rejectTrackedChanges: async params => {
|
|
1620
|
+
const result = await rejectTrackedChanges(params);
|
|
1621
|
+
return deps.confirmReviewWriteback ? deps.confirmReviewWriteback(params, result) : result;
|
|
1622
|
+
},
|
|
1634
1623
|
collectTrackedChangeRefsForPaths,
|
|
1635
1624
|
prepareTrackedChangeCapture, getTrackedChangeCaptureStatus,
|
|
1636
1625
|
captureTrackedWrite,
|
|
@@ -246,7 +246,7 @@
|
|
|
246
246
|
if (node) {
|
|
247
247
|
dispatchFileTreeOpenClick(node);
|
|
248
248
|
await delay(250);
|
|
249
|
-
const active = await waitForActiveFile(normalizedPath, 5000);
|
|
249
|
+
const active = await waitForActiveFile(normalizedPath, options.activeWaitMs ?? 5000);
|
|
250
250
|
diagnostics.domClickActivePath = getActiveFilePath();
|
|
251
251
|
if (active) {
|
|
252
252
|
return {
|
|
@@ -254,6 +254,20 @@
|
|
|
254
254
|
method: 'dom-click'
|
|
255
255
|
};
|
|
256
256
|
}
|
|
257
|
+
// Overleaf can drop a click while the previous document is still
|
|
258
|
+
// settling (e.g. right after a multi-file write). Re-resolve the row,
|
|
259
|
+
// activate the row itself plus a keyboard Enter, and wait once more.
|
|
260
|
+
const retryNode = findFileTreeNode(normalizedPath, { invalidateCache: true }) || node;
|
|
261
|
+
dispatchActivationSequence(retryNode);
|
|
262
|
+
dispatchKeyboardOpen(findFileTreeOpenClickTarget(retryNode) || retryNode);
|
|
263
|
+
const retried = await waitForActiveFile(normalizedPath, options.retryWaitMs ?? 4000);
|
|
264
|
+
diagnostics.domRetryActivePath = getActiveFilePath() || 'unknown';
|
|
265
|
+
if (retried) {
|
|
266
|
+
return {
|
|
267
|
+
ok: true,
|
|
268
|
+
method: 'dom-click-retry'
|
|
269
|
+
};
|
|
270
|
+
}
|
|
257
271
|
}
|
|
258
272
|
|
|
259
273
|
const manager = findFileTreeManager();
|
|
@@ -322,7 +336,7 @@
|
|
|
322
336
|
.map(item => `${item.method}/${item.argType}:ok=${item.ok ? 'yes' : 'no'},active=${item.activePath || 'unknown'}${item.error ? ',error=' + item.error : ''}`)
|
|
323
337
|
.slice(0, 8)
|
|
324
338
|
.join('|') || 'none';
|
|
325
|
-
return `open diagnostics initial=${diagnostics.initialActivePath || 'unknown'}, initialNode=${diagnostics.initialDomNodeFound ? 'yes' : 'no'}, folders=${folders}, postExpandNode=${diagnostics.postExpandDomNodeFound ? 'yes' : 'no'}, domClickActive=${diagnostics.domClickActivePath || 'unknown'}, manager=${managers}`;
|
|
339
|
+
return `open diagnostics initial=${diagnostics.initialActivePath || 'unknown'}, initialNode=${diagnostics.initialDomNodeFound ? 'yes' : 'no'}, folders=${folders}, postExpandNode=${diagnostics.postExpandDomNodeFound ? 'yes' : 'no'}, domClickActive=${diagnostics.domClickActivePath || 'unknown'}, domRetryActive=${diagnostics.domRetryActivePath || 'none'}, manager=${managers}`;
|
|
326
340
|
}
|
|
327
341
|
|
|
328
342
|
function dispatchFileTreeOpenClick(node) {
|
|
@@ -361,6 +375,16 @@
|
|
|
361
375
|
}
|
|
362
376
|
}
|
|
363
377
|
|
|
378
|
+
function dispatchKeyboardOpen(node) {
|
|
379
|
+
for (const type of ['keydown', 'keyup']) {
|
|
380
|
+
try {
|
|
381
|
+
node?.dispatchEvent(new KeyboardEvent(type, { key: 'Enter', code: 'Enter', bubbles: true, cancelable: true }));
|
|
382
|
+
} catch (_error) {
|
|
383
|
+
// KeyboardEvent may be unavailable in synthetic harnesses.
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
364
388
|
function findFileTreeOpenClickTarget(node) {
|
|
365
389
|
const selectors = [
|
|
366
390
|
'.file-tree-entity-details',
|
|
@@ -1052,7 +1076,7 @@
|
|
|
1052
1076
|
return labelPath;
|
|
1053
1077
|
}
|
|
1054
1078
|
|
|
1055
|
-
const textPath = normalizeProjectPathCandidate(node
|
|
1079
|
+
const textPath = normalizeProjectPathCandidate(readFileTreeNodeText(node));
|
|
1056
1080
|
if (!textPath) {
|
|
1057
1081
|
const docIdPath = resolveProjectPathFromDomDocId(node);
|
|
1058
1082
|
const domTreePath = resolveProjectPathFromDomTree(node);
|
|
@@ -1181,7 +1205,7 @@
|
|
|
1181
1205
|
node.getAttribute?.('data-name'),
|
|
1182
1206
|
node.getAttribute?.('aria-label'),
|
|
1183
1207
|
node.getAttribute?.('title'),
|
|
1184
|
-
node
|
|
1208
|
+
readFileTreeNodeText(node)
|
|
1185
1209
|
];
|
|
1186
1210
|
for (const value of candidates) {
|
|
1187
1211
|
const path = normalizeProjectPathCandidate(value);
|
|
@@ -1244,21 +1268,12 @@
|
|
|
1244
1268
|
}
|
|
1245
1269
|
|
|
1246
1270
|
function normalizeProjectPathCandidate(value) {
|
|
1247
|
-
const text =
|
|
1271
|
+
const text = String(value || '').trim();
|
|
1248
1272
|
if (!text || hasMultipleTextPathExtensions(text)) {
|
|
1249
1273
|
return '';
|
|
1250
1274
|
}
|
|
1251
|
-
const
|
|
1252
|
-
|
|
1253
|
-
text
|
|
1254
|
-
];
|
|
1255
|
-
for (const candidate of candidates) {
|
|
1256
|
-
const normalized = normalizeSafeProjectPath(candidate);
|
|
1257
|
-
if (normalized && window.CodexOverleafProjectFiles.isTextProjectPath(normalized)) {
|
|
1258
|
-
return normalized;
|
|
1259
|
-
}
|
|
1260
|
-
}
|
|
1261
|
-
return '';
|
|
1275
|
+
const normalized = normalizeSafeProjectPath(text);
|
|
1276
|
+
return normalized && window.CodexOverleafProjectFiles.isTextProjectPath(normalized) ? normalized : '';
|
|
1262
1277
|
}
|
|
1263
1278
|
|
|
1264
1279
|
function normalizeDomText(value) {
|
|
@@ -1275,19 +1290,11 @@
|
|
|
1275
1290
|
return false;
|
|
1276
1291
|
}
|
|
1277
1292
|
|
|
1278
|
-
function
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
.replace(/(?:more_vert\s*Menu|more_vert|Menu)$/i, '')
|
|
1284
|
-
.trim();
|
|
1285
|
-
if (next === text) {
|
|
1286
|
-
break;
|
|
1287
|
-
}
|
|
1288
|
-
text = next;
|
|
1289
|
-
}
|
|
1290
|
-
return text;
|
|
1293
|
+
function readFileTreeNodeText(node) {
|
|
1294
|
+
// Icon ligatures can be valid filename prefixes; use the actual label.
|
|
1295
|
+
const names = Array.from(node.querySelectorAll?.('.item-name') || []);
|
|
1296
|
+
if (names.length > 1) return '';
|
|
1297
|
+
return names.length === 1 ? names[0].textContent || '' : node.textContent || '';
|
|
1291
1298
|
}
|
|
1292
1299
|
|
|
1293
1300
|
function inferPathFromTreeAncestors(node, fileName) {
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
(function (root, factory) {
|
|
2
|
+
const api = factory();
|
|
3
|
+
if (typeof module === 'object' && module.exports) module.exports = api;
|
|
4
|
+
if (root) root.CodexOverleafWritebackReceiptJournal = api;
|
|
5
|
+
})(typeof window !== 'undefined' ? window : globalThis, function () {
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
function create({ getProjectId, prepareEditor, applyOperations, now = Date.now,
|
|
9
|
+
retentionMs = 600000, maxReceipts = 16 }) {
|
|
10
|
+
const receipts = new Map();
|
|
11
|
+
let active = null;
|
|
12
|
+
const clone = value => JSON.parse(JSON.stringify(value));
|
|
13
|
+
const empty = () => ({ applied: [], skipped: [], trackedChanges: [], trackedChangeCaptures: [] });
|
|
14
|
+
function failure(code, error) { return { ok: false, code, error, changedDocument: false }; }
|
|
15
|
+
function deadlineFailure(params) {
|
|
16
|
+
return params.deadlineAt != null && (!Number.isFinite(params.deadlineAt) || now() >= params.deadlineAt)
|
|
17
|
+
? failure('writeback_deadline_exceeded', 'The operation deadline expired before any new write could start.') : null;
|
|
18
|
+
}
|
|
19
|
+
function prune() {
|
|
20
|
+
for (const [id, receipt] of receipts) {
|
|
21
|
+
if (receipt.state === 'completed' && now() - receipt.updatedAt > retentionMs) receipts.delete(id);
|
|
22
|
+
}
|
|
23
|
+
while (receipts.size >= maxReceipts) {
|
|
24
|
+
const oldest = Array.from(receipts).find(([, value]) => value.state === 'completed');
|
|
25
|
+
if (!oldest) break;
|
|
26
|
+
receipts.delete(oldest[0]);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function snapshot(receipt) {
|
|
30
|
+
const result = receipt.result || {
|
|
31
|
+
...receipt.partial,
|
|
32
|
+
ok: receipt.partial.skipped.length === 0,
|
|
33
|
+
trackedChanges: receipt.partial.trackedChangeCaptures.some(value => value.state !== 'observed')
|
|
34
|
+
? [] : receipt.partial.trackedChanges
|
|
35
|
+
};
|
|
36
|
+
return clone({ ok: true, requestId: receipt.id, runProjectId: receipt.projectId,
|
|
37
|
+
state: receipt.state, updatedAt: receipt.updatedAt, result });
|
|
38
|
+
}
|
|
39
|
+
function get(params = {}) {
|
|
40
|
+
if (!params.runProjectId || params.runProjectId !== getProjectId(params.runProjectId)) {
|
|
41
|
+
return failure('writeback_receipt_scope_changed', 'The writeback project is no longer active.');
|
|
42
|
+
}
|
|
43
|
+
const receipt = receipts.get(params.requestId);
|
|
44
|
+
if (!receipt || receipt.projectId !== params.runProjectId) {
|
|
45
|
+
return failure('writeback_receipt_missing', 'The original writeback receipt is unavailable. Do not replay the write.');
|
|
46
|
+
}
|
|
47
|
+
return snapshot(receipt);
|
|
48
|
+
}
|
|
49
|
+
async function apply(params = {}) {
|
|
50
|
+
const id = params.writebackRequestId, projectId = params.runProjectId;
|
|
51
|
+
if (typeof id !== 'string' || !id || id.length > 160 || !projectId || projectId !== getProjectId(projectId)) {
|
|
52
|
+
return failure('writeback_receipt_identity_invalid', 'Writeback request identity could not be confirmed.');
|
|
53
|
+
}
|
|
54
|
+
const fingerprint = JSON.stringify(params.operations || []);
|
|
55
|
+
const previous = receipts.get(id);
|
|
56
|
+
if (previous) {
|
|
57
|
+
if (previous.projectId !== projectId || previous.fingerprint !== fingerprint) {
|
|
58
|
+
return failure('writeback_receipt_conflict', 'The writeback request ID was reused with different operations.');
|
|
59
|
+
}
|
|
60
|
+
return previous.promise; // Duplicate delivery retrieves the original work; it never executes it again.
|
|
61
|
+
}
|
|
62
|
+
const expired = deadlineFailure(params);
|
|
63
|
+
if (expired) return expired;
|
|
64
|
+
if (active) return failure('writeback_in_progress', 'An earlier writeback is still running. Wait for its result before writing again.');
|
|
65
|
+
prune();
|
|
66
|
+
const receipt = { id, projectId, fingerprint, state: 'running', updatedAt: now(), partial: empty() };
|
|
67
|
+
receipts.set(id, receipt);
|
|
68
|
+
active = receipt;
|
|
69
|
+
const onOperationResult = ({ operation, result }) => {
|
|
70
|
+
const entry = clone({ operation, result });
|
|
71
|
+
(result.ok ? receipt.partial.applied : receipt.partial.skipped).push(entry);
|
|
72
|
+
if (operation.type === 'edit' && result.ok && Array.isArray(result.trackedChanges)) {
|
|
73
|
+
receipt.partial.trackedChanges.push(...clone(result.trackedChanges));
|
|
74
|
+
}
|
|
75
|
+
if (result.trackedChangeCapture) receipt.partial.trackedChangeCaptures.push(clone(result.trackedChangeCapture));
|
|
76
|
+
receipt.updatedAt = now();
|
|
77
|
+
};
|
|
78
|
+
// Defer execution until the promise is assigned, including for immediately completed operations.
|
|
79
|
+
receipt.promise = Promise.resolve().then(async () => {
|
|
80
|
+
if (deadlineFailure(params)) return deadlineFailure(params);
|
|
81
|
+
if (params.reviewingPolicy === 'no-trace-undo') {
|
|
82
|
+
const prepared = await prepareEditor(params);
|
|
83
|
+
if (prepared.ok !== true) return { applied: [], changedDocument: false,
|
|
84
|
+
skipped: (params.operations || []).map(operation => ({ operation, result: prepared })) };
|
|
85
|
+
}
|
|
86
|
+
if (deadlineFailure(params)) return deadlineFailure(params);
|
|
87
|
+
return applyOperations(params.operations || [], {
|
|
88
|
+
baseFiles: params.baseFiles || null,
|
|
89
|
+
reviewingPolicy: params.reviewingPolicy || '',
|
|
90
|
+
requireReviewing: params.requireReviewing === true,
|
|
91
|
+
requireEditing: params.requireEditing === true,
|
|
92
|
+
runProjectId: projectId,
|
|
93
|
+
...(params.deadlineAt == null ? {} : { deadlineAt: params.deadlineAt }),
|
|
94
|
+
onOperationResult
|
|
95
|
+
});
|
|
96
|
+
}).catch(error => ({
|
|
97
|
+
...snapshot(receipt).result, ok: false, code: error?.code || 'page_bridge_dispatch_failed',
|
|
98
|
+
error: error?.message || String(error), requestId: id, changedDocument: true
|
|
99
|
+
})).then(result => {
|
|
100
|
+
receipt.result = clone(result && typeof result === 'object' ? result
|
|
101
|
+
: { ok: false, code: 'writeback_result_unconfirmed', error: 'The page returned no writeback result.' });
|
|
102
|
+
receipt.state = 'completed';
|
|
103
|
+
receipt.updatedAt = now();
|
|
104
|
+
if (active === receipt) active = null;
|
|
105
|
+
return receipt.result;
|
|
106
|
+
});
|
|
107
|
+
return receipt.promise;
|
|
108
|
+
}
|
|
109
|
+
return Object.freeze({ apply, get });
|
|
110
|
+
}
|
|
111
|
+
return { create };
|
|
112
|
+
});
|