codex-overleaf-link 2.4.1 → 2.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +275 -305
- package/README.zh-CN.md +290 -320
- package/extension/bootstrap/background.js +99 -19
- package/extension/bootstrap/manifest.template.json +9 -4
- package/extension/bootstrap/popup.html +11 -16
- package/extension/bootstrap/popupFallback.js +55 -0
- package/extension/bootstrap/update.js +25 -2
- package/extension/bootstrap/updateStatus.js +1 -0
- package/extension/runtime-manifest.json +3 -1
- package/extension/src/background.js +234 -56
- package/extension/src/backgroundBootstrapMigration.js +181 -0
- package/extension/src/backgroundSharedSessions.js +440 -0
- package/extension/src/backgroundUpdateCoordinator.js +541 -381
- package/extension/src/backgroundUpdateSafety.js +173 -0
- package/extension/src/content/activeTurnControl.js +16 -2
- package/extension/src/content/applyResultFormatters.js +46 -73
- package/extension/src/content/assetTransferBroker.js +244 -12
- package/extension/src/content/changeHistoryView.js +175 -0
- package/extension/src/content/composerAttachments.js +117 -67
- package/extension/src/content/composerPanel.js +41 -8
- package/extension/src/content/contentRuntime.js +1084 -1099
- package/extension/src/content/diagnosticsController.js +122 -97
- package/extension/src/content/diagnosticsExport.js +236 -0
- package/extension/src/content/diagnosticsPanel.js +78 -19
- package/extension/src/content/diffReviewPanel.js +8 -5
- package/extension/src/content/directoryCleanupRecovery.js +54 -0
- package/extension/src/content/generated/content.bundle.js +14680 -3606
- package/extension/src/content/generated/content.bundle.meta.json +30 -3
- package/extension/src/content/globalPreferencesController.js +1 -1
- package/extension/src/content/legacyGlobalRegistry.js +25 -1
- package/extension/src/content/localSkillsPanel.js +141 -16
- package/extension/src/content/markdownDomRenderer.js +9 -4
- package/extension/src/content/markdownText.js +5 -6
- package/extension/src/content/modelPicker.js +8 -5
- package/extension/src/content/nativeCompatibilityController.js +45 -20
- package/extension/src/content/otWarmMirror.js +4 -5
- package/extension/src/content/otWarmMirrorController.js +17 -20
- package/extension/src/content/pageBridgeClient.js +33 -5
- package/extension/src/content/panelMaintenance.js +87 -132
- package/extension/src/content/panelRenderer.js +10 -0
- package/extension/src/content/pendingInputView.js +109 -76
- package/extension/src/content/projectProviderSelection.js +13 -4
- package/extension/src/content/projectSessionCleanup.js +109 -62
- package/extension/src/content/projectSettingsCoordinator.js +39 -2
- package/extension/src/content/providerSettingsCoordinator.js +63 -14
- package/extension/src/content/providerSettingsDialog.js +724 -113
- package/extension/src/content/recentProjects.js +21 -6
- package/extension/src/content/runActivitySummary.js +665 -0
- package/extension/src/content/runCompletionMeta.js +344 -0
- package/extension/src/content/runController.js +40 -15
- package/extension/src/content/runFailureNotice.js +34 -12
- package/extension/src/content/runGuidanceController.js +76 -30
- package/extension/src/content/runGuidanceView.js +59 -10
- package/extension/src/content/runPresence.js +306 -0
- package/extension/src/content/runQueueScheduler.js +150 -43
- package/extension/src/content/runRecoveryActions.js +146 -0
- package/extension/src/content/runResultActions.js +11 -8
- package/extension/src/content/runReviewController.js +574 -0
- package/extension/src/content/runScrollLayout.js +21 -2
- package/extension/src/content/runTimelineView.js +315 -290
- package/extension/src/content/scopedPersistencePanelState.js +51 -6
- package/extension/src/content/selectionContextView.js +300 -0
- package/extension/src/content/sensitivePreflight.js +140 -0
- package/extension/src/content/sessionForkController.js +80 -17
- package/extension/src/content/sessionManager.js +1 -1
- package/extension/src/content/sessionPersistence.js +6 -1
- package/extension/src/content/settingsPanel.js +84 -55
- package/extension/src/content/settingsWorkbench.js +379 -0
- package/extension/src/content/sharedSessionViewSync.js +109 -0
- package/extension/src/content/subagentActivityView.js +195 -0
- package/extension/src/content/trackedChangeCaptureController.js +7 -3
- package/extension/src/content/updateIdle.js +4 -1
- package/extension/src/content/updateNotice.js +179 -56
- package/extension/src/content/updateSafetyReceiver.js +58 -0
- package/extension/src/content/writebackController.js +308 -2
- package/extension/src/content/writebackOrchestrator.js +213 -199
- package/extension/src/content/writebackPlan.js +231 -0
- package/extension/src/content/writebackRecovery.js +122 -0
- package/extension/src/content/writingStyleSettings.js +600 -0
- package/extension/src/content/writtenChangesView.js +152 -0
- package/extension/src/page/binaryAssetUploader.js +223 -23
- package/extension/src/page/fileMover.js +256 -0
- package/extension/src/page/overleafProjectSnapshot.js +1 -0
- package/extension/src/page/ownedDirectoryCleanup.js +94 -0
- package/extension/src/page/referenceProjects.js +149 -0
- package/extension/src/page/reviewContext.js +113 -0
- package/extension/src/page/saveState.js +20 -6
- package/extension/src/page/snapshotRouter.js +124 -48
- package/extension/src/page/textCoordinates.js +102 -0
- package/extension/src/page/textFileCreator.js +442 -71
- package/extension/src/page/trackedChangeCapture.js +53 -57
- package/extension/src/page/trackedChangeOwnership.js +216 -0
- package/extension/src/page/trackedChangeReplay.js +184 -0
- package/extension/src/page/trackedChangesLifecycle.js +343 -339
- package/extension/src/page/treeOperations.js +33 -12
- package/extension/src/page/updateSafetyProbe.js +41 -0
- package/extension/src/page/writebackReceiptJournal.js +114 -0
- package/extension/src/page/writebackRouter.js +242 -201
- package/extension/src/pageBridge.js +73 -102
- package/extension/src/popup.js +261 -65
- package/extension/src/shared/agentTranscript.js +41 -4
- package/extension/src/shared/auditRecords.js +73 -0
- package/extension/src/shared/changeHistoryModel.js +94 -0
- package/extension/src/shared/compatibility.js +22 -6
- package/extension/src/shared/compileAdapter.js +101 -37
- package/extension/src/shared/composerAttachmentDraft.js +151 -0
- package/extension/src/shared/directoryCleanupProof.js +43 -0
- package/extension/src/shared/failureReasons.js +329 -3
- package/extension/src/shared/globalPreferences.js +31 -14
- package/extension/src/shared/governanceRules.js +4 -37
- package/extension/src/shared/i18n.js +389 -25
- package/extension/src/shared/managedUpdateProjection.js +8 -5
- package/extension/src/shared/nativeRequestIdentity.js +1 -0
- package/extension/src/shared/pageRpcContract.js +9 -2
- package/extension/src/shared/projectFiles.js +21 -44
- package/extension/src/shared/providerProfiles.js +114 -3
- 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/runInputQueue.js +48 -5
- package/extension/src/shared/scopedPersistenceBrowserAdapter.js +6 -3
- package/extension/src/shared/selectionContext.js +37 -0
- package/extension/src/shared/sessionState.js +166 -30
- package/extension/src/shared/settlementFacts.js +10 -2
- package/extension/src/shared/sharedSessionBridge.js +311 -0
- package/extension/src/shared/sharedSessionTransfer.js +140 -0
- package/extension/src/shared/staleGuard.js +118 -13
- package/extension/src/shared/storageDb.js +77 -78
- package/extension/src/shared/storageMigration.js +74 -111
- package/extension/src/shared/storageRunActions.js +211 -22
- package/extension/src/shared/storageValuePruning.js +40 -0
- package/extension/src/shared/subagentActivityModel.js +174 -0
- package/extension/src/shared/undoOperations.js +216 -6
- package/extension/src/shared/updateConsent.js +42 -11
- package/extension/src/shared/updateRuntimeIdentity.js +1 -1
- package/extension/src/shared/writebackIntent.js +78 -0
- package/extension/src/shared/writebackOperationEvidence.js +4 -15
- package/extension/src/shared/writebackSettlement.js +67 -48
- package/extension/src/shared/writingStyle.js +33 -0
- package/extension/styles/panel.css +1987 -385
- package/extension/styles/popup.css +110 -0
- package/native-host/src/anthropicBridgeRequest.js +6 -3
- package/native-host/src/anthropicBridgeResponse.js +6 -2
- package/native-host/src/anthropicMessagesBridge.js +24 -16
- package/native-host/src/bootstrapMigration.js +296 -0
- package/native-host/src/bootstrapMigrationContract.js +101 -0
- package/native-host/src/bootstrapUpdate.js +233 -0
- package/native-host/src/bootstrapUpdateWatchdog.js +44 -0
- package/native-host/src/chatBridgeResponse.js +10 -0
- package/native-host/src/chatCompletionsBridge.js +21 -15
- package/native-host/src/codexConfigPaths.js +106 -0
- package/native-host/src/codexHome.js +66 -73
- package/native-host/src/codexHomeScope.js +124 -0
- package/native-host/src/codexInheritedAuth.js +90 -0
- package/native-host/src/codexLocalSkills.js +301 -0
- package/native-host/src/codexModelRecovery.js +107 -0
- package/native-host/src/codexPromptAssembly.js +33 -12
- package/native-host/src/codexProviderLaunch.js +3 -3
- package/native-host/src/codexProviderTest.js +24 -26
- package/native-host/src/codexRuntimeIdentity.js +1 -0
- package/native-host/src/codexSessionRunner.js +211 -318
- package/native-host/src/codexSessionTiming.js +21 -8
- package/native-host/src/codexSkillIsolation.js +170 -0
- package/native-host/src/codexThreadFork.js +19 -3
- package/native-host/src/index.js +19 -7
- package/native-host/src/managedInstall.js +115 -39
- package/native-host/src/managedInstallRecovery.js +140 -0
- package/native-host/src/managedRuntimeEvidence.js +57 -0
- package/native-host/src/mirrorWorkspace.js +92 -22
- package/native-host/src/nativeDoctor.js +15 -0
- package/native-host/src/nativeEnvironment.js +70 -0
- package/native-host/src/nativeHelperLifecycle.js +21 -0
- package/native-host/src/nativeHostRegistration.js +33 -0
- package/native-host/src/nativeQuotas.js +15 -8
- package/native-host/src/nativeRunLifecycle.js +71 -0
- package/native-host/src/overleafWorkspaceRules.js +16 -0
- package/native-host/src/processStopBarrier.js +115 -0
- package/native-host/src/projectPathPlatform.js +30 -0
- package/native-host/src/providerHttp.js +80 -0
- package/native-host/src/providerModelCatalog.js +4 -3
- package/native-host/src/providerProfile.js +17 -3
- package/native-host/src/providerReasoning.js +10 -11
- package/native-host/src/providerRuntime.js +1 -0
- package/native-host/src/providerStore.js +76 -14
- package/native-host/src/releaseTransport.js +14 -5
- package/native-host/src/responsesPassthroughBridge.js +266 -52
- package/native-host/src/runtimeInstaller.js +21 -1
- package/native-host/src/selectionScope.js +86 -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/subagentAdmission.js +26 -0
- package/native-host/src/subagentBroker.js +176 -159
- package/native-host/src/subagentTelemetry.js +325 -0
- package/native-host/src/subagentWorkspace.js +103 -0
- package/native-host/src/subagentWorkspacePath.js +34 -0
- package/native-host/src/taskRunnerRuntime.js +130 -57
- package/native-host/src/tomlStatements.js +140 -0
- package/native-host/src/turnAttachments.js +113 -0
- package/native-host/src/updateManager.js +406 -38
- 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 +475 -0
- package/native-host/src/writingStyleStore.js +73 -0
- package/package.json +1 -1
- package/scripts/install-managed.mjs +1 -0
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
(function initCodexOverleafWritebackRouter(root, factory) {
|
|
2
2
|
if (typeof module === 'object' && module.exports) {
|
|
3
|
-
module.exports = factory();
|
|
3
|
+
module.exports = factory(require('./treeOperations'));
|
|
4
4
|
} else {
|
|
5
|
-
root.CodexOverleafWritebackRouter = factory();
|
|
5
|
+
root.CodexOverleafWritebackRouter = factory(root.CodexOverleafTreeOperations);
|
|
6
6
|
}
|
|
7
|
-
})(typeof window !== 'undefined' ? window : globalThis, function writebackRouterFactory() {
|
|
7
|
+
})(typeof window !== 'undefined' ? window : globalThis, function writebackRouterFactory(TreeOperations) {
|
|
8
8
|
'use strict';
|
|
9
|
+
const { fileTreeMethodNames } = TreeOperations;
|
|
9
10
|
|
|
10
11
|
function create(deps = {}) {
|
|
11
12
|
const window = deps.window || (typeof globalThis !== 'undefined' ? globalThis : {});
|
|
@@ -17,6 +18,7 @@
|
|
|
17
18
|
? Math.max(0, Number(deps.writebackOpenSettleMs))
|
|
18
19
|
: 1200;
|
|
19
20
|
const diagnosticsRevision = String(deps.diagnosticsRevision || '');
|
|
21
|
+
const now = deps.now || Date.now;
|
|
20
22
|
// Cross-world cancel signal reader. Returns the current page-bridge
|
|
21
23
|
// sequence number, which monotonically increments when content-side
|
|
22
24
|
// calls pageBridge.cancelActiveWrite. applyOperationsCore captures the
|
|
@@ -269,6 +271,11 @@
|
|
|
269
271
|
fallbackUserMessage: 'The edit anchor no longer matches current Overleaf content.',
|
|
270
272
|
fallbackNextAction: 'Rerun the task against the current document.'
|
|
271
273
|
},
|
|
274
|
+
write_operation_failed: {
|
|
275
|
+
stage: 'write', severity: 'error', defaultRetryable: true,
|
|
276
|
+
fallbackUserMessage: 'Editor write call failed.',
|
|
277
|
+
fallbackNextAction: 'Retry after the editor is stable.'
|
|
278
|
+
},
|
|
272
279
|
write_observed_mismatch: {
|
|
273
280
|
stage: 'verify', severity: 'error', defaultRetryable: false,
|
|
274
281
|
fallbackUserMessage: 'Codex attempted to write, but the content read back from Overleaf did not match the approved change.',
|
|
@@ -352,7 +359,9 @@
|
|
|
352
359
|
|
|
353
360
|
async function applyOperations(operations, options = {}) {
|
|
354
361
|
if (options.reviewingPolicy === 'no-trace-undo') {
|
|
355
|
-
|
|
362
|
+
const Context = window.CodexOverleafReviewContext || (typeof module === 'object' && module.exports ? require('./reviewContext') : null);
|
|
363
|
+
return Context.create({ window, now, readWriteCancellationSequence, getProjectId: () => treeOperations.getProjectId?.() }, options).run(
|
|
364
|
+
(scoped, input) => applyOperationsWithNoTraceUndo(operations, { ...input, reviewGuard: scoped.reviewGuard, reviewAwait: scoped.reviewAwait }));
|
|
356
365
|
}
|
|
357
366
|
const hasOperations = (operations || []).length > 0;
|
|
358
367
|
const trackReviewingChanges = options.requireReviewing === true && hasOperations;
|
|
@@ -382,6 +391,7 @@
|
|
|
382
391
|
}
|
|
383
392
|
const result = await applyOperationsCore(operations, {
|
|
384
393
|
...options,
|
|
394
|
+
noTraceUndo: false,
|
|
385
395
|
trackReviewingChanges
|
|
386
396
|
});
|
|
387
397
|
return reviewingPolicy
|
|
@@ -392,13 +402,16 @@
|
|
|
392
402
|
: result;
|
|
393
403
|
}
|
|
394
404
|
|
|
395
|
-
async function confirmNoTraceUndoEditing() {
|
|
405
|
+
async function confirmNoTraceUndoEditing(options = {}) {
|
|
396
406
|
let changed = false;
|
|
397
407
|
let toggle = { ok: true, changed: false, enabled: false };
|
|
398
408
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
409
|
+
const blocked = options.reviewGuard?.();
|
|
410
|
+
if (blocked) return blocked;
|
|
399
411
|
if (!isEditingConfirmedForNoTraceUndo(getReviewingState({}))) {
|
|
400
412
|
toggle = await setReviewingEnabled(false, { waitMs: 1800 });
|
|
401
|
-
if (!toggle.ok
|
|
413
|
+
if (!toggle.ok && (!['editing_not_confirmed', 'reviewing_disable_failed'].includes(toggle.code)
|
|
414
|
+
|| !isEditingConfirmedForNoTraceUndo(getReviewingState({})))) return toggle;
|
|
402
415
|
changed = changed || toggle.changed === true;
|
|
403
416
|
}
|
|
404
417
|
await delay(180);
|
|
@@ -411,8 +424,13 @@
|
|
|
411
424
|
reason: 'Overleaf Editing mode did not remain confirmed before undo; no undo write was started.' };
|
|
412
425
|
}
|
|
413
426
|
|
|
427
|
+
async function awaitReview(options, work) {
|
|
428
|
+
try { return options.reviewAwait ? await options.reviewAwait(work) : await work(); }
|
|
429
|
+
catch (error) { if (error?.reviewFailure) return error.reviewFailure; throw error; }
|
|
430
|
+
}
|
|
431
|
+
|
|
414
432
|
async function applyOperationsWithNoTraceUndo(operations, options = {}) {
|
|
415
|
-
const disabled = await confirmNoTraceUndoEditing();
|
|
433
|
+
const disabled = await awaitReview(options, () => confirmNoTraceUndoEditing(options));
|
|
416
434
|
if (!disabled.ok) return buildNoTraceUndoBlockedResult(operations, disabled);
|
|
417
435
|
const result = await applyOperationsCore(operations, {
|
|
418
436
|
...options, noTraceUndo: true, trackReviewingChanges: false
|
|
@@ -434,33 +452,15 @@
|
|
|
434
452
|
const safeBaseFiles = normalizeBaseFilesForSafety(options.baseFiles);
|
|
435
453
|
const baseFileLookup = window.CodexOverleafStaleGuard?.buildBaseFileLookup(safeBaseFiles);
|
|
436
454
|
const baseBinaryFileLookup = buildBaseBinaryFileLookup(safeBaseFiles);
|
|
437
|
-
//
|
|
438
|
-
// writeGuard once at entry, but each per-op step here can take 0.5-5s
|
|
439
|
-
// (openFileByPath, waitForActiveEditorText, save-state verification),
|
|
440
|
-
// so a multi-op write can span 10-30 seconds total. If the user SPA-
|
|
441
|
-
// navigates to a different project mid-flight, the remaining operations
|
|
442
|
-
// would land in the wrong project. Re-check the editor project before
|
|
443
|
-
// each op and short-circuit the rest of the queue when it diverges.
|
|
455
|
+
// Recheck project identity between awaited operations and before each write.
|
|
444
456
|
const runProjectId = typeof options.runProjectId === 'string' ? options.runProjectId : '';
|
|
445
457
|
const writeGuardSurface = window.CodexOverleafWriteGuard?.create({
|
|
446
458
|
window,
|
|
447
459
|
document: window.document,
|
|
448
460
|
treeOperations
|
|
449
461
|
});
|
|
450
|
-
//
|
|
451
|
-
//
|
|
452
|
-
// bumps. Two layers of responsiveness:
|
|
453
|
-
// 1. Between-ops check — short-circuits the next iteration so the
|
|
454
|
-
// remaining ops never start.
|
|
455
|
-
// 2. Race the in-flight op against a cancellation poller (50ms
|
|
456
|
-
// interval) so a click DURING a slow op (e.g. inside a 5s
|
|
457
|
-
// waitForActiveFile poll) is observed within ~50ms instead of
|
|
458
|
-
// having to wait out the op's internal timeout. The op promise
|
|
459
|
-
// keeps running in the page world after the race resolves — its
|
|
460
|
-
// eventual result is ignored. This is "user-perceived instant
|
|
461
|
-
// cancel": the spinner stops, the run settles to cancelled, and
|
|
462
|
-
// any DOM mutation already in flight on the op cannot be undone
|
|
463
|
-
// from here anyway.
|
|
462
|
+
// Preserve the actual result of an in-flight operation so its readback and
|
|
463
|
+
// undo evidence survive cancellation. The checkpoints stop undispatched work.
|
|
464
464
|
const cancelBaselineSequence = readWriteCancellationSequence();
|
|
465
465
|
const cancelledSkipResult = {
|
|
466
466
|
ok: false,
|
|
@@ -477,103 +477,78 @@
|
|
|
477
477
|
changedDocument: false
|
|
478
478
|
}
|
|
479
479
|
};
|
|
480
|
-
const
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
480
|
+
const createCandidates = operations.map(normalizeOperationPaths).filter(operation => operation.type === 'create'
|
|
481
|
+
&& operations.filter(other => [other.path, other.to].includes(operation.path)).length === 1);
|
|
482
|
+
const createBatch = createCandidates.length && typeof deps.beginTextCreateBatch === 'function'
|
|
483
|
+
? await deps.beginTextCreateBatch(createCandidates, { isCurrent: () =>
|
|
484
|
+
treeOperations.getProjectId?.() === runProjectId && readWriteCancellationSequence() === cancelBaselineSequence }) : null;
|
|
485
|
+
const deferredCreates = [];
|
|
486
|
+
let haltRemainingOperations = false;
|
|
487
|
+
const skipTail = (operation, result) => operations.slice(operations.indexOf(operation) + 1)
|
|
488
|
+
.forEach(tail => skipped.push({ operation: normalizeOperationPaths(tail), result }));
|
|
489
|
+
const reopenQueue = [];
|
|
490
|
+
const deadlineFailure = () => Number.isFinite(options.deadlineAt) && now() >= options.deadlineAt
|
|
491
|
+
? { ok: false, code: 'writeback_deadline_exceeded', changedDocument: false,
|
|
492
|
+
reason: 'The undo time budget expired before this operation could start.' } : null;
|
|
493
|
+
const editOptions = () => ({ baseFileLookup, runProjectId, deadlineAt: options.deadlineAt,
|
|
494
|
+
reviewGuard: options.reviewGuard, reviewAwait: options.reviewAwait,
|
|
495
|
+
recheckWriteProject: writeGuardSurface ? () => {
|
|
496
|
+
const expired = options.reviewGuard?.() || deadlineFailure();
|
|
497
|
+
return expired ? { applied: [], skipped: [{ operation: {}, result: expired }] }
|
|
498
|
+
: writeGuardSurface.runWriteGuard({ runProjectId });
|
|
499
|
+
} : null,
|
|
500
|
+
trackReviewingChanges: options.trackReviewingChanges === true, noTraceUndo: options.noTraceUndo === true });
|
|
501
|
+
const record = (operation, result) => {
|
|
502
|
+
if (result.trackedChangeCapture) trackedChangeCaptures.push(result.trackedChangeCapture);
|
|
503
|
+
if (operation.type === 'edit' && result.ok && Array.isArray(result.trackedChanges)) {
|
|
504
|
+
trackedChanges.push(...result.trackedChanges);
|
|
489
505
|
}
|
|
506
|
+
(result.ok ? applied : skipped).push({ operation, result });
|
|
507
|
+
options.onOperationResult?.({ operation, result });
|
|
490
508
|
};
|
|
491
|
-
// 50ms-poller racer using recursive setTimeout. setInterval is NOT
|
|
492
|
-
// exposed in the test VM context that hosts pageBridge (only setTimeout /
|
|
493
|
-
// clearTimeout are wired), so this implementation must avoid it. Each
|
|
494
|
-
// tick re-schedules itself only while the racer has not resolved;
|
|
495
|
-
// dispose() flips a flag so any tick that fires after dispose is a no-op.
|
|
496
|
-
// Resolves the first time the cancellation sequence bumps past baseline.
|
|
497
|
-
function createCancellationRacer() {
|
|
498
|
-
let resolved = false;
|
|
499
|
-
let resolveFn;
|
|
500
|
-
const promise = new Promise(resolve => { resolveFn = resolve; });
|
|
501
|
-
let timer = null;
|
|
502
|
-
function tick() {
|
|
503
|
-
if (resolved) return;
|
|
504
|
-
if (readWriteCancellationSequence() !== cancelBaselineSequence) {
|
|
505
|
-
resolved = true;
|
|
506
|
-
resolveFn();
|
|
507
|
-
return;
|
|
508
|
-
}
|
|
509
|
-
timer = window.setTimeout(tick, 50);
|
|
510
|
-
}
|
|
511
|
-
timer = window.setTimeout(tick, 50);
|
|
512
|
-
return {
|
|
513
|
-
promise,
|
|
514
|
-
dispose() {
|
|
515
|
-
resolved = true;
|
|
516
|
-
if (timer) window.clearTimeout(timer);
|
|
517
|
-
}
|
|
518
|
-
};
|
|
519
|
-
}
|
|
520
|
-
const CANCELLED_RACE_SENTINEL = Symbol('writebackRouter.cancelled');
|
|
521
|
-
async function raceOpAgainstCancellation(opPromise) {
|
|
522
|
-
// Once an editor operation starts, preserve its actual result and undo
|
|
523
|
-
// metadata. The loop's pre-operation cancellation check stops the tail.
|
|
524
|
-
return await opPromise;
|
|
525
|
-
}
|
|
526
509
|
|
|
527
510
|
for (const rawOperation of operations) {
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
511
|
+
const reviewBlock = options.reviewGuard?.();
|
|
512
|
+
if (reviewBlock) {
|
|
513
|
+
skipped.push({ operation: normalizeOperationPaths(rawOperation), result: reviewBlock });
|
|
514
|
+
skipTail(rawOperation, reviewBlock); break;
|
|
515
|
+
}
|
|
516
|
+
// Stop undispatched work when cancellation arrives during an awaited operation.
|
|
532
517
|
if (readWriteCancellationSequence() !== cancelBaselineSequence) {
|
|
533
518
|
skipped.push({ operation: normalizeOperationPaths(rawOperation), result: cancelledSkipResult });
|
|
534
|
-
|
|
535
|
-
for (const tailOperation of remainingForCancel) {
|
|
536
|
-
skipped.push({ operation: normalizeOperationPaths(tailOperation), result: cancelledSkipResult });
|
|
537
|
-
}
|
|
519
|
+
skipTail(rawOperation, cancelledSkipResult);
|
|
538
520
|
break;
|
|
539
521
|
}
|
|
540
|
-
//
|
|
541
|
-
// guard is available, verify the editor still shows the same project
|
|
542
|
-
// before committing the next write. Mismatch → push aborted_project_changed
|
|
543
|
-
// for THIS op and every remaining op in the queue, then return.
|
|
522
|
+
// Re-check project ownership before this operation and preserve every skipped tail entry.
|
|
544
523
|
if (runProjectId && writeGuardSurface) {
|
|
545
524
|
const guardBlock = await writeGuardSurface.runWriteGuard({ runProjectId });
|
|
546
525
|
if (guardBlock) {
|
|
547
|
-
//
|
|
548
|
-
// caller can attribute the abort to a real operation path, then
|
|
549
|
-
// pad the remaining ops with the same failure shape.
|
|
526
|
+
// Keep the current path and the remaining operations attributable.
|
|
550
527
|
const guardFailure = guardBlock.skipped[0].result;
|
|
551
528
|
skipped.push({ operation: normalizeOperationPaths(rawOperation), result: guardFailure });
|
|
552
|
-
|
|
553
|
-
for (const tailOperation of remaining) {
|
|
554
|
-
skipped.push({ operation: normalizeOperationPaths(tailOperation), result: guardFailure });
|
|
555
|
-
}
|
|
529
|
+
skipTail(rawOperation, guardFailure);
|
|
556
530
|
break;
|
|
557
531
|
}
|
|
558
532
|
}
|
|
559
533
|
const operation = normalizeOperationPaths(rawOperation);
|
|
560
|
-
const pathSafety = validateOperationProjectPaths(operation);
|
|
534
|
+
const pathSafety = deadlineFailure() || validateOperationProjectPaths(operation);
|
|
561
535
|
if (!pathSafety.ok) {
|
|
562
536
|
skipped.push({ operation, result: pathSafety });
|
|
563
537
|
continue;
|
|
564
538
|
}
|
|
565
|
-
let
|
|
539
|
+
let result;
|
|
566
540
|
if (operation.type === 'edit') {
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
}));
|
|
541
|
+
result = await applyEditOperation(operation, editOptions());
|
|
542
|
+
if (isUntouchedOpenFailure(result)) {
|
|
543
|
+
reopenQueue.push({ operation, result });
|
|
544
|
+
continue;
|
|
545
|
+
}
|
|
573
546
|
} else if (['binary-create', 'overwrite-binary'].includes(operation.type)) {
|
|
574
|
-
|
|
547
|
+
result = await applyBinaryAssetOperation(operation, { baseFileLookup, baseBinaryFileLookup });
|
|
575
548
|
} else if (['create', 'rename', 'move', 'delete'].includes(operation.type)) {
|
|
576
|
-
|
|
549
|
+
result = await applyFileTreeOperation(operation, { baseFileLookup, runProjectId, deadlineAt: options.deadlineAt, reviewGuard: options.reviewGuard, noTraceUndo: options.noTraceUndo === true,
|
|
550
|
+
createBatch: createBatch?.targets.has(operation.path) ? createBatch : null,
|
|
551
|
+
retryCreates: options.retryCreates === true });
|
|
577
552
|
} else {
|
|
578
553
|
skipped.push({
|
|
579
554
|
operation,
|
|
@@ -584,27 +559,42 @@
|
|
|
584
559
|
});
|
|
585
560
|
continue;
|
|
586
561
|
}
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
if (raceResult === CANCELLED_RACE_SENTINEL) {
|
|
592
|
-
skipped.push({ operation, result: cancelledInFlightResult });
|
|
593
|
-
const remainingAfterCancel = operations.slice(operations.indexOf(rawOperation) + 1);
|
|
594
|
-
for (const tailOperation of remainingAfterCancel) {
|
|
595
|
-
skipped.push({ operation: normalizeOperationPaths(tailOperation), result: cancelledSkipResult });
|
|
596
|
-
}
|
|
597
|
-
break;
|
|
562
|
+
if (operation.type === 'create' && createBatch?.pending.has(operation.path)
|
|
563
|
+
&& !createBatch.blocked.has(operation.path)) {
|
|
564
|
+
deferredCreates.push({ operation, result });
|
|
565
|
+
continue;
|
|
598
566
|
}
|
|
599
|
-
|
|
600
|
-
if (
|
|
601
|
-
|
|
602
|
-
|
|
567
|
+
record(operation, result);
|
|
568
|
+
if (operation.type === 'move' && operation.moveProof && !result.ok) {
|
|
569
|
+
haltRemainingOperations = true;
|
|
570
|
+
skipTail(rawOperation, { ok: false, code: 'file_plan_not_completed', changedDocument: false,
|
|
571
|
+
reason: 'The file move did not finish; the remaining file plan was not started.' }); break;
|
|
603
572
|
}
|
|
604
|
-
(result.ok ? applied : skipped).push({ operation, result });
|
|
605
573
|
}
|
|
606
574
|
|
|
607
|
-
|
|
575
|
+
// A file that could not be opened mid-batch usually opens once the
|
|
576
|
+
// previous document has settled: give untouched open failures one pass.
|
|
577
|
+
if (!haltRemainingOperations && reopenQueue.length && readWriteCancellationSequence() === cancelBaselineSequence
|
|
578
|
+
&& !skipped.some(entry => entry.result?.code === 'aborted_project_changed')) {
|
|
579
|
+
await delay(deps.reopenRetryDelayMs ?? 1200);
|
|
580
|
+
}
|
|
581
|
+
for (const entry of reopenQueue) {
|
|
582
|
+
const blocked = options.reviewGuard?.() || haltRemainingOperations || readWriteCancellationSequence() !== cancelBaselineSequence
|
|
583
|
+
|| skipped.some(item => item.result?.code === 'aborted_project_changed')
|
|
584
|
+
|| Boolean(runProjectId && writeGuardSurface && await writeGuardSurface.runWriteGuard({ runProjectId }));
|
|
585
|
+
const result = blocked ? entry.result : await applyEditOperation(entry.operation, editOptions());
|
|
586
|
+
record(entry.operation, result);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
if (deferredCreates.length) {
|
|
590
|
+
const confirmed = await deps.finishTextCreateBatch(createBatch, deferredCreates, applied);
|
|
591
|
+
for (const entry of confirmed) {
|
|
592
|
+
(entry.result.ok ? applied : skipped).push(entry);
|
|
593
|
+
if (entry.result.ok) recordFileTreeOperationSuccess(entry.operation, baseFileLookup);
|
|
594
|
+
options.onOperationResult?.(entry);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
if (applied.some(entry => entry.result?.changedDocument !== false)) {
|
|
608
598
|
compileBridge.markSourceEdited();
|
|
609
599
|
}
|
|
610
600
|
|
|
@@ -612,44 +602,26 @@
|
|
|
612
602
|
ok: skipped.length === 0,
|
|
613
603
|
applied,
|
|
614
604
|
skipped,
|
|
605
|
+
...(haltRemainingOperations ? { haltRemainingOperations: true } : {}),
|
|
615
606
|
trackedChanges: trackedChangeCaptures.some(capture => capture.state !== 'observed') ? [] : mergeTrackedChangeRefs(trackedChanges),
|
|
616
607
|
trackedChangeCaptures
|
|
617
608
|
};
|
|
618
609
|
}
|
|
619
610
|
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
611
|
+
const isUntouchedOpenFailure = result => result?.ok === false && result.failure?.code === 'target_file_open_failed'
|
|
612
|
+
&& result.failure.changedDocument === false;
|
|
643
613
|
|
|
644
614
|
async function applyEditOperation(operation, options = {}) {
|
|
615
|
+
const reviewBlock = options.reviewGuard?.();
|
|
616
|
+
if (reviewBlock) return reviewBlock;
|
|
645
617
|
const currentPath = getActiveFilePath();
|
|
646
|
-
const editorReady = await ensureEditorReadyForOperation(operation, options.baseFileLookup, currentPath);
|
|
618
|
+
const editorReady = await awaitReview(options, () => ensureEditorReadyForOperation(operation, options.baseFileLookup, currentPath));
|
|
647
619
|
if (!editorReady.ok) {
|
|
648
620
|
return editorReady;
|
|
649
621
|
}
|
|
650
622
|
|
|
651
623
|
if (options.noTraceUndo === true) {
|
|
652
|
-
const editing = await confirmNoTraceUndoEditing();
|
|
624
|
+
const editing = await awaitReview(options, () => confirmNoTraceUndoEditing(options));
|
|
653
625
|
if (!editing.ok) return buildNoTraceUndoBlockedResult([operation], editing).skipped[0].result;
|
|
654
626
|
}
|
|
655
627
|
const trackReviewingChanges = options.trackReviewingChanges === true;
|
|
@@ -667,7 +639,8 @@
|
|
|
667
639
|
options.baseFileLookup
|
|
668
640
|
) || { ok: true };
|
|
669
641
|
if (!freshness.ok) {
|
|
670
|
-
const ready = await waitForFreshEditorTextForOperation(operation, options.baseFileLookup, 1500);
|
|
642
|
+
const ready = await awaitReview(options, () => waitForFreshEditorTextForOperation(operation, options.baseFileLookup, 1500));
|
|
643
|
+
if (options.reviewGuard?.()) return options.reviewGuard();
|
|
671
644
|
if (!ready.ok) {
|
|
672
645
|
const decorated = attachWritebackDebug(freshness, 'stale_guard', operation, options.baseFileLookup, current, {
|
|
673
646
|
initialActivePath: currentPath,
|
|
@@ -707,8 +680,11 @@
|
|
|
707
680
|
}
|
|
708
681
|
|
|
709
682
|
let nextContent = null;
|
|
683
|
+
let preparedPatches;
|
|
710
684
|
if (Array.isArray(operation.patches) && operation.patches.length) {
|
|
711
|
-
|
|
685
|
+
preparedPatches = window.CodexOverleafStaleGuard?.prepareOperationPatches(operation, current, options.baseFileLookup)
|
|
686
|
+
|| { ok: true, patches: operation.patches };
|
|
687
|
+
const patched = preparedPatches.ok ? applyTextPatches(current, preparedPatches.patches) : preparedPatches;
|
|
712
688
|
if (!patched.ok) {
|
|
713
689
|
const decorated = attachWritebackDebug(patched, 'apply_text_patches', operation, options.baseFileLookup, current, {
|
|
714
690
|
initialActivePath: currentPath,
|
|
@@ -771,19 +747,34 @@
|
|
|
771
747
|
reason: 'Overleaf left Editing mode before the undo write.' }).skipped[0].result;
|
|
772
748
|
}
|
|
773
749
|
|
|
750
|
+
const finalReviewBlock = options.reviewGuard?.();
|
|
751
|
+
if (finalReviewBlock) return finalReviewBlock;
|
|
774
752
|
const result = Array.isArray(operation.patches) && operation.patches.length
|
|
775
|
-
? replaceActiveEditorPatches(
|
|
753
|
+
? replaceActiveEditorPatches(preparedPatches.patches, nextContent)
|
|
776
754
|
: replaceActiveEditorText(nextContent);
|
|
777
755
|
if (!result.ok) {
|
|
778
756
|
return result;
|
|
779
757
|
}
|
|
780
758
|
|
|
781
|
-
const
|
|
759
|
+
const verifyWaitMs = Math.min(deps.writeVerifyWaitMs ?? 2500, Number.isFinite(options.deadlineAt)
|
|
760
|
+
? Math.max(0, options.deadlineAt - now()) : Infinity);
|
|
761
|
+
const verified = await verifyActiveEditorText(nextContent, operation.path, verifyWaitMs, current);
|
|
782
762
|
if (!verified.ok) {
|
|
783
763
|
const decorated = attachWritebackDebug(verified, 'write_verification', operation, options.baseFileLookup, readActiveEditorText(), {
|
|
784
764
|
initialActivePath: currentPath,
|
|
785
765
|
editorReadyDebug: editorReady.debug || null
|
|
786
766
|
});
|
|
767
|
+
const evidence = { originalCode: verified.code || '', writeMethod: result.method || '', writeStarted: true,
|
|
768
|
+
...verified.evidence };
|
|
769
|
+
if (verified.evidence?.observedIsBefore && verified.evidence.activeMatchesTarget) {
|
|
770
|
+
// The editor still holds exactly the pre-write text: the write never landed, so a retry is safe.
|
|
771
|
+
decorated.failure = buildPageFailure('write_operation_failed', {
|
|
772
|
+
file: operation?.path || '', operationType: operation?.type || 'edit', changedDocument: false,
|
|
773
|
+
userMessage: `Overleaf did not accept the edit to ${operation?.path || 'the target file'}; the document was left unchanged.`,
|
|
774
|
+
technicalMessage: verified.reason || '', evidence
|
|
775
|
+
});
|
|
776
|
+
return decorated;
|
|
777
|
+
}
|
|
787
778
|
// §9.3 write_observed_mismatch: the write call landed but the readback
|
|
788
779
|
// does not match. changedDocument:true — the editor state moved, just
|
|
789
780
|
// not as Codex expected.
|
|
@@ -793,12 +784,7 @@
|
|
|
793
784
|
changedDocument: true,
|
|
794
785
|
userMessage: `${operation?.path || 'The target file'} did not read back the content Codex wrote; the document state may differ from what was approved.`,
|
|
795
786
|
technicalMessage: verified.reason || '',
|
|
796
|
-
evidence
|
|
797
|
-
originalCode: verified.code || '',
|
|
798
|
-
expectedLength: verified.expectedLength,
|
|
799
|
-
actualLength: verified.actualLength,
|
|
800
|
-
writeStarted: true
|
|
801
|
-
}
|
|
787
|
+
evidence
|
|
802
788
|
});
|
|
803
789
|
return decorated;
|
|
804
790
|
}
|
|
@@ -808,12 +794,12 @@
|
|
|
808
794
|
// Overleaf renders review markers asynchronously after the editor text
|
|
809
795
|
// has already changed. A single 120 ms snapshot intermittently missed
|
|
810
796
|
// those markers, leaving a Reviewing write with Undo but no Accept.
|
|
811
|
-
//
|
|
812
|
-
//
|
|
813
|
-
//
|
|
797
|
+
// Complete normal Track attribution while this file is still active.
|
|
798
|
+
// Slow batches are covered by request receipts; Accept replay retains
|
|
799
|
+
// its independent safety window proving that no new tracking was added.
|
|
814
800
|
const trackedDiff = trackReviewingChanges
|
|
815
|
-
? await captureTrackedWrite({ trackedBefore, captureBaseline, operation, beforeContent: current,
|
|
816
|
-
postContent: nextContent, runProjectId: options.runProjectId })
|
|
801
|
+
? await captureTrackedWrite({ trackedBefore, captureBaseline, operation: { ...operation, patches: preparedPatches?.patches }, beforeContent: current,
|
|
802
|
+
postContent: nextContent, runProjectId: options.runProjectId, waitMs: deps.trackCaptureWaitMs ?? 35000 })
|
|
817
803
|
: await waitForTrackedChangeDiff(trackedBefore, operationPaths, {
|
|
818
804
|
waitMs: 3600, intervalMs: 180, stopOnFirst: true
|
|
819
805
|
});
|
|
@@ -848,7 +834,7 @@
|
|
|
848
834
|
window.CodexOverleafStaleGuard?.updateExpectedFileContent(
|
|
849
835
|
options.baseFileLookup,
|
|
850
836
|
operation.path,
|
|
851
|
-
nextContent
|
|
837
|
+
preparedPatches?.sourceContent ?? nextContent
|
|
852
838
|
);
|
|
853
839
|
return {
|
|
854
840
|
...result,
|
|
@@ -859,8 +845,7 @@
|
|
|
859
845
|
};
|
|
860
846
|
}
|
|
861
847
|
|
|
862
|
-
|
|
863
|
-
async function verifyActiveEditorText(expected, filePath, waitMs = 1000) {
|
|
848
|
+
async function verifyActiveEditorText(expected, filePath, waitMs = 1000, before) {
|
|
864
849
|
const deadline = Date.now() + waitMs;
|
|
865
850
|
let actual = readActiveEditorText();
|
|
866
851
|
while (actual !== expected && Date.now() < deadline) {
|
|
@@ -877,10 +862,37 @@
|
|
|
877
862
|
code: 'write_verification_failed',
|
|
878
863
|
reason: `${filePath || '当前文件'} 写入后读回内容和 Codex 预期不一致,已停止把这次操作标记为成功。请刷新 Overleaf 后重试。`,
|
|
879
864
|
expectedLength: String(expected || '').length,
|
|
880
|
-
actualLength: String(actual || '').length
|
|
865
|
+
actualLength: String(actual || '').length,
|
|
866
|
+
evidence: describeReadbackMismatch(expected, actual, before, filePath)
|
|
881
867
|
};
|
|
882
868
|
}
|
|
883
869
|
|
|
870
|
+
// Content-free mismatch evidence: offsets, lengths and short hashes only.
|
|
871
|
+
function describeReadbackMismatch(expected, actual, before, filePath) {
|
|
872
|
+
const left = String(expected ?? ''), right = String(actual ?? '');
|
|
873
|
+
let firstDiff = 0;
|
|
874
|
+
while (firstDiff < left.length && left[firstDiff] === right[firstDiff]) firstDiff += 1;
|
|
875
|
+
let tail = 0;
|
|
876
|
+
while (tail < left.length - firstDiff && tail < right.length - firstDiff
|
|
877
|
+
&& left[left.length - 1 - tail] === right[right.length - 1 - tail]) tail += 1;
|
|
878
|
+
const activePath = getActiveFilePath() || '';
|
|
879
|
+
return { expectedLength: left.length, actualLength: right.length, firstDiffOffset: firstDiff,
|
|
880
|
+
expectedDiffLength: left.length - firstDiff - tail, actualDiffLength: right.length - firstDiff - tail,
|
|
881
|
+
expectedHash: shortHash(left), actualHash: shortHash(right),
|
|
882
|
+
beforeHash: typeof before === 'string' ? shortHash(before) : '',
|
|
883
|
+
observedIsBefore: typeof before === 'string' && right === before,
|
|
884
|
+
activePath, activeMatchesTarget: !filePath || activePath === filePath };
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
function shortHash(value) {
|
|
888
|
+
let hash = 0x811c9dc5;
|
|
889
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
890
|
+
hash ^= value.charCodeAt(index);
|
|
891
|
+
hash = Math.imul(hash, 0x01000193) >>> 0;
|
|
892
|
+
}
|
|
893
|
+
return hash.toString(16).padStart(8, '0');
|
|
894
|
+
}
|
|
895
|
+
|
|
884
896
|
async function ensureEditorReadyForOperation(operation, baseFileLookup, initialActivePath) {
|
|
885
897
|
if (!operation?.path) {
|
|
886
898
|
return {
|
|
@@ -1158,7 +1170,6 @@
|
|
|
1158
1170
|
};
|
|
1159
1171
|
}
|
|
1160
1172
|
|
|
1161
|
-
|
|
1162
1173
|
async function applyBinaryAssetOperation(operation, options = {}) {
|
|
1163
1174
|
const freshness = await checkBinaryAssetFreshness(operation, options);
|
|
1164
1175
|
if (!freshness.ok) {
|
|
@@ -1328,9 +1339,7 @@
|
|
|
1328
1339
|
return baseFile.size == null || currentSize == null || baseFile.size === currentSize;
|
|
1329
1340
|
}
|
|
1330
1341
|
|
|
1331
|
-
|
|
1332
|
-
return String(value || '').replace(/\s+/g, '');
|
|
1333
|
-
}
|
|
1342
|
+
const normalizeBase64 = value => String(value || '').replace(/\s+/g, '');
|
|
1334
1343
|
|
|
1335
1344
|
function decodeBase64Bytes(contentBase64) {
|
|
1336
1345
|
try {
|
|
@@ -1376,13 +1385,37 @@
|
|
|
1376
1385
|
}
|
|
1377
1386
|
|
|
1378
1387
|
async function applyFileTreeOperation(operation, options = {}) {
|
|
1388
|
+
if (operation.type === 'delete' && operation.undoCreatedFile) {
|
|
1389
|
+
return applyCreatedFileUndo(operation, options);
|
|
1390
|
+
}
|
|
1379
1391
|
const initialProjectId = treeOperations.getProjectId?.();
|
|
1380
1392
|
const initialCancellationSequence = readWriteCancellationSequence();
|
|
1393
|
+
if (operation.type === 'move' && operation.moveProof) {
|
|
1394
|
+
if (options.noTraceUndo !== true) return { ok: false, code: 'file_tree_controls_unavailable', changedDocument: false,
|
|
1395
|
+
reason: 'Native file moves are available only to undo a previously recorded move.' };
|
|
1396
|
+
if (typeof deps.moveFile !== 'function') return { ok: false, code: 'file_move_unavailable', changedDocument: false,
|
|
1397
|
+
reason: 'Verified native file moves are unavailable. Reload the extension and Overleaf.' };
|
|
1398
|
+
const result = await deps.moveFile(operation, { noTraceUndo: true, runProjectId: options.runProjectId, deadlineAt: options.deadlineAt,
|
|
1399
|
+
isCurrent: () => treeOperations.getProjectId?.() === initialProjectId
|
|
1400
|
+
&& readWriteCancellationSequence() === initialCancellationSequence && !options.reviewGuard?.() });
|
|
1401
|
+
if (result.ok) recordFileTreeOperationSuccess(operation, options.baseFileLookup);
|
|
1402
|
+
return result;
|
|
1403
|
+
}
|
|
1404
|
+
if (operation.type === 'create' && options.createBatch && typeof deps.createTextFile === 'function') {
|
|
1405
|
+
if (options.baseFileLookup?.has(operation.path) && options.retryCreates !== true) {
|
|
1406
|
+
return checkFileTreeOperationFreshness(operation, options.baseFileLookup);
|
|
1407
|
+
}
|
|
1408
|
+
return deps.createTextFile(operation, { batch: options.createBatch,
|
|
1409
|
+
allowExistingMatches: options.retryCreates === true,
|
|
1410
|
+
isCurrent: () => treeOperations.getProjectId?.() === initialProjectId
|
|
1411
|
+
&& readWriteCancellationSequence() === initialCancellationSequence && !options.reviewGuard?.() });
|
|
1412
|
+
}
|
|
1381
1413
|
const freshness = await checkFileTreeOperationFreshness(operation, options.baseFileLookup);
|
|
1382
1414
|
if (!freshness.ok) {
|
|
1383
1415
|
return freshness;
|
|
1384
1416
|
}
|
|
1385
1417
|
|
|
1418
|
+
const ownerBlocked = options.reviewGuard?.(); if (ownerBlocked) return ownerBlocked;
|
|
1386
1419
|
const manager = findFileTreeManager();
|
|
1387
1420
|
const methodNames = fileTreeMethodNames(operation.type);
|
|
1388
1421
|
|
|
@@ -1429,14 +1462,14 @@
|
|
|
1429
1462
|
const nativeOperation = { create: deps.createTextFile, delete: deps.deleteTextFile }[operation.type];
|
|
1430
1463
|
if (typeof nativeOperation === 'function' && (operation.type === 'delete' || typeof operation.content === 'string')) {
|
|
1431
1464
|
const isCurrent = () => Boolean(initialProjectId) && treeOperations.getProjectId?.() === initialProjectId
|
|
1432
|
-
&& readWriteCancellationSequence() === initialCancellationSequence;
|
|
1465
|
+
&& readWriteCancellationSequence() === initialCancellationSequence && !options.reviewGuard?.();
|
|
1433
1466
|
const created = await nativeOperation(operation, { isCurrent, expectedContent: options.baseFileLookup?.get(operation.path) });
|
|
1434
1467
|
if (!created.ok) return created;
|
|
1435
1468
|
if (!isCurrent() || created.verified !== true || created.verification !== 'overleaf-zip') {
|
|
1436
1469
|
return { ...fileTreeVerificationFailed(operation, 'Server receipt is missing or stale.'), changedDocument: true };
|
|
1437
1470
|
}
|
|
1438
1471
|
recordFileTreeOperationSuccess(operation, options.baseFileLookup);
|
|
1439
|
-
return { ok: true, method: created.method, verified: true };
|
|
1472
|
+
return { ...created, ok: true, method: created.method, verified: true };
|
|
1440
1473
|
}
|
|
1441
1474
|
return {
|
|
1442
1475
|
ok: false,
|
|
@@ -1445,6 +1478,43 @@
|
|
|
1445
1478
|
};
|
|
1446
1479
|
}
|
|
1447
1480
|
|
|
1481
|
+
async function applyCreatedFileUndo(operation, options = {}) {
|
|
1482
|
+
const projectId = treeOperations.getProjectId?.();
|
|
1483
|
+
const cancellation = readWriteCancellationSequence();
|
|
1484
|
+
const proof = operation.undoCreatedFile;
|
|
1485
|
+
const expected = options.baseFileLookup?.get(operation.path);
|
|
1486
|
+
const text = proof?.v === 1 && proof.kind === 'text' && typeof expected === 'string';
|
|
1487
|
+
const binary = proof?.v === 1 && proof.kind === 'binary' && /^[a-f0-9]{64}$/i.test(proof.sha256 || '');
|
|
1488
|
+
const isCurrent = () => Boolean(projectId) && projectId === options.runProjectId
|
|
1489
|
+
&& treeOperations.getProjectId?.() === projectId && readWriteCancellationSequence() === cancellation && !options.reviewGuard?.();
|
|
1490
|
+
if (!isCurrent() || (!text && !binary) || typeof deps.deleteTextFile !== 'function') {
|
|
1491
|
+
return { ok: false, code: 'undo_operation_failed', changedDocument: false,
|
|
1492
|
+
reason: 'Verified created-file deletion is unavailable for this run.' };
|
|
1493
|
+
}
|
|
1494
|
+
if (text && projectPathExists(operation.path)) {
|
|
1495
|
+
const current = await readCurrentTextFileForFreshness(operation.path);
|
|
1496
|
+
if (!current.ok || current.text !== expected || !isCurrent()) {
|
|
1497
|
+
return { ok: false, code: 'undo_operation_failed', changedDocument: false,
|
|
1498
|
+
reason: 'The created file changed after this run and was left untouched.' };
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
const result = await deps.deleteTextFile(operation, {
|
|
1502
|
+
isCurrent, undoCreatedFile: true, deadlineAt: options.deadlineAt,
|
|
1503
|
+
expectedContent: text ? expected : undefined,
|
|
1504
|
+
prepareTextPreimage: text ? () => readCurrentTextFileForFreshness(operation.path) : undefined,
|
|
1505
|
+
expectedSha256: binary ? proof.sha256.toLowerCase() : undefined,
|
|
1506
|
+
canDelete: () => isCurrent() && (binary || (treeOperations.getActiveFilePath?.() === operation.path
|
|
1507
|
+
&& readActiveEditorText() === expected))
|
|
1508
|
+
});
|
|
1509
|
+
if (!result.ok) return result;
|
|
1510
|
+
if (!isCurrent() || result.verified !== true || result.verification !== 'overleaf-zip') {
|
|
1511
|
+
return { ok: false, code: 'undo_operation_failed', changedDocument: result.changedDocument !== false,
|
|
1512
|
+
reason: 'The created file has no current server deletion receipt.' };
|
|
1513
|
+
}
|
|
1514
|
+
recordFileTreeOperationSuccess(operation, options.baseFileLookup);
|
|
1515
|
+
return result;
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1448
1518
|
async function verifyFileTreeOperation(operation) {
|
|
1449
1519
|
await delay(120);
|
|
1450
1520
|
const sourcePath = operation.path;
|
|
@@ -1613,15 +1683,6 @@
|
|
|
1613
1683
|
}
|
|
1614
1684
|
}
|
|
1615
1685
|
|
|
1616
|
-
function fileTreeMethodNames(type) {
|
|
1617
|
-
return {
|
|
1618
|
-
create: ['createDoc', 'createFile', 'addDoc', 'addFile'],
|
|
1619
|
-
rename: ['renameEntity', 'renameFile', 'renameDoc'],
|
|
1620
|
-
move: ['moveEntity', 'moveFile', 'moveDoc'],
|
|
1621
|
-
delete: ['deleteEntity', 'deleteFile', 'deleteDoc', 'removeEntity']
|
|
1622
|
-
}[type] || [];
|
|
1623
|
-
}
|
|
1624
|
-
|
|
1625
1686
|
function normalizeOperationPaths(operation) {
|
|
1626
1687
|
if (!operation || typeof operation !== 'object') {
|
|
1627
1688
|
return operation;
|
|
@@ -1694,10 +1755,6 @@
|
|
|
1694
1755
|
}
|
|
1695
1756
|
|
|
1696
1757
|
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
1758
|
function normalizeTrackedChangeRefs(refs = []) {
|
|
1702
1759
|
const seen = new Set();
|
|
1703
1760
|
const normalized = [];
|
|
@@ -1756,23 +1813,12 @@
|
|
|
1756
1813
|
|
|
1757
1814
|
async function applyOperationsForBridge(operationsOrOptions, options = {}) {
|
|
1758
1815
|
if (Array.isArray(operationsOrOptions)) {
|
|
1759
|
-
//
|
|
1760
|
-
// also runs on the array-shaped entry. T2 only guarded the
|
|
1761
|
-
// payload-object branch; if any future caller goes straight to the
|
|
1762
|
-
// array entry without `options.runProjectId`, the router would have
|
|
1763
|
-
// silently dispatched. Mirror the same `editor_project_id_unavailable`
|
|
1764
|
-
// failure shape the payload branch and the page-side guard already
|
|
1765
|
-
// emit.
|
|
1816
|
+
// Both public call shapes require the original project identity.
|
|
1766
1817
|
const writeGuardBlock = checkWritebackRunProjectId(options);
|
|
1767
1818
|
if (writeGuardBlock) return writeGuardBlock;
|
|
1768
1819
|
return applyOperations(operationsOrOptions, options);
|
|
1769
1820
|
}
|
|
1770
1821
|
const payload = operationsOrOptions || {};
|
|
1771
|
-
// Welcome-panel + write-guard: defense-in-depth.
|
|
1772
|
-
// The pageBridge wrapper already runs the runProjectId guard, but a
|
|
1773
|
-
// future caller could reach the router directly. A missing or empty
|
|
1774
|
-
// `runProjectId` on the payload-shaped call blocks the write with the
|
|
1775
|
-
// same `editor_project_id_unavailable` shape the page-side guard uses.
|
|
1776
1822
|
const writeGuardBlock = checkWritebackRunProjectId(payload);
|
|
1777
1823
|
if (writeGuardBlock) return writeGuardBlock;
|
|
1778
1824
|
return applyOperations(payload.operations || [], payload);
|
|
@@ -1781,10 +1827,7 @@
|
|
|
1781
1827
|
function checkWritebackRunProjectId(params) {
|
|
1782
1828
|
const runProjectId = params && typeof params.runProjectId === 'string' ? params.runProjectId : '';
|
|
1783
1829
|
if (runProjectId) return null;
|
|
1784
|
-
// operation
|
|
1785
|
-
// dispatch; matches the abortDispatchResult shape in pageBridge.js and
|
|
1786
|
-
// avoids crashing downstream audit / transcript code that reads
|
|
1787
|
-
// operation.path without a null guard.
|
|
1830
|
+
// Keep operation.path safe for downstream readers of batch-level failures.
|
|
1788
1831
|
return {
|
|
1789
1832
|
ok: false,
|
|
1790
1833
|
applied: [],
|
|
@@ -1876,9 +1919,7 @@
|
|
|
1876
1919
|
};
|
|
1877
1920
|
}
|
|
1878
1921
|
|
|
1879
|
-
// Tracked
|
|
1880
|
-
// v1.8.0 (structural-debt phase 7, #117). Loaded just before this file
|
|
1881
|
-
// in the manifest's page-script list; the Node test path requires it.
|
|
1922
|
+
// Tracked lifecycle is loaded by the Page script list or required by Node tests.
|
|
1882
1923
|
const trackedChangesLifecycleModule = (typeof window !== 'undefined' && window.CodexOverleafTrackedChangesLifecycle)
|
|
1883
1924
|
|| (typeof module === 'object' && module.exports ? require('./trackedChangesLifecycle.js') : null)
|
|
1884
1925
|
|| (typeof globalThis !== 'undefined' ? globalThis.CodexOverleafTrackedChangesLifecycle : null);
|
|
@@ -1890,7 +1931,7 @@
|
|
|
1890
1931
|
captureTrackedWrite, reconcileTrackedChangeCapture,
|
|
1891
1932
|
waitForTrackedChangeDiff
|
|
1892
1933
|
} = trackedChangesLifecycleModule.create({
|
|
1893
|
-
window, confirmReviewWriteback: deps.confirmReviewWriteback,
|
|
1934
|
+
window, now, readWriteCancellationSequence, confirmReviewWriteback: deps.confirmReviewWriteback,
|
|
1894
1935
|
checkWritebackRunProjectId,
|
|
1895
1936
|
buildNoTraceUndoBlockedResult,
|
|
1896
1937
|
buildReviewingRequiredBlockedResult,
|