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
|
@@ -0,0 +1,631 @@
|
|
|
1
|
+
(function initCodexOverleafRunActivitySummary() {
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
function create(deps = {}) {
|
|
5
|
+
if (!deps.RunActivityModel) return null;
|
|
6
|
+
const { RunActivityModel: Model, tx, findRunRecord, getPanel, cssEscape, isGuidance,
|
|
7
|
+
formatElapsed, renderMarkdownBlockText, renderRunEvent, presence, classifyStatus, getProjectId, summarizeCommand,
|
|
8
|
+
sanitizeAssistantVisibleText: sanitize = value => String(value || '') } = deps;
|
|
9
|
+
const cards = new WeakMap();
|
|
10
|
+
const choices = new Map();
|
|
11
|
+
const storageKey = 'codex-overleaf:workflow-disclosure:v1';
|
|
12
|
+
try {
|
|
13
|
+
const saved = JSON.parse(window.sessionStorage.getItem(storageKey) || '[]');
|
|
14
|
+
if (Array.isArray(saved)) for (const entry of saved.slice(-200)) {
|
|
15
|
+
if (Array.isArray(entry) && typeof entry[0] === 'string' && typeof entry[1] === 'boolean') choices.set(entry[0], entry[1]);
|
|
16
|
+
}
|
|
17
|
+
} catch { /* Presentation preferences must not affect run storage. */ }
|
|
18
|
+
|
|
19
|
+
const text = (node, value) => { if (node && node.textContent !== value) node.textContent = value; };
|
|
20
|
+
const plain = value => String(sanitize(value) || '').trim();
|
|
21
|
+
const make = (tag, className) => {
|
|
22
|
+
const node = document.createElement(tag);
|
|
23
|
+
node.className = className;
|
|
24
|
+
return node;
|
|
25
|
+
};
|
|
26
|
+
const subagentView = deps.SubagentActivityView?.create({
|
|
27
|
+
tx, getPanel, plain, make, icon, formatElapsed,
|
|
28
|
+
renderBlocks: (parent, blocks, rows, card, run) => reconcile(parent, blocks, rows,
|
|
29
|
+
block => buildBlock(block, card), (row, block) => updateBlock(row, block, card, run))
|
|
30
|
+
});
|
|
31
|
+
function remember(key, open) {
|
|
32
|
+
choices.delete(key);
|
|
33
|
+
choices.set(key, open);
|
|
34
|
+
if (choices.size > 200) choices.delete(choices.keys().next().value);
|
|
35
|
+
try { window.sessionStorage.setItem(storageKey, JSON.stringify([...choices])); } catch { /* Optional. */ }
|
|
36
|
+
}
|
|
37
|
+
function disclosure(details, key) {
|
|
38
|
+
const summary = details.querySelector('summary');
|
|
39
|
+
if (choices.has(key)) details.open = choices.get(key);
|
|
40
|
+
summary.addEventListener('click', () => remember(key, !details.open));
|
|
41
|
+
details.addEventListener('toggle', () => summary.setAttribute('aria-expanded', String(details.open)));
|
|
42
|
+
summary.setAttribute('aria-expanded', String(details.open));
|
|
43
|
+
}
|
|
44
|
+
function resolve(view) {
|
|
45
|
+
let root = view?.root || view?.events?.closest('[data-run-id]');
|
|
46
|
+
const id = view?.recordId || root?.dataset.runId;
|
|
47
|
+
if (root?.isConnected === false && id) root = getPanel?.()?.querySelector('[data-run-id="' + cssEscape(id) + '"]') || root;
|
|
48
|
+
return { root, run: id ? findRunRecord?.(id, view?.sessionId) : null };
|
|
49
|
+
}
|
|
50
|
+
function icon(kind) {
|
|
51
|
+
const node = make('span', 'run-workflow-icon');
|
|
52
|
+
node.setAttribute('aria-hidden', 'true');
|
|
53
|
+
const glyphs = { exploreGroup: 'search', explore: 'search', edit: 'file', command: 'terminal', compile: 'terminal', sync: 'sync', notice: 'notice', agent: 'agent', plan: 'plan', tool: 'tool' };
|
|
54
|
+
const paths = {
|
|
55
|
+
search: '<circle cx="7" cy="7" r="4.5"/><path d="m10.5 10.5 3.5 3.5"/>',
|
|
56
|
+
file: '<path d="M9 2H4v12h8V5L9 2Z M9 2v4h3 M6 9h4 M6 11h3"/>',
|
|
57
|
+
terminal: '<rect x="2" y="3" width="12" height="10" rx="1.5"/><path d="m5 6 2 2-2 2 M9 10h2"/>',
|
|
58
|
+
sync: '<path d="M3 6a5 5 0 0 1 8-3l2 2 M13 2v3h-3 M13 10a5 5 0 0 1-8 3l-2-2 M3 14v-3h3"/>',
|
|
59
|
+
notice: '<circle cx="8" cy="8" r="6"/><path d="M8 4.5v4 M8 11h.01"/>',
|
|
60
|
+
agent: '<circle cx="8" cy="5" r="2.5"/><path d="M3 14v-2a5 5 0 0 1 10 0v2"/>',
|
|
61
|
+
plan: '<path d="m2 4 1 1 2-2 M7 4h7 M2 8h3 M7 8h7 M2 12h3 M7 12h7"/>',
|
|
62
|
+
tool: '<path d="m3 3 10 10 M10 3l3 3 M11 2l3 3 M2 11l3 3 M3 10l3 3"/>'
|
|
63
|
+
};
|
|
64
|
+
node.innerHTML = '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round">' + paths[glyphs[kind] || 'tool'] + '</svg>';
|
|
65
|
+
return node;
|
|
66
|
+
}
|
|
67
|
+
function effectiveState(item, run) {
|
|
68
|
+
const state = item.meta?.state || 'info';
|
|
69
|
+
if (!['running', 'pending'].includes(state) || run.status === 'running') return state;
|
|
70
|
+
return ['cancelled', 'rejected', 'interrupted', 'abandoned_after_navigation'].includes(run.status) ? 'cancelled' : 'unknown';
|
|
71
|
+
}
|
|
72
|
+
function stateLabel(state) {
|
|
73
|
+
return ({
|
|
74
|
+
running: tx('In progress', '进行中'), pending: tx('Pending', '等待中'),
|
|
75
|
+
completed: tx('Completed', '已完成'), failed: tx('Failed', '失败'),
|
|
76
|
+
warning: tx('Needs attention', '需留意'), cancelled: tx('Stopped', '已停止'),
|
|
77
|
+
skipped: tx('Skipped', '已跳过'), triggered: tx('Triggered; awaiting result', '已触发,待结果'),
|
|
78
|
+
unknown: tx('Result unconfirmed', '结果未确认'), info: ''
|
|
79
|
+
})[state] || '';
|
|
80
|
+
}
|
|
81
|
+
function kindLabel(item) {
|
|
82
|
+
if (item.kind === 'edit' && item.file) return ({ add: tx('Create locally', '本地新建'), delete: tx('Delete locally', '本地删除'), move: tx('Move locally', '本地移动') })[item.file.operation] || tx('Edit locally', '本地修改');
|
|
83
|
+
if (item.kind === 'explore') return ({ read: tx('Read', '读取'), search: tx('Search', '搜索'), list: tx('List', '查看目录') })[item.meta.action] || tx('Explore', '查阅');
|
|
84
|
+
return ({ command: tx('Run', '执行'), edit: tx('Edit locally', '本地修改'), sync: tx('Sync to Overleaf', '同步到 Overleaf'),
|
|
85
|
+
compile: tx('Overleaf compile', 'Overleaf 编译'), tool: tx('Tool', '工具'),
|
|
86
|
+
agent: tx('Subagent', '子代理'), plan: tx('Plan', '计划'), notice: tx('Notice', '提示') })[item.kind] || tx('Activity', '活动');
|
|
87
|
+
}
|
|
88
|
+
function targetText(item) {
|
|
89
|
+
const meta = item.meta || {};
|
|
90
|
+
if (item.file) return item.file.path;
|
|
91
|
+
if (item.kind === 'sync' && meta.written !== undefined) {
|
|
92
|
+
return tx(meta.written + ' written' + (meta.skipped ? ', ' + meta.skipped + ' skipped' : ''),
|
|
93
|
+
'已写入 ' + meta.written + ' 项' + (meta.skipped ? ',跳过 ' + meta.skipped + ' 项' : ''));
|
|
94
|
+
}
|
|
95
|
+
if (meta.target) return meta.target;
|
|
96
|
+
if (meta.paths?.length) return meta.paths.join(', ');
|
|
97
|
+
if (meta.command) return summarizeCommand?.(meta.command) || meta.command.replace(/\s+/g, ' ');
|
|
98
|
+
return plain(item.event?.title);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function makeTool(item, card) {
|
|
102
|
+
const el = make('details', 'run-workflow-tool run-work-block');
|
|
103
|
+
el.dataset.kind = item.kind;
|
|
104
|
+
const summary = make('summary', 'run-workflow-tool-summary');
|
|
105
|
+
const label = make('span', 'run-workflow-tool-kind');
|
|
106
|
+
const target = make('span', 'run-workflow-tool-target');
|
|
107
|
+
const status = make('span', 'run-workflow-tool-state');
|
|
108
|
+
const diff = make('span', 'run-workflow-diff-count');
|
|
109
|
+
const arrow = make('span', 'run-workflow-chevron');
|
|
110
|
+
arrow.setAttribute('aria-hidden', 'true');
|
|
111
|
+
summary.append(icon(item.kind), label, target, diff, status, arrow);
|
|
112
|
+
const body = make('div', 'run-workflow-tool-body');
|
|
113
|
+
el.append(summary, body);
|
|
114
|
+
const key = card.id + ':tool:' + item.key;
|
|
115
|
+
disclosure(el, key);
|
|
116
|
+
return { el, label, target, status, diff, body, key, bodyStamp: '' };
|
|
117
|
+
}
|
|
118
|
+
function renderTool(row, item, card, run) {
|
|
119
|
+
const meta = item.meta || {};
|
|
120
|
+
const state = effectiveState(item, run);
|
|
121
|
+
row.el.dataset.state = state;
|
|
122
|
+
text(row.label, kindLabel(item));
|
|
123
|
+
text(row.target, targetText(item));
|
|
124
|
+
row.target.title = targetText(item);
|
|
125
|
+
let status = stateLabel(state);
|
|
126
|
+
if (state === 'running' && item.kind === 'compile') {
|
|
127
|
+
const start = Date.parse(item.startedAt || '');
|
|
128
|
+
if (Number.isFinite(start)) status += ' ' + formatElapsed(Math.max(0, Date.now() - start));
|
|
129
|
+
}
|
|
130
|
+
text(row.status, status);
|
|
131
|
+
const file = item.file;
|
|
132
|
+
const showDiff = state === 'completed' && file && file.added !== undefined && file.removed !== undefined;
|
|
133
|
+
row.diff.hidden = !showDiff;
|
|
134
|
+
if (showDiff) {
|
|
135
|
+
if (!row.diff.firstChild) {
|
|
136
|
+
row.diff.append(make('span', 'run-workflow-added'), make('span', 'run-workflow-removed'));
|
|
137
|
+
}
|
|
138
|
+
text(row.diff.firstChild, '+' + file.added);
|
|
139
|
+
text(row.diff.lastChild, '-' + file.removed);
|
|
140
|
+
row.status.hidden = true;
|
|
141
|
+
} else row.status.hidden = false;
|
|
142
|
+
const publicText = plain(item.event?.title);
|
|
143
|
+
const stamp = [publicText, meta.output, meta.command, meta.exitCode, file?.preview, state, meta.clipped].join('\0');
|
|
144
|
+
if (stamp !== row.bodyStamp) {
|
|
145
|
+
row.bodyStamp = stamp;
|
|
146
|
+
row.body.replaceChildren();
|
|
147
|
+
if (file?.preview) {
|
|
148
|
+
const diffBody = make('pre', 'run-workflow-patch');
|
|
149
|
+
for (const line of file.preview.split('\n')) {
|
|
150
|
+
const lineNode = make('span', line.startsWith('+') && !line.startsWith('+++') ? 'is-added' : line.startsWith('-') && !line.startsWith('---') ? 'is-removed' : '');
|
|
151
|
+
lineNode.textContent = line + '\n';
|
|
152
|
+
diffBody.append(lineNode);
|
|
153
|
+
}
|
|
154
|
+
row.body.append(diffBody);
|
|
155
|
+
} else {
|
|
156
|
+
if (meta.command) { const command = make('pre', 'run-workflow-command'); command.textContent = plain(meta.command); row.body.append(command); }
|
|
157
|
+
if (meta.output) { const output = make('pre', 'run-workflow-output'); output.textContent = plain(meta.output); row.body.append(output); }
|
|
158
|
+
const note = make('div', 'run-workflow-tool-note');
|
|
159
|
+
note.textContent = publicText;
|
|
160
|
+
row.body.append(note);
|
|
161
|
+
}
|
|
162
|
+
if (meta.exitCode !== undefined) { const exit = make('div', 'run-workflow-tool-note'); exit.textContent = tx('Exit code: ', '退出码:') + meta.exitCode; row.body.append(exit); }
|
|
163
|
+
if (meta.clipped || file?.clipped) { const more = make('div', 'run-workflow-tool-note'); more.textContent = tx('Preview only. More detail may be available in diagnostics.', '当前为摘要预览,更多信息可通过诊断查看。'); row.body.append(more); }
|
|
164
|
+
}
|
|
165
|
+
if (!choices.has(row.key)) row.el.open = card.projection.notices.some(notice => notice.key === item.key);
|
|
166
|
+
}
|
|
167
|
+
function reconcile(parent, entries, cache, build, updateRow) {
|
|
168
|
+
const keep = new Set();
|
|
169
|
+
let cursor = parent.firstChild;
|
|
170
|
+
for (const entry of entries) {
|
|
171
|
+
keep.add(entry.key);
|
|
172
|
+
let row = cache.get(entry.key);
|
|
173
|
+
if (!row) { row = build(entry); cache.set(entry.key, row); }
|
|
174
|
+
updateRow(row, entry);
|
|
175
|
+
if (row.el !== cursor) parent.insertBefore(row.el, cursor);
|
|
176
|
+
cursor = row.el.nextSibling;
|
|
177
|
+
}
|
|
178
|
+
for (const [key, row] of cache) if (!keep.has(key)) { row.el.remove(); cache.delete(key); }
|
|
179
|
+
}
|
|
180
|
+
// Reasoning (CoT): the live one streams its last lines; settled ones fold to one line and open to the full text.
|
|
181
|
+
function makeThought(block, card) {
|
|
182
|
+
const el = make('details', 'run-work-block run-workflow-thought');
|
|
183
|
+
el.dataset.kind = 'thought';
|
|
184
|
+
const summary = make('summary', 'run-workflow-thought-line');
|
|
185
|
+
const label = make('span', 'run-workflow-thought-label');
|
|
186
|
+
const lead = make('span', 'run-workflow-thought-lead');
|
|
187
|
+
summary.append(label, lead);
|
|
188
|
+
const tail = make('div', 'run-workflow-thought-tail');
|
|
189
|
+
tail.append(make('span', ''));
|
|
190
|
+
const full = make('div', 'run-workflow-thought-full');
|
|
191
|
+
el.append(summary, tail, full);
|
|
192
|
+
const key = card.id + ':thought:' + block.key;
|
|
193
|
+
disclosure(el, key);
|
|
194
|
+
const row = { el, key, label, lead, tail, full, stamp: '', value: '', rendered: null, live: false };
|
|
195
|
+
// Full text renders only when opened; long CoT stays cheap in collapsed history.
|
|
196
|
+
row.showFull = () => {
|
|
197
|
+
if (row.live || !el.open || row.rendered === row.value) return;
|
|
198
|
+
row.rendered = row.value;
|
|
199
|
+
renderMarkdownBlockText(full, row.value, { streaming: false });
|
|
200
|
+
};
|
|
201
|
+
el.addEventListener('toggle', row.showFull);
|
|
202
|
+
return row;
|
|
203
|
+
}
|
|
204
|
+
function updateThought(row, block, run) {
|
|
205
|
+
const value = String(sanitize(block.event.title) || '').trim();
|
|
206
|
+
const live = run.status === 'running' && block.event.status === 'running';
|
|
207
|
+
const stamp = String(live) + ':' + value;
|
|
208
|
+
if (row.stamp === stamp) return;
|
|
209
|
+
row.stamp = stamp;
|
|
210
|
+
row.el.dataset.live = String(live);
|
|
211
|
+
row.live = live;
|
|
212
|
+
// A closed <details> hides everything but its summary, so the live tail needs the row open.
|
|
213
|
+
if (live) { row.el.open = true; text(row.tail.firstChild, value.slice(-900)); return; }
|
|
214
|
+
if (!choices.has(row.key)) row.el.open = false;
|
|
215
|
+
const started = Date.parse(block.startedAt || ''), ended = Date.parse(block.event.timestamp || '');
|
|
216
|
+
const seconds = Number.isFinite(started) && Number.isFinite(ended) && ended > started ? formatElapsed(ended - started) : '';
|
|
217
|
+
text(row.label, seconds ? tx('Thought ' + seconds, '思考 ' + seconds) : tx('Thought', '思考'));
|
|
218
|
+
const flat = value.replace(/\s+/g, ' ');
|
|
219
|
+
text(row.lead, (flat.match(/^.{12,160}?[.!?。!?](?=\s|$)/) || [flat.slice(0, 160)])[0]);
|
|
220
|
+
row.value = value;
|
|
221
|
+
row.showFull();
|
|
222
|
+
}
|
|
223
|
+
// Start-up block: what happens between Send and the model's first response, step by step.
|
|
224
|
+
const SETUP_CALM_MS = 30000;
|
|
225
|
+
function setupStepText(entry, live) {
|
|
226
|
+
const n = entry.count;
|
|
227
|
+
const copy = {
|
|
228
|
+
editing: live ? tx('Checking Overleaf editing mode', '检查 Overleaf 编辑模式')
|
|
229
|
+
: entry.reviewing ? tx('Overleaf Track Changes is on', 'Overleaf 已开启留痕') : tx('Overleaf is in Editing mode', 'Overleaf 处于编辑模式'),
|
|
230
|
+
read: live ? tx('Reading the Overleaf project', '正在读取 Overleaf 项目')
|
|
231
|
+
: n ? tx('Read the Overleaf project · ' + n + ' text files', '已读取 Overleaf 项目 · ' + n + ' 个文本文件') : tx('Read the Overleaf project', '已读取 Overleaf 项目'),
|
|
232
|
+
warm: tx('Using the already synced workspace', '使用已同步的工作区,无需重新读取项目'),
|
|
233
|
+
workspace: live ? tx('Writing the local workspace', '正在写入本地工作区')
|
|
234
|
+
: n ? tx('Synced ' + n + ' files to the local workspace', '已同步 ' + n + ' 个文件到本地工作区') : tx('Synced the local workspace', '已同步本地工作区'),
|
|
235
|
+
codex: live ? tx('Starting Codex', '正在启动 Codex')
|
|
236
|
+
: entry.version ? tx('Started Codex CLI ' + entry.version, '已启动 Codex CLI ' + entry.version) : tx('Started Codex', '已启动 Codex'),
|
|
237
|
+
waiting: live ? tx("Waiting for the model's first response", '等待模型首次响应') : tx('The model responded', '模型已开始响应')
|
|
238
|
+
};
|
|
239
|
+
return copy[entry.step] || '';
|
|
240
|
+
}
|
|
241
|
+
function setupNote(note) {
|
|
242
|
+
const empty = /^(\d+) file\(s\) have empty\/loading content\.$/.exec(note);
|
|
243
|
+
if (empty) return tx(empty[1] + ' file(s) are empty or still loading', empty[1] + ' 个文件内容为空或尚未加载完');
|
|
244
|
+
const short = /^(\d+) captured file\(s\) are shorter than 80 characters\.$/.exec(note);
|
|
245
|
+
if (short) return tx(short[1] + ' file(s) are very short and may not have loaded', short[1] + ' 个文件内容很短,可能没有加载完');
|
|
246
|
+
return note;
|
|
247
|
+
}
|
|
248
|
+
function setupLiveLabel(setup) {
|
|
249
|
+
const live = setup.steps.findLast(entry => entry.state === 'running');
|
|
250
|
+
return live ? setupStepText(live, true) : tx('Starting the task', '正在启动任务');
|
|
251
|
+
}
|
|
252
|
+
function renderSetup(card, setup, active) {
|
|
253
|
+
const el = card.setup;
|
|
254
|
+
const steps = setup?.steps || [];
|
|
255
|
+
el.hidden = !steps.length && !active;
|
|
256
|
+
if (el.hidden) return;
|
|
257
|
+
const folded = setup.done || !active;
|
|
258
|
+
el.dataset.folded = String(folded);
|
|
259
|
+
el.dataset.live = String(active && !setup.done);
|
|
260
|
+
const first = Date.parse(steps[0]?.at || ''), waitAt = Date.parse(steps.find(entry => entry.step === 'waiting')?.at || '');
|
|
261
|
+
const parts = [Number.isFinite(first) && Number.isFinite(waitAt) && waitAt >= first
|
|
262
|
+
? tx('Setup ' + formatElapsed(waitAt - first), '启动 ' + formatElapsed(waitAt - first)) : tx('Setup', '启动')];
|
|
263
|
+
const files = steps.find(entry => entry.step === 'workspace')?.count;
|
|
264
|
+
if (files) parts.push(tx(files + ' files', files + ' 个文件'));
|
|
265
|
+
else if (steps.some(entry => entry.step === 'warm')) parts.push(tx('synced workspace', '已同步的工作区'));
|
|
266
|
+
const version = steps.find(entry => entry.version)?.version;
|
|
267
|
+
if (version) parts.push('Codex ' + version);
|
|
268
|
+
text(card.setupFold, parts.join(' · '));
|
|
269
|
+
card.setupSummary.dataset.notes = String(steps.some(entry => entry.notes?.length));
|
|
270
|
+
const rows = steps.length ? steps : [{ step: 'start', state: 'running', at: '' }];
|
|
271
|
+
while (card.setupSteps.children.length > rows.length) card.setupSteps.lastChild.remove();
|
|
272
|
+
rows.forEach((entry, index) => {
|
|
273
|
+
let row = card.setupSteps.children[index];
|
|
274
|
+
if (!row) {
|
|
275
|
+
row = make('div', 'run-setup-step');
|
|
276
|
+
row.append(make('span', 'run-setup-glyph'), make('span', 'run-setup-text'), make('span', 'run-setup-time'));
|
|
277
|
+
card.setupSteps.append(row);
|
|
278
|
+
}
|
|
279
|
+
const live = active && entry.state === 'running';
|
|
280
|
+
const warn = Boolean(entry.notes?.length);
|
|
281
|
+
row.dataset.state = live ? 'running' : warn ? 'warning' : 'completed';
|
|
282
|
+
const glyph = row.children[0];
|
|
283
|
+
const glyphKind = live ? 'spinner' : warn ? 'notice' : 'check';
|
|
284
|
+
if (glyph.dataset.kind !== glyphKind) {
|
|
285
|
+
glyph.dataset.kind = glyphKind;
|
|
286
|
+
glyph.innerHTML = '<svg viewBox="0 0 16 16" aria-hidden="true" focusable="false">' + ({
|
|
287
|
+
spinner: '<circle cx="8" cy="8" r="5.5" opacity=".25"/><path d="M13.5 8A5.5 5.5 0 0 0 8 2.5"/>',
|
|
288
|
+
notice: '<circle cx="8" cy="8" r="6"/><path d="M8 4.5v4 M8 11h.01"/>', check: '<path d="m3.5 8 3 3 6-6"/>' })[glyphKind] + '</svg>';
|
|
289
|
+
}
|
|
290
|
+
const label = entry.step === 'start' ? tx('Starting the task', '正在启动任务') : setupStepText(entry, live);
|
|
291
|
+
const body = row.children[1];
|
|
292
|
+
const extras = [...(entry.notes || []).map(note => ['run-setup-note', setupNote(note)])];
|
|
293
|
+
const started = Date.parse(entry.at || ''), ended = Date.parse(entry.endAt || '');
|
|
294
|
+
const elapsed = Number.isFinite(started) ? Math.max(0, (live ? Date.now() : (Number.isFinite(ended) ? ended : started)) - started) : NaN;
|
|
295
|
+
if (live && entry.step === 'waiting' && elapsed > SETUP_CALM_MS) {
|
|
296
|
+
extras.push(['run-setup-calm', tx('The model is thinking. With some third-party providers, its reasoning arrives all at once when this step ends.',
|
|
297
|
+
'模型正在思考。部分第三方服务的思考内容会在这一段结束后一起显示。')]);
|
|
298
|
+
}
|
|
299
|
+
const stamp = label + '\0' + extras.map(pair => pair.join(':')).join('\0');
|
|
300
|
+
if (body.dataset.stamp !== stamp) {
|
|
301
|
+
body.dataset.stamp = stamp;
|
|
302
|
+
const main = make('span', 'run-setup-label');
|
|
303
|
+
main.textContent = label + (live ? '…' : '');
|
|
304
|
+
body.replaceChildren(main);
|
|
305
|
+
for (const [className, value] of extras) { const line = make('span', className); line.textContent = value; body.append(line); }
|
|
306
|
+
}
|
|
307
|
+
text(row.children[2], Number.isFinite(elapsed) && (live || elapsed >= 1000) ? formatElapsed(elapsed) : '');
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
// Collapsed live peek: a three-row window onto the newest start-up step, thought or tool call.
|
|
311
|
+
// Prose stays out of it; new rows enter at the bottom and push older ones up.
|
|
312
|
+
const PEEK_ROWS = 3;
|
|
313
|
+
const PEEK_GLYPHS = {
|
|
314
|
+
spinner: '<circle cx="8" cy="8" r="5.5" opacity=".25"/><path d="M13.5 8A5.5 5.5 0 0 0 8 2.5"/>',
|
|
315
|
+
check: '<path d="m3.5 8 3 3 6-6"/>', notice: '<circle cx="8" cy="8" r="6"/><path d="M8 4.5v4 M8 11h.01"/>',
|
|
316
|
+
fail: '<path d="m4 4 8 8M12 4l-8 8"/>'
|
|
317
|
+
};
|
|
318
|
+
function firstSentence(value) {
|
|
319
|
+
const flat = String(value || '').replace(/\s+/g, ' ').trim();
|
|
320
|
+
return (flat.match(/^.{12,160}?[.!?。!?](?=\s|$)/) || [flat.slice(0, 160)])[0];
|
|
321
|
+
}
|
|
322
|
+
function peekToolResult(item, state) {
|
|
323
|
+
if (state === 'running' || state === 'pending') return '';
|
|
324
|
+
if (['failed', 'warning', 'cancelled', 'unknown', 'skipped'].includes(state)) return stateLabel(state);
|
|
325
|
+
if (item.file && item.file.added !== undefined) return '+' + item.file.added + ' −' + item.file.removed;
|
|
326
|
+
const found = /found (\d+) relevant line|找到 (\d+) 处/.exec(plain(item.event?.title));
|
|
327
|
+
const count = found && Number(found[1] || found[2]);
|
|
328
|
+
return count ? tx(count + (count === 1 ? ' match' : ' matches'), count + ' 处匹配') : '';
|
|
329
|
+
}
|
|
330
|
+
function peekEntries(card, result, run) {
|
|
331
|
+
const entries = [];
|
|
332
|
+
const setup = result.setup || { steps: [] };
|
|
333
|
+
if (!setup.done) {
|
|
334
|
+
const steps = setup.steps.length ? setup.steps : [{ step: 'start', state: 'running' }];
|
|
335
|
+
steps.forEach((entry, index) => {
|
|
336
|
+
const live = entry.state === 'running';
|
|
337
|
+
const started = Date.parse(entry.at || ''), ended = Date.parse(entry.endAt || '');
|
|
338
|
+
const elapsed = Number.isFinite(started) ? Math.max(0, (live ? Date.now() : (Number.isFinite(ended) ? ended : started)) - started) : NaN;
|
|
339
|
+
entries.push({ key: 'setup:' + index, kind: 'setup', glyph: live ? 'spinner' : entry.notes?.length ? 'notice' : 'check',
|
|
340
|
+
state: live ? 'running' : entry.notes?.length ? 'warning' : 'completed',
|
|
341
|
+
lead: (entry.step === 'start' ? tx('Starting the task', '正在启动任务') : setupStepText(entry, live)) + (live ? '…' : ''),
|
|
342
|
+
result: entry.notes?.length ? setupNote(entry.notes[0]) : Number.isFinite(elapsed) && (live || elapsed >= 1000) ? formatElapsed(elapsed) : '' });
|
|
343
|
+
});
|
|
344
|
+
return entries;
|
|
345
|
+
}
|
|
346
|
+
if (setup.steps.length) entries.push({ key: 'setup:fold', kind: 'setup', glyph: 'check', state: 'completed', lead: card.setupFold.textContent });
|
|
347
|
+
for (const block of result.blocks) {
|
|
348
|
+
if (block.kind === 'thought') {
|
|
349
|
+
const value = String(sanitize(block.event.title) || '').trim();
|
|
350
|
+
const live = run.status === 'running' && block.event.status === 'running';
|
|
351
|
+
const started = Date.parse(block.startedAt || ''), ended = Date.parse(block.event.timestamp || '');
|
|
352
|
+
const seconds = Number.isFinite(started) && Number.isFinite(ended) && ended > started ? ' ' + formatElapsed(ended - started) : '';
|
|
353
|
+
const flat = value.replace(/\s+/g, ' ');
|
|
354
|
+
entries.push({ key: block.key, kind: 'thought', state: live ? 'running' : 'completed',
|
|
355
|
+
label: live ? tx('Thinking', '思考中') : tx('Thought', '思考') + seconds,
|
|
356
|
+
lead: live ? (flat.length > 90 ? '…' + flat.slice(-90) : flat) : firstSentence(value) });
|
|
357
|
+
} else if (block.kind !== 'message' && block.kind !== 'guidance') {
|
|
358
|
+
for (const item of block.kind === 'exploreGroup' ? block.items : [block]) {
|
|
359
|
+
if (item.kind === 'notice') continue;
|
|
360
|
+
const state = effectiveState(item, run);
|
|
361
|
+
entries.push({ key: item.key + (item.file ? ':' + item.file.path : ''), kind: 'tool', state, toolKind: item.kind,
|
|
362
|
+
glyph: state === 'running' ? 'spinner' : state === 'failed' ? 'fail' : '',
|
|
363
|
+
label: kindLabel(item), target: targetText(item), result: peekToolResult(item, state) });
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return entries;
|
|
368
|
+
}
|
|
369
|
+
function renderPeek(card, result, run, active) {
|
|
370
|
+
const show = active && !card.process.open;
|
|
371
|
+
card.peek.hidden = !show;
|
|
372
|
+
card.peekMore.hidden = true;
|
|
373
|
+
if (!show) return;
|
|
374
|
+
const entries = peekEntries(card, result, run);
|
|
375
|
+
const recent = entries.slice(-PEEK_ROWS);
|
|
376
|
+
const keep = new Set(recent.map(entry => entry.key));
|
|
377
|
+
for (const [key, row] of card.peekRows) if (!keep.has(key)) { row.el.remove(); card.peekRows.delete(key); }
|
|
378
|
+
let cursor = card.peekTrack.firstChild;
|
|
379
|
+
for (const entry of recent) {
|
|
380
|
+
let row = card.peekRows.get(entry.key);
|
|
381
|
+
if (!row) {
|
|
382
|
+
const el = make('div', 'run-peek-row is-entering');
|
|
383
|
+
row = { el, glyph: make('span', 'run-peek-glyph'), label: make('span', 'run-peek-label'), lead: make('span', 'run-peek-lead'),
|
|
384
|
+
result: make('span', 'run-peek-result') };
|
|
385
|
+
el.append(row.glyph, row.label, row.lead, row.result);
|
|
386
|
+
card.peekRows.set(entry.key, row);
|
|
387
|
+
} else if (row.el.className !== 'run-peek-row') {
|
|
388
|
+
row.el.className = 'run-peek-row'; // the slide-in plays once, on the render that created the row
|
|
389
|
+
}
|
|
390
|
+
// Touch the DOM only when the order changes: re-inserting a node restarts its CSS animation,
|
|
391
|
+
// which made the rows jump on every one-second timer tick.
|
|
392
|
+
if (row.el !== cursor) card.peekTrack.insertBefore(row.el, cursor);
|
|
393
|
+
cursor = row.el.nextSibling;
|
|
394
|
+
row.el.dataset.kind = entry.kind;
|
|
395
|
+
row.el.dataset.state = entry.state;
|
|
396
|
+
const glyph = entry.kind === 'tool' && !entry.glyph ? 'tool:' + entry.toolKind : entry.glyph || 'dot';
|
|
397
|
+
if (row.glyphKind !== glyph) {
|
|
398
|
+
row.glyphKind = glyph;
|
|
399
|
+
row.glyph.replaceChildren();
|
|
400
|
+
if (glyph.startsWith('tool:')) row.glyph.append(icon(entry.toolKind));
|
|
401
|
+
else if (glyph !== 'dot') row.glyph.innerHTML = '<svg viewBox="0 0 16 16" aria-hidden="true" focusable="false">' + PEEK_GLYPHS[glyph] + '</svg>';
|
|
402
|
+
}
|
|
403
|
+
text(row.label, entry.label || '');
|
|
404
|
+
text(row.lead, entry.kind === 'tool' ? entry.target : entry.lead);
|
|
405
|
+
text(row.result, entry.result ? (entry.kind === 'tool' ? '⎿ ' : '') + entry.result : '');
|
|
406
|
+
}
|
|
407
|
+
const hidden = entries.length - recent.length;
|
|
408
|
+
// The window grows with its rows (1→3) so a fresh run has no empty band; the top fade only appears once rows scroll out.
|
|
409
|
+
card.peek.dataset.rows = String(recent.length);
|
|
410
|
+
card.peek.dataset.overflow = String(hidden > 0);
|
|
411
|
+
card.peekMore.hidden = hidden <= 0;
|
|
412
|
+
text(card.peekMore, tx(hidden + (hidden === 1 ? ' earlier step' : ' earlier steps') + ' · expand to see all', '之前还有 ' + hidden + ' 步 · 展开查看全部'));
|
|
413
|
+
}
|
|
414
|
+
function buildBlock(block, card) {
|
|
415
|
+
if (block.kind === 'thought') return makeThought(block, card);
|
|
416
|
+
if (block.kind === 'message' || block.kind === 'guidance') {
|
|
417
|
+
const el = make('div', 'run-work-block run-workflow-' + block.kind + (block.kind === 'message' ? ' run-stream-text' : ''));
|
|
418
|
+
el.dataset.kind = block.kind;
|
|
419
|
+
return { el, stamp: '' };
|
|
420
|
+
}
|
|
421
|
+
const row = makeTool(block, card);
|
|
422
|
+
if (block.kind === 'exploreGroup') row.children = new Map();
|
|
423
|
+
return row;
|
|
424
|
+
}
|
|
425
|
+
function updateBlock(row, block, card, run) {
|
|
426
|
+
if (block.kind === 'thought') { updateThought(row, block, run); return; }
|
|
427
|
+
if (block.kind === 'message') {
|
|
428
|
+
const value = String(sanitize(block.event.title) || '');
|
|
429
|
+
const streaming = run.status === 'running' && block.event.status === 'running';
|
|
430
|
+
const stamp = String(streaming) + ':' + value;
|
|
431
|
+
if (row.stamp !== stamp) { row.stamp = stamp; renderMarkdownBlockText(row.el, value, { streaming }); }
|
|
432
|
+
row.el.dataset.streaming = String(streaming);
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
if (block.kind === 'guidance') {
|
|
436
|
+
const stamp = [block.event.title, block.event.status, block.event.guidanceId].join('\0');
|
|
437
|
+
if (row.stamp !== stamp) { row.stamp = stamp; row.el.replaceChildren(renderRunEvent(block.event)); }
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
if (block.kind !== 'exploreGroup') { renderTool(row, block, card, run); return; }
|
|
441
|
+
const items = block.items;
|
|
442
|
+
const last = items.at(-1);
|
|
443
|
+
if (items.length === 1) {
|
|
444
|
+
if (row.grouped) { row.children.clear(); row.bodyStamp = ''; }
|
|
445
|
+
row.grouped = false;
|
|
446
|
+
renderTool(row, last, card, run);
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
if (!row.grouped) { row.body.replaceChildren(); row.children.clear(); row.grouped = true; }
|
|
450
|
+
const states = items.map(item => effectiveState(item, run));
|
|
451
|
+
const groupState = states.includes('failed') ? 'failed' : states.includes('warning') ? 'warning'
|
|
452
|
+
: states.includes('running') ? 'running' : states.includes('unknown') ? 'unknown'
|
|
453
|
+
: states.includes('cancelled') ? 'cancelled' : states.every(state => state === 'completed') ? 'completed' : 'info';
|
|
454
|
+
row.el.dataset.state = groupState;
|
|
455
|
+
text(row.label, items.length === 1 ? kindLabel(last) : tx('Explore', '查阅与搜索'));
|
|
456
|
+
const paths = [...new Set(items.flatMap(item => item.meta.paths || []))];
|
|
457
|
+
text(row.target, items.length === 1 ? targetText(last)
|
|
458
|
+
: tx(items.length + ' operations', items.length + ' 项操作') + (paths.length ? ' · ' + paths.join(', ') : ''));
|
|
459
|
+
row.target.title = row.target.textContent;
|
|
460
|
+
text(row.status, stateLabel(groupState));
|
|
461
|
+
row.diff.hidden = true;
|
|
462
|
+
reconcile(row.body, items, row.children, item => makeTool(item, card),
|
|
463
|
+
(child, item) => renderTool(child, item, card, run));
|
|
464
|
+
if (!choices.has(row.key)) row.el.open = items.some(item => card.projection.notices.some(notice => notice.key === item.key));
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function mount(root, run) {
|
|
468
|
+
if (!Model || cards.has(root)) return;
|
|
469
|
+
const process = root.querySelector('[data-run-process]');
|
|
470
|
+
const summary = root.querySelector('[data-run-process-summary]');
|
|
471
|
+
const events = root.querySelector('[data-run-events]');
|
|
472
|
+
if (!process || !summary || !events) return;
|
|
473
|
+
root.classList.add('run-presentation-workflow');
|
|
474
|
+
events.classList.add('run-workflow-list');
|
|
475
|
+
events.replaceChildren();
|
|
476
|
+
const metrics = make('span', 'run-workflow-metrics');
|
|
477
|
+
summary.append(metrics);
|
|
478
|
+
const attention = make('button', 'run-workflow-attention');
|
|
479
|
+
attention.type = 'button';
|
|
480
|
+
attention.hidden = true;
|
|
481
|
+
attention.addEventListener('click', () => { remember(String(run.id) + ':run', true); process.open = true; update({ root, recordId: run.id }); });
|
|
482
|
+
process.before(attention);
|
|
483
|
+
const setupEl = make('details', 'run-setup');
|
|
484
|
+
const setupSummary = make('summary', 'run-setup-summary');
|
|
485
|
+
const setupFold = make('span', 'run-setup-fold');
|
|
486
|
+
setupSummary.append(make('span', 'run-setup-done'), setupFold);
|
|
487
|
+
const setupSteps = make('div', 'run-setup-steps');
|
|
488
|
+
setupEl.append(setupSummary, setupSteps);
|
|
489
|
+
setupEl.hidden = true;
|
|
490
|
+
events.before(setupEl);
|
|
491
|
+
const peek = make('div', 'run-peek');
|
|
492
|
+
peek.setAttribute('aria-hidden', 'true');
|
|
493
|
+
const peekTrack = make('div', 'run-peek-track');
|
|
494
|
+
peek.append(peekTrack);
|
|
495
|
+
peek.hidden = true;
|
|
496
|
+
const peekMore = make('button', 'run-peek-more');
|
|
497
|
+
peekMore.type = 'button';
|
|
498
|
+
peekMore.hidden = true;
|
|
499
|
+
setupEl.before(peek);
|
|
500
|
+
setupEl.before(peekMore);
|
|
501
|
+
const busy = make('div', 'run-workflow-busy');
|
|
502
|
+
busy.setAttribute('role', 'status');
|
|
503
|
+
events.after(busy);
|
|
504
|
+
const card = { id: String(run.id), root, process, summary, events, metrics, attention,
|
|
505
|
+
busy, rows: new Map(), run, setup: setupEl, setupSummary, setupFold, setupSteps,
|
|
506
|
+
peek, peekTrack, peekMore, peekRows: new Map() };
|
|
507
|
+
const expand = () => { remember(card.id + ':run', true); process.open = true; update({ root, recordId: run.id }); };
|
|
508
|
+
peek.addEventListener('click', expand);
|
|
509
|
+
peekMore.addEventListener('click', expand);
|
|
510
|
+
disclosure(setupEl, String(run.id) + ':setup');
|
|
511
|
+
cards.set(root, card);
|
|
512
|
+
disclosure(process, card.id + ':run');
|
|
513
|
+
process.addEventListener('toggle', () => {
|
|
514
|
+
events.dataset.expanded = String(process.open);
|
|
515
|
+
card.attention.hidden = process.open || !card.noticeCount;
|
|
516
|
+
if (card.projection) {
|
|
517
|
+
renderSetup(card, card.projection.setup, card.run.status === 'running');
|
|
518
|
+
if (!process.open) card.setup.hidden = true;
|
|
519
|
+
renderPeek(card, card.projection, card.run, card.run.status === 'running');
|
|
520
|
+
}
|
|
521
|
+
});
|
|
522
|
+
render(card, run);
|
|
523
|
+
}
|
|
524
|
+
function render(card, run, incoming) {
|
|
525
|
+
card.run = run;
|
|
526
|
+
const result = Model.project(run, incoming, { isGuidance });
|
|
527
|
+
card.projection = result;
|
|
528
|
+
subagentView?.update(card);
|
|
529
|
+
const active = run.status === 'running';
|
|
530
|
+
const abnormal = ['failed', 'interrupted', 'needs_review_after_navigation', 'abandoned_after_navigation'].includes(run.status);
|
|
531
|
+
if (choices.has(card.id + ':run')) card.process.open = choices.get(card.id + ':run');
|
|
532
|
+
// A live run starts collapsed onto its peek window; problems open it.
|
|
533
|
+
else card.process.open = abnormal;
|
|
534
|
+
card.events.dataset.expanded = String(card.process.open);
|
|
535
|
+
card.summary.setAttribute('aria-expanded', String(card.process.open));
|
|
536
|
+
reconcile(card.events, result.blocks, card.rows, block => buildBlock(block, card),
|
|
537
|
+
(row, block) => updateBlock(row, block, card, run));
|
|
538
|
+
renderSetup(card, result.setup, active);
|
|
539
|
+
// Live start-up stays open; once work begins (or in history) it follows the run disclosure.
|
|
540
|
+
if (active && !result.setup?.done) card.setup.open = true;
|
|
541
|
+
else if (!choices.has(card.id + ':setup')) card.setup.open = false;
|
|
542
|
+
if (!card.process.open) card.setup.hidden = true;
|
|
543
|
+
renderPeek(card, result, run, active);
|
|
544
|
+
card.noticeCount = result.notices.length;
|
|
545
|
+
const latestNotice = result.notices.at(-1);
|
|
546
|
+
card.attention.hidden = card.process.open || !latestNotice;
|
|
547
|
+
text(card.attention, latestNotice ? plain(latestNotice.event.title) : '');
|
|
548
|
+
paintPresence(card, run, result, active);
|
|
549
|
+
// The ∎ header carries the file count (and its recorded-only caveat) whenever presence is on.
|
|
550
|
+
card.metrics.hidden = active || !result.fileCount || Boolean(presence);
|
|
551
|
+
text(card.metrics, (result.clipped ? tx('Recorded: ', '已记录:') : '')
|
|
552
|
+
+ tx(result.fileCount + ' local files changed', result.fileCount + ' 个本地文件有改动'));
|
|
553
|
+
const hasActive = result.blocks.some(block => block.kind === 'message' && block.event.status === 'running'
|
|
554
|
+
|| block.kind === 'exploreGroup' && block.items.some(item => item.meta.state === 'running')
|
|
555
|
+
|| block.meta?.state === 'running');
|
|
556
|
+
// The presence header already narrates the live state.
|
|
557
|
+
card.busy.hidden = !active || hasActive || Boolean(presence);
|
|
558
|
+
text(card.busy, result.stage === 'local_completed'
|
|
559
|
+
? (run.mode === 'ask' ? tx('Preparing the answer…', '正在整理回答…') : tx('Preparing writeback and verification…', '正在准备写回与验证…'))
|
|
560
|
+
: result.stage === 'preparing' ? tx('Preparing project context…', '正在准备项目上下文…') : tx('Working…', '正在处理…'));
|
|
561
|
+
}
|
|
562
|
+
// Live header: long phases are named; otherwise a rarely-changing word. Tool steps stay in the round list.
|
|
563
|
+
function runningLabel(result, run) {
|
|
564
|
+
if (result.stage === 'sync') return { kind: 'stage', text: tx('Syncing changes to Overleaf', '正在同步改动到 Overleaf') };
|
|
565
|
+
// Before the model's first response the header names the real start-up step, not a playful word.
|
|
566
|
+
if (result.setup && !result.setup.done) return { kind: 'stage', text: setupLiveLabel(result.setup) };
|
|
567
|
+
if (result.stage === 'preparing') return { kind: 'stage', text: tx('Preparing project context', '正在准备项目上下文') };
|
|
568
|
+
if (result.stage === 'local_completed') {
|
|
569
|
+
return { kind: 'stage', text: run.mode === 'ask' ? tx('Preparing the answer', '正在整理回答')
|
|
570
|
+
: tx('Preparing writeback and verification', '正在准备写回与验证') };
|
|
571
|
+
}
|
|
572
|
+
return { kind: 'idle' };
|
|
573
|
+
}
|
|
574
|
+
function paintPresence(card, run, result, active) {
|
|
575
|
+
const status = card.root.querySelector('[data-run-status]');
|
|
576
|
+
if (!presence || !status) return;
|
|
577
|
+
// History cards arrive with plain status text; keep it for failure and fallback labels.
|
|
578
|
+
if (!status.dataset.presence && !status.dataset.presenceText) status.dataset.presenceText = status.textContent;
|
|
579
|
+
const started = Date.parse(run.startedAt || '');
|
|
580
|
+
if (active) {
|
|
581
|
+
presence.paintRunning(status, { runId: card.id, label: runningLabel(result, run),
|
|
582
|
+
elapsedMs: Number.isFinite(started) ? Math.max(0, Date.now() - started) : undefined });
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
const finished = Date.parse(run.finishedAt || '');
|
|
586
|
+
const facts = { kind: classifyStatus?.(run) || 'plain', text: status.dataset.presenceText || status.textContent,
|
|
587
|
+
elapsedMs: Number.isFinite(started) && Number.isFinite(finished) ? Math.max(0, finished - started) : null,
|
|
588
|
+
files: result.fileCount, filesClipped: result.clipped === true, added: 0, removed: 0, steps: 0, compiled: false,
|
|
589
|
+
projectId: getProjectId?.() || '', animate: card.animateNext === true };
|
|
590
|
+
card.animateNext = false;
|
|
591
|
+
for (const block of result.blocks) {
|
|
592
|
+
if (['message', 'guidance', 'thought'].includes(block.kind)) continue;
|
|
593
|
+
facts.steps += block.kind === 'exploreGroup' ? block.items.length : 1;
|
|
594
|
+
if (block.file && block.meta?.state === 'completed') {
|
|
595
|
+
facts.added += block.file.added || 0;
|
|
596
|
+
facts.removed += block.file.removed || 0;
|
|
597
|
+
}
|
|
598
|
+
if (block.kind === 'compile' && block.meta?.state === 'completed') facts.compiled = true;
|
|
599
|
+
}
|
|
600
|
+
presence.paintSettled(status, facts);
|
|
601
|
+
}
|
|
602
|
+
function update(view, incoming) {
|
|
603
|
+
const { root, run } = resolve(view);
|
|
604
|
+
const card = root && cards.get(root);
|
|
605
|
+
if (!card || !run) return false;
|
|
606
|
+
const status = view?.terminalStatus || run.status || root.dataset.status;
|
|
607
|
+
render(card, status === run.status ? run : { ...run, status }, incoming);
|
|
608
|
+
return true;
|
|
609
|
+
}
|
|
610
|
+
function settle(view, statusText) {
|
|
611
|
+
const { root } = resolve(view);
|
|
612
|
+
const card = root && cards.get(root);
|
|
613
|
+
const status = view?.status || root?.querySelector('[data-run-status]');
|
|
614
|
+
if (presence && card && status) {
|
|
615
|
+
status.dataset.presenceText = statusText;
|
|
616
|
+
card.animateNext = true;
|
|
617
|
+
if (update(view)) return;
|
|
618
|
+
}
|
|
619
|
+
update(view);
|
|
620
|
+
text(status, statusText);
|
|
621
|
+
}
|
|
622
|
+
function appendDetail(view, row, event) {
|
|
623
|
+
if (!update(view, event)) view.events?.append(row);
|
|
624
|
+
}
|
|
625
|
+
return { mount, update, settle, appendDetail,
|
|
626
|
+
closeSubagentView: () => subagentView?.close(),
|
|
627
|
+
isSubagentViewOpen: () => subagentView?.isOpen() || false };
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
window.CodexOverleafRunActivitySummary = { create };
|
|
631
|
+
})();
|
|
@@ -232,7 +232,9 @@
|
|
|
232
232
|
}
|
|
233
233
|
|
|
234
234
|
function isRetryReplacementEligible(run = {}, projection = {}) {
|
|
235
|
-
if (
|
|
235
|
+
if (run.retryWriteback || run.saveCheck) return false;
|
|
236
|
+
if (!run.id || run.forkSnapshot === true
|
|
237
|
+
|| !['failed', 'interrupted', 'cancelled', 'rejected'].includes(run.status)) return false;
|
|
236
238
|
if (run.trackedChangeStatus || run.undoStatus) return false;
|
|
237
239
|
if (['undoOperations', 'undoTrackedChanges', 'undoExpectedFiles', 'undoBaseFiles', 'appliedOperations']
|
|
238
240
|
.some(field => Array.isArray(run[field]) && run[field].length)) return false;
|