codex-overleaf-link 2.4.1 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +272 -314
- package/README.zh-CN.md +287 -329
- package/extension/bootstrap/background.js +47 -10
- package/extension/bootstrap/manifest.template.json +9 -4
- package/extension/bootstrap/popup.html +10 -16
- package/extension/bootstrap/update.js +25 -2
- package/extension/runtime-manifest.json +3 -1
- package/extension/src/background.js +28 -3
- package/extension/src/backgroundSharedSessions.js +380 -0
- package/extension/src/backgroundUpdateCoordinator.js +442 -379
- package/extension/src/content/activeTurnControl.js +8 -0
- package/extension/src/content/assetTransferBroker.js +186 -12
- package/extension/src/content/changeHistoryView.js +175 -0
- package/extension/src/content/composerAttachments.js +24 -22
- package/extension/src/content/composerPanel.js +23 -8
- package/extension/src/content/contentRuntime.js +507 -507
- package/extension/src/content/diagnosticsController.js +1 -2
- package/extension/src/content/diagnosticsExport.js +222 -0
- package/extension/src/content/diagnosticsPanel.js +48 -19
- package/extension/src/content/diffReviewPanel.js +8 -5
- package/extension/src/content/generated/content.bundle.js +8330 -1349
- package/extension/src/content/generated/content.bundle.meta.json +22 -3
- package/extension/src/content/legacyGlobalRegistry.js +19 -1
- package/extension/src/content/localSkillsPanel.js +42 -7
- package/extension/src/content/markdownDomRenderer.js +9 -4
- package/extension/src/content/modelPicker.js +1 -1
- package/extension/src/content/pageBridgeClient.js +18 -3
- package/extension/src/content/panelMaintenance.js +48 -121
- package/extension/src/content/panelRenderer.js +4 -0
- package/extension/src/content/pendingInputView.js +109 -76
- package/extension/src/content/providerSettingsCoordinator.js +17 -6
- package/extension/src/content/providerSettingsDialog.js +661 -108
- package/extension/src/content/recentProjects.js +10 -1
- package/extension/src/content/runActivitySummary.js +631 -0
- package/extension/src/content/runController.js +3 -1
- package/extension/src/content/runFailureNotice.js +14 -1
- package/extension/src/content/runGuidanceController.js +4 -3
- package/extension/src/content/runPresence.js +306 -0
- package/extension/src/content/runQueueScheduler.js +2 -1
- package/extension/src/content/runResultActions.js +123 -3
- package/extension/src/content/runTimelineView.js +186 -154
- package/extension/src/content/selectionContextView.js +300 -0
- package/extension/src/content/sessionPersistence.js +6 -1
- package/extension/src/content/settingsPanel.js +77 -52
- package/extension/src/content/settingsWorkbench.js +374 -0
- package/extension/src/content/sharedSessionViewSync.js +72 -0
- package/extension/src/content/subagentActivityView.js +195 -0
- package/extension/src/content/trackedChangeCaptureController.js +7 -3
- package/extension/src/content/updateNotice.js +121 -50
- package/extension/src/content/writebackController.js +257 -0
- package/extension/src/content/writebackOrchestrator.js +146 -141
- package/extension/src/content/writebackPlan.js +231 -0
- package/extension/src/content/writebackRecovery.js +122 -0
- package/extension/src/content/writingStyleSettings.js +576 -0
- package/extension/src/content/writtenChangesView.js +152 -0
- package/extension/src/page/binaryAssetUploader.js +97 -19
- package/extension/src/page/overleafProjectSnapshot.js +1 -0
- package/extension/src/page/referenceProjects.js +148 -0
- package/extension/src/page/saveState.js +14 -2
- package/extension/src/page/snapshotRouter.js +44 -13
- package/extension/src/page/textCoordinates.js +102 -0
- package/extension/src/page/textFileCreator.js +350 -59
- package/extension/src/page/trackedChangeCapture.js +42 -56
- package/extension/src/page/trackedChangeOwnership.js +198 -0
- package/extension/src/page/trackedChangeReplay.js +164 -0
- package/extension/src/page/trackedChangesLifecycle.js +135 -149
- package/extension/src/page/treeOperations.js +26 -2
- package/extension/src/page/writebackReceiptJournal.js +112 -0
- package/extension/src/page/writebackRouter.js +175 -135
- package/extension/src/pageBridge.js +56 -101
- package/extension/src/popup.js +203 -59
- package/extension/src/shared/agentTranscript.js +18 -4
- package/extension/src/shared/auditRecords.js +71 -0
- package/extension/src/shared/changeHistoryModel.js +94 -0
- package/extension/src/shared/compatibility.js +1 -1
- package/extension/src/shared/compileAdapter.js +42 -0
- package/extension/src/shared/failureReasons.js +20 -0
- package/extension/src/shared/globalPreferences.js +1 -1
- package/extension/src/shared/i18n.js +93 -25
- package/extension/src/shared/managedUpdateProjection.js +6 -3
- package/extension/src/shared/pageRpcContract.js +7 -1
- package/extension/src/shared/providerProfiles.js +109 -0
- package/extension/src/shared/runActivityModel.js +361 -0
- package/extension/src/shared/runExecutionSnapshot.js +8 -2
- package/extension/src/shared/runExecutionSnapshotCodec.js +16 -4
- package/extension/src/shared/scopedPersistenceBrowserAdapter.js +6 -3
- package/extension/src/shared/selectionContext.js +28 -0
- package/extension/src/shared/sessionState.js +97 -6
- package/extension/src/shared/sharedSessionBridge.js +288 -0
- package/extension/src/shared/storageDb.js +22 -55
- package/extension/src/shared/storageMigration.js +3 -0
- package/extension/src/shared/storageRunActions.js +10 -4
- package/extension/src/shared/storageValuePruning.js +40 -0
- package/extension/src/shared/subagentActivityModel.js +174 -0
- package/extension/src/shared/undoOperations.js +87 -0
- package/extension/src/shared/updateConsent.js +37 -8
- package/extension/src/shared/writebackIntent.js +62 -0
- package/extension/src/shared/writebackSettlement.js +29 -10
- package/extension/src/shared/writingStyle.js +33 -0
- package/extension/styles/panel.css +1972 -384
- package/extension/styles/popup.css +110 -0
- package/native-host/src/anthropicBridgeRequest.js +2 -1
- package/native-host/src/codexModelRecovery.js +107 -0
- package/native-host/src/codexPromptAssembly.js +2 -0
- package/native-host/src/codexProviderLaunch.js +3 -3
- package/native-host/src/codexRuntimeIdentity.js +1 -0
- package/native-host/src/codexSessionRunner.js +106 -140
- package/native-host/src/codexSessionTiming.js +3 -0
- package/native-host/src/managedInstall.js +5 -4
- package/native-host/src/nativeEnvironment.js +70 -0
- package/native-host/src/nativeQuotas.js +15 -8
- package/native-host/src/overleafWorkspaceRules.js +16 -0
- package/native-host/src/processStopBarrier.js +80 -0
- package/native-host/src/providerModelCatalog.js +4 -3
- package/native-host/src/providerProfile.js +13 -1
- package/native-host/src/providerReasoning.js +9 -5
- package/native-host/src/providerStore.js +4 -0
- package/native-host/src/releaseTransport.js +14 -5
- package/native-host/src/selectionScope.js +58 -0
- package/native-host/src/skills/parallel-subagents/SKILL.md +31 -3
- package/native-host/src/skills/writing-style-builder/SKILL.md +146 -0
- package/native-host/src/subagentBroker.js +102 -98
- package/native-host/src/subagentTelemetry.js +316 -0
- package/native-host/src/subagentWorkspace.js +103 -0
- package/native-host/src/subagentWorkspacePath.js +31 -0
- package/native-host/src/taskRunnerRuntime.js +55 -5
- package/native-host/src/turnAttachments.js +113 -0
- package/native-host/src/updateManager.js +122 -12
- package/native-host/src/updateNetworkControl.js +75 -0
- package/native-host/src/updateTrust.js +21 -2
- package/native-host/src/vendor/pdfjs/LICENSE +177 -0
- package/native-host/src/vendor/pdfjs/SOURCE.txt +3 -0
- package/native-host/src/vendor/pdfjs/cmaps/78-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78ms-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78ms-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/83pv-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/90ms-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/90ms-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/90msp-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/90msp-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/90pv-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/90pv-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Add-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Add-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Add-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Add-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-0.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-1.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-3.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-4.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-5.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-6.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-0.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-1.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-3.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-4.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-5.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-0.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-1.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-3.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-4.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-5.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-6.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-0.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-1.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/B5pc-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/B5pc-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/CNS-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/CNS-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/CNS1-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/CNS1-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/CNS2-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/CNS2-V.bcmap +3 -0
- package/native-host/src/vendor/pdfjs/cmaps/ETHK-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/ETHK-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/ETen-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/ETen-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/ETenms-B5-H.bcmap +3 -0
- package/native-host/src/vendor/pdfjs/cmaps/ETenms-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Ext-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Ext-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Ext-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Ext-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GB-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GB-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GB-H.bcmap +4 -0
- package/native-host/src/vendor/pdfjs/cmaps/GB-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBK-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBK-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBK2K-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBK2K-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBKp-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBKp-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBT-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBT-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBT-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBT-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBTpc-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBTpc-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBpc-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBpc-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKdla-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKdla-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKdlb-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKdlb-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKgccs-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKgccs-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKm314-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKm314-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKm471-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKm471-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKscs-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKscs-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Hankaku.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Hiragana.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSC-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSC-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSC-Johab-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSC-Johab-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSCpc-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSCpc-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Katakana.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/LICENSE +36 -0
- package/native-host/src/vendor/pdfjs/cmaps/NWP-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/NWP-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Roman.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UCS2-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UCS2-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF16-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF16-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF8-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF8-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UCS2-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UCS2-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF16-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF16-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF8-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF8-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF16-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF16-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF8-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF8-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UCS2-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UCS2-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF16-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF16-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF8-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF8-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/WP-Symbol.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/pdf.mjs +26740 -0
- package/native-host/src/vendor/pdfjs/pdf.worker.mjs +62201 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitDingbats.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixed.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedBold.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedItalic.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerif.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifBold.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifItalic.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSymbol.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/LICENSE_FOXIT +27 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/LICENSE_LIBERATION +102 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Bold.ttf +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Italic.ttf +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Regular.ttf +0 -0
- package/native-host/src/writingStyleEvidence.js +102 -0
- package/native-host/src/writingStylePdfWorker.js +35 -0
- package/native-host/src/writingStyleProfile.js +165 -0
- package/native-host/src/writingStyleRuntime.js +447 -0
- package/package.json +1 -1
|
@@ -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
|
-
|
|
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
1178
|
|
|
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
1179
|
|
|
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
1180
|
|
|
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;
|
|
@@ -5768,6 +5526,8 @@
|
|
|
5768
5526
|
} else {
|
|
5769
5527
|
throw error;
|
|
5770
5528
|
}
|
|
5529
|
+
} finally {
|
|
5530
|
+
endSharedSave?.();
|
|
5771
5531
|
}
|
|
5772
5532
|
}
|
|
5773
5533
|
|
|
@@ -6004,6 +5764,7 @@
|
|
|
6004
5764
|
button.dataset.active = active ? 'true' : 'false';
|
|
6005
5765
|
button.setAttribute('aria-pressed', active ? 'true' : 'false');
|
|
6006
5766
|
});
|
|
5767
|
+
syncProbeStatus(currentMode);
|
|
6007
5768
|
}
|
|
6008
5769
|
|
|
6009
5770
|
function readPanelInputs() {
|
|
@@ -6077,11 +5838,14 @@
|
|
|
6077
5838
|
}
|
|
6078
5839
|
composerSkillInvocation = null;
|
|
6079
5840
|
renderComposerSkillInvocation();
|
|
5841
|
+
selectionContextView.clear();
|
|
6080
5842
|
state = updateActiveSession(state, { task: '' });
|
|
6081
5843
|
saveStateSoon();
|
|
6082
5844
|
}
|
|
6083
5845
|
|
|
6084
5846
|
function applyStateToPanel(options = {}) {
|
|
5847
|
+
selectionContextView.render();
|
|
5848
|
+
writingStyleSettings.sync();
|
|
6085
5849
|
applyPanelTheme(getThemePreference());
|
|
6086
5850
|
if ((state.providerId || 'builtin') === 'builtin' && !modelSelectHasOption(state.model)) {
|
|
6087
5851
|
renderModelOptions(getModelCatalog().FALLBACK_MODELS, state.model);
|
|
@@ -6159,17 +5923,38 @@
|
|
|
6159
5923
|
}
|
|
6160
5924
|
panel.dataset.running = running ? 'true' : 'false';
|
|
6161
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
|
+
});
|
|
6162
5931
|
renderPendingInputs();
|
|
6163
5932
|
}
|
|
6164
5933
|
|
|
6165
|
-
function prepareRetryReplacement(run) {
|
|
5934
|
+
function prepareRetryReplacement(run, task) {
|
|
6166
5935
|
const sessionId = state?.activeSessionId || '';
|
|
6167
5936
|
const source = findRunRecord(run?.id, sessionId);
|
|
6168
|
-
const eligible = source &&
|
|
5937
|
+
const eligible = source && !source.forkSnapshot
|
|
5938
|
+
&& (!source.runProjectId || source.runProjectId === getCurrentProjectId())
|
|
5939
|
+
&& runController.isRetryReplacementEligible(
|
|
6169
5940
|
source,
|
|
6170
5941
|
WritebackSettlement.projectRunSettlement(source)
|
|
6171
5942
|
);
|
|
6172
|
-
|
|
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 });
|
|
6173
5958
|
return Boolean(eligible);
|
|
6174
5959
|
}
|
|
6175
5960
|
|
|
@@ -6346,6 +6131,17 @@
|
|
|
6346
6131
|
return;
|
|
6347
6132
|
}
|
|
6348
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
|
+
|
|
6349
6145
|
const activity = mapAgentEventToActivity(event, { locale: getLocale() });
|
|
6350
6146
|
if (!activity?.visible || activity.kind === 'technical') {
|
|
6351
6147
|
return;
|
|
@@ -6415,9 +6211,11 @@
|
|
|
6415
6211
|
kind: input.kind || 'activity',
|
|
6416
6212
|
subagent: input.subagent === true ? true : undefined,
|
|
6417
6213
|
technicalDetail: sanitizeAssistantVisibleValue(input.technicalDetail),
|
|
6214
|
+
activity: Modules.RunActivityModel.capture(input, sanitizeAssistantVisibleText),
|
|
6418
6215
|
guidanceId: sanitizeAssistantVisibleText(input.guidanceId),
|
|
6419
6216
|
streamKey: sanitizeAssistantVisibleText(input.streamKey),
|
|
6420
6217
|
streamRole: sanitizeAssistantVisibleText(input.streamRole),
|
|
6218
|
+
streamPhase: sanitizeAssistantVisibleText(input.streamPhase),
|
|
6421
6219
|
appendText: typeof input.appendText === 'string' ? sanitizeAssistantVisibleText(input.appendText) : input.appendText,
|
|
6422
6220
|
replaceText: input.replaceText,
|
|
6423
6221
|
// Structured FailureReason (§7) attached to the event when the caller
|
|
@@ -6531,6 +6329,7 @@
|
|
|
6531
6329
|
}
|
|
6532
6330
|
|
|
6533
6331
|
function appendRunEventToView(view, event) {
|
|
6332
|
+
const projected = event.kind !== 'stream' && runTimelineView.refreshActivitySummary?.(view, event);
|
|
6534
6333
|
if (event.kind === 'report') {
|
|
6535
6334
|
view.report.hidden = false;
|
|
6536
6335
|
const record = view?.recordId ? findRunRecord(view.recordId, view.sessionId) : null;
|
|
@@ -6541,6 +6340,7 @@
|
|
|
6541
6340
|
if (event.kind === 'technical') {
|
|
6542
6341
|
return;
|
|
6543
6342
|
}
|
|
6343
|
+
if (projected) { bumpUnreadIfDetached(); return; }
|
|
6544
6344
|
if (runGuidanceController.appendToView(event, view)) return;
|
|
6545
6345
|
if (event.kind === 'stream') {
|
|
6546
6346
|
// Stream deltas update an existing line in place — they must not inflate
|
|
@@ -6548,7 +6348,7 @@
|
|
|
6548
6348
|
upsertStreamEvent(view, event);
|
|
6549
6349
|
return;
|
|
6550
6350
|
}
|
|
6551
|
-
|
|
6351
|
+
runTimelineView.appendActivityDetail(view, renderRunEvent(event), event);
|
|
6552
6352
|
bumpUnreadIfDetached();
|
|
6553
6353
|
}
|
|
6554
6354
|
|
|
@@ -6559,6 +6359,7 @@
|
|
|
6559
6359
|
if (existing) {
|
|
6560
6360
|
const nextTitle = sanitizeAssistantVisibleText(event.title);
|
|
6561
6361
|
const nextRole = sanitizeAssistantVisibleText(event.streamRole) || existing.streamRole;
|
|
6362
|
+
if (event.streamPhase) existing.streamPhase = event.streamPhase;
|
|
6562
6363
|
const combinedTitle = event.replaceText
|
|
6563
6364
|
? nextTitle
|
|
6564
6365
|
: sanitizeAssistantVisibleText(appendStreamText(existing.title, nextTitle));
|
|
@@ -6618,10 +6419,6 @@
|
|
|
6618
6419
|
}
|
|
6619
6420
|
|
|
6620
6421
|
|
|
6621
|
-
|
|
6622
|
-
|
|
6623
|
-
|
|
6624
|
-
|
|
6625
6422
|
function applyPanelWidth(width, options = {}) {
|
|
6626
6423
|
const nextWidth = PanelRenderer.setWidth(panelRendererInstance, width, { notify: false });
|
|
6627
6424
|
if (state) {
|
|
@@ -6633,10 +6430,6 @@
|
|
|
6633
6430
|
return nextWidth;
|
|
6634
6431
|
}
|
|
6635
6432
|
|
|
6636
|
-
|
|
6637
|
-
|
|
6638
|
-
|
|
6639
|
-
|
|
6640
6433
|
function getCurrentProjectMathSources() {
|
|
6641
6434
|
const sources = [];
|
|
6642
6435
|
const seen = new Set();
|
|
@@ -6812,7 +6605,8 @@
|
|
|
6812
6605
|
await pendingMirror.catch(() => {});
|
|
6813
6606
|
}
|
|
6814
6607
|
|
|
6815
|
-
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))) {
|
|
6816
6610
|
await undoRunTrackedChanges(runId, run);
|
|
6817
6611
|
return;
|
|
6818
6612
|
}
|
|
@@ -6870,6 +6664,7 @@
|
|
|
6870
6664
|
}
|
|
6871
6665
|
}
|
|
6872
6666
|
|
|
6667
|
+
const deadlineAt = Date.now() + getPageBridgeTimeoutMs('rejectTrackedChanges');
|
|
6873
6668
|
setRunUndoStatus(runId, 'running');
|
|
6874
6669
|
appendRunRecordEvent(runId, {
|
|
6875
6670
|
title: tr('undoNoTraceStarted'),
|
|
@@ -6878,12 +6673,10 @@
|
|
|
6878
6673
|
});
|
|
6879
6674
|
|
|
6880
6675
|
const result = await callPageBridge('applyOperations', {
|
|
6881
|
-
operations: selectedOperations,
|
|
6676
|
+
operations: selectedOperations, deadlineAt,
|
|
6882
6677
|
baseFiles: run.undoBaseFiles || [],
|
|
6883
6678
|
reviewingPolicy: 'no-trace-undo',
|
|
6884
|
-
//
|
|
6885
|
-
// route the undo through the same project-ID guard. The undo is
|
|
6886
|
-
// bound to the run's original project, not the editor's active one.
|
|
6679
|
+
// Undo remains bound to its original project, including after navigation.
|
|
6887
6680
|
runProjectId: getRunProjectIdForWriteback(run)
|
|
6888
6681
|
});
|
|
6889
6682
|
const undoApplied = isUndoResultEffectivelyApplied(run, result);
|
|
@@ -6915,15 +6708,18 @@
|
|
|
6915
6708
|
}
|
|
6916
6709
|
|
|
6917
6710
|
async function undoRunTrackedChanges(runId, run) {
|
|
6711
|
+
const createdUndoOperations = (run.undoOperations || []).filter(operation => operation?.undoCreatedFile?.v === 1);
|
|
6918
6712
|
const trackedUndo = Array.isArray(run.undoTrackedChanges) && run.undoTrackedChanges.length > 0;
|
|
6713
|
+
const hasTextUndo = trackedUndo || buildTrackedUndoPostFiles(run).length > 0;
|
|
6919
6714
|
const approved = await showPluginConfirm({
|
|
6920
|
-
title: trackedUndo ? tr('undoTrackedTitle') : tr('undoNativeTitle'),
|
|
6715
|
+
title: !hasTextUndo ? tr('undoNoTraceTitle') : trackedUndo ? tr('undoTrackedTitle') : tr('undoNativeTitle'),
|
|
6921
6716
|
message: [
|
|
6922
6717
|
truncateRunTitle(run.task),
|
|
6923
6718
|
'',
|
|
6924
|
-
trackedUndo
|
|
6719
|
+
...(hasTextUndo ? [trackedUndo
|
|
6925
6720
|
? tr('undoTrackedMessage', { files: formatTrackedChangeFiles(run.undoTrackedChanges) })
|
|
6926
|
-
: tr('undoNativeMessage', { files: formatTrackedUndoFiles(run) })
|
|
6721
|
+
: tr('undoNativeMessage', { files: formatTrackedUndoFiles(run) })] : []),
|
|
6722
|
+
...(createdUndoOperations.length ? [tr('undoNoTraceMessage', { files: formatOperationFiles(createdUndoOperations) })] : [])
|
|
6927
6723
|
].join('\n'),
|
|
6928
6724
|
confirmLabel: trackedUndo ? tr('undoTrackedConfirm') : tr('undoConfirm'),
|
|
6929
6725
|
cancelLabel: tr('confirmDefaultCancel'),
|
|
@@ -6933,10 +6729,10 @@
|
|
|
6933
6729
|
return;
|
|
6934
6730
|
}
|
|
6935
6731
|
|
|
6936
|
-
|
|
6937
|
-
//
|
|
6938
|
-
//
|
|
6939
|
-
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);
|
|
6940
6736
|
if (lifecycleReject) {
|
|
6941
6737
|
trackedChangeInFlight.set(runId, 'reject');
|
|
6942
6738
|
refreshRunCardControls(runId);
|
|
@@ -6944,41 +6740,72 @@
|
|
|
6944
6740
|
setRunUndoStatus(runId, 'running');
|
|
6945
6741
|
}
|
|
6946
6742
|
appendRunRecordEvent(runId, {
|
|
6947
|
-
title: trackedUndo ? tr('undoTrackedStarted') : tr('undoNativeStarted'),
|
|
6743
|
+
title: !hasTextUndo ? tr('undoNoTraceStarted') : trackedUndo ? tr('undoTrackedStarted') : tr('undoNativeStarted'),
|
|
6948
6744
|
status: 'running',
|
|
6949
|
-
detail: { [tr('detailWillUndo')]:
|
|
6745
|
+
detail: { [tr('detailWillUndo')]: !hasTextUndo ? formatOperationFiles(createdUndoOperations)
|
|
6746
|
+
: trackedUndo ? formatTrackedChangeFiles(run.undoTrackedChanges) : formatTrackedUndoFiles(run) }
|
|
6950
6747
|
});
|
|
6951
6748
|
|
|
6952
6749
|
try {
|
|
6953
6750
|
const trackedUndoPostFilesAtDispatch = buildTrackedUndoPostFiles(run);
|
|
6954
|
-
|
|
6955
|
-
trackedChanges: run.undoTrackedChanges || [],
|
|
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)
|
|
6966
|
-
});
|
|
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
|
+
}
|
|
6967
6794
|
writebackOrchestrator.invalidateMirrorAfterUndo(runId, getRunProjectIdForWriteback(run), result);
|
|
6968
6795
|
appendRunRecordEvent(runId, {
|
|
6969
|
-
title: trackedUndo
|
|
6796
|
+
title: createdUndoOperations.length ? tr('undoResult', { applied: result.applied?.length || 0, skipped: result.skipped?.length || 0 }) : trackedUndo
|
|
6970
6797
|
? tr('undoTrackedResult', { applied: result.applied?.length || 0, skipped: result.skipped?.length || 0 })
|
|
6971
6798
|
: tr('undoNativeResult', { applied: result.applied?.length || 0, skipped: result.skipped?.length || 0 }),
|
|
6972
6799
|
status: result.skipped?.length ? 'failed' : 'completed',
|
|
6973
6800
|
detail: {
|
|
6974
|
-
[trackedUndo ? tr('detailRejected') : tr('detailUndone')]: (result.applied || []).map(item => ({
|
|
6975
|
-
[tr('detailFile')]: item.trackedChange?.path || tr('unknownFile'),
|
|
6976
|
-
[tr('detailRecord')]: item.trackedChange?.label || item.trackedChange?.id || item.trackedChange?.key
|
|
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
|
|
6977
6804
|
})),
|
|
6978
6805
|
[tr('detailSkipped')]: (result.skipped || []).map(item => ({
|
|
6979
|
-
[tr('detailFile')]: item.trackedChange?.path || tr('unknownFile'),
|
|
6980
|
-
[tr('detailRecord')]: item.trackedChange?.label || item.trackedChange?.id || item.trackedChange?.key || '',
|
|
6981
|
-
[tr('detailReason')]: formatBridgeResultReason(item.result, item.trackedChange?.path)
|
|
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)
|
|
6982
6809
|
}))
|
|
6983
6810
|
}
|
|
6984
6811
|
});
|
|
@@ -7114,14 +6941,16 @@
|
|
|
7114
6941
|
}
|
|
7115
6942
|
|
|
7116
6943
|
async function applyTrackedChangeSettlement(runId, kind, result) {
|
|
7117
|
-
const
|
|
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;
|
|
7118
6947
|
const settlement = WritebackSettlement.settleTrackedChangeLifecycle({
|
|
7119
6948
|
kind,
|
|
7120
6949
|
run,
|
|
7121
6950
|
result,
|
|
7122
6951
|
failureReasons: FailureReasons
|
|
7123
6952
|
});
|
|
7124
|
-
if (settlement.decision === 'blocked') {
|
|
6953
|
+
if (settlement.decision === 'blocked' && !(kind === 'reject' && createdUndo)) {
|
|
7125
6954
|
return;
|
|
7126
6955
|
}
|
|
7127
6956
|
await Modules.ScopedPersistenceCoordinator.applyReviewTransition({
|
|
@@ -7130,18 +6959,160 @@
|
|
|
7130
6959
|
});
|
|
7131
6960
|
}
|
|
7132
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
|
+
}
|
|
7133
6969
|
function getRunUndoCount(run) {
|
|
7134
6970
|
if (!run) {
|
|
7135
6971
|
return 0;
|
|
7136
6972
|
}
|
|
7137
6973
|
const trackedEditorUndoCount = hasTrackedEditorUndo(run) ? 1 : 0;
|
|
7138
6974
|
if (trackedEditorUndoCount) {
|
|
7139
|
-
return trackedEditorUndoCount;
|
|
6975
|
+
return trackedEditorUndoCount + (run.undoOperations || []).filter(operation => operation?.undoCreatedFile?.v === 1).length;
|
|
7140
6976
|
}
|
|
7141
6977
|
return (run.undoOperations?.length || 0)
|
|
7142
6978
|
+ (run.undoTrackedChanges?.length || 0);
|
|
7143
6979
|
}
|
|
7144
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
|
+
|
|
7145
7116
|
function appendUndoReviewingPolicyEvent(runId, reviewingPolicy) {
|
|
7146
7117
|
if (!reviewingPolicy || reviewingPolicy.policy !== 'no-trace-undo') {
|
|
7147
7118
|
return;
|
|
@@ -7225,7 +7196,7 @@
|
|
|
7225
7196
|
}
|
|
7226
7197
|
|
|
7227
7198
|
function recordUndoFromApply(project, applyResult) {
|
|
7228
|
-
const appliedEntries = getAppliedEntries(applyResult);
|
|
7199
|
+
const appliedEntries = getAppliedEntries(applyResult).filter(entry => entry.result?.idempotent !== true);
|
|
7229
7200
|
if (!currentRunView?.recordId || !appliedEntries.length) {
|
|
7230
7201
|
return;
|
|
7231
7202
|
}
|
|
@@ -7244,14 +7215,15 @@
|
|
|
7244
7215
|
...appliedOperations
|
|
7245
7216
|
];
|
|
7246
7217
|
record.appliedOperations = combinedAppliedOperations;
|
|
7218
|
+
const createdCheckpoint = buildCreatedFileUndoCheckpoint(project, combinedAppliedOperations, record);
|
|
7247
7219
|
|
|
7248
7220
|
if ((currentRunView?.executionSnapshot?.requireReviewing ?? state.requireReviewing) === true) {
|
|
7249
7221
|
const combinedTrackedChanges = normalizeApplyTrackedChanges([
|
|
7250
7222
|
...(Array.isArray(record.undoTrackedChanges) ? record.undoTrackedChanges : []),
|
|
7251
7223
|
...trackedChanges
|
|
7252
7224
|
]);
|
|
7253
|
-
record.undoOperations =
|
|
7254
|
-
record.undoBaseFiles =
|
|
7225
|
+
record.undoOperations = createdCheckpoint.undoOperations;
|
|
7226
|
+
record.undoBaseFiles = createdCheckpoint.undoBaseFiles;
|
|
7255
7227
|
record.undoTrackedChanges = combinedTrackedChanges;
|
|
7256
7228
|
record.undoExpectedFiles = selectExpectedFilesForTrackedUndo(
|
|
7257
7229
|
project,
|
|
@@ -7286,6 +7258,11 @@
|
|
|
7286
7258
|
[tr('detailMethod')]: tr('undoCheckpointNativeMethod')
|
|
7287
7259
|
}
|
|
7288
7260
|
});
|
|
7261
|
+
} else if (record.undoOperations.length) {
|
|
7262
|
+
appendRunEvent({
|
|
7263
|
+
title: tr('undoCheckpointPlain', { count: record.undoOperations.length }),
|
|
7264
|
+
status: 'completed'
|
|
7265
|
+
});
|
|
7289
7266
|
} else {
|
|
7290
7267
|
appendRunEvent({
|
|
7291
7268
|
title: tr('undoCheckpointMissing'),
|
|
@@ -7300,6 +7277,15 @@
|
|
|
7300
7277
|
}
|
|
7301
7278
|
|
|
7302
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
|
+
];
|
|
7303
7289
|
if (!checkpoint.undoOperations.length) {
|
|
7304
7290
|
return;
|
|
7305
7291
|
}
|
|
@@ -7374,6 +7360,7 @@
|
|
|
7374
7360
|
timestamp: event.timestamp || new Date().toISOString(),
|
|
7375
7361
|
kind: event.kind || 'activity',
|
|
7376
7362
|
technicalDetail: event.technicalDetail,
|
|
7363
|
+
activity: Modules.RunActivityModel.capture(event, sanitizeAssistantVisibleText),
|
|
7377
7364
|
guidanceId: sanitizeAssistantVisibleText(event.guidanceId)
|
|
7378
7365
|
};
|
|
7379
7366
|
record.events = [...(record.events || []), normalized].slice(-MAX_RUN_EVENTS);
|
|
@@ -7403,10 +7390,12 @@
|
|
|
7403
7390
|
function applyLegacyUndoSettlement(runId, undoStatus, result) {
|
|
7404
7391
|
const run = findRunRecord(runId);
|
|
7405
7392
|
if (!run) return;
|
|
7393
|
+
const checkpoint = run.undoOperations?.some(operation => operation?.undoCreatedFile?.v === 1)
|
|
7394
|
+
? advanceRunUndoProgress(run, result) : run;
|
|
7406
7395
|
Object.assign(run, WritebackSettlement.applySettlementTransition(
|
|
7407
|
-
|
|
7396
|
+
checkpoint,
|
|
7408
7397
|
WritebackSettlement.settleLegacyUndo({
|
|
7409
|
-
run,
|
|
7398
|
+
run: checkpoint,
|
|
7410
7399
|
status: undoStatus,
|
|
7411
7400
|
result
|
|
7412
7401
|
})
|
|
@@ -7416,13 +7405,19 @@
|
|
|
7416
7405
|
}
|
|
7417
7406
|
|
|
7418
7407
|
function refreshRunCardControls(runId) {
|
|
7419
|
-
const run = findRunRecord(runId);
|
|
7420
|
-
const root = panel?.querySelector(`[data-run-id="${cssEscape(runId)}"]`);
|
|
7408
|
+
const run = findRunRecord(runId), root = panel?.querySelector(`[data-run-id="${cssEscape(runId)}"]`);
|
|
7421
7409
|
if (!run || !root) {
|
|
7422
7410
|
return;
|
|
7423
7411
|
}
|
|
7412
|
+
if (runTimelineView.refreshResolvedUndo?.(runId)) return;
|
|
7424
7413
|
configureAcceptButton(root, run);
|
|
7425
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
|
+
}
|
|
7426
7421
|
}
|
|
7427
7422
|
|
|
7428
7423
|
function findRunRecord(runId, sessionId = '') {
|
|
@@ -7543,6 +7538,11 @@
|
|
|
7543
7538
|
// v1.8.0 C1: a change-history row jumps to the run it describes —
|
|
7544
7539
|
// switch to its session if needed, then scroll + flash the run card.
|
|
7545
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
|
+
}
|
|
7546
7546
|
closeCustomInstructionsSettings();
|
|
7547
7547
|
if (record.sessionId && record.sessionId !== state.activeSessionId) {
|
|
7548
7548
|
const target = (state.sessions || []).find(session => session.id === record.sessionId);
|
|
@@ -7621,7 +7621,7 @@
|
|
|
7621
7621
|
if (primaryNext) return primaryNext;
|
|
7622
7622
|
return tx('Expand the write result, review the skipped reasons, then retry after fixing them.', '请展开写入结果查看跳过原因,处理后可以重试。');
|
|
7623
7623
|
}
|
|
7624
|
-
if (input.status === 'rejected') {
|
|
7624
|
+
if (input.status === 'cancelled' || input.status === 'rejected') {
|
|
7625
7625
|
return tx('Adjust the task description and run again.', '可以调整任务描述后重新运行。');
|
|
7626
7626
|
}
|
|
7627
7627
|
if (input.status === 'blocked' || input.status === 'failed') {
|