codex-overleaf-link 2.4.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +272 -311
- package/README.zh-CN.md +287 -326
- package/extension/bootstrap/background.js +47 -10
- package/extension/bootstrap/manifest.template.json +9 -4
- package/extension/bootstrap/popup.html +10 -16
- package/extension/bootstrap/update.js +25 -2
- package/extension/runtime-manifest.json +3 -1
- package/extension/src/background.js +28 -3
- package/extension/src/backgroundSharedSessions.js +380 -0
- package/extension/src/backgroundUpdateCoordinator.js +442 -379
- package/extension/src/content/activeTurnControl.js +8 -0
- package/extension/src/content/assetTransferBroker.js +186 -12
- package/extension/src/content/changeHistoryView.js +175 -0
- package/extension/src/content/composerAttachments.js +24 -22
- package/extension/src/content/composerPanel.js +23 -8
- package/extension/src/content/contentRuntime.js +572 -571
- package/extension/src/content/diagnosticsController.js +1 -2
- package/extension/src/content/diagnosticsExport.js +222 -0
- package/extension/src/content/diagnosticsPanel.js +48 -19
- package/extension/src/content/diffReviewPanel.js +8 -5
- package/extension/src/content/generated/content.bundle.js +8974 -1781
- package/extension/src/content/generated/content.bundle.meta.json +22 -3
- package/extension/src/content/legacyGlobalRegistry.js +19 -1
- package/extension/src/content/localSkillsPanel.js +42 -7
- package/extension/src/content/markdownDomRenderer.js +9 -4
- package/extension/src/content/modelPicker.js +1 -1
- package/extension/src/content/pageBridgeClient.js +18 -3
- package/extension/src/content/panelMaintenance.js +51 -120
- package/extension/src/content/panelRenderer.js +4 -0
- package/extension/src/content/pendingInputView.js +109 -76
- package/extension/src/content/providerSettingsCoordinator.js +17 -6
- package/extension/src/content/providerSettingsDialog.js +661 -108
- package/extension/src/content/recentProjects.js +364 -356
- package/extension/src/content/runActivitySummary.js +631 -0
- package/extension/src/content/runController.js +3 -1
- package/extension/src/content/runFailureNotice.js +14 -1
- package/extension/src/content/runGuidanceController.js +4 -3
- package/extension/src/content/runPresence.js +306 -0
- package/extension/src/content/runQueueScheduler.js +2 -1
- package/extension/src/content/runResultActions.js +123 -3
- package/extension/src/content/runTimelineView.js +194 -164
- package/extension/src/content/scopedPersistenceCoordinator.js +2 -1
- package/extension/src/content/scopedPersistencePanelState.js +45 -2
- package/extension/src/content/selectionContextView.js +300 -0
- package/extension/src/content/sessionPersistence.js +10 -2
- package/extension/src/content/settingsPanel.js +93 -54
- package/extension/src/content/settingsWorkbench.js +374 -0
- package/extension/src/content/sharedSessionViewSync.js +72 -0
- package/extension/src/content/subagentActivityView.js +195 -0
- package/extension/src/content/trackedChangeCaptureController.js +7 -3
- package/extension/src/content/updateNotice.js +121 -50
- package/extension/src/content/writebackController.js +257 -0
- package/extension/src/content/writebackOrchestrator.js +146 -141
- package/extension/src/content/writebackPlan.js +231 -0
- package/extension/src/content/writebackRecovery.js +122 -0
- package/extension/src/content/writingStyleSettings.js +576 -0
- package/extension/src/content/writtenChangesView.js +152 -0
- package/extension/src/page/binaryAssetUploader.js +97 -19
- package/extension/src/page/overleafProjectSnapshot.js +1 -0
- package/extension/src/page/referenceProjects.js +148 -0
- package/extension/src/page/saveState.js +58 -3
- package/extension/src/page/snapshotRouter.js +44 -13
- package/extension/src/page/textCoordinates.js +102 -0
- package/extension/src/page/textFileCreator.js +350 -59
- package/extension/src/page/trackedChangeCapture.js +42 -56
- package/extension/src/page/trackedChangeOwnership.js +198 -0
- package/extension/src/page/trackedChangeReplay.js +164 -0
- package/extension/src/page/trackedChangesLifecycle.js +139 -150
- package/extension/src/page/treeOperations.js +36 -29
- package/extension/src/page/writebackReceiptJournal.js +112 -0
- package/extension/src/page/writebackRouter.js +176 -136
- package/extension/src/pageBridge.js +59 -101
- package/extension/src/popup.js +203 -59
- package/extension/src/shared/agentTranscript.js +18 -4
- package/extension/src/shared/auditRecords.js +71 -0
- package/extension/src/shared/changeHistoryModel.js +94 -0
- package/extension/src/shared/compatibility.js +1 -1
- package/extension/src/shared/compileAdapter.js +42 -0
- package/extension/src/shared/failureReasons.js +20 -0
- package/extension/src/shared/globalPreferences.js +1 -1
- package/extension/src/shared/i18n.js +187 -65
- package/extension/src/shared/managedUpdateProjection.js +6 -3
- package/extension/src/shared/pageRpcContract.js +7 -1
- package/extension/src/shared/providerProfiles.js +109 -0
- package/extension/src/shared/runActivityModel.js +361 -0
- package/extension/src/shared/runExecutionSnapshot.js +8 -2
- package/extension/src/shared/runExecutionSnapshotCodec.js +16 -4
- package/extension/src/shared/scopedPersistenceBrowserAdapter.js +6 -3
- package/extension/src/shared/selectionContext.js +28 -0
- package/extension/src/shared/sessionState.js +97 -6
- package/extension/src/shared/sharedSessionBridge.js +288 -0
- package/extension/src/shared/storageDb.js +23 -55
- package/extension/src/shared/storageMigration.js +3 -0
- package/extension/src/shared/storageRunActions.js +54 -4
- package/extension/src/shared/storageValuePruning.js +40 -0
- package/extension/src/shared/subagentActivityModel.js +174 -0
- package/extension/src/shared/undoOperations.js +87 -0
- package/extension/src/shared/updateConsent.js +37 -8
- package/extension/src/shared/writebackIntent.js +62 -0
- package/extension/src/shared/writebackSettlement.js +29 -10
- package/extension/src/shared/writingStyle.js +33 -0
- package/extension/styles/panel.css +2136 -744
- package/extension/styles/popup.css +110 -0
- package/native-host/src/anthropicBridgeRequest.js +2 -1
- package/native-host/src/codexModelRecovery.js +107 -0
- package/native-host/src/codexPromptAssembly.js +2 -0
- package/native-host/src/codexProviderLaunch.js +3 -3
- package/native-host/src/codexRuntimeIdentity.js +1 -0
- package/native-host/src/codexSessionRunner.js +146 -177
- package/native-host/src/codexSessionTiming.js +71 -0
- package/native-host/src/managedInstall.js +5 -4
- package/native-host/src/nativeEnvironment.js +70 -0
- package/native-host/src/nativeQuotas.js +15 -8
- package/native-host/src/overleafWorkspaceRules.js +16 -0
- package/native-host/src/processStopBarrier.js +80 -0
- package/native-host/src/providerModelCatalog.js +4 -3
- package/native-host/src/providerProfile.js +13 -1
- package/native-host/src/providerReasoning.js +9 -5
- package/native-host/src/providerStore.js +4 -0
- package/native-host/src/readProgressGuard.js +84 -17
- package/native-host/src/releaseTransport.js +14 -5
- package/native-host/src/selectionScope.js +58 -0
- package/native-host/src/skills/parallel-subagents/SKILL.md +31 -3
- package/native-host/src/skills/writing-style-builder/SKILL.md +146 -0
- package/native-host/src/subagentBroker.js +102 -98
- package/native-host/src/subagentTelemetry.js +316 -0
- package/native-host/src/subagentWorkspace.js +103 -0
- package/native-host/src/subagentWorkspacePath.js +31 -0
- package/native-host/src/taskRunnerRuntime.js +55 -5
- package/native-host/src/turnAttachments.js +113 -0
- package/native-host/src/updateManager.js +122 -12
- package/native-host/src/updateNetworkControl.js +75 -0
- package/native-host/src/updateTrust.js +21 -2
- package/native-host/src/vendor/pdfjs/LICENSE +177 -0
- package/native-host/src/vendor/pdfjs/SOURCE.txt +3 -0
- package/native-host/src/vendor/pdfjs/cmaps/78-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78ms-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78ms-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/83pv-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/90ms-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/90ms-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/90msp-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/90msp-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/90pv-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/90pv-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Add-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Add-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Add-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Add-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-0.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-1.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-3.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-4.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-5.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-6.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-0.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-1.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-3.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-4.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-5.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-0.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-1.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-3.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-4.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-5.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-6.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-0.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-1.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/B5pc-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/B5pc-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/CNS-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/CNS-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/CNS1-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/CNS1-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/CNS2-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/CNS2-V.bcmap +3 -0
- package/native-host/src/vendor/pdfjs/cmaps/ETHK-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/ETHK-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/ETen-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/ETen-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/ETenms-B5-H.bcmap +3 -0
- package/native-host/src/vendor/pdfjs/cmaps/ETenms-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Ext-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Ext-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Ext-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Ext-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GB-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GB-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GB-H.bcmap +4 -0
- package/native-host/src/vendor/pdfjs/cmaps/GB-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBK-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBK-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBK2K-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBK2K-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBKp-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBKp-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBT-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBT-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBT-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBT-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBTpc-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBTpc-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBpc-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBpc-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKdla-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKdla-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKdlb-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKdlb-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKgccs-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKgccs-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKm314-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKm314-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKm471-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKm471-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKscs-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKscs-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Hankaku.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Hiragana.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSC-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSC-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSC-Johab-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSC-Johab-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSCpc-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSCpc-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Katakana.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/LICENSE +36 -0
- package/native-host/src/vendor/pdfjs/cmaps/NWP-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/NWP-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Roman.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UCS2-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UCS2-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF16-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF16-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF8-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF8-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UCS2-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UCS2-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF16-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF16-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF8-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF8-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF16-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF16-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF8-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF8-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UCS2-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UCS2-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF16-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF16-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF8-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF8-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/WP-Symbol.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/pdf.mjs +26740 -0
- package/native-host/src/vendor/pdfjs/pdf.worker.mjs +62201 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitDingbats.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixed.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedBold.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedItalic.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerif.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifBold.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifItalic.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSymbol.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/LICENSE_FOXIT +27 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/LICENSE_LIBERATION +102 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Bold.ttf +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Italic.ttf +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Regular.ttf +0 -0
- package/native-host/src/writingStyleEvidence.js +102 -0
- package/native-host/src/writingStylePdfWorker.js +35 -0
- package/native-host/src/writingStyleProfile.js +165 -0
- package/native-host/src/writingStyleRuntime.js +447 -0
- package/package.json +1 -1
|
@@ -99,6 +99,7 @@
|
|
|
99
99
|
const {
|
|
100
100
|
buildExpectedFilesAfterOperations,
|
|
101
101
|
buildSnapshotRestoreUndo,
|
|
102
|
+
buildCreatedFileUndoCheckpoint,
|
|
102
103
|
buildUndoCheckpoint
|
|
103
104
|
} = Modules.UndoOperations;
|
|
104
105
|
const { buildHumanCompletionReport, mapAgentEventToActivity, stripEmptyHtmlCommentPlaceholders,
|
|
@@ -215,7 +216,7 @@
|
|
|
215
216
|
refreshStorageUsageSummary: () => refreshStorageUsageSummary(),
|
|
216
217
|
renderAuditHistoryPanel: () => renderAuditHistoryPanel(),
|
|
217
218
|
renderRecentProjectsVariant: (...args) => renderRecentProjectsVariant(...args),
|
|
218
|
-
saveStateSoon:
|
|
219
|
+
saveStateSoon: delay => saveStateSoon(delay),
|
|
219
220
|
updateGlobalPreferences: patch => getGlobalPreferences().update(patch),
|
|
220
221
|
setState: next => { state = next; },
|
|
221
222
|
tr,
|
|
@@ -365,6 +366,9 @@
|
|
|
365
366
|
// whose deps reference the recovery handlers.
|
|
366
367
|
const panelMaintenance = Modules.PanelMaintenance.create({
|
|
367
368
|
StorageDb: Modules.StorageDb,
|
|
369
|
+
ChangeHistoryView: Modules.ChangeHistoryView,
|
|
370
|
+
getAccountScopeId: () => cachedAccountScopeId || '',
|
|
371
|
+
sanitizeText: sanitizeAssistantVisibleText,
|
|
368
372
|
tx,
|
|
369
373
|
showPluginToast: (...args) => showPluginToast(...args),
|
|
370
374
|
showPluginConfirm: (...args) => showPluginConfirm(...args),
|
|
@@ -384,7 +388,7 @@
|
|
|
384
388
|
setState: next => { state = next; },
|
|
385
389
|
getCurrentRunView: () => currentRunView,
|
|
386
390
|
getSettingsPanelInstance: () => settingsPanelInstance,
|
|
387
|
-
prepareRetryReplacement: run => prepareRetryReplacement(run)
|
|
391
|
+
prepareRetryReplacement: (run, task) => prepareRetryReplacement(run, task)
|
|
388
392
|
});
|
|
389
393
|
const {
|
|
390
394
|
showUndoFileSelection,
|
|
@@ -415,6 +419,13 @@
|
|
|
415
419
|
forkRunFromNode: sessionForkController.forkRunFromNode
|
|
416
420
|
});
|
|
417
421
|
const runTimelineView = Modules.RunTimelineView.create({
|
|
422
|
+
RunActivitySummary: Modules.RunActivitySummary,
|
|
423
|
+
RunPresence: Modules.RunPresence,
|
|
424
|
+
// recentProjects is composed below; the empty state only reads it after startup.
|
|
425
|
+
getProjectName: () => { try { return recentProjects.readCurrentProjectNameFromDom(); } catch { return ''; } },
|
|
426
|
+
getCurrentProjectId: () => getCurrentProjectId(),
|
|
427
|
+
RunActivityModel: Modules.RunActivityModel,
|
|
428
|
+
SubagentActivityView: Modules.SubagentActivityView,
|
|
418
429
|
RunGuidanceView: Modules.RunGuidanceView,
|
|
419
430
|
RunResultActions: runResultActions,
|
|
420
431
|
RunScrollLayout: Modules.RunScrollLayout,
|
|
@@ -428,6 +439,7 @@
|
|
|
428
439
|
formatEventDetail,
|
|
429
440
|
formatEventTime,
|
|
430
441
|
renderAttachmentPreviewList,
|
|
442
|
+
renderSentSelection: Modules.SelectionContextView.renderSent,
|
|
431
443
|
formatModeLabel,
|
|
432
444
|
undoRun,
|
|
433
445
|
acceptRun,
|
|
@@ -443,6 +455,8 @@
|
|
|
443
455
|
getState: () => state,
|
|
444
456
|
getCurrentRunView: () => currentRunView,
|
|
445
457
|
refillComposerForRetry,
|
|
458
|
+
canEditRun: run => runController.isRetryReplacementEligible(run, WritebackSettlement.projectRunSettlement(run)),
|
|
459
|
+
retryWriteback: retryRunWriteback,
|
|
446
460
|
showNativeSetupGuidance: () => showNativeUpdateGuidanceModal({}),
|
|
447
461
|
openProjectFileForFailure,
|
|
448
462
|
openStorageSettings,
|
|
@@ -465,6 +479,8 @@
|
|
|
465
479
|
upsertStreamEvent,
|
|
466
480
|
renderCompletionReport,
|
|
467
481
|
isTrackedChangeLifecycleRun,
|
|
482
|
+
configureEditButton,
|
|
483
|
+
configureWritebackButton,
|
|
468
484
|
configureUndoButton,
|
|
469
485
|
configureAcceptButton
|
|
470
486
|
} = runTimelineView;
|
|
@@ -536,7 +552,80 @@
|
|
|
536
552
|
// lives in writebackOrchestrator.js. Every dep below is either a hoisted
|
|
537
553
|
// function declaration, an already-initialized const above, or a lazy
|
|
538
554
|
// accessor thunk — safe in the top-of-init() wiring zone.
|
|
555
|
+
const selectionContextView = Modules.SelectionContextView.create({
|
|
556
|
+
getPanel: () => panel,
|
|
557
|
+
getState: () => state,
|
|
558
|
+
getProjectId: getCurrentProjectId,
|
|
559
|
+
openComposer: () => ensurePanelOpen(),
|
|
560
|
+
setSelection: (value, options = {}) => {
|
|
561
|
+
if (options.edit && panel?.querySelector('[data-task]')) readPanelInputs();
|
|
562
|
+
state = updateActiveSession(state, {
|
|
563
|
+
selectionContext: value,
|
|
564
|
+
...(options.edit ? { mode: 'auto' } : {})
|
|
565
|
+
});
|
|
566
|
+
if (options.edit && panel) {
|
|
567
|
+
const modeInput = panel.querySelector('[data-mode]');
|
|
568
|
+
if (modeInput) modeInput.value = 'auto';
|
|
569
|
+
syncModeControls();
|
|
570
|
+
}
|
|
571
|
+
saveStateSoon();
|
|
572
|
+
},
|
|
573
|
+
callPageBridge, tx, toast: showPluginToast
|
|
574
|
+
});
|
|
575
|
+
selectionContextView.start();
|
|
576
|
+
const writingStyleSettings = Modules.WritingStyleSettings.create({
|
|
577
|
+
tx,
|
|
578
|
+
getScope: () => {
|
|
579
|
+
const projectId = getCurrentProjectId();
|
|
580
|
+
return cachedAccountScopeId && projectId ? { accountScopeId: cachedAccountScopeId, projectId } : null;
|
|
581
|
+
},
|
|
582
|
+
request: sendBackgroundNative,
|
|
583
|
+
getReferenceSnapshot: async (projectId, requestId) => {
|
|
584
|
+
const result = await callPageBridge('getReferenceProjectSnapshot', { projectId, requestId });
|
|
585
|
+
if (!result?.ok) throw Object.assign(new Error(result?.error || result?.reason || tx(
|
|
586
|
+
'The reference project could not be read.', '参考项目未能读取。')), { code: result?.code });
|
|
587
|
+
return result;
|
|
588
|
+
},
|
|
589
|
+
cancelReferenceRead: async requestId => {
|
|
590
|
+
const result = await callPageBridge('cancelReferenceRead', { requestId });
|
|
591
|
+
if (!result?.ok) throw new Error(result?.error || tx('The reference read could not be cancelled.', '参考资料读取未能取消。'));
|
|
592
|
+
return result;
|
|
593
|
+
},
|
|
594
|
+
isRunning: () => Boolean(currentRunView),
|
|
595
|
+
listProjects: async () => {
|
|
596
|
+
const result = await callPageBridge('listReferenceProjects', {});
|
|
597
|
+
if (!result?.ok) throw new Error(result?.error || tx(
|
|
598
|
+
'The Overleaf project directory could not be loaded.', 'Overleaf 项目目录未能加载。'));
|
|
599
|
+
return result.projects;
|
|
600
|
+
},
|
|
601
|
+
getModelSettings: async () => {
|
|
602
|
+
await providerSettingsCoordinator.ensureLoaded();
|
|
603
|
+
if (panel?.querySelector('[data-task]')) readPanelInputs();
|
|
604
|
+
return {
|
|
605
|
+
model: state.model,
|
|
606
|
+
reasoningEffort: state.reasoningEffort,
|
|
607
|
+
speedTier: state.speedTier,
|
|
608
|
+
providerSelection: providerSettingsCoordinator.getRunSelection(state.providerId || 'builtin'),
|
|
609
|
+
locale: getLocale()
|
|
610
|
+
};
|
|
611
|
+
},
|
|
612
|
+
startBuild: async params => {
|
|
613
|
+
const gate = await nativeCompatibilityController.ensureForMethod('codex.run');
|
|
614
|
+
if (!gate.ok) throw new Error(gate.response?.error?.message || 'Native host update required.');
|
|
615
|
+
const id = crypto.randomUUID();
|
|
616
|
+
const promise = nativeChannel.sendBackgroundNative(nativeCompatibilityController.attachEvidence({
|
|
617
|
+
id, method: 'codex.run', params
|
|
618
|
+
}, gate.compatibility));
|
|
619
|
+
return { id, promise };
|
|
620
|
+
}
|
|
621
|
+
});
|
|
539
622
|
const assetTransferBroker = Modules.AssetTransferBroker.create({ callPageBridge, sendBackgroundNative });
|
|
623
|
+
const { partitionUnsafeProjectPathOperations, normalizeOperationProjectPaths, getInvalidOperationProjectPath,
|
|
624
|
+
evaluateGovernedOperations, buildGovernanceSkippedApplyResult, filterSyncChangesByOperations, mergeApplyResultSkipped,
|
|
625
|
+
confirmBinaryOperations, buildAuditSummaryFromApply, summarizeOperationForAudit } = Modules.WritebackPlan.create({
|
|
626
|
+
tx, tr, normalizeSafeProjectPath, GovernanceRules, getGovernanceRulesForCurrentProject,
|
|
627
|
+
showPluginConfirm, formatOperationFiles, getAppliedEntries, getSkippedEntries
|
|
628
|
+
});
|
|
540
629
|
const writebackOrchestrator = Modules.WritebackOrchestrator.create({
|
|
541
630
|
tr,
|
|
542
631
|
tx,
|
|
@@ -577,6 +666,8 @@
|
|
|
577
666
|
filterSyncChangesByOperations,
|
|
578
667
|
writebackController,
|
|
579
668
|
assetTransferBroker,
|
|
669
|
+
stageWritebackRecovery,
|
|
670
|
+
settleWritebackRecovery,
|
|
580
671
|
writebackSettlement: WritebackSettlement,
|
|
581
672
|
compileAdapter: Modules.CompileAdapter,
|
|
582
673
|
RUN_SNAPSHOT_ZIP_TIMEOUT_MS,
|
|
@@ -774,6 +865,7 @@
|
|
|
774
865
|
getRunEvents: () => currentRunView?.events,
|
|
775
866
|
appendRunEvent,
|
|
776
867
|
scrollLogToBottom,
|
|
868
|
+
renderWrittenChanges: changes => Modules.WrittenChangesView.render(changes, { document, tx }),
|
|
777
869
|
onRejectedHunks: summaries => {
|
|
778
870
|
if (currentRunView && Array.isArray(summaries) && summaries.length) {
|
|
779
871
|
currentRunView.rejectedHunks = summaries;
|
|
@@ -922,6 +1014,15 @@
|
|
|
922
1014
|
rolled_back: tx('The update failed its health check, so the previous version was restored.', '更新未通过健康检查,已自动恢复上一版本。')
|
|
923
1015
|
}[state] || '')
|
|
924
1016
|
});
|
|
1017
|
+
const diagnosticsExporter = Modules.DiagnosticsExport.create({
|
|
1018
|
+
root, window, document, Blob, URL, TextEncoder, AuditRecords, StorageDb: Modules.StorageDb,
|
|
1019
|
+
CodexOverleafCompatibility, getState: () => state, getCurrentRunView: () => currentRunView,
|
|
1020
|
+
getCurrentProjectId, findRunRecord, getMirrorFreshness, getExtensionCompatibilityMetadata,
|
|
1021
|
+
getModelDiscovery, getGovernanceRulesForCurrentProject, sendBackgroundNative,
|
|
1022
|
+
fallbackNativeCompatibility, isNativeCompatibilityCompatible, getNativeCompatibilityClassification,
|
|
1023
|
+
callPageBridge, showPluginToast, tr, RUN_SNAPSHOT_ZIP_TIMEOUT_MS
|
|
1024
|
+
});
|
|
1025
|
+
|
|
925
1026
|
root[RUNTIME_INSTALLED_FLAG] = true;
|
|
926
1027
|
root[RUNTIME_STATE_KEY] = { ok: true, alreadyInstalled: false };
|
|
927
1028
|
|
|
@@ -948,7 +1049,6 @@
|
|
|
948
1049
|
if (message?.type === 'codex-overleaf/toggle-launcher') {
|
|
949
1050
|
const visible = !PanelRenderer.isLauncherVisible(panelRendererInstance);
|
|
950
1051
|
PanelRenderer.setLauncherVisible(panelRendererInstance, visible, { persist: true });
|
|
951
|
-
if (!visible) closePanel();
|
|
952
1052
|
sendResponse?.(getPanelStateResponse());
|
|
953
1053
|
return;
|
|
954
1054
|
}
|
|
@@ -969,7 +1069,7 @@
|
|
|
969
1069
|
}
|
|
970
1070
|
});
|
|
971
1071
|
|
|
972
|
-
exposeSmokeHelper();
|
|
1072
|
+
diagnosticsExporter.exposeSmokeHelper();
|
|
973
1073
|
init().catch(error => {
|
|
974
1074
|
root[RUNTIME_STATE_KEY] = {
|
|
975
1075
|
ok: false,
|
|
@@ -981,11 +1081,19 @@
|
|
|
981
1081
|
throw error;
|
|
982
1082
|
});
|
|
983
1083
|
|
|
1084
|
+
function normalizeLoadedPanelState(input) {
|
|
1085
|
+
// Shared history may belong to a live run in another tab. Loading it is
|
|
1086
|
+
// read-only; only an owner-lost journal may mark that run interrupted.
|
|
1087
|
+
return normalizePanelState(getGlobalPreferences().overlay(input), {
|
|
1088
|
+
restoreRunningRuns: Modules.StorageDb.sharedSessionsEnabled?.() !== true, recoverSettledRuns: true
|
|
1089
|
+
});
|
|
1090
|
+
}
|
|
1091
|
+
|
|
984
1092
|
async function init() {
|
|
985
1093
|
await getGlobalPreferences().initialize();
|
|
986
1094
|
await refreshAccountScopeId();
|
|
987
1095
|
storageKey = getProjectStorageKey(LEGACY_STORAGE_KEY, window.location.href);
|
|
988
|
-
state =
|
|
1096
|
+
state = normalizeLoadedPanelState(await loadStoredState());
|
|
989
1097
|
initializeRunQueueScheduler();
|
|
990
1098
|
recoverInterruptedRunJournals()
|
|
991
1099
|
.then(() => applyStateToPanel())
|
|
@@ -1067,129 +1175,9 @@
|
|
|
1067
1175
|
: '';
|
|
1068
1176
|
}
|
|
1069
1177
|
|
|
1070
|
-
function exposeSmokeHelper() {
|
|
1071
|
-
const helper = Object.freeze({
|
|
1072
|
-
probeNative: smokeProbeNative,
|
|
1073
|
-
probeProject: smokeProbeProject,
|
|
1074
|
-
getProjectSnapshotMetrics: smokeProbeProject
|
|
1075
|
-
});
|
|
1076
|
-
try {
|
|
1077
|
-
Object.defineProperty(globalThis, 'CodexOverleafSmoke', {
|
|
1078
|
-
configurable: true,
|
|
1079
|
-
enumerable: false,
|
|
1080
|
-
value: helper
|
|
1081
|
-
});
|
|
1082
|
-
} catch (_error) {
|
|
1083
|
-
globalThis.CodexOverleafSmoke = helper;
|
|
1084
|
-
}
|
|
1085
|
-
}
|
|
1086
1178
|
|
|
1087
|
-
async function smokeProbeNative() {
|
|
1088
|
-
try {
|
|
1089
|
-
const params = CodexOverleafCompatibility?.buildBridgePingParams
|
|
1090
|
-
? CodexOverleafCompatibility.buildBridgePingParams(getExtensionCompatibilityMetadata())
|
|
1091
|
-
: {};
|
|
1092
|
-
const response = await sendBackgroundNative({ method: 'bridge.ping', params });
|
|
1093
|
-
const compatibility = CodexOverleafCompatibility?.evaluateNativeCompatibility
|
|
1094
|
-
? CodexOverleafCompatibility.evaluateNativeCompatibility(response, getExtensionCompatibilityMetadata())
|
|
1095
|
-
: fallbackNativeCompatibility(response);
|
|
1096
|
-
return {
|
|
1097
|
-
supported: true,
|
|
1098
|
-
ok: response?.ok === true && isNativeCompatibilityCompatible(compatibility),
|
|
1099
|
-
status: compatibility?.status || (response?.ok ? 'ok' : 'native_missing'),
|
|
1100
|
-
classification: getNativeCompatibilityClassification(compatibility),
|
|
1101
|
-
errorCode: response?.error?.code || compatibility?.status || '',
|
|
1102
|
-
nativeCompatibility: summarizeSmokeNativeCompatibility(compatibility, response)
|
|
1103
|
-
};
|
|
1104
|
-
} catch (_error) {
|
|
1105
|
-
return {
|
|
1106
|
-
supported: true,
|
|
1107
|
-
ok: false,
|
|
1108
|
-
status: 'native_probe_failed',
|
|
1109
|
-
errorCode: 'native_probe_failed'
|
|
1110
|
-
};
|
|
1111
|
-
}
|
|
1112
|
-
}
|
|
1113
1179
|
|
|
1114
|
-
async function smokeProbeProject(options = {}) {
|
|
1115
|
-
try {
|
|
1116
|
-
const project = await callPageBridge('getProjectSnapshot', {
|
|
1117
|
-
force: Boolean(options.force),
|
|
1118
|
-
preferLightweight: true,
|
|
1119
|
-
allowZipFallback: true,
|
|
1120
|
-
allowEditorNavigation: false,
|
|
1121
|
-
requireFullProject: false,
|
|
1122
|
-
includeBinaryFiles: true,
|
|
1123
|
-
includeContent: false,
|
|
1124
|
-
zipTimeoutMs: RUN_SNAPSHOT_ZIP_TIMEOUT_MS
|
|
1125
|
-
});
|
|
1126
|
-
const files = Array.isArray(project?.files) ? project.files : [];
|
|
1127
|
-
const skipped = Array.isArray(project?.capabilities?.skipped) ? project.capabilities.skipped : [];
|
|
1128
|
-
const bytes = summarizeSmokeProjectBytes(files);
|
|
1129
|
-
const ok = project?.ok !== false && files.length > 0;
|
|
1130
|
-
return {
|
|
1131
|
-
supported: true,
|
|
1132
|
-
ok,
|
|
1133
|
-
status: ok ? 'ok' : 'project_snapshot_unavailable',
|
|
1134
|
-
errorCode: ok ? '' : project?.code || 'project_snapshot_unavailable',
|
|
1135
|
-
counts: {
|
|
1136
|
-
files: files.length,
|
|
1137
|
-
skipped: skipped.length
|
|
1138
|
-
},
|
|
1139
|
-
bytes,
|
|
1140
|
-
method: project?.capabilities?.method || ''
|
|
1141
|
-
};
|
|
1142
|
-
} catch (_error) {
|
|
1143
|
-
return {
|
|
1144
|
-
supported: true,
|
|
1145
|
-
ok: false,
|
|
1146
|
-
status: 'project_probe_failed',
|
|
1147
|
-
errorCode: 'project_probe_failed',
|
|
1148
|
-
counts: {
|
|
1149
|
-
files: 0,
|
|
1150
|
-
skipped: 0
|
|
1151
|
-
},
|
|
1152
|
-
bytes: {
|
|
1153
|
-
text: 0,
|
|
1154
|
-
binary: 0
|
|
1155
|
-
}
|
|
1156
|
-
};
|
|
1157
|
-
}
|
|
1158
|
-
}
|
|
1159
1180
|
|
|
1160
|
-
function summarizeSmokeNativeCompatibility(compatibility = {}, response = {}) {
|
|
1161
|
-
const native = compatibility?.native || response?.result || {};
|
|
1162
|
-
return {
|
|
1163
|
-
status: compatibility?.status || (response?.ok ? 'ok' : 'native_missing'),
|
|
1164
|
-
classification: getNativeCompatibilityClassification(compatibility),
|
|
1165
|
-
nativeVersion: compatibility?.nativeVersion || native.version || '',
|
|
1166
|
-
version: compatibility?.version || native.version || '',
|
|
1167
|
-
minimumNativeVersion: compatibility?.minimumNativeVersion || compatibility?.minNativeVersion || '',
|
|
1168
|
-
protocolVersion: compatibility?.protocolVersion || native.protocolVersion || '',
|
|
1169
|
-
supportedProtocol: compatibility?.supportedProtocol || native.supportedProtocol || ''
|
|
1170
|
-
};
|
|
1171
|
-
}
|
|
1172
|
-
|
|
1173
|
-
function summarizeSmokeProjectBytes(files = []) {
|
|
1174
|
-
return files.reduce((bytes, file) => {
|
|
1175
|
-
let size = Number(file?.size || file?.byteLength || 0);
|
|
1176
|
-
if ((!Number.isFinite(size) || size <= 0) && typeof file?.content === 'string') {
|
|
1177
|
-
size = new TextEncoder().encode(file.content).byteLength;
|
|
1178
|
-
}
|
|
1179
|
-
if (!Number.isFinite(size) || size <= 0) {
|
|
1180
|
-
return bytes;
|
|
1181
|
-
}
|
|
1182
|
-
if (file?.kind === 'binary') {
|
|
1183
|
-
bytes.binary += size;
|
|
1184
|
-
} else {
|
|
1185
|
-
bytes.text += size;
|
|
1186
|
-
}
|
|
1187
|
-
return bytes;
|
|
1188
|
-
}, {
|
|
1189
|
-
text: 0,
|
|
1190
|
-
binary: 0
|
|
1191
|
-
});
|
|
1192
|
-
}
|
|
1193
1181
|
|
|
1194
1182
|
function listSeparator() {
|
|
1195
1183
|
return getLocale() === 'zh' ? '、' : ', ';
|
|
@@ -1209,7 +1197,6 @@
|
|
|
1209
1197
|
callbacks: {
|
|
1210
1198
|
onLauncherToggle: () => ensurePanelOpen(),
|
|
1211
1199
|
onClosePanel: () => closePanel(),
|
|
1212
|
-
onLauncherVisibilityChange: visible => { if (!visible) closePanel(); },
|
|
1213
1200
|
onRefresh: () => refreshProbe({ userInitiated: true }),
|
|
1214
1201
|
onNewSession: () => startNewSession(),
|
|
1215
1202
|
onChangeHistory: () => openChangeHistory(),
|
|
@@ -1285,6 +1272,7 @@
|
|
|
1285
1272
|
onOtToggleClick: handleExperimentalOtToggleClick
|
|
1286
1273
|
}
|
|
1287
1274
|
});
|
|
1275
|
+
writingStyleSettings.mount(panel);
|
|
1288
1276
|
providerSettingsCoordinator.refreshSummary().catch(() => {});
|
|
1289
1277
|
|
|
1290
1278
|
sessionPanelInstance = SessionPanel.create({
|
|
@@ -1476,7 +1464,7 @@
|
|
|
1476
1464
|
setElementTitleAndAria('[data-context-refresh]', tr('refreshFileList'), tr('refreshFileList'));
|
|
1477
1465
|
setElementTitleAndAria('[data-reasoning]', tr('reasoningLabel'), tr('reasoningLabel'));
|
|
1478
1466
|
setElementTitleAndAria('[data-speed]', tr('speedLabel'), tr('speedLabel'));
|
|
1479
|
-
|
|
1467
|
+
syncComposerSendAvailability();
|
|
1480
1468
|
setElementTitleAndAria('[data-stop-run]', tr('cancelRun'), tr('cancelRun'));
|
|
1481
1469
|
|
|
1482
1470
|
const actions = panel.querySelector('.codex-vscode-head-actions');
|
|
@@ -1525,10 +1513,8 @@
|
|
|
1525
1513
|
if (contextStatus && !contextStatus.dataset.customStatus) {
|
|
1526
1514
|
contextStatus.textContent = tr('contextStatus');
|
|
1527
1515
|
}
|
|
1528
|
-
|
|
1529
|
-
if (
|
|
1530
|
-
emptyRunLabel.textContent = tr('emptyRunLabel');
|
|
1531
|
-
}
|
|
1516
|
+
// Re-render rather than patch text: the first div is the animated mark.
|
|
1517
|
+
if (panel.querySelector('.empty-runs')) renderRunHistory();
|
|
1532
1518
|
|
|
1533
1519
|
syncModeControls();
|
|
1534
1520
|
updateOtStatusDisplay();
|
|
@@ -1537,14 +1523,7 @@
|
|
|
1537
1523
|
updateModelDisplay();
|
|
1538
1524
|
renderSessionList();
|
|
1539
1525
|
renderContextSelection();
|
|
1540
|
-
|
|
1541
|
-
if (probeStatus?.dataset.refreshing === 'true') probeStatus.textContent = tr('refreshProbeLoading');
|
|
1542
|
-
else if (probeStatus && probeStatusSnapshot?.projectId === getCurrentProjectId()) {
|
|
1543
|
-
const { failed, probe, userInitiated } = probeStatusSnapshot;
|
|
1544
|
-
const text = failed ? tr('refreshProbeFailed') : formatProbeStatusBar(probe);
|
|
1545
|
-
probeStatus.textContent = userInitiated && !failed ? tr('refreshProbeDone', { status: text }) : text;
|
|
1546
|
-
if (!failed) updateExistingProbeNotice(probe);
|
|
1547
|
-
}
|
|
1526
|
+
writingStyleSettings.sync();
|
|
1548
1527
|
updateSkillsEntrySummary();
|
|
1549
1528
|
providerSettingsCoordinator.renderSummary();
|
|
1550
1529
|
if (settingsPanelInstance?.container?.querySelector('[data-storage-card]')?.open) refreshStorageUsageSummary();
|
|
@@ -1603,88 +1582,14 @@
|
|
|
1603
1582
|
}
|
|
1604
1583
|
|
|
1605
1584
|
|
|
1606
|
-
async function exportDiagnosticsBundle() {
|
|
1607
|
-
if (!AuditRecords?.buildDiagnosticBundle) {
|
|
1608
|
-
throw new Error('Audit diagnostics helper is unavailable');
|
|
1609
|
-
}
|
|
1610
|
-
const [auditLogs, mirror, nativeDiagnostics] = await Promise.all([
|
|
1611
|
-
getRecentAuditLogsForCurrentProject(),
|
|
1612
|
-
getMirrorFreshness().catch(error => ({ status: 'unavailable', errorCode: error.message })),
|
|
1613
|
-
getNativeDiagnosticsSummaryForBundle()
|
|
1614
|
-
]);
|
|
1615
|
-
const bundle = AuditRecords.buildDiagnosticBundle({
|
|
1616
|
-
excludeContent: true,
|
|
1617
|
-
compatibility: {
|
|
1618
|
-
extension: getExtensionCompatibilityMetadata(),
|
|
1619
|
-
modelDiscovery: getModelDiscovery()
|
|
1620
|
-
},
|
|
1621
|
-
platform: nativeDiagnostics.platform,
|
|
1622
|
-
nativeEnvironment: nativeDiagnostics.nativeEnvironment,
|
|
1623
|
-
mirror,
|
|
1624
|
-
auditLogs,
|
|
1625
|
-
run: currentRunView ? {
|
|
1626
|
-
id: currentRunView.recordId || '',
|
|
1627
|
-
status: 'running'
|
|
1628
|
-
} : {},
|
|
1629
|
-
governance: getGovernanceRulesForCurrentProject(),
|
|
1630
|
-
projectId: getCurrentProjectId()
|
|
1631
|
-
});
|
|
1632
|
-
const blob = new Blob([JSON.stringify(bundle, null, 2)], { type: 'application/json' });
|
|
1633
|
-
const url = URL.createObjectURL(blob);
|
|
1634
|
-
const link = document.createElement('a');
|
|
1635
|
-
link.href = url;
|
|
1636
|
-
link.download = `codex-overleaf-diagnostics-${new Date().toISOString().replace(/[:.]/g, '-')}.json`;
|
|
1637
|
-
document.body.append(link);
|
|
1638
|
-
link.click();
|
|
1639
|
-
link.remove();
|
|
1640
|
-
window.setTimeout(() => URL.revokeObjectURL(url), 1000);
|
|
1641
|
-
showPluginToast(tr('diagnosticsExportDone'), { status: 'completed' });
|
|
1642
|
-
}
|
|
1643
|
-
|
|
1644
|
-
async function getNativeDiagnosticsSummaryForBundle() {
|
|
1645
|
-
try {
|
|
1646
|
-
const params = CodexOverleafCompatibility?.buildBridgePingParams
|
|
1647
|
-
? CodexOverleafCompatibility.buildBridgePingParams(getExtensionCompatibilityMetadata())
|
|
1648
|
-
: {};
|
|
1649
|
-
const response = await sendBackgroundNative({ method: 'bridge.ping', params });
|
|
1650
|
-
if (!response?.ok) {
|
|
1651
|
-
const errorCode = response?.error?.code || 'native_unavailable';
|
|
1652
|
-
return {
|
|
1653
|
-
platform: { status: 'unavailable', errorCode },
|
|
1654
|
-
nativeEnvironment: { status: 'unavailable', errorCode }
|
|
1655
|
-
};
|
|
1656
|
-
}
|
|
1657
|
-
return {
|
|
1658
|
-
platform: {
|
|
1659
|
-
host: response.result?.host || '',
|
|
1660
|
-
platform: response.result?.platform || '',
|
|
1661
|
-
version: response.result?.version || '',
|
|
1662
|
-
protocolVersion: response.result?.protocolVersion || ''
|
|
1663
|
-
},
|
|
1664
|
-
nativeEnvironment: response.result?.environment || {}
|
|
1665
|
-
};
|
|
1666
|
-
} catch (error) {
|
|
1667
|
-
const errorCode = error?.message || 'native_unavailable';
|
|
1668
|
-
return {
|
|
1669
|
-
platform: { status: 'unavailable', errorCode },
|
|
1670
|
-
nativeEnvironment: { status: 'unavailable', errorCode }
|
|
1671
|
-
};
|
|
1672
|
-
}
|
|
1673
|
-
}
|
|
1674
1585
|
|
|
1675
|
-
async function getRecentAuditLogsForCurrentProject(limit = 12) {
|
|
1676
|
-
const StorageDb = Modules.StorageDb;
|
|
1677
|
-
if (!StorageDb?.getAllByIndex) {
|
|
1678
|
-
return [];
|
|
1679
|
-
}
|
|
1680
|
-
const records = await StorageDb.getAllByIndex('auditLogs', 'projectId', getCurrentProjectId());
|
|
1681
|
-
return (records || [])
|
|
1682
|
-
.slice()
|
|
1683
|
-
.sort((left, right) => String(right.createdAt || '').localeCompare(String(left.createdAt || '')))
|
|
1684
|
-
.slice(0, limit);
|
|
1685
|
-
}
|
|
1686
1586
|
|
|
1687
1587
|
|
|
1588
|
+
|
|
1589
|
+
function exportDiagnosticsBundle() {
|
|
1590
|
+
return diagnosticsExporter.exportDiagnosticsBundle();
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1688
1593
|
function isContextTrayClickTarget(target) {
|
|
1689
1594
|
return contextTrayController.isContextTrayClickTarget(target);
|
|
1690
1595
|
}
|
|
@@ -1796,6 +1701,7 @@
|
|
|
1796
1701
|
appendLog(tx('Enter a task first.', '请先输入任务。'));
|
|
1797
1702
|
return;
|
|
1798
1703
|
}
|
|
1704
|
+
const submittedWritingStyleScope = { accountScopeId: cachedAccountScopeId, projectId: getCurrentProjectId() };
|
|
1799
1705
|
const submittedPanelState = {
|
|
1800
1706
|
mode: state.mode,
|
|
1801
1707
|
providerId: state.providerId,
|
|
@@ -1804,13 +1710,21 @@
|
|
|
1804
1710
|
speedTier: state.speedTier,
|
|
1805
1711
|
autoRecompile: state.autoRecompile !== false,
|
|
1806
1712
|
requireReviewing: state.requireReviewing === true,
|
|
1807
|
-
focusFiles: getActiveFocusFiles()
|
|
1713
|
+
focusFiles: getActiveFocusFiles(),
|
|
1714
|
+
selectionContext: selectionContextView.capture()
|
|
1808
1715
|
};
|
|
1809
1716
|
const submittedCustomInstructions = getCustomInstructionsForCurrentProject();
|
|
1810
1717
|
const submittedSkillLoadingSettings = getSkillLoadingSettings();
|
|
1811
1718
|
const submittedAttachments = getComposerAttachmentsForRun();
|
|
1812
1719
|
const submittedSkillInvocation = getComposerSkillInvocationForRun();
|
|
1813
1720
|
await providerSettingsCoordinator.ensureLoaded();
|
|
1721
|
+
if (!queuedInput) await writingStyleSettings.ensureLoaded(true);
|
|
1722
|
+
if (submittedWritingStyleScope.accountScopeId !== cachedAccountScopeId
|
|
1723
|
+
|| submittedWritingStyleScope.projectId !== getCurrentProjectId()) {
|
|
1724
|
+
throw new Error(tx('The active project changed before submission. Submit the task again.',
|
|
1725
|
+
'提交前活动项目已改变,请重新提交任务。'));
|
|
1726
|
+
}
|
|
1727
|
+
submittedPanelState.writingStyle = queuedInput ? null : writingStyleSettings.capture();
|
|
1814
1728
|
const executionSnapshot = queuedInput
|
|
1815
1729
|
? RunExecutionSnapshot.resolveForExecution(
|
|
1816
1730
|
RunExecutionSnapshot.fromQueuePayload(queuedInput.payload),
|
|
@@ -2156,9 +2070,10 @@
|
|
|
2156
2070
|
submittedMode
|
|
2157
2071
|
}));
|
|
2158
2072
|
} else {
|
|
2159
|
-
appendRunEvent({ title: tx('Cancelled: user chose not to create a new thread.', '已取消:用户选择不新建线程。'), status: '
|
|
2160
|
-
|
|
2161
|
-
await
|
|
2073
|
+
appendRunEvent({ title: tx('Cancelled: user chose not to create a new thread.', '已取消:用户选择不新建线程。'), status: 'info',
|
|
2074
|
+
activity: { v: 1, kind: 'lifecycle', state: 'cancelled', target: 'cancelled' } });
|
|
2075
|
+
await finalizeAuditRecord(runAuditDraft, { resultStatus: 'cancelled' });
|
|
2076
|
+
await finishRunView(tx('Cancelled', '已取消'), 'cancelled');
|
|
2162
2077
|
return;
|
|
2163
2078
|
}
|
|
2164
2079
|
}
|
|
@@ -2166,7 +2081,7 @@
|
|
|
2166
2081
|
if (!response.ok) {
|
|
2167
2082
|
if (runCancellationRequested || isRunCancellationError(response.error)) {
|
|
2168
2083
|
appendRunCancelledReport();
|
|
2169
|
-
await finishRunView(tx('Cancelled', '
|
|
2084
|
+
await finishRunView(tx('Cancelled', '已取消'), 'cancelled');
|
|
2170
2085
|
void finalizeAuditRecord(runAuditDraft, { resultStatus: 'cancelled' });
|
|
2171
2086
|
return;
|
|
2172
2087
|
}
|
|
@@ -2420,7 +2335,7 @@
|
|
|
2420
2335
|
} catch (error) {
|
|
2421
2336
|
if (runCancellationRequested || isRunCancellationError(error)) {
|
|
2422
2337
|
appendRunCancelledReport();
|
|
2423
|
-
await finishRunView(tx('Cancelled', '
|
|
2338
|
+
await finishRunView(tx('Cancelled', '已取消'), 'cancelled');
|
|
2424
2339
|
void finalizeAuditRecord(runAuditDraft, { resultStatus: 'cancelled' });
|
|
2425
2340
|
return;
|
|
2426
2341
|
}
|
|
@@ -2544,7 +2459,7 @@
|
|
|
2544
2459
|
if (runCancellationRequested || isRunCancellationError(response.error)) {
|
|
2545
2460
|
appendRunCancelledReport();
|
|
2546
2461
|
await finalizeAuditRecord(runAuditDraft, { resultStatus: 'cancelled' });
|
|
2547
|
-
await finishRunView(tx('Cancelled', '
|
|
2462
|
+
await finishRunView(tx('Cancelled', '已取消'), 'cancelled');
|
|
2548
2463
|
return;
|
|
2549
2464
|
}
|
|
2550
2465
|
const translated = translateRawError(response.error.message, { mode: submittedMode, locale: getLocale() });
|
|
@@ -2771,6 +2686,7 @@
|
|
|
2771
2686
|
}),
|
|
2772
2687
|
clearTask: () => {
|
|
2773
2688
|
panel.querySelector('[data-task]').value = '';
|
|
2689
|
+
selectionContextView.clear();
|
|
2774
2690
|
updateSessionById(state.activeSessionId, { task: '' });
|
|
2775
2691
|
autosizeTaskTextarea();
|
|
2776
2692
|
syncComposerSendAvailability();
|
|
@@ -2801,6 +2717,9 @@
|
|
|
2801
2717
|
const requestedProviderId = submitted.providerId || state?.providerId || 'builtin';
|
|
2802
2718
|
const selection = providerSettingsCoordinator.getRunSelection(requestedProviderId);
|
|
2803
2719
|
const providerId = selection?.providerId || requestedProviderId;
|
|
2720
|
+
const selectedContext = Object.prototype.hasOwnProperty.call(submitted, 'selectionContext')
|
|
2721
|
+
? submitted.selectionContext : selectionContextView.capture();
|
|
2722
|
+
const selectedPaths = submitted.focusFiles ?? getActiveFocusFiles();
|
|
2804
2723
|
return RunExecutionSnapshot.capture({
|
|
2805
2724
|
mode: submitted.mode ?? state?.mode,
|
|
2806
2725
|
providerId,
|
|
@@ -2810,7 +2729,11 @@
|
|
|
2810
2729
|
speedTier: submitted.speedTier ?? state?.speedTier,
|
|
2811
2730
|
autoRecompile: submitted.autoRecompile ?? state?.autoRecompile !== false,
|
|
2812
2731
|
requireReviewing: submitted.requireReviewing ?? state?.requireReviewing === true,
|
|
2813
|
-
focusFiles:
|
|
2732
|
+
focusFiles: selectedContext?.mode === 'edit' && selectedPaths.length
|
|
2733
|
+
? [...new Set([...selectedPaths, selectedContext.path])] : selectedPaths,
|
|
2734
|
+
selectionContext: selectedContext,
|
|
2735
|
+
writingStyle: Object.prototype.hasOwnProperty.call(submitted, 'writingStyle')
|
|
2736
|
+
? submitted.writingStyle : writingStyleSettings.capture()
|
|
2814
2737
|
}, {
|
|
2815
2738
|
source: 'submitted',
|
|
2816
2739
|
requireProviderRevision: providerId !== 'builtin'
|
|
@@ -3078,7 +3001,10 @@
|
|
|
3078
3001
|
...params,
|
|
3079
3002
|
clientRunId: currentRunView?.recordId || '',
|
|
3080
3003
|
clientSessionId: currentRunView?.sessionId || '',
|
|
3081
|
-
providerSelection: RunExecutionSnapshot.toProviderSelection(executionSnapshot)
|
|
3004
|
+
providerSelection: RunExecutionSnapshot.toProviderSelection(executionSnapshot),
|
|
3005
|
+
selectionContext: executionSnapshot.selectionContext || null,
|
|
3006
|
+
accountScopeId: currentRunView?.runAccountScopeId || cachedAccountScopeId || '',
|
|
3007
|
+
writingStyle: executionSnapshot.writingStyle || null
|
|
3082
3008
|
};
|
|
3083
3009
|
}
|
|
3084
3010
|
|
|
@@ -3118,6 +3044,11 @@
|
|
|
3118
3044
|
const projectKey = getCurrentProjectId();
|
|
3119
3045
|
const recovery = await activeTurnControl.recoverJournals({
|
|
3120
3046
|
projectKey,
|
|
3047
|
+
requireOwnerLost: Modules.StorageDb.sharedSessionsEnabled?.() === true,
|
|
3048
|
+
normalizeInterruptedRun: record => Object.assign(record, Modules.SessionState.normalizeRuns([record], {
|
|
3049
|
+
restoreRunningRuns: true,
|
|
3050
|
+
locale: getLocale()
|
|
3051
|
+
})[0]),
|
|
3121
3052
|
findSession: findSessionById,
|
|
3122
3053
|
getActiveSession: () => getActiveSession(state),
|
|
3123
3054
|
createInterruptedRun: journal => ({
|
|
@@ -3364,11 +3295,12 @@
|
|
|
3364
3295
|
.some(item => item?.status === 'queued');
|
|
3365
3296
|
appendRunEvent({
|
|
3366
3297
|
title: tx('Current Codex task was cancelled.', '已中断当前 Codex 任务。'),
|
|
3367
|
-
status: '
|
|
3298
|
+
status: 'info',
|
|
3299
|
+
activity: { v: 1, kind: 'lifecycle', state: 'cancelled', target: 'cancelled' }
|
|
3368
3300
|
});
|
|
3369
3301
|
appendCompletionReport({
|
|
3370
3302
|
conclusion: tx('This run was cancelled. It did not continue syncing or writing to Overleaf.', '这轮已中断,没有继续同步或写入 Overleaf。'),
|
|
3371
|
-
status: '
|
|
3303
|
+
status: 'cancelled',
|
|
3372
3304
|
operations: [],
|
|
3373
3305
|
applyResults: [],
|
|
3374
3306
|
nextStep: hasQueuedFollowUp
|
|
@@ -3407,6 +3339,7 @@
|
|
|
3407
3339
|
: !hasInput;
|
|
3408
3340
|
runButton.title = label;
|
|
3409
3341
|
runButton.setAttribute('aria-label', label);
|
|
3342
|
+
if (currentRunView?.writebackRetry && hasInput) runButton.disabled = true;
|
|
3410
3343
|
}
|
|
3411
3344
|
|
|
3412
3345
|
function handleTaskInputKeydown(event) {
|
|
@@ -3941,72 +3874,6 @@
|
|
|
3941
3874
|
return writebackController.buildSyncApplyOperations(syncChanges, project);
|
|
3942
3875
|
}
|
|
3943
3876
|
|
|
3944
|
-
function partitionUnsafeProjectPathOperations(operations = []) {
|
|
3945
|
-
const safe = [];
|
|
3946
|
-
const skipped = [];
|
|
3947
|
-
for (const operation of operations || []) {
|
|
3948
|
-
const normalized = normalizeOperationProjectPaths(operation);
|
|
3949
|
-
const invalid = getInvalidOperationProjectPath(normalized);
|
|
3950
|
-
if (invalid) {
|
|
3951
|
-
skipped.push({
|
|
3952
|
-
operation: normalized,
|
|
3953
|
-
result: {
|
|
3954
|
-
ok: false,
|
|
3955
|
-
code: 'invalid_project_path',
|
|
3956
|
-
reason: tx(`Invalid ${invalid}. Codex did not write this file.`, `路径无效:${invalid}。Codex 没有写入这个文件。`)
|
|
3957
|
-
}
|
|
3958
|
-
});
|
|
3959
|
-
continue;
|
|
3960
|
-
}
|
|
3961
|
-
safe.push(normalized);
|
|
3962
|
-
}
|
|
3963
|
-
return { safe, skipped };
|
|
3964
|
-
}
|
|
3965
|
-
|
|
3966
|
-
function normalizeOperationProjectPaths(operation = {}) {
|
|
3967
|
-
if (!operation || typeof operation !== 'object') {
|
|
3968
|
-
return operation;
|
|
3969
|
-
}
|
|
3970
|
-
const normalized = { ...operation };
|
|
3971
|
-
if (typeof operation.path === 'string') {
|
|
3972
|
-
normalized.path = normalizeSafeProjectPath(operation.path);
|
|
3973
|
-
if (!normalized.path) {
|
|
3974
|
-
normalized.invalidProjectPath = true;
|
|
3975
|
-
}
|
|
3976
|
-
}
|
|
3977
|
-
if (typeof operation.to === 'string') {
|
|
3978
|
-
normalized.to = normalizeSafeProjectPath(operation.to);
|
|
3979
|
-
if (!normalized.to) {
|
|
3980
|
-
normalized.invalidProjectDestinationPath = true;
|
|
3981
|
-
}
|
|
3982
|
-
}
|
|
3983
|
-
if (typeof operation.destinationPath === 'string') {
|
|
3984
|
-
normalized.destinationPath = normalizeSafeProjectPath(operation.destinationPath);
|
|
3985
|
-
if (!normalized.destinationPath) {
|
|
3986
|
-
normalized.invalidProjectDestinationPath = true;
|
|
3987
|
-
}
|
|
3988
|
-
}
|
|
3989
|
-
return normalized;
|
|
3990
|
-
}
|
|
3991
|
-
|
|
3992
|
-
function getInvalidOperationProjectPath(operation = {}) {
|
|
3993
|
-
if (operation.invalidProjectPath || (requiresOperationPath(operation) && !operation.path)) {
|
|
3994
|
-
return 'operation path';
|
|
3995
|
-
}
|
|
3996
|
-
if (operation.invalidProjectDestinationPath || (requiresOperationDestinationPath(operation) && !(operation.to || operation.destinationPath))) {
|
|
3997
|
-
return 'operation destination path';
|
|
3998
|
-
}
|
|
3999
|
-
return '';
|
|
4000
|
-
}
|
|
4001
|
-
|
|
4002
|
-
function requiresOperationPath(operation = {}) {
|
|
4003
|
-
return ['edit', 'create', 'delete', 'rename', 'move', 'binary-create', 'overwrite-binary'].includes(operation.type);
|
|
4004
|
-
}
|
|
4005
|
-
|
|
4006
|
-
function requiresOperationDestinationPath(operation = {}) {
|
|
4007
|
-
return operation.type === 'rename' || operation.type === 'move';
|
|
4008
|
-
}
|
|
4009
|
-
|
|
4010
3877
|
function normalizeSafeProjectPath(value) {
|
|
4011
3878
|
if (Modules.ProjectFiles?.normalizeSafeProjectPath) {
|
|
4012
3879
|
return Modules.ProjectFiles.normalizeSafeProjectPath(value);
|
|
@@ -4018,154 +3885,6 @@
|
|
|
4018
3885
|
.replace(/^\/+/, '');
|
|
4019
3886
|
}
|
|
4020
3887
|
|
|
4021
|
-
function evaluateGovernedOperations(operations = []) {
|
|
4022
|
-
if (!GovernanceRules?.evaluateGovernedOperations) {
|
|
4023
|
-
return { allowed: operations || [], blocked: [], rules: getGovernanceRulesForCurrentProject() };
|
|
4024
|
-
}
|
|
4025
|
-
return GovernanceRules.evaluateGovernedOperations(operations, getGovernanceRulesForCurrentProject());
|
|
4026
|
-
}
|
|
4027
|
-
|
|
4028
|
-
function buildGovernanceSkippedApplyResult(blockedItems = []) {
|
|
4029
|
-
return {
|
|
4030
|
-
ok: blockedItems.length === 0,
|
|
4031
|
-
applied: [],
|
|
4032
|
-
skipped: (blockedItems || []).map(item => ({
|
|
4033
|
-
operation: item.operation,
|
|
4034
|
-
result: {
|
|
4035
|
-
ok: false,
|
|
4036
|
-
code: 'governance_blocked',
|
|
4037
|
-
reason: formatGovernanceBlockedReason(item),
|
|
4038
|
-
reasonKey: item.reason || 'governance_blocked'
|
|
4039
|
-
}
|
|
4040
|
-
}))
|
|
4041
|
-
};
|
|
4042
|
-
}
|
|
4043
|
-
|
|
4044
|
-
function formatGovernanceBlockedReason(item = {}) {
|
|
4045
|
-
if (item.reason === 'readonly') {
|
|
4046
|
-
return tx(
|
|
4047
|
-
'Project governance marked this path read-only, so Codex did not write it.',
|
|
4048
|
-
'项目治理规则将此路径标记为只读,因此 Codex 没有写入。'
|
|
4049
|
-
);
|
|
4050
|
-
}
|
|
4051
|
-
if (item.reason === 'writable_allowlist') {
|
|
4052
|
-
return tx(
|
|
4053
|
-
'Project governance allows writes only to configured writable patterns, and this path is outside that allowlist.',
|
|
4054
|
-
'项目治理规则只允许写入配置的可写路径,此路径不在允许范围内。'
|
|
4055
|
-
);
|
|
4056
|
-
}
|
|
4057
|
-
return tx('Project governance blocked this write.', '项目治理规则阻止了此写入。');
|
|
4058
|
-
}
|
|
4059
|
-
|
|
4060
|
-
function filterSyncChangesByOperations(syncChanges = [], operations = []) {
|
|
4061
|
-
const allowedPaths = new Set((operations || []).map(operation => operation.path).filter(Boolean));
|
|
4062
|
-
return (syncChanges || []).filter(change => allowedPaths.has(change?.path));
|
|
4063
|
-
}
|
|
4064
|
-
|
|
4065
|
-
function mergeApplyResultSkipped(result = {}, skipped = []) {
|
|
4066
|
-
if (!skipped.length) {
|
|
4067
|
-
return result;
|
|
4068
|
-
}
|
|
4069
|
-
return {
|
|
4070
|
-
...(result || {}),
|
|
4071
|
-
ok: false,
|
|
4072
|
-
applied: Array.isArray(result?.applied) ? result.applied : [],
|
|
4073
|
-
skipped: [
|
|
4074
|
-
...getSkippedEntries(result),
|
|
4075
|
-
...skipped
|
|
4076
|
-
]
|
|
4077
|
-
};
|
|
4078
|
-
}
|
|
4079
|
-
|
|
4080
|
-
async function confirmBinaryOperations(operations = []) {
|
|
4081
|
-
const binaryOperations = (operations || []).filter(operation => operation.type === 'binary-create' || operation.type === 'overwrite-binary');
|
|
4082
|
-
if (!binaryOperations.length) {
|
|
4083
|
-
return { operations, skipped: [] };
|
|
4084
|
-
}
|
|
4085
|
-
const approved = await showPluginConfirm({
|
|
4086
|
-
title: tr('binaryAssetConfirmTitle'),
|
|
4087
|
-
message: tr('binaryAssetConfirmMessage', { files: formatOperationFiles(binaryOperations) }),
|
|
4088
|
-
confirmLabel: tr('binaryAssetConfirm'),
|
|
4089
|
-
cancelLabel: tr('binaryAssetCancel'),
|
|
4090
|
-
destructive: true
|
|
4091
|
-
});
|
|
4092
|
-
if (approved) {
|
|
4093
|
-
return { operations, skipped: [] };
|
|
4094
|
-
}
|
|
4095
|
-
return {
|
|
4096
|
-
operations: operations.filter(operation => operation.type !== 'binary-create' && operation.type !== 'overwrite-binary'),
|
|
4097
|
-
skipped: binaryOperations.map(operation => ({
|
|
4098
|
-
operation,
|
|
4099
|
-
result: {
|
|
4100
|
-
ok: false,
|
|
4101
|
-
code: 'binary_confirmation_rejected',
|
|
4102
|
-
reason: tx('Binary asset writeback requires explicit confirmation and was skipped.', '二进制资源写回需要显式确认,已跳过。')
|
|
4103
|
-
}
|
|
4104
|
-
}))
|
|
4105
|
-
};
|
|
4106
|
-
}
|
|
4107
|
-
|
|
4108
|
-
function buildAuditDiffSummary(operations = []) {
|
|
4109
|
-
const changedFiles = new Set();
|
|
4110
|
-
let binaryFilesChanged = 0;
|
|
4111
|
-
for (const operation of operations || []) {
|
|
4112
|
-
if (operation?.path) {
|
|
4113
|
-
changedFiles.add(operation.path);
|
|
4114
|
-
}
|
|
4115
|
-
if (operation?.type === 'binary-create' || operation?.type === 'overwrite-binary') {
|
|
4116
|
-
binaryFilesChanged++;
|
|
4117
|
-
}
|
|
4118
|
-
}
|
|
4119
|
-
return {
|
|
4120
|
-
filesChanged: changedFiles.size,
|
|
4121
|
-
additions: 0,
|
|
4122
|
-
deletions: 0,
|
|
4123
|
-
binaryFilesChanged
|
|
4124
|
-
};
|
|
4125
|
-
}
|
|
4126
|
-
|
|
4127
|
-
function buildAuditSummaryFromApply({ operations = [], applyResults = [], blockedFiles = [], resultStatus = 'completed', saveVerification = null } = {}) {
|
|
4128
|
-
const appliedFiles = [];
|
|
4129
|
-
const skippedFiles = [];
|
|
4130
|
-
for (const result of applyResults || []) {
|
|
4131
|
-
for (const item of getAppliedEntries(result)) {
|
|
4132
|
-
appliedFiles.push(summarizeOperationForAudit(item.operation, item.result, 'applied'));
|
|
4133
|
-
}
|
|
4134
|
-
for (const item of getSkippedEntries(result)) {
|
|
4135
|
-
skippedFiles.push(summarizeOperationForAudit(item.operation, item.result, 'skipped'));
|
|
4136
|
-
}
|
|
4137
|
-
}
|
|
4138
|
-
return {
|
|
4139
|
-
changedFiles: (operations || []).map(operation => summarizeOperationForAudit(operation, {}, 'changed')),
|
|
4140
|
-
['diffSummary']: buildAuditDiffSummary(operations),
|
|
4141
|
-
blockedFiles,
|
|
4142
|
-
appliedFiles,
|
|
4143
|
-
skippedFiles,
|
|
4144
|
-
resultStatus,
|
|
4145
|
-
saveVerification
|
|
4146
|
-
};
|
|
4147
|
-
}
|
|
4148
|
-
|
|
4149
|
-
// Tolerates `operation` and `result` being null in addition to undefined.
|
|
4150
|
-
// Default-parameter values fire only for `undefined`, but the v1.3.8
|
|
4151
|
-
// write-guard (pageBridge.runWriteGuard / writebackRouter.checkWritebackRunProjectId)
|
|
4152
|
-
// emits batch-level skips with `operation: null` — there is no specific
|
|
4153
|
-
// op to attribute the block to. Without this normalization the audit pass
|
|
4154
|
-
// crashed with "Cannot read properties of null (reading 'path')", the
|
|
4155
|
-
// outer-catch swallowed the partial-sync conclusion, and the user saw the
|
|
4156
|
-
// misleading "local Codex returned no usable result" fallback.
|
|
4157
|
-
function summarizeOperationForAudit(operation, result, status = '') {
|
|
4158
|
-
const op = operation || {};
|
|
4159
|
-
const res = result || {};
|
|
4160
|
-
return {
|
|
4161
|
-
path: op.path || op.from || op.to || '',
|
|
4162
|
-
destinationPath: op.destinationPath || op.to || '',
|
|
4163
|
-
type: op.type || '',
|
|
4164
|
-
reason: res.reasonKey || res.code || res.reason || op.reasonKey || op.reason || '',
|
|
4165
|
-
status,
|
|
4166
|
-
size: op.size
|
|
4167
|
-
};
|
|
4168
|
-
}
|
|
4169
3888
|
|
|
4170
3889
|
function getSyncChangePatches(change = {}) {
|
|
4171
3890
|
return writebackController.getSyncChangePatches(change);
|
|
@@ -4276,6 +3995,25 @@
|
|
|
4276
3995
|
// saveState. Returning null puts the record in degraded mode and excludes
|
|
4277
3996
|
// it from cross-project queries (spec §5.2 storage rules).
|
|
4278
3997
|
window.codexOverleafDeriveAccountScopeId = () => cachedAccountScopeId;
|
|
3998
|
+
var sharedSessionViewSync = Modules.SharedSessionViewSync.install({
|
|
3999
|
+
Bridge: Modules.SharedSessionBridge,
|
|
4000
|
+
StorageDb: Modules.StorageDb,
|
|
4001
|
+
getScope: () => ({
|
|
4002
|
+
accountScopeId: cachedAccountScopeId,
|
|
4003
|
+
projectId: getCurrentProjectId(),
|
|
4004
|
+
generation: spaRouteGeneration
|
|
4005
|
+
}),
|
|
4006
|
+
getState: () => state,
|
|
4007
|
+
isBusy: () => Boolean(readLiveRunViewForSaveStateGuard() || document.querySelector('dialog[open]')),
|
|
4008
|
+
apply: sessions => {
|
|
4009
|
+
state = normalizePanelState({ ...state, sessions }, { restoreRunningRuns: false });
|
|
4010
|
+
applyStateToPanel();
|
|
4011
|
+
},
|
|
4012
|
+
notice: error => appendStorageNoticeOnce('shared-history-refresh', tx(
|
|
4013
|
+
`Could not refresh shared history: ${error.message}`,
|
|
4014
|
+
`共享会话历史刷新失败:${error.message}`
|
|
4015
|
+
))
|
|
4016
|
+
});
|
|
4279
4017
|
|
|
4280
4018
|
// -----------------------------------------------------------------------
|
|
4281
4019
|
// SPA route change lifecycle (spec §5.7).
|
|
@@ -4369,7 +4107,7 @@
|
|
|
4369
4107
|
try {
|
|
4370
4108
|
storageKey = getProjectStorageKey(LEGACY_STORAGE_KEY, window.location.href);
|
|
4371
4109
|
const reloaded = await loadStoredState();
|
|
4372
|
-
state =
|
|
4110
|
+
state = normalizeLoadedPanelState(reloaded);
|
|
4373
4111
|
applyStateToPanel();
|
|
4374
4112
|
} catch (_error) {
|
|
4375
4113
|
// Reload failures fall back to the in-memory state; the next saveState
|
|
@@ -5018,18 +4756,33 @@
|
|
|
5018
4756
|
button.setAttribute('aria-busy', loading ? 'true' : 'false');
|
|
5019
4757
|
}
|
|
5020
4758
|
|
|
5021
|
-
function
|
|
4759
|
+
function syncProbeStatus(mode = state?.mode) {
|
|
4760
|
+
const status = panel?.querySelector('[data-probe-status]');
|
|
4761
|
+
if (!status) return;
|
|
4762
|
+
if (status.dataset.refreshing === 'true') {
|
|
4763
|
+
status.textContent = tr('refreshProbeLoading');
|
|
4764
|
+
return;
|
|
4765
|
+
}
|
|
4766
|
+
if (probeStatusSnapshot?.projectId !== getCurrentProjectId()) return;
|
|
4767
|
+
const { failed, probe, userInitiated } = probeStatusSnapshot;
|
|
4768
|
+
const text = failed ? tr('refreshProbeFailed') : formatProbeStatusBar(probe, mode);
|
|
4769
|
+
status.textContent = userInitiated && !failed ? tr('refreshProbeDone', { status: text }) : text;
|
|
4770
|
+
status.dataset.ok = !failed && isProbeReadyForCurrentMode(probe, mode) ? 'true' : 'false';
|
|
4771
|
+
if (!failed) updateExistingProbeNotice(probe, mode);
|
|
4772
|
+
}
|
|
4773
|
+
|
|
4774
|
+
function formatProbeStatusBar(probe, mode = state?.mode) {
|
|
5022
4775
|
const readiness = getProbeRunReadiness(probe);
|
|
5023
4776
|
const reviewingOk = readiness.reviewingOk;
|
|
5024
4777
|
const editorWritable = readiness.editorWritable;
|
|
5025
4778
|
|
|
5026
|
-
if (
|
|
4779
|
+
if (mode === 'ask') {
|
|
5027
4780
|
return appendOtStatusToProbeStatus(`${formatModeLabel('ask')} · ${readiness.contextLabel}`);
|
|
5028
4781
|
}
|
|
5029
4782
|
if (reviewingOk) {
|
|
5030
4783
|
const status = editorWritable
|
|
5031
4784
|
? `${tr('canRun')} · ${readiness.contextLabel}`
|
|
5032
|
-
: `${formatModeLabel(
|
|
4785
|
+
: `${formatModeLabel(mode)} · ${tr('validatingEditor')}`;
|
|
5033
4786
|
return appendOtStatusToProbeStatus(status);
|
|
5034
4787
|
}
|
|
5035
4788
|
if (readiness.contextReady) {
|
|
@@ -5059,9 +4812,9 @@
|
|
|
5059
4812
|
status.textContent = appendOtStatusToProbeStatus(base);
|
|
5060
4813
|
}
|
|
5061
4814
|
|
|
5062
|
-
function isProbeReadyForCurrentMode(probe) {
|
|
4815
|
+
function isProbeReadyForCurrentMode(probe, mode = state?.mode) {
|
|
5063
4816
|
const readiness = getProbeRunReadiness(probe);
|
|
5064
|
-
return
|
|
4817
|
+
return mode === 'ask' || readiness.reviewingOk;
|
|
5065
4818
|
}
|
|
5066
4819
|
|
|
5067
4820
|
function getProbeRunReadiness(probe) {
|
|
@@ -5126,22 +4879,22 @@
|
|
|
5126
4879
|
appendLog(message);
|
|
5127
4880
|
}
|
|
5128
4881
|
|
|
5129
|
-
function updateExistingProbeNotice(probe) {
|
|
4882
|
+
function updateExistingProbeNotice(probe, mode = state?.mode) {
|
|
5130
4883
|
if (currentRunView || !panel?.querySelector('[data-probe-notice]')) {
|
|
5131
4884
|
return;
|
|
5132
4885
|
}
|
|
5133
|
-
const { ready, message } = formatProbeUserNotice(probe);
|
|
4886
|
+
const { ready, message } = formatProbeUserNotice(probe, mode);
|
|
5134
4887
|
updateProbeNotice(ready ? '' : message);
|
|
5135
4888
|
}
|
|
5136
4889
|
|
|
5137
|
-
function formatProbeUserNotice(probe) {
|
|
4890
|
+
function formatProbeUserNotice(probe, mode = state?.mode) {
|
|
5138
4891
|
const readiness = getProbeRunReadiness(probe);
|
|
5139
4892
|
const reviewingOk = readiness.reviewingOk;
|
|
5140
4893
|
const editorOk = readiness.editorOk;
|
|
5141
4894
|
const manualOverride = probe.reviewing?.status === 'manual-override';
|
|
5142
4895
|
const editorWriteBlocked = probe.capabilities?.editor?.write === false;
|
|
5143
4896
|
|
|
5144
|
-
if (
|
|
4897
|
+
if (mode === 'ask') {
|
|
5145
4898
|
return {
|
|
5146
4899
|
ready: true,
|
|
5147
4900
|
message: tx(
|
|
@@ -5155,8 +4908,8 @@
|
|
|
5155
4908
|
return {
|
|
5156
4909
|
ready: true,
|
|
5157
4910
|
message: tx(
|
|
5158
|
-
`Ready: ${formatModeLabel(
|
|
5159
|
-
`可以运行:已选择“${formatModeLabel(
|
|
4911
|
+
`Ready: ${formatModeLabel(mode)} is selected. This page has not exposed a writable editor yet; Codex will reopen and verify the target file when writing. If writeback fails, reload Overleaf and retry.`,
|
|
4912
|
+
`可以运行:已选择“${formatModeLabel(mode)}”。当前页面暂时没有暴露可写编辑器,写入时会重新打开目标文件并验证;如果写回失败,再刷新 Overleaf 页面后重试。`
|
|
5160
4913
|
)
|
|
5161
4914
|
};
|
|
5162
4915
|
}
|
|
@@ -5489,6 +5242,9 @@
|
|
|
5489
5242
|
}
|
|
5490
5243
|
|
|
5491
5244
|
async function callPageBridge(method, params) {
|
|
5245
|
+
if (method === 'applyOperations' && params?.reviewingPolicy === 'no-trace-undo') {
|
|
5246
|
+
return Modules.AssetTransferBroker.create({ callPageBridge: (name, input) => pageBridgeClient.call(name, input), sendBackgroundNative }).applyOperations(params);
|
|
5247
|
+
}
|
|
5492
5248
|
return pageBridgeClient.call(method, params);
|
|
5493
5249
|
}
|
|
5494
5250
|
|
|
@@ -5569,7 +5325,7 @@
|
|
|
5569
5325
|
accountScopeId: session.accountScopeId || accountScopeId,
|
|
5570
5326
|
title: session.title || '',
|
|
5571
5327
|
titleSource: session.titleSource || 'auto',
|
|
5572
|
-
focusFiles: session.focusFiles || [],
|
|
5328
|
+
focusFiles: session.focusFiles || [], selectionContext: session.selectionContext?.projectId === projectId ? session.selectionContext : null,
|
|
5573
5329
|
projectReferenceFiles: session.projectReferenceFiles || [],
|
|
5574
5330
|
codexThreadId: session.codexThreadId || '',
|
|
5575
5331
|
createdAt: session.createdAt,
|
|
@@ -5640,6 +5396,8 @@
|
|
|
5640
5396
|
}
|
|
5641
5397
|
|
|
5642
5398
|
async function saveState(options) {
|
|
5399
|
+
const endSharedSave = typeof sharedSessionViewSync !== 'undefined'
|
|
5400
|
+
? sharedSessionViewSync?.beginSave() : null;
|
|
5643
5401
|
try {
|
|
5644
5402
|
const StorageDb = Modules.StorageDb;
|
|
5645
5403
|
const Migration = Modules.StorageMigration;
|
|
@@ -5666,7 +5424,7 @@
|
|
|
5666
5424
|
const urlProjectId = getCurrentProjectId();
|
|
5667
5425
|
const projectId = projectIdOverride || urlProjectId;
|
|
5668
5426
|
if (!projectId) {
|
|
5669
|
-
return;
|
|
5427
|
+
if (options?.reviewRunIds?.length) throw new Error('Review persistence lost its project.'); return;
|
|
5670
5428
|
}
|
|
5671
5429
|
// Read currentRunView through a defensive accessor so historical test
|
|
5672
5430
|
// harnesses that inline `saveState` without re-declaring the module-
|
|
@@ -5678,7 +5436,7 @@
|
|
|
5678
5436
|
'Skipped saveState: run is in flight on a different project than the current URL; settlement owns persistence.',
|
|
5679
5437
|
'已跳过 saveState:本次运行所属项目与当前 URL 不一致,写回由 settlement 负责。'
|
|
5680
5438
|
));
|
|
5681
|
-
return;
|
|
5439
|
+
if (options?.reviewRunIds?.length) throw new Error('Review persistence project changed.'); return;
|
|
5682
5440
|
}
|
|
5683
5441
|
const compactState = prepareStateForStorage(state, { onAggressive: notifyAggressiveCompactionOnce });
|
|
5684
5442
|
compactState.autoRecompile = state.autoRecompile;
|
|
@@ -5699,7 +5457,7 @@
|
|
|
5699
5457
|
state: stateSnapshot,
|
|
5700
5458
|
compactState: compactStateSnapshot,
|
|
5701
5459
|
projectId,
|
|
5702
|
-
deletedSessionIds: options?.deletedSessionIds,
|
|
5460
|
+
deletedSessionIds: options?.deletedSessionIds, reviewRunIds: options?.reviewRunIds,
|
|
5703
5461
|
Migration,
|
|
5704
5462
|
StorageDb,
|
|
5705
5463
|
SessionPersistence: Modules.SessionPersistence,
|
|
@@ -5727,7 +5485,7 @@
|
|
|
5727
5485
|
persistScopedState
|
|
5728
5486
|
);
|
|
5729
5487
|
if (!committed.ok && (
|
|
5730
|
-
options?.queueMutation
|
|
5488
|
+
options?.reviewRunIds?.length || options?.queueMutation
|
|
5731
5489
|
|| options?.queueMutations?.length
|
|
5732
5490
|
|| committed.reason !== 'stale_view'
|
|
5733
5491
|
)) {
|
|
@@ -5739,12 +5497,12 @@
|
|
|
5739
5497
|
} catch (error) {
|
|
5740
5498
|
if (
|
|
5741
5499
|
error?.code === 'account_scope_unavailable' &&
|
|
5742
|
-
!options?.queueMutation &&
|
|
5500
|
+
!options?.reviewRunIds?.length && !options?.queueMutation &&
|
|
5743
5501
|
!(Array.isArray(options?.queueMutations) && options.queueMutations.length)
|
|
5744
5502
|
) {
|
|
5745
5503
|
return;
|
|
5746
5504
|
}
|
|
5747
|
-
if (options?.queueMutation || options?.queueMutations?.length) {
|
|
5505
|
+
if (options?.reviewRunIds?.length || options?.queueMutation || options?.queueMutations?.length) {
|
|
5748
5506
|
throw error;
|
|
5749
5507
|
}
|
|
5750
5508
|
let fallbackError = null;
|
|
@@ -5768,6 +5526,8 @@
|
|
|
5768
5526
|
} else {
|
|
5769
5527
|
throw error;
|
|
5770
5528
|
}
|
|
5529
|
+
} finally {
|
|
5530
|
+
endSharedSave?.();
|
|
5771
5531
|
}
|
|
5772
5532
|
}
|
|
5773
5533
|
|
|
@@ -5869,6 +5629,7 @@
|
|
|
5869
5629
|
// here (e.g. fallback chrome.storage.local.set rethrew).
|
|
5870
5630
|
emitStorageQuotaFailure(error, null);
|
|
5871
5631
|
}
|
|
5632
|
+
if (persistenceOptions?.reviewRunIds?.length) throw error;
|
|
5872
5633
|
appendPlainLog(tx(`Failed to save session state: ${formatStateSaveError(error)}`, `保存会话状态失败:${formatStateSaveError(error)}`));
|
|
5873
5634
|
})
|
|
5874
5635
|
.finally(() => {
|
|
@@ -5923,6 +5684,7 @@
|
|
|
5923
5684
|
...(current || {}),
|
|
5924
5685
|
...incoming,
|
|
5925
5686
|
queueMutation: undefined,
|
|
5687
|
+
reviewRunIds: Array.from(new Set([...(current?.reviewRunIds || []), ...(incoming?.reviewRunIds || [])])),
|
|
5926
5688
|
queueMutations,
|
|
5927
5689
|
deletedSessionIds: Array.from(new Set([
|
|
5928
5690
|
...(current?.deletedSessionIds || []),
|
|
@@ -6002,6 +5764,7 @@
|
|
|
6002
5764
|
button.dataset.active = active ? 'true' : 'false';
|
|
6003
5765
|
button.setAttribute('aria-pressed', active ? 'true' : 'false');
|
|
6004
5766
|
});
|
|
5767
|
+
syncProbeStatus(currentMode);
|
|
6005
5768
|
}
|
|
6006
5769
|
|
|
6007
5770
|
function readPanelInputs() {
|
|
@@ -6075,11 +5838,14 @@
|
|
|
6075
5838
|
}
|
|
6076
5839
|
composerSkillInvocation = null;
|
|
6077
5840
|
renderComposerSkillInvocation();
|
|
5841
|
+
selectionContextView.clear();
|
|
6078
5842
|
state = updateActiveSession(state, { task: '' });
|
|
6079
5843
|
saveStateSoon();
|
|
6080
5844
|
}
|
|
6081
5845
|
|
|
6082
5846
|
function applyStateToPanel(options = {}) {
|
|
5847
|
+
selectionContextView.render();
|
|
5848
|
+
writingStyleSettings.sync();
|
|
6083
5849
|
applyPanelTheme(getThemePreference());
|
|
6084
5850
|
if ((state.providerId || 'builtin') === 'builtin' && !modelSelectHasOption(state.model)) {
|
|
6085
5851
|
renderModelOptions(getModelCatalog().FALLBACK_MODELS, state.model);
|
|
@@ -6157,17 +5923,38 @@
|
|
|
6157
5923
|
}
|
|
6158
5924
|
panel.dataset.running = running ? 'true' : 'false';
|
|
6159
5925
|
panel.dataset.cancelling = running && runCancellationRequested ? 'true' : 'false';
|
|
5926
|
+
panel.querySelectorAll('[data-run-id]').forEach(root => {
|
|
5927
|
+
const record = findRunRecord(root.dataset.runId);
|
|
5928
|
+
if (record) configureEditButton(root, record, { running });
|
|
5929
|
+
if (record) configureWritebackButton(root, record, { running });
|
|
5930
|
+
});
|
|
6160
5931
|
renderPendingInputs();
|
|
6161
5932
|
}
|
|
6162
5933
|
|
|
6163
|
-
function prepareRetryReplacement(run) {
|
|
5934
|
+
function prepareRetryReplacement(run, task) {
|
|
6164
5935
|
const sessionId = state?.activeSessionId || '';
|
|
6165
5936
|
const source = findRunRecord(run?.id, sessionId);
|
|
6166
|
-
const eligible = source &&
|
|
5937
|
+
const eligible = source && !source.forkSnapshot
|
|
5938
|
+
&& (!source.runProjectId || source.runProjectId === getCurrentProjectId())
|
|
5939
|
+
&& runController.isRetryReplacementEligible(
|
|
6167
5940
|
source,
|
|
6168
5941
|
WritebackSettlement.projectRunSettlement(source)
|
|
6169
5942
|
);
|
|
6170
|
-
|
|
5943
|
+
const returnToDraft = eligible && !currentRunView
|
|
5944
|
+
&& ['cancelled', 'rejected'].includes(source.status);
|
|
5945
|
+
const draft = { task: typeof task === 'string' ? task : String(run?.task || '') };
|
|
5946
|
+
if (returnToDraft) {
|
|
5947
|
+
const snapshot = source.executionSnapshot || {};
|
|
5948
|
+
const mode = snapshot.mode || source.mode;
|
|
5949
|
+
draft.runs = (state.runs || []).filter(item => item.id !== source.id);
|
|
5950
|
+
draft.mode = ['ask', 'auto'].includes(mode) ? mode : state.mode;
|
|
5951
|
+
draft.focusFiles = Array.isArray(snapshot.focusFiles) ? snapshot.focusFiles : state.focusFiles;
|
|
5952
|
+
draft.selectionContext = snapshot.selectionContext || null;
|
|
5953
|
+
}
|
|
5954
|
+
// Persist the composer through its session owner, not only the top-level alias.
|
|
5955
|
+
state = updateActiveSession(state, draft);
|
|
5956
|
+
pendingRetryReplacement = eligible && !returnToDraft ? { sessionId, runId: source.id } : null;
|
|
5957
|
+
if (returnToDraft) applyStateToPanel({ preserveScroll: true });
|
|
6171
5958
|
return Boolean(eligible);
|
|
6172
5959
|
}
|
|
6173
5960
|
|
|
@@ -6344,6 +6131,17 @@
|
|
|
6344
6131
|
return;
|
|
6345
6132
|
}
|
|
6346
6133
|
|
|
6134
|
+
const owner = currentRunView && findRunRecord(currentRunView.recordId, currentRunView.sessionId);
|
|
6135
|
+
if (owner && Modules.SubagentActivityModel.ingest(owner, event, {
|
|
6136
|
+
locale: getLocale(), sanitize: sanitizeAssistantVisibleText, nativeEventSeq: journalSeq
|
|
6137
|
+
})) {
|
|
6138
|
+
owner.nativeEventSeq = Math.max(Number(owner.nativeEventSeq || 0), Number(journalSeq || 0));
|
|
6139
|
+
scheduleRunStateSave('stream');
|
|
6140
|
+
const visible = getCurrentRunViewForRender();
|
|
6141
|
+
if (visible) runTimelineView.refreshActivitySummary?.(visible);
|
|
6142
|
+
return;
|
|
6143
|
+
}
|
|
6144
|
+
|
|
6347
6145
|
const activity = mapAgentEventToActivity(event, { locale: getLocale() });
|
|
6348
6146
|
if (!activity?.visible || activity.kind === 'technical') {
|
|
6349
6147
|
return;
|
|
@@ -6413,9 +6211,11 @@
|
|
|
6413
6211
|
kind: input.kind || 'activity',
|
|
6414
6212
|
subagent: input.subagent === true ? true : undefined,
|
|
6415
6213
|
technicalDetail: sanitizeAssistantVisibleValue(input.technicalDetail),
|
|
6214
|
+
activity: Modules.RunActivityModel.capture(input, sanitizeAssistantVisibleText),
|
|
6416
6215
|
guidanceId: sanitizeAssistantVisibleText(input.guidanceId),
|
|
6417
6216
|
streamKey: sanitizeAssistantVisibleText(input.streamKey),
|
|
6418
6217
|
streamRole: sanitizeAssistantVisibleText(input.streamRole),
|
|
6218
|
+
streamPhase: sanitizeAssistantVisibleText(input.streamPhase),
|
|
6419
6219
|
appendText: typeof input.appendText === 'string' ? sanitizeAssistantVisibleText(input.appendText) : input.appendText,
|
|
6420
6220
|
replaceText: input.replaceText,
|
|
6421
6221
|
// Structured FailureReason (§7) attached to the event when the caller
|
|
@@ -6529,6 +6329,7 @@
|
|
|
6529
6329
|
}
|
|
6530
6330
|
|
|
6531
6331
|
function appendRunEventToView(view, event) {
|
|
6332
|
+
const projected = event.kind !== 'stream' && runTimelineView.refreshActivitySummary?.(view, event);
|
|
6532
6333
|
if (event.kind === 'report') {
|
|
6533
6334
|
view.report.hidden = false;
|
|
6534
6335
|
const record = view?.recordId ? findRunRecord(view.recordId, view.sessionId) : null;
|
|
@@ -6539,6 +6340,7 @@
|
|
|
6539
6340
|
if (event.kind === 'technical') {
|
|
6540
6341
|
return;
|
|
6541
6342
|
}
|
|
6343
|
+
if (projected) { bumpUnreadIfDetached(); return; }
|
|
6542
6344
|
if (runGuidanceController.appendToView(event, view)) return;
|
|
6543
6345
|
if (event.kind === 'stream') {
|
|
6544
6346
|
// Stream deltas update an existing line in place — they must not inflate
|
|
@@ -6546,7 +6348,7 @@
|
|
|
6546
6348
|
upsertStreamEvent(view, event);
|
|
6547
6349
|
return;
|
|
6548
6350
|
}
|
|
6549
|
-
|
|
6351
|
+
runTimelineView.appendActivityDetail(view, renderRunEvent(event), event);
|
|
6550
6352
|
bumpUnreadIfDetached();
|
|
6551
6353
|
}
|
|
6552
6354
|
|
|
@@ -6557,6 +6359,7 @@
|
|
|
6557
6359
|
if (existing) {
|
|
6558
6360
|
const nextTitle = sanitizeAssistantVisibleText(event.title);
|
|
6559
6361
|
const nextRole = sanitizeAssistantVisibleText(event.streamRole) || existing.streamRole;
|
|
6362
|
+
if (event.streamPhase) existing.streamPhase = event.streamPhase;
|
|
6560
6363
|
const combinedTitle = event.replaceText
|
|
6561
6364
|
? nextTitle
|
|
6562
6365
|
: sanitizeAssistantVisibleText(appendStreamText(existing.title, nextTitle));
|
|
@@ -6616,10 +6419,6 @@
|
|
|
6616
6419
|
}
|
|
6617
6420
|
|
|
6618
6421
|
|
|
6619
|
-
|
|
6620
|
-
|
|
6621
|
-
|
|
6622
|
-
|
|
6623
6422
|
function applyPanelWidth(width, options = {}) {
|
|
6624
6423
|
const nextWidth = PanelRenderer.setWidth(panelRendererInstance, width, { notify: false });
|
|
6625
6424
|
if (state) {
|
|
@@ -6631,10 +6430,6 @@
|
|
|
6631
6430
|
return nextWidth;
|
|
6632
6431
|
}
|
|
6633
6432
|
|
|
6634
|
-
|
|
6635
|
-
|
|
6636
|
-
|
|
6637
|
-
|
|
6638
6433
|
function getCurrentProjectMathSources() {
|
|
6639
6434
|
const sources = [];
|
|
6640
6435
|
const seen = new Set();
|
|
@@ -6810,7 +6605,8 @@
|
|
|
6810
6605
|
await pendingMirror.catch(() => {});
|
|
6811
6606
|
}
|
|
6812
6607
|
|
|
6813
|
-
if ((Array.isArray(run.undoTrackedChanges) && run.undoTrackedChanges.length) || hasTrackedEditorUndo(run)
|
|
6608
|
+
if ((Array.isArray(run.undoTrackedChanges) && run.undoTrackedChanges.length) || hasTrackedEditorUndo(run)
|
|
6609
|
+
|| (run.trackedChangeStatus === 'needs_review' && run.undoOperations?.some(operation => operation?.undoCreatedFile?.v === 1))) {
|
|
6814
6610
|
await undoRunTrackedChanges(runId, run);
|
|
6815
6611
|
return;
|
|
6816
6612
|
}
|
|
@@ -6868,6 +6664,7 @@
|
|
|
6868
6664
|
}
|
|
6869
6665
|
}
|
|
6870
6666
|
|
|
6667
|
+
const deadlineAt = Date.now() + getPageBridgeTimeoutMs('rejectTrackedChanges');
|
|
6871
6668
|
setRunUndoStatus(runId, 'running');
|
|
6872
6669
|
appendRunRecordEvent(runId, {
|
|
6873
6670
|
title: tr('undoNoTraceStarted'),
|
|
@@ -6876,12 +6673,10 @@
|
|
|
6876
6673
|
});
|
|
6877
6674
|
|
|
6878
6675
|
const result = await callPageBridge('applyOperations', {
|
|
6879
|
-
operations: selectedOperations,
|
|
6676
|
+
operations: selectedOperations, deadlineAt,
|
|
6880
6677
|
baseFiles: run.undoBaseFiles || [],
|
|
6881
6678
|
reviewingPolicy: 'no-trace-undo',
|
|
6882
|
-
//
|
|
6883
|
-
// route the undo through the same project-ID guard. The undo is
|
|
6884
|
-
// bound to the run's original project, not the editor's active one.
|
|
6679
|
+
// Undo remains bound to its original project, including after navigation.
|
|
6885
6680
|
runProjectId: getRunProjectIdForWriteback(run)
|
|
6886
6681
|
});
|
|
6887
6682
|
const undoApplied = isUndoResultEffectivelyApplied(run, result);
|
|
@@ -6913,15 +6708,18 @@
|
|
|
6913
6708
|
}
|
|
6914
6709
|
|
|
6915
6710
|
async function undoRunTrackedChanges(runId, run) {
|
|
6711
|
+
const createdUndoOperations = (run.undoOperations || []).filter(operation => operation?.undoCreatedFile?.v === 1);
|
|
6916
6712
|
const trackedUndo = Array.isArray(run.undoTrackedChanges) && run.undoTrackedChanges.length > 0;
|
|
6713
|
+
const hasTextUndo = trackedUndo || buildTrackedUndoPostFiles(run).length > 0;
|
|
6917
6714
|
const approved = await showPluginConfirm({
|
|
6918
|
-
title: trackedUndo ? tr('undoTrackedTitle') : tr('undoNativeTitle'),
|
|
6715
|
+
title: !hasTextUndo ? tr('undoNoTraceTitle') : trackedUndo ? tr('undoTrackedTitle') : tr('undoNativeTitle'),
|
|
6919
6716
|
message: [
|
|
6920
6717
|
truncateRunTitle(run.task),
|
|
6921
6718
|
'',
|
|
6922
|
-
trackedUndo
|
|
6719
|
+
...(hasTextUndo ? [trackedUndo
|
|
6923
6720
|
? tr('undoTrackedMessage', { files: formatTrackedChangeFiles(run.undoTrackedChanges) })
|
|
6924
|
-
: tr('undoNativeMessage', { files: formatTrackedUndoFiles(run) })
|
|
6721
|
+
: tr('undoNativeMessage', { files: formatTrackedUndoFiles(run) })] : []),
|
|
6722
|
+
...(createdUndoOperations.length ? [tr('undoNoTraceMessage', { files: formatOperationFiles(createdUndoOperations) })] : [])
|
|
6925
6723
|
].join('\n'),
|
|
6926
6724
|
confirmLabel: trackedUndo ? tr('undoTrackedConfirm') : tr('undoConfirm'),
|
|
6927
6725
|
cancelLabel: tr('confirmDefaultCancel'),
|
|
@@ -6931,10 +6729,10 @@
|
|
|
6931
6729
|
return;
|
|
6932
6730
|
}
|
|
6933
6731
|
|
|
6934
|
-
|
|
6935
|
-
//
|
|
6936
|
-
//
|
|
6937
|
-
const lifecycleReject = trackedUndo && isTrackedChangeLifecycleRun(run);
|
|
6732
|
+
const deadlineAt = Date.now() + getPageBridgeTimeoutMs('rejectTrackedChanges');
|
|
6733
|
+
// Keep the review lifecycle until every pending part has settled.
|
|
6734
|
+
// Its local lock stays active while verified recovery progress is persisted.
|
|
6735
|
+
const lifecycleReject = (trackedUndo || createdUndoOperations.length > 0) && isTrackedChangeLifecycleRun(run);
|
|
6938
6736
|
if (lifecycleReject) {
|
|
6939
6737
|
trackedChangeInFlight.set(runId, 'reject');
|
|
6940
6738
|
refreshRunCardControls(runId);
|
|
@@ -6942,60 +6740,90 @@
|
|
|
6942
6740
|
setRunUndoStatus(runId, 'running');
|
|
6943
6741
|
}
|
|
6944
6742
|
appendRunRecordEvent(runId, {
|
|
6945
|
-
title: trackedUndo ? tr('undoTrackedStarted') : tr('undoNativeStarted'),
|
|
6743
|
+
title: !hasTextUndo ? tr('undoNoTraceStarted') : trackedUndo ? tr('undoTrackedStarted') : tr('undoNativeStarted'),
|
|
6946
6744
|
status: 'running',
|
|
6947
|
-
detail: { [tr('detailWillUndo')]:
|
|
6745
|
+
detail: { [tr('detailWillUndo')]: !hasTextUndo ? formatOperationFiles(createdUndoOperations)
|
|
6746
|
+
: trackedUndo ? formatTrackedChangeFiles(run.undoTrackedChanges) : formatTrackedUndoFiles(run) }
|
|
6948
6747
|
});
|
|
6949
6748
|
|
|
6950
|
-
let result;
|
|
6951
|
-
let trackedUndoPostFilesAtDispatch;
|
|
6952
6749
|
try {
|
|
6953
|
-
trackedUndoPostFilesAtDispatch = buildTrackedUndoPostFiles(run);
|
|
6954
|
-
result = await callPageBridge('rejectTrackedChanges', {
|
|
6955
|
-
trackedChanges: run.undoTrackedChanges || [],
|
|
6750
|
+
const trackedUndoPostFilesAtDispatch = buildTrackedUndoPostFiles(run);
|
|
6751
|
+
let result = hasTextUndo ? await callPageBridge('rejectTrackedChanges', {
|
|
6752
|
+
trackedChanges: run.undoTrackedChanges || [], deadlineAt,
|
|
6956
6753
|
expectedFiles: run.undoExpectedFiles || [],
|
|
6957
6754
|
postFiles: trackedUndoPostFilesAtDispatch,
|
|
6958
6755
|
untrackedUndo: run.executionSnapshot
|
|
6959
6756
|
? run.executionSnapshot.requireReviewing === false && ['submitted', 'legacy-captured'].includes(run.executionSnapshot.source)
|
|
6960
6757
|
: getTrackedChangeCaptureController().hasLegacyUntrackedCheckpoint(run),
|
|
6961
|
-
//
|
|
6962
|
-
// bind the reject to the run's original project. If the user has
|
|
6963
|
-
// navigated away the page-side guard refuses with
|
|
6964
|
-
// `aborted_project_changed` and the document is left untouched.
|
|
6758
|
+
// The page-side project guard still refuses writes after navigation.
|
|
6965
6759
|
runProjectId: getRunProjectIdForWriteback(run)
|
|
6760
|
+
}) : { ok: true, applied: [], skipped: [] };
|
|
6761
|
+
if (createdUndoOperations.length && lifecycleReject && hasTextUndo) {
|
|
6762
|
+
WritebackSettlement.attachUndoNotVerifiedFailure(run, result, { buildFailure: buildContentFailure, postFiles: trackedUndoPostFilesAtDispatch });
|
|
6763
|
+
await applyTrackedChangeSettlement(runId, 'reject', { ...result, ok: false });
|
|
6764
|
+
}
|
|
6765
|
+
if (createdUndoOperations.length) {
|
|
6766
|
+
let createdResult;
|
|
6767
|
+
try {
|
|
6768
|
+
if (result.ok === false || result.skipped?.length) {
|
|
6769
|
+
throw new Error('Text changes remain unresolved; created files were kept for the next undo attempt.');
|
|
6770
|
+
}
|
|
6771
|
+
createdResult = await callPageBridge('applyOperations', {
|
|
6772
|
+
operations: createdUndoOperations, deadlineAt,
|
|
6773
|
+
baseFiles: run.undoBaseFiles || [],
|
|
6774
|
+
reviewingPolicy: 'no-trace-undo',
|
|
6775
|
+
runProjectId: getRunProjectIdForWriteback(run)
|
|
6776
|
+
});
|
|
6777
|
+
} catch (error) {
|
|
6778
|
+
createdResult = { ok: false, applied: [], skipped: createdUndoOperations.map(operation => ({
|
|
6779
|
+
operation, result: { ok: false, code: 'undo_operation_failed', reason: error.message }
|
|
6780
|
+
})) };
|
|
6781
|
+
}
|
|
6782
|
+
const applied = [...(result.applied || []), ...(createdResult.applied || [])];
|
|
6783
|
+
const skipped = [...(result.skipped || []), ...(createdResult.skipped || [])];
|
|
6784
|
+
for (const operation of createdUndoOperations) {
|
|
6785
|
+
if (!(createdResult.applied || []).some(entry => entry.operation?.path === operation.path
|
|
6786
|
+
&& entry.result?.ok === true && entry.result?.verified === true)
|
|
6787
|
+
&& !(createdResult.skipped || []).some(entry => entry.operation?.path === operation.path)) {
|
|
6788
|
+
skipped.push({ operation, result: { ok: false, code: 'undo_operation_failed',
|
|
6789
|
+
reason: 'The created file has no verified deletion receipt.' } });
|
|
6790
|
+
}
|
|
6791
|
+
}
|
|
6792
|
+
result = { ...result, ok: result.ok !== false && createdResult.ok !== false && !skipped.length, applied, skipped };
|
|
6793
|
+
}
|
|
6794
|
+
writebackOrchestrator.invalidateMirrorAfterUndo(runId, getRunProjectIdForWriteback(run), result);
|
|
6795
|
+
appendRunRecordEvent(runId, {
|
|
6796
|
+
title: createdUndoOperations.length ? tr('undoResult', { applied: result.applied?.length || 0, skipped: result.skipped?.length || 0 }) : trackedUndo
|
|
6797
|
+
? tr('undoTrackedResult', { applied: result.applied?.length || 0, skipped: result.skipped?.length || 0 })
|
|
6798
|
+
: tr('undoNativeResult', { applied: result.applied?.length || 0, skipped: result.skipped?.length || 0 }),
|
|
6799
|
+
status: result.skipped?.length ? 'failed' : 'completed',
|
|
6800
|
+
detail: {
|
|
6801
|
+
[trackedUndo && !createdUndoOperations.length ? tr('detailRejected') : tr('detailUndone')]: (result.applied || []).map(item => ({
|
|
6802
|
+
[tr('detailFile')]: item.trackedChange?.path || item.operation?.path || tr('unknownFile'),
|
|
6803
|
+
[tr('detailRecord')]: item.trackedChange?.label || item.trackedChange?.id || item.trackedChange?.key || item.operation?.type
|
|
6804
|
+
})),
|
|
6805
|
+
[tr('detailSkipped')]: (result.skipped || []).map(item => ({
|
|
6806
|
+
[tr('detailFile')]: item.trackedChange?.path || item.operation?.path || tr('unknownFile'),
|
|
6807
|
+
[tr('detailRecord')]: item.trackedChange?.label || item.trackedChange?.id || item.trackedChange?.key || item.operation?.type || '',
|
|
6808
|
+
[tr('detailReason')]: formatBridgeResultReason(item.result, item.trackedChange?.path || item.operation?.path)
|
|
6809
|
+
}))
|
|
6810
|
+
}
|
|
6966
6811
|
});
|
|
6812
|
+
if (lifecycleReject) {
|
|
6813
|
+
WritebackSettlement.attachUndoNotVerifiedFailure(run, result, {
|
|
6814
|
+
buildFailure: buildContentFailure,
|
|
6815
|
+
postFiles: trackedUndoPostFilesAtDispatch
|
|
6816
|
+
});
|
|
6817
|
+
await applyTrackedChangeSettlement(runId, 'reject', result);
|
|
6818
|
+
return;
|
|
6819
|
+
}
|
|
6820
|
+
applyLegacyUndoSettlement(runId, result.skipped?.length ? 'partial' : 'applied', result);
|
|
6967
6821
|
} finally {
|
|
6968
6822
|
if (lifecycleReject) {
|
|
6969
6823
|
trackedChangeInFlight.delete(runId);
|
|
6824
|
+
refreshRunCardControls(runId);
|
|
6970
6825
|
}
|
|
6971
6826
|
}
|
|
6972
|
-
writebackOrchestrator.invalidateMirrorAfterUndo(runId, getRunProjectIdForWriteback(run), result);
|
|
6973
|
-
appendRunRecordEvent(runId, {
|
|
6974
|
-
title: trackedUndo
|
|
6975
|
-
? tr('undoTrackedResult', { applied: result.applied?.length || 0, skipped: result.skipped?.length || 0 })
|
|
6976
|
-
: tr('undoNativeResult', { applied: result.applied?.length || 0, skipped: result.skipped?.length || 0 }),
|
|
6977
|
-
status: result.skipped?.length ? 'failed' : 'completed',
|
|
6978
|
-
detail: {
|
|
6979
|
-
[trackedUndo ? tr('detailRejected') : tr('detailUndone')]: (result.applied || []).map(item => ({
|
|
6980
|
-
[tr('detailFile')]: item.trackedChange?.path || tr('unknownFile'),
|
|
6981
|
-
[tr('detailRecord')]: item.trackedChange?.label || item.trackedChange?.id || item.trackedChange?.key
|
|
6982
|
-
})),
|
|
6983
|
-
[tr('detailSkipped')]: (result.skipped || []).map(item => ({
|
|
6984
|
-
[tr('detailFile')]: item.trackedChange?.path || tr('unknownFile'),
|
|
6985
|
-
[tr('detailRecord')]: item.trackedChange?.label || item.trackedChange?.id || item.trackedChange?.key || '',
|
|
6986
|
-
[tr('detailReason')]: formatBridgeResultReason(item.result, item.trackedChange?.path)
|
|
6987
|
-
}))
|
|
6988
|
-
}
|
|
6989
|
-
});
|
|
6990
|
-
if (lifecycleReject) {
|
|
6991
|
-
WritebackSettlement.attachUndoNotVerifiedFailure(run, result, {
|
|
6992
|
-
buildFailure: buildContentFailure,
|
|
6993
|
-
postFiles: trackedUndoPostFilesAtDispatch
|
|
6994
|
-
});
|
|
6995
|
-
applyTrackedChangeSettlement(runId, 'reject', result);
|
|
6996
|
-
return;
|
|
6997
|
-
}
|
|
6998
|
-
applyLegacyUndoSettlement(runId, result.skipped?.length ? 'partial' : 'applied', result);
|
|
6999
6827
|
}
|
|
7000
6828
|
|
|
7001
6829
|
async function acceptRun(runId) {
|
|
@@ -7025,50 +6853,50 @@
|
|
|
7025
6853
|
detail: { [tr('detailAccepted')]: formatTrackedChangeFiles(run.undoTrackedChanges) }
|
|
7026
6854
|
});
|
|
7027
6855
|
|
|
7028
|
-
let result;
|
|
7029
6856
|
try {
|
|
7030
|
-
result = await callPageBridge('acceptTrackedChanges', {
|
|
6857
|
+
const result = await callPageBridge('acceptTrackedChanges', {
|
|
7031
6858
|
trackedChanges: run.undoTrackedChanges || [],
|
|
7032
6859
|
expectedFiles: run.undoExpectedFiles || [],
|
|
7033
6860
|
postFiles: buildTrackedUndoPostFiles(run),
|
|
7034
6861
|
appliedOperations: Array.isArray(run.appliedOperations) ? run.appliedOperations : [],
|
|
7035
6862
|
runProjectId: getRunProjectIdForWriteback(run)
|
|
7036
6863
|
});
|
|
7037
|
-
|
|
7038
|
-
trackedChangeInFlight.delete(runId);
|
|
7039
|
-
}
|
|
7040
|
-
appendAcceptDiagnosticEvents(runId, Array.isArray(result.diagnostics) ? result.diagnostics : []);
|
|
7041
|
-
appendRunRecordEvent(runId, {
|
|
7042
|
-
title: tr('runAcceptTrackedResult', { applied: result.applied?.length || 0, skipped: result.skipped?.length || 0 }),
|
|
7043
|
-
status: result.skipped?.length ? 'failed' : 'completed',
|
|
7044
|
-
detail: {
|
|
7045
|
-
[tr('detailAccepted')]: (result.applied || []).map(item => ({
|
|
7046
|
-
[tr('detailFile')]: item.trackedChange?.path || tr('unknownFile'),
|
|
7047
|
-
[tr('detailRecord')]: item.trackedChange?.label || item.trackedChange?.id || item.trackedChange?.key
|
|
7048
|
-
})),
|
|
7049
|
-
[tr('detailSkipped')]: (result.skipped || []).map(item => ({
|
|
7050
|
-
[tr('detailFile')]: item.trackedChange?.path || tr('unknownFile'),
|
|
7051
|
-
[tr('detailRecord')]: item.trackedChange?.label || item.trackedChange?.id || item.trackedChange?.key || '',
|
|
7052
|
-
[tr('detailReason')]: formatBridgeResultReason(item.result, item.trackedChange?.path)
|
|
7053
|
-
}))
|
|
7054
|
-
}
|
|
7055
|
-
});
|
|
7056
|
-
if (result.ok === false) {
|
|
6864
|
+
appendAcceptDiagnosticEvents(runId, Array.isArray(result.diagnostics) ? result.diagnostics : []);
|
|
7057
6865
|
appendRunRecordEvent(runId, {
|
|
7058
|
-
title: tr('
|
|
7059
|
-
status: 'failed',
|
|
6866
|
+
title: tr('runAcceptTrackedResult', { applied: result.applied?.length || 0, skipped: result.skipped?.length || 0 }),
|
|
6867
|
+
status: result.skipped?.length ? 'failed' : 'completed',
|
|
7060
6868
|
detail: {
|
|
7061
|
-
[tr('
|
|
6869
|
+
[tr('detailAccepted')]: (result.applied || []).map(item => ({
|
|
6870
|
+
[tr('detailFile')]: item.trackedChange?.path || tr('unknownFile'),
|
|
6871
|
+
[tr('detailRecord')]: item.trackedChange?.label || item.trackedChange?.id || item.trackedChange?.key
|
|
6872
|
+
})),
|
|
6873
|
+
[tr('detailSkipped')]: (result.skipped || []).map(item => ({
|
|
6874
|
+
[tr('detailFile')]: item.trackedChange?.path || tr('unknownFile'),
|
|
6875
|
+
[tr('detailRecord')]: item.trackedChange?.label || item.trackedChange?.id || item.trackedChange?.key || '',
|
|
6876
|
+
[tr('detailReason')]: formatBridgeResultReason(item.result, item.trackedChange?.path)
|
|
6877
|
+
}))
|
|
7062
6878
|
}
|
|
7063
6879
|
});
|
|
7064
|
-
if (
|
|
7065
|
-
|
|
6880
|
+
if (result.ok === false) {
|
|
6881
|
+
appendRunRecordEvent(runId, {
|
|
6882
|
+
title: tr('runAcceptTrackedFailed'),
|
|
6883
|
+
status: 'failed',
|
|
6884
|
+
detail: {
|
|
6885
|
+
[tr('detailReason')]: tr('runAcceptTrackedFailedReason')
|
|
6886
|
+
}
|
|
6887
|
+
});
|
|
6888
|
+
if (!WritebackSettlement.isSuccessfulTrackedChangeSettlement(result)) {
|
|
6889
|
+
refreshRunCardControls(runId);
|
|
6890
|
+
}
|
|
7066
6891
|
}
|
|
6892
|
+
WritebackSettlement.attachAcceptNotVerifiedFailure(run, result, {
|
|
6893
|
+
buildFailure: buildContentFailure
|
|
6894
|
+
});
|
|
6895
|
+
await applyTrackedChangeSettlement(runId, 'accept', result);
|
|
6896
|
+
} finally {
|
|
6897
|
+
trackedChangeInFlight.delete(runId);
|
|
6898
|
+
refreshRunCardControls(runId);
|
|
7067
6899
|
}
|
|
7068
|
-
WritebackSettlement.attachAcceptNotVerifiedFailure(run, result, {
|
|
7069
|
-
buildFailure: buildContentFailure
|
|
7070
|
-
});
|
|
7071
|
-
applyTrackedChangeSettlement(runId, 'accept', result);
|
|
7072
6900
|
}
|
|
7073
6901
|
|
|
7074
6902
|
function getRunProjectIdForWriteback(run) {
|
|
@@ -7112,35 +6940,179 @@
|
|
|
7112
6940
|
);
|
|
7113
6941
|
}
|
|
7114
6942
|
|
|
7115
|
-
function applyTrackedChangeSettlement(runId, kind, result) {
|
|
7116
|
-
const
|
|
6943
|
+
async function applyTrackedChangeSettlement(runId, kind, result) {
|
|
6944
|
+
const record = findRunRecord(runId);
|
|
6945
|
+
const createdUndo = record?.undoOperations?.some(operation => operation?.undoCreatedFile?.v === 1);
|
|
6946
|
+
const run = kind === 'reject' && createdUndo ? advanceRunUndoProgress(record, result) : record;
|
|
7117
6947
|
const settlement = WritebackSettlement.settleTrackedChangeLifecycle({
|
|
7118
6948
|
kind,
|
|
7119
6949
|
run,
|
|
7120
6950
|
result,
|
|
7121
6951
|
failureReasons: FailureReasons
|
|
7122
6952
|
});
|
|
7123
|
-
if (settlement.decision === 'blocked') {
|
|
7124
|
-
refreshRunCardControls(runId);
|
|
6953
|
+
if (settlement.decision === 'blocked' && !(kind === 'reject' && createdUndo)) {
|
|
7125
6954
|
return;
|
|
7126
6955
|
}
|
|
7127
|
-
|
|
7128
|
-
|
|
7129
|
-
|
|
6956
|
+
await Modules.ScopedPersistenceCoordinator.applyReviewTransition({
|
|
6957
|
+
getState: () => state, runId, transition: WritebackSettlement.applySettlementTransition(run, settlement),
|
|
6958
|
+
persist: flushQueuedSaveState
|
|
6959
|
+
});
|
|
7130
6960
|
}
|
|
7131
6961
|
|
|
6962
|
+
|
|
6963
|
+
function advanceRunUndoProgress(run, result) {
|
|
6964
|
+
const postFiles = buildTrackedUndoPostFiles(run);
|
|
6965
|
+
return Modules.UndoOperations.advanceUndoCheckpoint(run, result, file =>
|
|
6966
|
+
WritebackSettlement.isUndoVerifiedContentMatching({ undoExpectedFiles: [file] }, result, { postFiles })
|
|
6967
|
+
);
|
|
6968
|
+
}
|
|
7132
6969
|
function getRunUndoCount(run) {
|
|
7133
6970
|
if (!run) {
|
|
7134
6971
|
return 0;
|
|
7135
6972
|
}
|
|
7136
6973
|
const trackedEditorUndoCount = hasTrackedEditorUndo(run) ? 1 : 0;
|
|
7137
6974
|
if (trackedEditorUndoCount) {
|
|
7138
|
-
return trackedEditorUndoCount;
|
|
6975
|
+
return trackedEditorUndoCount + (run.undoOperations || []).filter(operation => operation?.undoCreatedFile?.v === 1).length;
|
|
7139
6976
|
}
|
|
7140
6977
|
return (run.undoOperations?.length || 0)
|
|
7141
6978
|
+ (run.undoTrackedChanges?.length || 0);
|
|
7142
6979
|
}
|
|
7143
6980
|
|
|
6981
|
+
function recoveryOwner(target) {
|
|
6982
|
+
if (!target.runProjectId || target.runProjectId !== getCurrentProjectId() || !cachedAccountScopeId) {
|
|
6983
|
+
throw new Error('Writeback recovery lost its project or account identity.');
|
|
6984
|
+
}
|
|
6985
|
+
return { projectId: target.runProjectId, accountScopeId: cachedAccountScopeId,
|
|
6986
|
+
sessionId: target.sessionId, runId: target.recordId, createdAt: new Date().toISOString() };
|
|
6987
|
+
}
|
|
6988
|
+
|
|
6989
|
+
async function stageWritebackRecovery(operations, target, requireReviewing) {
|
|
6990
|
+
const record = findRunRecord(target.recordId, target.sessionId);
|
|
6991
|
+
if (!record) throw new Error('The writeback run is no longer available.');
|
|
6992
|
+
const creates = operations.filter(op => op.type === 'create' && typeof op.content === 'string');
|
|
6993
|
+
record.retryRequireReviewing = requireReviewing === true; // In-memory; seeds an edit-only retry intent.
|
|
6994
|
+
if (!creates.length) return;
|
|
6995
|
+
const candidate = Modules.WritebackIntent.normalize({ ...recoveryOwner(target), id: crypto.randomUUID(),
|
|
6996
|
+
operations: creates, baseFiles: [], requireReviewing });
|
|
6997
|
+
const safe = Modules.SessionState.pickWritebackRecovery({ ...record, retryWriteback: candidate }).retryWriteback;
|
|
6998
|
+
if (safe) record.retryWriteback = safe; else delete record.retryWriteback;
|
|
6999
|
+
await flushQueuedSaveState();
|
|
7000
|
+
}
|
|
7001
|
+
|
|
7002
|
+
async function settleWritebackRecovery(applied, project, verification, target) {
|
|
7003
|
+
const record = findRunRecord(target.recordId, target.sessionId);
|
|
7004
|
+
if (!record) return;
|
|
7005
|
+
const owner = recoveryOwner(target);
|
|
7006
|
+
const skippedPaths = new Set((applied.skipped || []).map(entry => entry.operation?.path));
|
|
7007
|
+
const creates = (record.retryWriteback?.operations || []).filter(op => skippedPaths.has(op.path));
|
|
7008
|
+
// Untouched edits (never opened / rejected) and deletes whose server check failed are safe to replay.
|
|
7009
|
+
const edits = (applied.skipped || []).filter(({ operation: op, result }) => result?.failure?.changedDocument === false && ((op?.type === 'edit'
|
|
7010
|
+
&& (result.failure.stage === 'navigation' || result.failure.code === 'write_operation_failed')) || (op?.type === 'delete' && result.failure.code === 'source_zip_unavailable'))).map(entry => entry.operation);
|
|
7011
|
+
const base = { ...(record.retryWriteback || { ...owner, id: crypto.randomUUID(), requireReviewing: record.retryRequireReviewing === true }),
|
|
7012
|
+
baseFiles: project?.files || [], requestId: applied.receiptUnconfirmed ? applied.requestId || '' : '' };
|
|
7013
|
+
// An oversized edit pre-image must not cost the create retries (the intent has a 300 KiB ceiling).
|
|
7014
|
+
const safeRetry = [[...creates, ...edits], creates].filter(ops => ops.length).map(ops => Modules.SessionState
|
|
7015
|
+
.pickWritebackRecovery({ ...record, retryWriteback: Modules.WritebackIntent.normalize({ ...base, operations: ops }) }).retryWriteback).find(Boolean);
|
|
7016
|
+
if (safeRetry) record.retryWriteback = safeRetry; else delete record.retryWriteback;
|
|
7017
|
+
delete record.retryRequireReviewing;
|
|
7018
|
+
const next = await writebackController.buildSaveCheck(applied, project, owner);
|
|
7019
|
+
const files = new Map((record.saveCheck?.files || []).map(file => [file.path, file]));
|
|
7020
|
+
for (const file of next?.files || []) {
|
|
7021
|
+
if (verification.state === 'verified_saved') files.delete(file.path);
|
|
7022
|
+
else files.set(file.path, file);
|
|
7023
|
+
}
|
|
7024
|
+
if (files.size) record.saveCheck = Modules.WritebackIntent.normalizeSaveCheck({ ...owner, files: [...files.values()] });
|
|
7025
|
+
else {
|
|
7026
|
+
delete record.saveCheck;
|
|
7027
|
+
if (verification.state === 'verified_saved') record.saveConfirmedAt = new Date().toISOString();
|
|
7028
|
+
}
|
|
7029
|
+
await flushQueuedSaveState();
|
|
7030
|
+
}
|
|
7031
|
+
|
|
7032
|
+
async function retryRunWriteback(runId) {
|
|
7033
|
+
if (currentRunView || trackedChangeInFlight.size) return;
|
|
7034
|
+
const session = getActiveSession(state);
|
|
7035
|
+
const record = (session?.runs || []).find(run => run.id === runId);
|
|
7036
|
+
const intent = Modules.WritebackIntent.normalize(record?.retryWriteback);
|
|
7037
|
+
const check = Modules.WritebackIntent.normalizeSaveCheck(record?.saveCheck);
|
|
7038
|
+
const owner = intent || check;
|
|
7039
|
+
if (!record || record.forkSnapshot || !owner || owner.projectId !== getCurrentProjectId()
|
|
7040
|
+
|| owner.accountScopeId !== cachedAccountScopeId || owner.sessionId !== session.id
|
|
7041
|
+
|| owner.runId !== record.id || record.undoStatus === 'applied' || record.trackedChangeStatus === 'rejected') return;
|
|
7042
|
+
const originalStatus = record.status;
|
|
7043
|
+
// State is renormalized during the awaits below (probes, session sync), which
|
|
7044
|
+
// replaces run objects; always write through the current copy.
|
|
7045
|
+
const live = () => findRunRecord(runId, session.id) || record;
|
|
7046
|
+
let finished = false;
|
|
7047
|
+
runCancellationRequested = false;
|
|
7048
|
+
runCancellationController = new AbortController();
|
|
7049
|
+
record.status = 'running';
|
|
7050
|
+
record.retryingWriteback = true;
|
|
7051
|
+
renderRunHistory({ preserveScroll: true });
|
|
7052
|
+
const root = panel.querySelector(`[data-run-id="${cssEscape(runId)}"]`);
|
|
7053
|
+
currentRunView = { root, recordId: runId, sessionId: session.id, runProjectId: owner.projectId,
|
|
7054
|
+
runAccountScopeId: owner.accountScopeId, executionSnapshot: record.executionSnapshot,
|
|
7055
|
+
startedAt: Date.now(), writebackRetry: true, events: root?.querySelector('[data-run-events]'),
|
|
7056
|
+
report: root?.querySelector('[data-run-report]'), status: root?.querySelector('[data-run-status]'),
|
|
7057
|
+
runProcess: root?.querySelector('[data-run-process]'), processLabel: root?.querySelector('[data-run-process-summary]') };
|
|
7058
|
+
setRunning(true);
|
|
7059
|
+
const assertOwner = () => {
|
|
7060
|
+
if (runCancellationRequested || currentRunView?.recordId !== runId) {
|
|
7061
|
+
throw Object.assign(new Error('Save checking was cancelled.'), { code: 'codex_cancelled' });
|
|
7062
|
+
}
|
|
7063
|
+
if (owner.projectId !== getCurrentProjectId() || owner.accountScopeId !== cachedAccountScopeId) {
|
|
7064
|
+
throw Object.assign(new Error('The project or account changed.'), { code: 'aborted_project_changed' });
|
|
7065
|
+
}
|
|
7066
|
+
};
|
|
7067
|
+
try {
|
|
7068
|
+
assertOwner();
|
|
7069
|
+
if (intent?.requestId) {
|
|
7070
|
+
const receipt = await callPageBridge('getWritebackReceipt', { requestId: intent.requestId, runProjectId: owner.projectId });
|
|
7071
|
+
if (receipt?.state === 'running') throw new Error(tx('The previous upload is still finishing. Try again shortly.', '上一轮上传仍在收尾,请稍后再试。'));
|
|
7072
|
+
}
|
|
7073
|
+
if (intent?.operations.length) {
|
|
7074
|
+
// Edits replay against the run's original base files, so the stale guard still refuses changed documents.
|
|
7075
|
+
const result = await applySyncChangesToOverleaf(intent.operations.map(op => op.type === 'edit'
|
|
7076
|
+
? { type: 'write', path: op.path, patches: op.patches, content: op.replaceAll } : op.type === 'delete' ? { type: 'delete', path: op.path } : { ...op, type: 'create' }),
|
|
7077
|
+
{ id: owner.projectId, files: intent.baseFiles }, { mode: 'auto', requireReviewing: intent.requireReviewing,
|
|
7078
|
+
retryCreates: true, assistantMessage: tx('Retried the remaining file transfers for this task.', '已重试本轮未完成的文件同步。') });
|
|
7079
|
+
assertOwner();
|
|
7080
|
+
if (result.settlement?.facts) live().settlement = WritebackSettlement.mergeRetrySettlement(live().settlement, result.settlement.facts); // Keep files outside the retry.
|
|
7081
|
+
await finishRunView(result.hasSkippedOperations ? tx('Sync incomplete', '同步未完成') : tx('Synced', '已同步'),
|
|
7082
|
+
result.hasSkippedOperations ? 'failed' : 'completed');
|
|
7083
|
+
finished = true;
|
|
7084
|
+
} else if (check) {
|
|
7085
|
+
const result = await writebackController.confirmSaveCheck(check, { assertCurrent: assertOwner,
|
|
7086
|
+
readSnapshot: params => callPageBridge('getProjectSnapshot', { ...params, runProjectId: owner.projectId }) });
|
|
7087
|
+
assertOwner();
|
|
7088
|
+
const current = live();
|
|
7089
|
+
if (result.ok) {
|
|
7090
|
+
delete current.saveCheck;
|
|
7091
|
+
current.saveConfirmedAt = new Date().toISOString();
|
|
7092
|
+
if (current.settlement) current.settlement.evidence = { ...current.settlement.evidence, saved: 'verified' };
|
|
7093
|
+
}
|
|
7094
|
+
showPluginToast(result.ok ? tx('Saved content confirmed.', '已确认文件保存。')
|
|
7095
|
+
: tx('Saved content is still unconfirmed. No file was uploaded again.', '保存状态仍待确认,本次没有重复上传文件。'));
|
|
7096
|
+
}
|
|
7097
|
+
await flushQueuedSaveState();
|
|
7098
|
+
} catch (error) {
|
|
7099
|
+
showPluginToast(error.message || String(error));
|
|
7100
|
+
} finally {
|
|
7101
|
+
// Only finishRunView settles a new terminal status; every other exit
|
|
7102
|
+
// returns the card to the status it had before the retry.
|
|
7103
|
+
for (const copy of new Set([record, live()])) {
|
|
7104
|
+
delete copy.retryingWriteback;
|
|
7105
|
+
if (!finished && copy.status === 'running') copy.status = originalStatus;
|
|
7106
|
+
}
|
|
7107
|
+
if (currentRunView?.recordId === runId) currentRunView = null;
|
|
7108
|
+
runCancellationRequested = false;
|
|
7109
|
+
runCancellationController = null;
|
|
7110
|
+
setRunning(false);
|
|
7111
|
+
saveStateSoon();
|
|
7112
|
+
renderRunHistory({ preserveScroll: true });
|
|
7113
|
+
}
|
|
7114
|
+
}
|
|
7115
|
+
|
|
7144
7116
|
function appendUndoReviewingPolicyEvent(runId, reviewingPolicy) {
|
|
7145
7117
|
if (!reviewingPolicy || reviewingPolicy.policy !== 'no-trace-undo') {
|
|
7146
7118
|
return;
|
|
@@ -7224,7 +7196,7 @@
|
|
|
7224
7196
|
}
|
|
7225
7197
|
|
|
7226
7198
|
function recordUndoFromApply(project, applyResult) {
|
|
7227
|
-
const appliedEntries = getAppliedEntries(applyResult);
|
|
7199
|
+
const appliedEntries = getAppliedEntries(applyResult).filter(entry => entry.result?.idempotent !== true);
|
|
7228
7200
|
if (!currentRunView?.recordId || !appliedEntries.length) {
|
|
7229
7201
|
return;
|
|
7230
7202
|
}
|
|
@@ -7243,14 +7215,15 @@
|
|
|
7243
7215
|
...appliedOperations
|
|
7244
7216
|
];
|
|
7245
7217
|
record.appliedOperations = combinedAppliedOperations;
|
|
7218
|
+
const createdCheckpoint = buildCreatedFileUndoCheckpoint(project, combinedAppliedOperations, record);
|
|
7246
7219
|
|
|
7247
7220
|
if ((currentRunView?.executionSnapshot?.requireReviewing ?? state.requireReviewing) === true) {
|
|
7248
7221
|
const combinedTrackedChanges = normalizeApplyTrackedChanges([
|
|
7249
7222
|
...(Array.isArray(record.undoTrackedChanges) ? record.undoTrackedChanges : []),
|
|
7250
7223
|
...trackedChanges
|
|
7251
7224
|
]);
|
|
7252
|
-
record.undoOperations =
|
|
7253
|
-
record.undoBaseFiles =
|
|
7225
|
+
record.undoOperations = createdCheckpoint.undoOperations;
|
|
7226
|
+
record.undoBaseFiles = createdCheckpoint.undoBaseFiles;
|
|
7254
7227
|
record.undoTrackedChanges = combinedTrackedChanges;
|
|
7255
7228
|
record.undoExpectedFiles = selectExpectedFilesForTrackedUndo(
|
|
7256
7229
|
project,
|
|
@@ -7285,6 +7258,11 @@
|
|
|
7285
7258
|
[tr('detailMethod')]: tr('undoCheckpointNativeMethod')
|
|
7286
7259
|
}
|
|
7287
7260
|
});
|
|
7261
|
+
} else if (record.undoOperations.length) {
|
|
7262
|
+
appendRunEvent({
|
|
7263
|
+
title: tr('undoCheckpointPlain', { count: record.undoOperations.length }),
|
|
7264
|
+
status: 'completed'
|
|
7265
|
+
});
|
|
7288
7266
|
} else {
|
|
7289
7267
|
appendRunEvent({
|
|
7290
7268
|
title: tr('undoCheckpointMissing'),
|
|
@@ -7299,6 +7277,15 @@
|
|
|
7299
7277
|
}
|
|
7300
7278
|
|
|
7301
7279
|
const checkpoint = buildUndoCheckpoint(project, combinedAppliedOperations);
|
|
7280
|
+
const createdPaths = new Set(createdCheckpoint.undoOperations.map(operation => operation.path));
|
|
7281
|
+
checkpoint.undoOperations = [
|
|
7282
|
+
...checkpoint.undoOperations.filter(operation => !createdPaths.has(operation.path)),
|
|
7283
|
+
...createdCheckpoint.undoOperations
|
|
7284
|
+
];
|
|
7285
|
+
checkpoint.undoBaseFiles = [
|
|
7286
|
+
...checkpoint.undoBaseFiles.filter(file => !createdPaths.has(file.path)),
|
|
7287
|
+
...createdCheckpoint.undoBaseFiles
|
|
7288
|
+
];
|
|
7302
7289
|
if (!checkpoint.undoOperations.length) {
|
|
7303
7290
|
return;
|
|
7304
7291
|
}
|
|
@@ -7373,6 +7360,7 @@
|
|
|
7373
7360
|
timestamp: event.timestamp || new Date().toISOString(),
|
|
7374
7361
|
kind: event.kind || 'activity',
|
|
7375
7362
|
technicalDetail: event.technicalDetail,
|
|
7363
|
+
activity: Modules.RunActivityModel.capture(event, sanitizeAssistantVisibleText),
|
|
7376
7364
|
guidanceId: sanitizeAssistantVisibleText(event.guidanceId)
|
|
7377
7365
|
};
|
|
7378
7366
|
record.events = [...(record.events || []), normalized].slice(-MAX_RUN_EVENTS);
|
|
@@ -7402,10 +7390,12 @@
|
|
|
7402
7390
|
function applyLegacyUndoSettlement(runId, undoStatus, result) {
|
|
7403
7391
|
const run = findRunRecord(runId);
|
|
7404
7392
|
if (!run) return;
|
|
7393
|
+
const checkpoint = run.undoOperations?.some(operation => operation?.undoCreatedFile?.v === 1)
|
|
7394
|
+
? advanceRunUndoProgress(run, result) : run;
|
|
7405
7395
|
Object.assign(run, WritebackSettlement.applySettlementTransition(
|
|
7406
|
-
|
|
7396
|
+
checkpoint,
|
|
7407
7397
|
WritebackSettlement.settleLegacyUndo({
|
|
7408
|
-
run,
|
|
7398
|
+
run: checkpoint,
|
|
7409
7399
|
status: undoStatus,
|
|
7410
7400
|
result
|
|
7411
7401
|
})
|
|
@@ -7415,13 +7405,19 @@
|
|
|
7415
7405
|
}
|
|
7416
7406
|
|
|
7417
7407
|
function refreshRunCardControls(runId) {
|
|
7418
|
-
const run = findRunRecord(runId);
|
|
7419
|
-
const root = panel?.querySelector(`[data-run-id="${cssEscape(runId)}"]`);
|
|
7408
|
+
const run = findRunRecord(runId), root = panel?.querySelector(`[data-run-id="${cssEscape(runId)}"]`);
|
|
7420
7409
|
if (!run || !root) {
|
|
7421
7410
|
return;
|
|
7422
7411
|
}
|
|
7412
|
+
if (runTimelineView.refreshResolvedUndo?.(runId)) return;
|
|
7423
7413
|
configureAcceptButton(root, run);
|
|
7424
7414
|
configureUndoButton(root, run);
|
|
7415
|
+
const reportEvent = (run.events || []).filter(event => event.kind === 'report').pop();
|
|
7416
|
+
const report = root.querySelector('[data-run-report]');
|
|
7417
|
+
if (reportEvent && report) {
|
|
7418
|
+
report.replaceChildren(renderCompletionReport(reportEvent, run));
|
|
7419
|
+
report.hidden = false;
|
|
7420
|
+
}
|
|
7425
7421
|
}
|
|
7426
7422
|
|
|
7427
7423
|
function findRunRecord(runId, sessionId = '') {
|
|
@@ -7542,6 +7538,11 @@
|
|
|
7542
7538
|
// v1.8.0 C1: a change-history row jumps to the run it describes —
|
|
7543
7539
|
// switch to its session if needed, then scroll + flash the run card.
|
|
7544
7540
|
async function jumpToHistoryRun(record = {}) {
|
|
7541
|
+
if (!cachedAccountScopeId || record.accountScopeId !== cachedAccountScopeId
|
|
7542
|
+
|| record.projectId !== getCurrentProjectId()) {
|
|
7543
|
+
showPluginToast(tx('The project or account changed. Reopen file history and try again.', '项目或账号已变化,请重新打开文件修改记录。'));
|
|
7544
|
+
return;
|
|
7545
|
+
}
|
|
7545
7546
|
closeCustomInstructionsSettings();
|
|
7546
7547
|
if (record.sessionId && record.sessionId !== state.activeSessionId) {
|
|
7547
7548
|
const target = (state.sessions || []).find(session => session.id === record.sessionId);
|
|
@@ -7620,7 +7621,7 @@
|
|
|
7620
7621
|
if (primaryNext) return primaryNext;
|
|
7621
7622
|
return tx('Expand the write result, review the skipped reasons, then retry after fixing them.', '请展开写入结果查看跳过原因,处理后可以重试。');
|
|
7622
7623
|
}
|
|
7623
|
-
if (input.status === 'rejected') {
|
|
7624
|
+
if (input.status === 'cancelled' || input.status === 'rejected') {
|
|
7624
7625
|
return tx('Adjust the task description and run again.', '可以调整任务描述后重新运行。');
|
|
7625
7626
|
}
|
|
7626
7627
|
if (input.status === 'blocked' || input.status === 'failed') {
|