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
|
@@ -0,0 +1,574 @@
|
|
|
1
|
+
(function (root, factory) {
|
|
2
|
+
const api = factory();
|
|
3
|
+
if (typeof module === 'object' && module.exports) module.exports = api;
|
|
4
|
+
if (root) root.CodexOverleafRunReviewController = api;
|
|
5
|
+
})(typeof window !== 'undefined' ? window : globalThis, function () {
|
|
6
|
+
'use strict';
|
|
7
|
+
function create(deps = {}) {
|
|
8
|
+
const {
|
|
9
|
+
Modules, WritebackSettlement, trackedChangeInFlight, findRunRecord,
|
|
10
|
+
getRunUndoCount, isTrackedChangeLifecycleRun, getPendingMirrorRefresh, hasTrackedEditorUndo,
|
|
11
|
+
buildNoTraceUndoRestore, findUnsafeFullFileUndoOperation, showUndoFileSelection, showPluginConfirm,
|
|
12
|
+
tr, truncateRunTitle, formatOperationFiles, formatTrackedChangeFiles,
|
|
13
|
+
formatTrackedUndoFiles, getPageBridgeTimeoutMs, callPageBridge, setRunUndoStatus,
|
|
14
|
+
appendRunRecordEvent, getRunProjectIdForWriteback, isUndoResultEffectivelyApplied, writebackOrchestrator,
|
|
15
|
+
appendUndoReviewingPolicyEvent, formatOperationType, formatApplyResultReason, buildTrackedUndoPostFiles,
|
|
16
|
+
getTrackedChangeCaptureController, buildContentFailure, applyTrackedChangeSettlement, refreshRunCardControls,
|
|
17
|
+
formatBridgeResultReason, advanceRunUndoProgress, saveStateSoon, flushQueuedSaveState,
|
|
18
|
+
getState, getCurrentProjectId, getAccountScopeId, getRouteGeneration, notify, tx,
|
|
19
|
+
} = deps;
|
|
20
|
+
const reviewOwners = new Map();
|
|
21
|
+
function reviewEventFailure(run, result) {
|
|
22
|
+
const reasons = deps.FailureReasons || Modules.FailureReasons;
|
|
23
|
+
if (!reasons?.normalizeFailureReason) return undefined;
|
|
24
|
+
const primary = reasons.selectPrimaryWritebackFailure(WritebackSettlement.collectFailuresFromResult(result, reasons));
|
|
25
|
+
if (!primary) return undefined;
|
|
26
|
+
const paths = new Set(['appliedOperations', 'undoOperations', 'undoBaseFiles', 'undoExpectedFiles', 'undoTrackedChanges']
|
|
27
|
+
.flatMap(key => (Array.isArray(run?.[key]) ? run[key] : []).map(item => item?.path)));
|
|
28
|
+
const candidate = typeof primary.file === 'string' ? primary.file : '';
|
|
29
|
+
const file = paths.has(candidate) && candidate.length <= 300 && !/[\r\n]/.test(candidate)
|
|
30
|
+
&& !candidate.replace(/\\/g, '/').startsWith('/') && !/^[A-Za-z]:/.test(candidate) && !candidate.replace(/\\/g, '/').split('/').includes('..') ? candidate : '';
|
|
31
|
+
const code = Object.hasOwn(reasons.FAILURE_CODE_CATALOG, primary.code) ? primary.code : 'unknown_legacy_failure';
|
|
32
|
+
let displayCode = code;
|
|
33
|
+
reasons.formatFailureReasonForDisplay({ ...primary, userMessage: String(primary.userMessage || '').slice(0, 2000) }, undefined, key => {
|
|
34
|
+
const value = tr(key), match = /^failureReason_([a-z0-9_]+)_user$/.exec(key);
|
|
35
|
+
if (value && value !== key) { if (match) displayCode = match[1]; return value; }
|
|
36
|
+
});
|
|
37
|
+
// This event keeps only machine facts and owned UI copy, never the Page's
|
|
38
|
+
// arbitrary reason, technical message or evidence payload.
|
|
39
|
+
const safe = reasons.normalizeFailureReason({ code }, file ? { path: file } : undefined);
|
|
40
|
+
if (displayCode !== code) safe.evidence = { originalCode: displayCode };
|
|
41
|
+
const localized = reasons.localizeFailureReason(safe, undefined, key => { const value = tr(key, file ? undefined : { file: tr('unknownFile'), activeFile: tr('unknownFile') }); return value && value !== key ? value : undefined; });
|
|
42
|
+
safe.userMessage = localized.userMessage;
|
|
43
|
+
safe.nextAction = localized.nextAction || safe.nextAction;
|
|
44
|
+
if (displayCode === 'unknown_legacy_failure') {
|
|
45
|
+
safe.userMessage = tr('unknownReason'); safe.nextAction = tr('failureReason_review_detail_next');
|
|
46
|
+
}
|
|
47
|
+
return safe;
|
|
48
|
+
}
|
|
49
|
+
let undoRecoveryTimer = null, undoRecoveryView = null, undoRecoveryGeneration = 0;
|
|
50
|
+
const undoRecoveryFailures = new Map();
|
|
51
|
+
async function prepareUndoDispatch(runId) {
|
|
52
|
+
const owner = reviewOwners.get(runId);
|
|
53
|
+
if (owner && !owner.deadlineAt) await owner.markDispatched();
|
|
54
|
+
owner?.();
|
|
55
|
+
return Math.min(Date.now() + getPageBridgeTimeoutMs('rejectTrackedChanges'), owner?.deadlineAt || Infinity);
|
|
56
|
+
}
|
|
57
|
+
async function persistUndoOwnerMarker(runId) {
|
|
58
|
+
if (Modules.StorageDb?.sharedSessionsEnabled?.() !== true) return;
|
|
59
|
+
findRunRecord(runId).undoOwnerProtocol = 1;
|
|
60
|
+
try { await flushQueuedSaveState({ requireDurable: true, reviewRunIds: [runId] }); }
|
|
61
|
+
catch (cause) { throw Object.assign(new Error('The Undo owner marker could not be durably saved.'), { code: 'review_state_not_persisted', cause }); }
|
|
62
|
+
reviewOwners.get(runId)?.();
|
|
63
|
+
const saved = await Modules.StorageDb.getRecord('sessions', getState().activeSessionId);
|
|
64
|
+
if (saved?.runs?.find(run => run.id === runId)?.undoOwnerProtocol !== 1)
|
|
65
|
+
throw Object.assign(new Error('The Undo owner marker was not durably retained.'), { code: 'review_state_not_persisted' });
|
|
66
|
+
reviewOwners.get(runId)?.();
|
|
67
|
+
}
|
|
68
|
+
async function withSharedReviewOwnership(runId, work) {
|
|
69
|
+
const db = Modules.StorageDb;
|
|
70
|
+
if (db?.sharedSessionsEnabled?.() !== true) return work();
|
|
71
|
+
const run = findRunRecord(runId);
|
|
72
|
+
if (!run || trackedChangeInFlight.has(runId)) return;
|
|
73
|
+
const assertCurrent = undoOwner(run);
|
|
74
|
+
const sessionId = getState().activeSessionId;
|
|
75
|
+
return db.withSharedReviewLock({ projectId: getRunProjectIdForWriteback(run), accountScopeId: getAccountScopeId(), runId,
|
|
76
|
+
onLost: token => { void callPageBridge('cancelActiveWrite', { reviewOwnerToken: token }).catch(() => {}); } }, async assertOwner => {
|
|
77
|
+
reviewOwners.set(runId, assertOwner);
|
|
78
|
+
try {
|
|
79
|
+
assertCurrent();
|
|
80
|
+
const session = await db.getRecord('sessions', sessionId);
|
|
81
|
+
assertCurrent();
|
|
82
|
+
const latest = session?.runs?.find(record => record.id === runId);
|
|
83
|
+
if (!latest || session.projectId !== getRunProjectIdForWriteback(run) || session.accountScopeId !== getAccountScopeId())
|
|
84
|
+
throw Object.assign(new Error('The shared Undo run is no longer available in its original scope.'), { code: 'review_context_changed' });
|
|
85
|
+
const restored = Modules.SessionState.normalizeRuns([latest], { recoverSettledRuns: true })[0];
|
|
86
|
+
// A budget-omitted first checkpoint may still be complete in its original page.
|
|
87
|
+
// Shared partial/terminal progress always wins over that in-memory copy.
|
|
88
|
+
const keepCheckpoint = restored.recoveryRetention?.state === 'omitted' && restored.recoveryRetention.coreRetained !== true
|
|
89
|
+
&& !restored.undoStatus && !restored.trackedChangeStatus && !run.undoStatus && !run.trackedChangeStatus
|
|
90
|
+
&& restored.runProjectId === run.runProjectId && restored.nativeEventSeq === run.nativeEventSeq
|
|
91
|
+
&& restored.codexThreadId === run.codexThreadId && restored.codexTurnId === run.codexTurnId
|
|
92
|
+
&& restored.startedAt === run.startedAt && JSON.stringify(restored.executionSnapshot) === JSON.stringify(run.executionSnapshot);
|
|
93
|
+
const checkpoint = keepCheckpoint ? Object.fromEntries(['appliedOperations', 'undoOperations', 'undoBaseFiles', 'undoTrackedChanges', 'undoExpectedFiles', 'trackedChangeCaptures']
|
|
94
|
+
.filter(key => Object.hasOwn(run, key)).map(key => [key, run[key]])) : {};
|
|
95
|
+
for (const key of Object.keys(run)) delete run[key];
|
|
96
|
+
Object.assign(run, restored, checkpoint);
|
|
97
|
+
if (run.undoStatus === 'applied' || ['accepted', 'rejected'].includes(run.trackedChangeStatus)) return;
|
|
98
|
+
if (run.undoStatus === 'running' && run.undoOwnerProtocol !== 1) run.undoRecoveryCheckRequired = true;
|
|
99
|
+
return await work();
|
|
100
|
+
} finally { reviewOwners.delete(runId); refreshRunCardControls(runId); }
|
|
101
|
+
}).catch(error => {
|
|
102
|
+
if (error.code === 'review_busy') notify?.(tx('Another page is reviewing this run. Wait for it to finish.', '另一页面正在审阅本轮记录,请等待其完成。'));
|
|
103
|
+
throw error;
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
async function recoverInterruptedUndoStatuses(options = {}) {
|
|
107
|
+
if (undoRecoveryTimer) { clearTimeout(undoRecoveryTimer); undoRecoveryTimer = null; }
|
|
108
|
+
const generation = ++undoRecoveryGeneration;
|
|
109
|
+
const captured = getState(), sessionId = captured.activeSessionId;
|
|
110
|
+
const scope = JSON.stringify([getCurrentProjectId?.(), getAccountScopeId?.(), getRouteGeneration?.()]);
|
|
111
|
+
const sameScope = () => JSON.stringify([getCurrentProjectId?.(), getAccountScopeId?.(), getRouteGeneration?.()]) === scope;
|
|
112
|
+
const current = () => generation === undoRecoveryGeneration && sameScope()
|
|
113
|
+
&& getState() === captured && captured.activeSessionId === sessionId;
|
|
114
|
+
const schedule = delay => {
|
|
115
|
+
if (generation !== undoRecoveryGeneration || !sameScope()) return;
|
|
116
|
+
if (undoRecoveryTimer) clearTimeout(undoRecoveryTimer);
|
|
117
|
+
undoRecoveryTimer = setTimeout(() => {
|
|
118
|
+
if (generation === undoRecoveryGeneration && sameScope())
|
|
119
|
+
void recoverInterruptedUndoStatuses({ automatic: true }).catch(() => {});
|
|
120
|
+
}, delay);
|
|
121
|
+
undoRecoveryTimer.unref?.();
|
|
122
|
+
};
|
|
123
|
+
if (undoRecoveryView?.state !== captured || undoRecoveryView?.scope !== scope || undoRecoveryView?.sessionId !== sessionId) {
|
|
124
|
+
undoRecoveryFailures.clear(); undoRecoveryView = { state: captured, scope, sessionId };
|
|
125
|
+
}
|
|
126
|
+
if (options.automatic !== true) undoRecoveryFailures.clear();
|
|
127
|
+
let nextCheck = Infinity;
|
|
128
|
+
const db = Modules.StorageDb;
|
|
129
|
+
const runs = Array.from(new Set([...(captured.runs || []), ...(captured.sessions || []).flatMap(session => session.runs || [])]));
|
|
130
|
+
for (const run of runs) {
|
|
131
|
+
if (run.undoStatus !== 'running' || (undoRecoveryFailures.get(run.id) || 0) >= 3) continue;
|
|
132
|
+
if (db?.sharedSessionsEnabled?.() === true) {
|
|
133
|
+
let owner;
|
|
134
|
+
try {
|
|
135
|
+
owner = await db.hasSharedReviewOwner({ projectId: getRunProjectIdForWriteback(run), accountScopeId: getAccountScopeId(), runId: run.id });
|
|
136
|
+
if (!owner || typeof owner.busy !== 'boolean') throw new Error('Undo recovery ownership is unavailable.');
|
|
137
|
+
} catch (_error) {
|
|
138
|
+
if (!current()) { schedule(50); return; }
|
|
139
|
+
delete run.undoRecoveryCheckRequired; run.undoRecoveryUnavailable = true; refreshRunCardControls(run.id);
|
|
140
|
+
const attempts = (undoRecoveryFailures.get(run.id) || 0) + 1; undoRecoveryFailures.set(run.id, attempts);
|
|
141
|
+
if (attempts === 1) notify?.(tx('Undo recovery checks are temporarily unavailable. Other tasks remain available; keep the recovery files and retry after the connection recovers.',
|
|
142
|
+
'撤销恢复检查暂不可用,其他任务仍可继续。请保留恢复材料,连接恢复后再检查。'));
|
|
143
|
+
if (attempts < 3) nextCheck = Math.min(nextCheck, 5000 * attempts);
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
if (!current()) { schedule(50); return; }
|
|
147
|
+
undoRecoveryFailures.delete(run.id); delete run.undoRecoveryUnavailable;
|
|
148
|
+
if (!owner.busy && run.undoOwnerProtocol !== 1) {
|
|
149
|
+
run.undoRecoveryCheckRequired = true; refreshRunCardControls(run.id); continue;
|
|
150
|
+
}
|
|
151
|
+
if (owner.busy) { nextCheck = Math.min(nextCheck, owner.deadlineAt > Date.now() ? owner.deadlineAt - Date.now() + 50 : 5000); continue; }
|
|
152
|
+
}
|
|
153
|
+
// Recovery only restores an explicit action; Page work is never replayed.
|
|
154
|
+
delete run.undoRecoveryCheckRequired; run.undoStatus = 'partial'; refreshRunCardControls(run.id);
|
|
155
|
+
}
|
|
156
|
+
if (nextCheck !== Infinity) schedule(Math.min(30000, Math.max(50, nextCheck)));
|
|
157
|
+
}
|
|
158
|
+
async function withLocalUndoLock(runId, work) {
|
|
159
|
+
const run = findRunRecord(runId);
|
|
160
|
+
if (!run || run.forkSnapshot || run.undoStatus === 'applied' || !getRunUndoCount(run) || trackedChangeInFlight.has(runId)) return;
|
|
161
|
+
const assertOwner = undoOwner(run);
|
|
162
|
+
trackedChangeInFlight.set(runId, 'reject'); refreshRunCardControls(runId);
|
|
163
|
+
try { return await work(); }
|
|
164
|
+
catch (error) {
|
|
165
|
+
let current = true; try { assertOwner(); } catch (_stale) { current = false; }
|
|
166
|
+
if (current && findRunRecord(runId) === run) {
|
|
167
|
+
if (run.undoStatus === 'running') setRunUndoStatus(runId, 'partial');
|
|
168
|
+
appendRunRecordEvent(runId, { title: tr('undoNoTraceTitle'), status: 'failed',
|
|
169
|
+
detail: { [tr('detailReason')]: error.message } });
|
|
170
|
+
}
|
|
171
|
+
notify?.(error.code === 'review_state_not_persisted' ? tx('Undo recovery ownership could not be saved. No Undo was dispatched; keep this page open and inspect the files before retrying.',
|
|
172
|
+
'撤销恢复归属未能保存,尚未派发撤销。请保留本页并核对文件后重试。') : error.message);
|
|
173
|
+
throw error;
|
|
174
|
+
} finally { trackedChangeInFlight.delete(runId); refreshRunCardControls(runId); }
|
|
175
|
+
}
|
|
176
|
+
const withUndoLock = (runId, work) => withSharedReviewOwnership(runId, () => withLocalUndoLock(runId, work));
|
|
177
|
+
const undoRun = runId => withUndoLock(runId, () => executeUndo(runId));
|
|
178
|
+
const acceptRun = runId => withSharedReviewOwnership(runId, () => executeAcceptRun(runId));
|
|
179
|
+
const undoRunTrackedChanges = (runId, run) => withUndoLock(runId, () => executeTrackedUndo(runId, run));
|
|
180
|
+
|
|
181
|
+
function undoOwner(run) {
|
|
182
|
+
const captured = getState(), sessionId = captured.activeSessionId;
|
|
183
|
+
const scope = [getCurrentProjectId?.(), getAccountScopeId?.(), getRouteGeneration?.()];
|
|
184
|
+
return () => {
|
|
185
|
+
reviewOwners.get(run.id)?.();
|
|
186
|
+
if (getState() !== captured || captured.activeSessionId !== sessionId || findRunRecord(run.id) !== run
|
|
187
|
+
|| JSON.stringify(scope) !== JSON.stringify([getCurrentProjectId?.(), getAccountScopeId?.(), getRouteGeneration?.()]))
|
|
188
|
+
throw Object.assign(new Error('The Undo project, account or session changed.'), { code: 'review_context_changed' });
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function undoConfirmationTask(run) {
|
|
193
|
+
const task = truncateRunTitle(run.task);
|
|
194
|
+
return run.undoStatus === 'running' && run.undoOwnerProtocol !== 1
|
|
195
|
+
? task + '\n\n' + tx('Before confirming Undo, close or reload every older project page and inspect the current files in Overleaf. Continue only after those checks are complete.',
|
|
196
|
+
'确认撤销前,请先关闭或重载全部旧版项目页面,并在 Overleaf 核对当前文件。完成这些检查后再继续。')
|
|
197
|
+
: task;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async function executeUndo(runId) {
|
|
201
|
+
const run = findRunRecord(runId);
|
|
202
|
+
if (run) Object.assign(run, Modules.UndoOperations.prepareRunUndo(run));
|
|
203
|
+
const assertCurrent = undoOwner(run);
|
|
204
|
+
if (!getRunUndoCount(run) || run.undoStatus === 'applied') {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
// Wait out any background mirror refresh before undoing (v1.7.5): a
|
|
208
|
+
// mirror.sync finishing after the undo would push the pre-undo snapshot
|
|
209
|
+
// as the local baseline and resurrect the undone content next run.
|
|
210
|
+
const pendingMirror = getPendingMirrorRefresh?.();
|
|
211
|
+
if (pendingMirror) {
|
|
212
|
+
await pendingMirror.catch(() => {});
|
|
213
|
+
assertCurrent();
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if ((Array.isArray(run.undoTrackedChanges) && run.undoTrackedChanges.length) || hasTrackedEditorUndo(run)
|
|
217
|
+
|| (run.trackedChangeStatus === 'needs_review' && run.undoOperations?.some(Modules.UndoOperations.isFileUndoOperation))) {
|
|
218
|
+
await executeTrackedUndo(runId, run);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const undoRestore = buildNoTraceUndoRestore(run);
|
|
223
|
+
const undoOperations = undoRestore.operations;
|
|
224
|
+
const unsafeFullFileUndo = findUnsafeFullFileUndoOperation(undoOperations, {
|
|
225
|
+
allowSnapshotRestore: undoRestore.snapshotRestore
|
|
226
|
+
});
|
|
227
|
+
if (unsafeFullFileUndo) {
|
|
228
|
+
appendRunRecordEvent(runId, {
|
|
229
|
+
title: tr('undoUnsafeFullFileTitle'),
|
|
230
|
+
status: 'failed',
|
|
231
|
+
detail: {
|
|
232
|
+
[tr('detailFile')]: unsafeFullFileUndo.path,
|
|
233
|
+
[tr('detailReason')]: tr('undoUnsafeFullFileReason')
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// v1.8.0 C3: multi-file undos confirm through a per-file selection —
|
|
240
|
+
// undoing a subset leaves undoStatus 'partial' and the button usable;
|
|
241
|
+
// re-undoing an already-restored file is skipped by the base check.
|
|
242
|
+
const undoPaths = Array.from(new Set(undoOperations.map(operation => operation?.path).filter(Boolean)));
|
|
243
|
+
let selectedOperations = undoOperations;
|
|
244
|
+
if (undoPaths.length > 1 && typeof showUndoFileSelection === 'function') {
|
|
245
|
+
const selectedPaths = await showUndoFileSelection({
|
|
246
|
+
title: tr('undoFileSelectTitle'),
|
|
247
|
+
task: undoConfirmationTask(run),
|
|
248
|
+
confirmLabel: tr('undoFileSelectConfirm'),
|
|
249
|
+
cancelLabel: tr('confirmDefaultCancel'),
|
|
250
|
+
selectAllLabel: tr('undoFileSelectAll'),
|
|
251
|
+
paths: undoPaths
|
|
252
|
+
});
|
|
253
|
+
if (!selectedPaths) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
const selectedSet = new Set(selectedPaths);
|
|
257
|
+
selectedOperations = undoOperations.filter(operation => selectedSet.has(operation?.path));
|
|
258
|
+
} else {
|
|
259
|
+
const approved = await showPluginConfirm({
|
|
260
|
+
title: tr('undoNoTraceTitle'),
|
|
261
|
+
message: [
|
|
262
|
+
undoConfirmationTask(run),
|
|
263
|
+
'',
|
|
264
|
+
tr('undoNoTraceMessage', { files: formatOperationFiles(undoOperations) })
|
|
265
|
+
].join('\n'),
|
|
266
|
+
confirmLabel: tr('undoConfirm'),
|
|
267
|
+
cancelLabel: tr('confirmDefaultCancel'),
|
|
268
|
+
destructive: true
|
|
269
|
+
});
|
|
270
|
+
if (!approved) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
assertCurrent();
|
|
276
|
+
const deadlineAt = await prepareUndoDispatch(runId);
|
|
277
|
+
setRunUndoStatus(runId, 'running');
|
|
278
|
+
appendRunRecordEvent(runId, {
|
|
279
|
+
title: tr('undoNoTraceStarted'),
|
|
280
|
+
status: 'running',
|
|
281
|
+
detail: { [tr('detailWillUndo')]: formatOperationFiles(selectedOperations) }
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
await persistUndoOwnerMarker(runId); assertCurrent();
|
|
285
|
+
const result = await callPageBridge('applyOperations', {
|
|
286
|
+
operations: selectedOperations, deadlineAt, reviewOwnerToken: reviewOwners.get(runId)?.token,
|
|
287
|
+
baseFiles: run.undoBaseFiles || [],
|
|
288
|
+
reviewingPolicy: 'no-trace-undo',
|
|
289
|
+
// Undo remains bound to its original project, including after navigation.
|
|
290
|
+
runProjectId: getRunProjectIdForWriteback(run)
|
|
291
|
+
});
|
|
292
|
+
assertCurrent();
|
|
293
|
+
const undoApplied = isUndoResultEffectivelyApplied(run, result);
|
|
294
|
+
writebackOrchestrator.invalidateMirrorAfterUndo(runId, getRunProjectIdForWriteback(run), result);
|
|
295
|
+
appendUndoReviewingPolicyEvent(runId, result.reviewingPolicy);
|
|
296
|
+
appendRunRecordEvent(runId, {
|
|
297
|
+
title: tr('undoResult', { applied: result.applied?.length || 0, skipped: result.skipped?.length || 0 }),
|
|
298
|
+
failure: reviewEventFailure(run, result),
|
|
299
|
+
status: undoApplied ? 'completed' : 'failed',
|
|
300
|
+
detail: {
|
|
301
|
+
[tr('detailUndone')]: (result.applied || []).map(item => ({
|
|
302
|
+
[tr('detailAction')]: formatOperationType(item.operation?.type),
|
|
303
|
+
[tr('detailFile')]: item.operation?.path
|
|
304
|
+
})),
|
|
305
|
+
[tr('detailSkipped')]: (result.skipped || []).map(item => ({
|
|
306
|
+
[tr('detailAction')]: formatOperationType(item.operation?.type),
|
|
307
|
+
[tr('detailFile')]: item.operation?.path,
|
|
308
|
+
[tr('detailReason')]: formatApplyResultReason(item)
|
|
309
|
+
}))
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
// A subset undo never closes the ledger: unselected files can still
|
|
313
|
+
// be undone later, so the run stays 'partial' and the button usable.
|
|
314
|
+
const fullSelection = selectedOperations.length === undoOperations.length;
|
|
315
|
+
await applyLegacyUndoSettlement(
|
|
316
|
+
runId,
|
|
317
|
+
undoApplied && fullSelection ? 'applied' : 'partial',
|
|
318
|
+
result
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
async function executeTrackedUndo(runId, run) {
|
|
323
|
+
const assertCurrent = undoOwner(run);
|
|
324
|
+
const fileUndoOperations = Modules.UndoOperations.getFileUndoOperations(run);
|
|
325
|
+
const textRun = Modules.UndoOperations.textUndoRun(run);
|
|
326
|
+
const trackedUndo = textRun.undoTrackedChanges.length > 0;
|
|
327
|
+
const hasTextUndo = trackedUndo || buildTrackedUndoPostFiles(textRun).length > 0;
|
|
328
|
+
const approved = await showPluginConfirm({
|
|
329
|
+
title: !hasTextUndo ? tr('undoNoTraceTitle') : trackedUndo ? tr('undoTrackedTitle') : tr('undoNativeTitle'),
|
|
330
|
+
message: [
|
|
331
|
+
undoConfirmationTask(run),
|
|
332
|
+
'',
|
|
333
|
+
...(hasTextUndo ? [trackedUndo
|
|
334
|
+
? tr('undoTrackedMessage', { files: formatTrackedChangeFiles(run.undoTrackedChanges) })
|
|
335
|
+
: tr('undoNativeMessage', { files: formatTrackedUndoFiles(run) })] : []),
|
|
336
|
+
...(fileUndoOperations.length ? [tr('undoNoTraceMessage', { files: formatOperationFiles(fileUndoOperations) })] : [])
|
|
337
|
+
].join('\n'),
|
|
338
|
+
confirmLabel: trackedUndo ? tr('undoTrackedConfirm') : tr('undoConfirm'),
|
|
339
|
+
cancelLabel: tr('confirmDefaultCancel'),
|
|
340
|
+
destructive: true
|
|
341
|
+
});
|
|
342
|
+
if (!approved) {
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
assertCurrent();
|
|
347
|
+
const deadlineAt = await prepareUndoDispatch(runId);
|
|
348
|
+
// Keep the review lifecycle until every pending part has settled.
|
|
349
|
+
// Its local lock stays active while verified recovery progress is persisted.
|
|
350
|
+
const lifecycleReject = (trackedUndo || fileUndoOperations.length > 0) && isTrackedChangeLifecycleRun(run);
|
|
351
|
+
if (lifecycleReject) {
|
|
352
|
+
trackedChangeInFlight.set(runId, 'reject');
|
|
353
|
+
refreshRunCardControls(runId);
|
|
354
|
+
} else {
|
|
355
|
+
setRunUndoStatus(runId, 'running');
|
|
356
|
+
}
|
|
357
|
+
appendRunRecordEvent(runId, {
|
|
358
|
+
title: !hasTextUndo ? tr('undoNoTraceStarted') : trackedUndo ? tr('undoTrackedStarted') : tr('undoNativeStarted'),
|
|
359
|
+
status: 'running',
|
|
360
|
+
detail: { [tr('detailWillUndo')]: !hasTextUndo ? formatOperationFiles(fileUndoOperations)
|
|
361
|
+
: trackedUndo ? formatTrackedChangeFiles(run.undoTrackedChanges) : formatTrackedUndoFiles(run) }
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
let result;
|
|
365
|
+
try {
|
|
366
|
+
await persistUndoOwnerMarker(runId); assertCurrent();
|
|
367
|
+
const trackedUndoPostFilesAtDispatch = buildTrackedUndoPostFiles(textRun);
|
|
368
|
+
result = hasTextUndo ? await callPageBridge('rejectTrackedChanges', {
|
|
369
|
+
trackedChanges: textRun.undoTrackedChanges || [], deadlineAt, reviewOwnerToken: reviewOwners.get(runId)?.token,
|
|
370
|
+
expectedFiles: textRun.undoExpectedFiles || [],
|
|
371
|
+
postFiles: trackedUndoPostFilesAtDispatch,
|
|
372
|
+
untrackedUndo: run.executionSnapshot
|
|
373
|
+
? run.executionSnapshot.requireReviewing === false && ['submitted', 'legacy-captured'].includes(run.executionSnapshot.source)
|
|
374
|
+
: getTrackedChangeCaptureController().hasLegacyUntrackedCheckpoint(run),
|
|
375
|
+
// The page-side project guard still refuses writes after navigation.
|
|
376
|
+
runProjectId: getRunProjectIdForWriteback(run)
|
|
377
|
+
}) : { ok: true, applied: [], skipped: [] };
|
|
378
|
+
assertCurrent();
|
|
379
|
+
if (hasTextUndo) WritebackSettlement.attachUndoNotVerifiedFailure(textRun, result, {
|
|
380
|
+
buildFailure: buildContentFailure, postFiles: trackedUndoPostFilesAtDispatch });
|
|
381
|
+
if (fileUndoOperations.length && lifecycleReject && hasTextUndo) {
|
|
382
|
+
WritebackSettlement.attachUndoNotVerifiedFailure(textRun, result, { buildFailure: buildContentFailure, postFiles: trackedUndoPostFilesAtDispatch });
|
|
383
|
+
await applyTrackedChangeSettlement(runId, 'reject', { ...result, ok: false }, { assertCurrent });
|
|
384
|
+
}
|
|
385
|
+
if (fileUndoOperations.length) {
|
|
386
|
+
let createdResult;
|
|
387
|
+
try {
|
|
388
|
+
if (result.ok === false || result.skipped?.length) {
|
|
389
|
+
throw new Error('Text changes remain unresolved; file restoration was kept for the next undo attempt.');
|
|
390
|
+
}
|
|
391
|
+
createdResult = await callPageBridge('applyOperations', {
|
|
392
|
+
operations: fileUndoOperations, reviewOwnerToken: reviewOwners.get(runId)?.token, deadlineAt,
|
|
393
|
+
baseFiles: run.undoBaseFiles || [],
|
|
394
|
+
reviewingPolicy: 'no-trace-undo',
|
|
395
|
+
runProjectId: getRunProjectIdForWriteback(run)
|
|
396
|
+
});
|
|
397
|
+
} catch (error) {
|
|
398
|
+
createdResult = { ok: false, applied: [], skipped: fileUndoOperations.map(operation => ({
|
|
399
|
+
operation, result: { ok: false, code: 'undo_operation_failed', reason: error.message }
|
|
400
|
+
})) };
|
|
401
|
+
}
|
|
402
|
+
assertCurrent();
|
|
403
|
+
result = Modules.UndoOperations.mergeFileUndoResult(result, createdResult, fileUndoOperations);
|
|
404
|
+
}
|
|
405
|
+
appendRunRecordEvent(runId, {
|
|
406
|
+
title: fileUndoOperations.length ? tr('undoResult', { applied: result.applied?.length || 0, skipped: result.skipped?.length || 0 }) : trackedUndo
|
|
407
|
+
? tr('undoTrackedResult', { applied: result.applied?.length || 0, skipped: result.skipped?.length || 0 })
|
|
408
|
+
: tr('undoNativeResult', { applied: result.applied?.length || 0, skipped: result.skipped?.length || 0 }),
|
|
409
|
+
failure: reviewEventFailure(run, result),
|
|
410
|
+
status: result.ok === true && !result.skipped?.length ? 'completed' : 'failed',
|
|
411
|
+
detail: {
|
|
412
|
+
[trackedUndo && !fileUndoOperations.length ? tr('detailRejected') : tr('detailUndone')]: (result.applied || []).map(item => ({
|
|
413
|
+
[tr('detailFile')]: item.trackedChange?.path || item.operation?.path || tr('unknownFile'),
|
|
414
|
+
[tr('detailRecord')]: item.trackedChange?.label || item.trackedChange?.id || item.trackedChange?.key || item.operation?.type
|
|
415
|
+
})),
|
|
416
|
+
[tr('detailSkipped')]: (result.skipped || []).map(item => ({
|
|
417
|
+
[tr('detailFile')]: item.trackedChange?.path || item.operation?.path || tr('unknownFile'),
|
|
418
|
+
[tr('detailRecord')]: item.trackedChange?.label || item.trackedChange?.id || item.trackedChange?.key || item.operation?.type || '',
|
|
419
|
+
[tr('detailReason')]: formatBridgeResultReason(item.result, item.trackedChange?.path || item.operation?.path)
|
|
420
|
+
}))
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
if (lifecycleReject) {
|
|
424
|
+
WritebackSettlement.attachUndoNotVerifiedFailure(textRun, result, {
|
|
425
|
+
buildFailure: buildContentFailure,
|
|
426
|
+
postFiles: trackedUndoPostFilesAtDispatch
|
|
427
|
+
});
|
|
428
|
+
await applyTrackedChangeSettlement(runId, 'reject', result, { assertCurrent });
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
await applyLegacyUndoSettlement(runId, result.ok === true && !result.skipped?.length ? 'applied' : 'partial', result);
|
|
432
|
+
} finally {
|
|
433
|
+
// Known Page changes require invalidation even when a durable checkpoint fails.
|
|
434
|
+
if (result) writebackOrchestrator.invalidateMirrorAfterUndo(runId, getRunProjectIdForWriteback(run), result);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
function reviewOwner(run) {
|
|
439
|
+
const owner = { run, state: getState(), sessionId: getState().activeSessionId,
|
|
440
|
+
projectId: getCurrentProjectId(), accountScopeId: getAccountScopeId(), generation: getRouteGeneration() };
|
|
441
|
+
const assert = () => {
|
|
442
|
+
reviewOwners.get(run.id)?.();
|
|
443
|
+
if (!owner.projectId || !owner.accountScopeId || run.runProjectId !== owner.projectId
|
|
444
|
+
|| getCurrentProjectId() !== owner.projectId || getAccountScopeId() !== owner.accountScopeId
|
|
445
|
+
|| getRouteGeneration() !== owner.generation || getState() !== owner.state
|
|
446
|
+
|| getState().activeSessionId !== owner.sessionId || findRunRecord(run.id) !== run
|
|
447
|
+
|| (run.runAccountScopeId && run.runAccountScopeId !== owner.accountScopeId))
|
|
448
|
+
throw Object.assign(new Error('The original review project, account or session changed.'), { code: 'review_context_changed' });
|
|
449
|
+
return run;
|
|
450
|
+
};
|
|
451
|
+
assert(); return { ...owner, assert };
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
async function executeAcceptRun(runId) {
|
|
455
|
+
const run = findRunRecord(runId);
|
|
456
|
+
if (!run || !isTrackedChangeLifecycleRun(run)) {
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
const status = run.trackedChangeStatus || '';
|
|
460
|
+
// pending and needs_review are both actionable per §7: needs_review means
|
|
461
|
+
// the prior attempt could not prove a clean post-action state, and the
|
|
462
|
+
// user is supposed to be able to retry after inspecting Overleaf.
|
|
463
|
+
if (status !== 'pending' && status !== 'needs_review') {
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
if (!Array.isArray(run.undoTrackedChanges) || !run.undoTrackedChanges.length) {
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
if (trackedChangeInFlight.get(runId)) {
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
const owner = reviewOwner(run);
|
|
474
|
+
trackedChangeInFlight.set(runId, 'accept');
|
|
475
|
+
refreshRunCardControls(runId);
|
|
476
|
+
appendRunRecordEvent(runId, {
|
|
477
|
+
title: tr('runAcceptTrackedStarted'),
|
|
478
|
+
status: 'running',
|
|
479
|
+
detail: { [tr('detailAccepted')]: formatTrackedChangeFiles(run.undoTrackedChanges) }
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
try {
|
|
483
|
+
const deadlineAt = await prepareUndoDispatch(runId);
|
|
484
|
+
const result = await callPageBridge('acceptTrackedChanges', { deadlineAt, reviewOwnerToken: reviewOwners.get(runId)?.token,
|
|
485
|
+
trackedChanges: run.undoTrackedChanges || [],
|
|
486
|
+
expectedFiles: run.undoExpectedFiles || [],
|
|
487
|
+
postFiles: buildTrackedUndoPostFiles(run),
|
|
488
|
+
appliedOperations: Array.isArray(run.appliedOperations) ? run.appliedOperations : [],
|
|
489
|
+
runProjectId: owner.projectId, accountScopeId: owner.accountScopeId
|
|
490
|
+
});
|
|
491
|
+
owner.assert();
|
|
492
|
+
appendAcceptDiagnosticEvents(runId, Array.isArray(result.diagnostics) ? result.diagnostics : []);
|
|
493
|
+
appendRunRecordEvent(runId, {
|
|
494
|
+
title: tr('runAcceptTrackedResult', { applied: result.applied?.length || 0, skipped: result.skipped?.length || 0 }),
|
|
495
|
+
failure: reviewEventFailure(run, result),
|
|
496
|
+
status: result.ok === true && !result.skipped?.length ? 'completed' : 'failed',
|
|
497
|
+
detail: {
|
|
498
|
+
[tr('detailAccepted')]: (result.applied || []).map(item => ({
|
|
499
|
+
[tr('detailFile')]: item.trackedChange?.path || tr('unknownFile'),
|
|
500
|
+
[tr('detailRecord')]: item.trackedChange?.label || item.trackedChange?.id || item.trackedChange?.key
|
|
501
|
+
})),
|
|
502
|
+
[tr('detailSkipped')]: (result.skipped || []).map(item => ({
|
|
503
|
+
[tr('detailFile')]: item.trackedChange?.path || tr('unknownFile'),
|
|
504
|
+
[tr('detailRecord')]: item.trackedChange?.label || item.trackedChange?.id || item.trackedChange?.key || '',
|
|
505
|
+
[tr('detailReason')]: formatBridgeResultReason(item.result, item.trackedChange?.path)
|
|
506
|
+
}))
|
|
507
|
+
}
|
|
508
|
+
});
|
|
509
|
+
if (result.ok === false) {
|
|
510
|
+
appendRunRecordEvent(runId, {
|
|
511
|
+
title: tr('runAcceptTrackedFailed'),
|
|
512
|
+
status: 'failed',
|
|
513
|
+
detail: {
|
|
514
|
+
[tr('detailReason')]: tr('runAcceptTrackedFailedReason')
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
if (!WritebackSettlement.isSuccessfulTrackedChangeSettlement(result)) {
|
|
518
|
+
refreshRunCardControls(runId);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
WritebackSettlement.attachAcceptNotVerifiedFailure(run, result, {
|
|
522
|
+
buildFailure: buildContentFailure
|
|
523
|
+
});
|
|
524
|
+
await applyTrackedChangeSettlement(runId, 'accept', result, { assertCurrent: owner.assert });
|
|
525
|
+
owner.assert();
|
|
526
|
+
} catch (error) { notify?.(error.message); throw error; }
|
|
527
|
+
finally {
|
|
528
|
+
trackedChangeInFlight.delete(runId);
|
|
529
|
+
refreshRunCardControls(runId);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
function appendAcceptDiagnosticEvents(runId, diagnostics) {
|
|
534
|
+
for (const entry of diagnostics || []) {
|
|
535
|
+
const step = entry && entry.step;
|
|
536
|
+
const info = (entry && entry.info) || {};
|
|
537
|
+
const titleKey = WritebackSettlement.ACCEPT_DIAGNOSTIC_TITLE_KEYS[step];
|
|
538
|
+
if (!titleKey) {
|
|
539
|
+
continue;
|
|
540
|
+
}
|
|
541
|
+
const title = titleKey === 'runAcceptTrackedStepReplayStart' || titleKey === 'runAcceptTrackedStepReplayDone'
|
|
542
|
+
? tr(titleKey, { path: info.path || tr('unknownFile') })
|
|
543
|
+
: tr(titleKey);
|
|
544
|
+
const status = WritebackSettlement.acceptDiagnosticStatus(step, info);
|
|
545
|
+
appendRunRecordEvent(runId, {
|
|
546
|
+
title,
|
|
547
|
+
kind: 'activity',
|
|
548
|
+
status,
|
|
549
|
+
detail: info
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
async function applyLegacyUndoSettlement(runId, undoStatus, result) {
|
|
555
|
+
const run = findRunRecord(runId);
|
|
556
|
+
if (!run) return;
|
|
557
|
+
const assertCurrent = undoOwner(run);
|
|
558
|
+
const checkpoint = advanceRunUndoProgress(run, result);
|
|
559
|
+
const transition = WritebackSettlement.applySettlementTransition(
|
|
560
|
+
checkpoint,
|
|
561
|
+
WritebackSettlement.settleLegacyUndo({
|
|
562
|
+
run: checkpoint,
|
|
563
|
+
status: undoStatus,
|
|
564
|
+
result
|
|
565
|
+
})
|
|
566
|
+
);
|
|
567
|
+
await Modules.ScopedPersistenceCoordinator.applyReviewTransition({ getState, runId, transition,
|
|
568
|
+
legacyUndo: true, persist: flushQueuedSaveState, assertCurrent });
|
|
569
|
+
refreshRunCardControls(runId);
|
|
570
|
+
}
|
|
571
|
+
return { recoverInterruptedUndoStatuses, undoRun, undoRunTrackedChanges, acceptRun, applyLegacyUndoSettlement };
|
|
572
|
+
}
|
|
573
|
+
return { create };
|
|
574
|
+
});
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
})(typeof window !== 'undefined' ? window : globalThis, function runScrollLayoutFactory() {
|
|
8
8
|
'use strict';
|
|
9
9
|
|
|
10
|
-
const READING_ANCHORS = '.run-final-answer p, .run-final-answer li, .run-final-answer pre, .run-final-answer h1, .run-final-answer h2, .run-final-answer h3, .run-stream p, .run-stream li, .run-stream pre, [data-run-task], [data-run-status]';
|
|
10
|
+
const READING_ANCHORS = '.run-final-answer p, .run-final-answer li, .run-final-answer pre, .run-final-answer h1, .run-final-answer h2, .run-final-answer h3, .run-stream p, .run-stream li, .run-stream pre, .run-guidance-text, [data-run-task], [data-run-status]';
|
|
11
11
|
|
|
12
12
|
function create({ getScroller, onLayoutChange, isFollowing = () => true, window: host = globalThis } = {}) {
|
|
13
13
|
let current = null;
|
|
@@ -66,6 +66,25 @@
|
|
|
66
66
|
captureAnchor(true);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
function revealGuidance(row) {
|
|
70
|
+
const scroller = getScroller();
|
|
71
|
+
if (!isFollowing() || !scroller?.contains?.(row)) return null;
|
|
72
|
+
const bounds = scroller.getBoundingClientRect?.(), start = row.getBoundingClientRect?.();
|
|
73
|
+
if (!bounds || !start || !start.height) return null;
|
|
74
|
+
const summary = row.closest?.('[data-run-id]')?.querySelector('[data-run-process-summary]');
|
|
75
|
+
const end = Math.max(start.bottom, summary?.getBoundingClientRect?.().bottom || start.bottom);
|
|
76
|
+
const bottom = Math.max(0, scroller.scrollHeight - scroller.clientHeight), shift = bottom - scroller.scrollTop;
|
|
77
|
+
const fitsAtBottom = start.top - shift >= bounds.top + 8 && end - shift <= bounds.bottom - 8;
|
|
78
|
+
// Default folded runs can show the new input and header while following.
|
|
79
|
+
// A long expanded runtime may require leaving its bottom; show the input
|
|
80
|
+
// without changing disclosure or asking the surrounding page to scroll.
|
|
81
|
+
if (fitsAtBottom) scroller.scrollTop = bottom;
|
|
82
|
+
else if (start.top < bounds.top + 8 || end > bounds.bottom - 8) {
|
|
83
|
+
scroller.scrollTop += start.top - bounds.top - 8;
|
|
84
|
+
}
|
|
85
|
+
return { following: fitsAtBottom || Math.abs(bottom - scroller.scrollTop) < 1 };
|
|
86
|
+
}
|
|
87
|
+
|
|
69
88
|
function dispose() {
|
|
70
89
|
resizeObserver?.disconnect();
|
|
71
90
|
mutationObserver?.disconnect();
|
|
@@ -117,7 +136,7 @@
|
|
|
117
136
|
}
|
|
118
137
|
}
|
|
119
138
|
|
|
120
|
-
return Object.freeze({ bind, dispose, captureAnchor, snapshot, restore });
|
|
139
|
+
return Object.freeze({ bind, dispose, captureAnchor, snapshot, restore, revealGuidance });
|
|
121
140
|
}
|
|
122
141
|
|
|
123
142
|
return Object.freeze({ create });
|