codex-overleaf-link 2.4.1 → 2.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +275 -305
- package/README.zh-CN.md +290 -320
- package/extension/bootstrap/background.js +99 -19
- package/extension/bootstrap/manifest.template.json +9 -4
- package/extension/bootstrap/popup.html +11 -16
- package/extension/bootstrap/popupFallback.js +55 -0
- package/extension/bootstrap/update.js +25 -2
- package/extension/bootstrap/updateStatus.js +1 -0
- package/extension/runtime-manifest.json +3 -1
- package/extension/src/background.js +234 -56
- package/extension/src/backgroundBootstrapMigration.js +181 -0
- package/extension/src/backgroundSharedSessions.js +440 -0
- package/extension/src/backgroundUpdateCoordinator.js +541 -381
- package/extension/src/backgroundUpdateSafety.js +173 -0
- package/extension/src/content/activeTurnControl.js +16 -2
- package/extension/src/content/applyResultFormatters.js +46 -73
- package/extension/src/content/assetTransferBroker.js +244 -12
- package/extension/src/content/changeHistoryView.js +175 -0
- package/extension/src/content/composerAttachments.js +117 -67
- package/extension/src/content/composerPanel.js +41 -8
- package/extension/src/content/contentRuntime.js +1084 -1099
- package/extension/src/content/diagnosticsController.js +122 -97
- package/extension/src/content/diagnosticsExport.js +236 -0
- package/extension/src/content/diagnosticsPanel.js +78 -19
- package/extension/src/content/diffReviewPanel.js +8 -5
- package/extension/src/content/directoryCleanupRecovery.js +54 -0
- package/extension/src/content/generated/content.bundle.js +14680 -3606
- package/extension/src/content/generated/content.bundle.meta.json +30 -3
- package/extension/src/content/globalPreferencesController.js +1 -1
- package/extension/src/content/legacyGlobalRegistry.js +25 -1
- package/extension/src/content/localSkillsPanel.js +141 -16
- package/extension/src/content/markdownDomRenderer.js +9 -4
- package/extension/src/content/markdownText.js +5 -6
- package/extension/src/content/modelPicker.js +8 -5
- package/extension/src/content/nativeCompatibilityController.js +45 -20
- package/extension/src/content/otWarmMirror.js +4 -5
- package/extension/src/content/otWarmMirrorController.js +17 -20
- package/extension/src/content/pageBridgeClient.js +33 -5
- package/extension/src/content/panelMaintenance.js +87 -132
- package/extension/src/content/panelRenderer.js +10 -0
- package/extension/src/content/pendingInputView.js +109 -76
- package/extension/src/content/projectProviderSelection.js +13 -4
- package/extension/src/content/projectSessionCleanup.js +109 -62
- package/extension/src/content/projectSettingsCoordinator.js +39 -2
- package/extension/src/content/providerSettingsCoordinator.js +63 -14
- package/extension/src/content/providerSettingsDialog.js +724 -113
- package/extension/src/content/recentProjects.js +21 -6
- package/extension/src/content/runActivitySummary.js +665 -0
- package/extension/src/content/runCompletionMeta.js +344 -0
- package/extension/src/content/runController.js +40 -15
- package/extension/src/content/runFailureNotice.js +34 -12
- package/extension/src/content/runGuidanceController.js +76 -30
- package/extension/src/content/runGuidanceView.js +59 -10
- package/extension/src/content/runPresence.js +306 -0
- package/extension/src/content/runQueueScheduler.js +150 -43
- package/extension/src/content/runRecoveryActions.js +146 -0
- package/extension/src/content/runResultActions.js +11 -8
- package/extension/src/content/runReviewController.js +574 -0
- package/extension/src/content/runScrollLayout.js +21 -2
- package/extension/src/content/runTimelineView.js +315 -290
- package/extension/src/content/scopedPersistencePanelState.js +51 -6
- package/extension/src/content/selectionContextView.js +300 -0
- package/extension/src/content/sensitivePreflight.js +140 -0
- package/extension/src/content/sessionForkController.js +80 -17
- package/extension/src/content/sessionManager.js +1 -1
- package/extension/src/content/sessionPersistence.js +6 -1
- package/extension/src/content/settingsPanel.js +84 -55
- package/extension/src/content/settingsWorkbench.js +379 -0
- package/extension/src/content/sharedSessionViewSync.js +109 -0
- package/extension/src/content/subagentActivityView.js +195 -0
- package/extension/src/content/trackedChangeCaptureController.js +7 -3
- package/extension/src/content/updateIdle.js +4 -1
- package/extension/src/content/updateNotice.js +179 -56
- package/extension/src/content/updateSafetyReceiver.js +58 -0
- package/extension/src/content/writebackController.js +308 -2
- package/extension/src/content/writebackOrchestrator.js +213 -199
- package/extension/src/content/writebackPlan.js +231 -0
- package/extension/src/content/writebackRecovery.js +122 -0
- package/extension/src/content/writingStyleSettings.js +600 -0
- package/extension/src/content/writtenChangesView.js +152 -0
- package/extension/src/page/binaryAssetUploader.js +223 -23
- package/extension/src/page/fileMover.js +256 -0
- package/extension/src/page/overleafProjectSnapshot.js +1 -0
- package/extension/src/page/ownedDirectoryCleanup.js +94 -0
- package/extension/src/page/referenceProjects.js +149 -0
- package/extension/src/page/reviewContext.js +113 -0
- package/extension/src/page/saveState.js +20 -6
- package/extension/src/page/snapshotRouter.js +124 -48
- package/extension/src/page/textCoordinates.js +102 -0
- package/extension/src/page/textFileCreator.js +442 -71
- package/extension/src/page/trackedChangeCapture.js +53 -57
- package/extension/src/page/trackedChangeOwnership.js +216 -0
- package/extension/src/page/trackedChangeReplay.js +184 -0
- package/extension/src/page/trackedChangesLifecycle.js +343 -339
- package/extension/src/page/treeOperations.js +33 -12
- package/extension/src/page/updateSafetyProbe.js +41 -0
- package/extension/src/page/writebackReceiptJournal.js +114 -0
- package/extension/src/page/writebackRouter.js +242 -201
- package/extension/src/pageBridge.js +73 -102
- package/extension/src/popup.js +261 -65
- package/extension/src/shared/agentTranscript.js +41 -4
- package/extension/src/shared/auditRecords.js +73 -0
- package/extension/src/shared/changeHistoryModel.js +94 -0
- package/extension/src/shared/compatibility.js +22 -6
- package/extension/src/shared/compileAdapter.js +101 -37
- package/extension/src/shared/composerAttachmentDraft.js +151 -0
- package/extension/src/shared/directoryCleanupProof.js +43 -0
- package/extension/src/shared/failureReasons.js +329 -3
- package/extension/src/shared/globalPreferences.js +31 -14
- package/extension/src/shared/governanceRules.js +4 -37
- package/extension/src/shared/i18n.js +389 -25
- package/extension/src/shared/managedUpdateProjection.js +8 -5
- package/extension/src/shared/nativeRequestIdentity.js +1 -0
- package/extension/src/shared/pageRpcContract.js +9 -2
- package/extension/src/shared/projectFiles.js +21 -44
- package/extension/src/shared/providerProfiles.js +114 -3
- package/extension/src/shared/runActivityModel.js +361 -0
- package/extension/src/shared/runExecutionSnapshot.js +8 -2
- package/extension/src/shared/runExecutionSnapshotCodec.js +16 -4
- package/extension/src/shared/runInputQueue.js +48 -5
- package/extension/src/shared/scopedPersistenceBrowserAdapter.js +6 -3
- package/extension/src/shared/selectionContext.js +37 -0
- package/extension/src/shared/sessionState.js +166 -30
- package/extension/src/shared/settlementFacts.js +10 -2
- package/extension/src/shared/sharedSessionBridge.js +311 -0
- package/extension/src/shared/sharedSessionTransfer.js +140 -0
- package/extension/src/shared/staleGuard.js +118 -13
- package/extension/src/shared/storageDb.js +77 -78
- package/extension/src/shared/storageMigration.js +74 -111
- package/extension/src/shared/storageRunActions.js +211 -22
- package/extension/src/shared/storageValuePruning.js +40 -0
- package/extension/src/shared/subagentActivityModel.js +174 -0
- package/extension/src/shared/undoOperations.js +216 -6
- package/extension/src/shared/updateConsent.js +42 -11
- package/extension/src/shared/updateRuntimeIdentity.js +1 -1
- package/extension/src/shared/writebackIntent.js +78 -0
- package/extension/src/shared/writebackOperationEvidence.js +4 -15
- package/extension/src/shared/writebackSettlement.js +67 -48
- package/extension/src/shared/writingStyle.js +33 -0
- package/extension/styles/panel.css +1987 -385
- package/extension/styles/popup.css +110 -0
- package/native-host/src/anthropicBridgeRequest.js +6 -3
- package/native-host/src/anthropicBridgeResponse.js +6 -2
- package/native-host/src/anthropicMessagesBridge.js +24 -16
- package/native-host/src/bootstrapMigration.js +296 -0
- package/native-host/src/bootstrapMigrationContract.js +101 -0
- package/native-host/src/bootstrapUpdate.js +233 -0
- package/native-host/src/bootstrapUpdateWatchdog.js +44 -0
- package/native-host/src/chatBridgeResponse.js +10 -0
- package/native-host/src/chatCompletionsBridge.js +21 -15
- package/native-host/src/codexConfigPaths.js +106 -0
- package/native-host/src/codexHome.js +66 -73
- package/native-host/src/codexHomeScope.js +124 -0
- package/native-host/src/codexInheritedAuth.js +90 -0
- package/native-host/src/codexLocalSkills.js +301 -0
- package/native-host/src/codexModelRecovery.js +107 -0
- package/native-host/src/codexPromptAssembly.js +33 -12
- package/native-host/src/codexProviderLaunch.js +3 -3
- package/native-host/src/codexProviderTest.js +24 -26
- package/native-host/src/codexRuntimeIdentity.js +1 -0
- package/native-host/src/codexSessionRunner.js +211 -318
- package/native-host/src/codexSessionTiming.js +21 -8
- package/native-host/src/codexSkillIsolation.js +170 -0
- package/native-host/src/codexThreadFork.js +19 -3
- package/native-host/src/index.js +19 -7
- package/native-host/src/managedInstall.js +115 -39
- package/native-host/src/managedInstallRecovery.js +140 -0
- package/native-host/src/managedRuntimeEvidence.js +57 -0
- package/native-host/src/mirrorWorkspace.js +92 -22
- package/native-host/src/nativeDoctor.js +15 -0
- package/native-host/src/nativeEnvironment.js +70 -0
- package/native-host/src/nativeHelperLifecycle.js +21 -0
- package/native-host/src/nativeHostRegistration.js +33 -0
- package/native-host/src/nativeQuotas.js +15 -8
- package/native-host/src/nativeRunLifecycle.js +71 -0
- package/native-host/src/overleafWorkspaceRules.js +16 -0
- package/native-host/src/processStopBarrier.js +115 -0
- package/native-host/src/projectPathPlatform.js +30 -0
- package/native-host/src/providerHttp.js +80 -0
- package/native-host/src/providerModelCatalog.js +4 -3
- package/native-host/src/providerProfile.js +17 -3
- package/native-host/src/providerReasoning.js +10 -11
- package/native-host/src/providerRuntime.js +1 -0
- package/native-host/src/providerStore.js +76 -14
- package/native-host/src/releaseTransport.js +14 -5
- package/native-host/src/responsesPassthroughBridge.js +266 -52
- package/native-host/src/runtimeInstaller.js +21 -1
- package/native-host/src/selectionScope.js +86 -0
- package/native-host/src/skills/parallel-subagents/SKILL.md +31 -3
- package/native-host/src/skills/writing-style-builder/SKILL.md +146 -0
- package/native-host/src/subagentAdmission.js +26 -0
- package/native-host/src/subagentBroker.js +176 -159
- package/native-host/src/subagentTelemetry.js +325 -0
- package/native-host/src/subagentWorkspace.js +103 -0
- package/native-host/src/subagentWorkspacePath.js +34 -0
- package/native-host/src/taskRunnerRuntime.js +130 -57
- package/native-host/src/tomlStatements.js +140 -0
- package/native-host/src/turnAttachments.js +113 -0
- package/native-host/src/updateManager.js +406 -38
- package/native-host/src/updateNetworkControl.js +75 -0
- package/native-host/src/updateTrust.js +21 -2
- package/native-host/src/vendor/pdfjs/LICENSE +177 -0
- package/native-host/src/vendor/pdfjs/SOURCE.txt +3 -0
- package/native-host/src/vendor/pdfjs/cmaps/78-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78ms-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/78ms-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/83pv-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/90ms-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/90ms-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/90msp-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/90msp-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/90pv-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/90pv-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Add-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Add-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Add-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Add-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-0.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-1.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-3.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-4.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-5.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-6.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-0.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-1.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-3.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-4.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-5.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-0.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-1.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-3.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-4.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-5.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-6.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-0.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-1.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/B5pc-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/B5pc-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/CNS-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/CNS-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/CNS1-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/CNS1-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/CNS2-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/CNS2-V.bcmap +3 -0
- package/native-host/src/vendor/pdfjs/cmaps/ETHK-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/ETHK-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/ETen-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/ETen-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/ETenms-B5-H.bcmap +3 -0
- package/native-host/src/vendor/pdfjs/cmaps/ETenms-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Ext-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Ext-RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Ext-RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Ext-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GB-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GB-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GB-H.bcmap +4 -0
- package/native-host/src/vendor/pdfjs/cmaps/GB-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBK-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBK-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBK2K-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBK2K-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBKp-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBKp-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBT-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBT-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBT-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBT-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBTpc-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBTpc-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBpc-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/GBpc-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKdla-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKdla-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKdlb-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKdlb-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKgccs-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKgccs-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKm314-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKm314-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKm471-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKm471-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKscs-B5-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/HKscs-B5-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Hankaku.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Hiragana.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSC-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSC-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSC-Johab-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSC-Johab-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSCms-UHC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSCpc-EUC-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/KSCpc-EUC-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Katakana.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/LICENSE +36 -0
- package/native-host/src/vendor/pdfjs/cmaps/NWP-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/NWP-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/RKSJ-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/RKSJ-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/Roman.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UCS2-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UCS2-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF16-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF16-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF8-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniCNS-UTF8-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UCS2-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UCS2-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF16-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF16-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF8-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniGB-UTF8-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UCS2-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF16-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF16-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF8-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS-UTF8-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UCS2-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UCS2-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF16-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF16-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF32-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF32-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF8-H.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/UniKS-UTF8-V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/V.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/cmaps/WP-Symbol.bcmap +0 -0
- package/native-host/src/vendor/pdfjs/pdf.mjs +26740 -0
- package/native-host/src/vendor/pdfjs/pdf.worker.mjs +62201 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitDingbats.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixed.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedBold.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitFixedItalic.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerif.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifBold.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSerifItalic.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/FoxitSymbol.pfb +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/LICENSE_FOXIT +27 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/LICENSE_LIBERATION +102 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Bold.ttf +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Italic.ttf +0 -0
- package/native-host/src/vendor/pdfjs/standard_fonts/LiberationSans-Regular.ttf +0 -0
- package/native-host/src/writingStyleEvidence.js +102 -0
- package/native-host/src/writingStylePdfWorker.js +35 -0
- package/native-host/src/writingStyleProfile.js +165 -0
- package/native-host/src/writingStyleRuntime.js +475 -0
- package/native-host/src/writingStyleStore.js +73 -0
- package/package.json +1 -1
- package/scripts/install-managed.mjs +1 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
color-scheme: dark;
|
|
3
|
+
--popup-bg: light-dark(#ffffff, #1b201d);
|
|
4
|
+
--popup-text: light-dark(#28312b, #e5eae6);
|
|
5
|
+
--popup-muted: light-dark(#717b74, #a3aea6);
|
|
6
|
+
--popup-border: light-dark(#e8ece9, #333c36);
|
|
7
|
+
--popup-surface: light-dark(#f6f8f6, #242c27);
|
|
8
|
+
--popup-green: light-dark(#35734a, #9ccdab);
|
|
9
|
+
--popup-on-green: light-dark(#ffffff, #182b1f);
|
|
10
|
+
--popup-danger: light-dark(#aa443d, #df928c);
|
|
11
|
+
--popup-warn: light-dark(#99702a, #d6b671);
|
|
12
|
+
}
|
|
13
|
+
:root[data-popup-theme="light"] { color-scheme: light; }
|
|
14
|
+
:root[data-popup-theme="auto"] { color-scheme: light dark; }
|
|
15
|
+
/* Give Chrome an intrinsic popup width; viewport-relative caps can shrink it
|
|
16
|
+
back to the initial narrow viewport during popup sizing. */
|
|
17
|
+
html.popup-minimal-root {
|
|
18
|
+
box-sizing: border-box;
|
|
19
|
+
width: 340px;
|
|
20
|
+
min-width: 340px;
|
|
21
|
+
margin: 0;
|
|
22
|
+
overflow-x: hidden;
|
|
23
|
+
overflow-y: auto;
|
|
24
|
+
background: var(--popup-bg);
|
|
25
|
+
}
|
|
26
|
+
.popup-minimal * { box-sizing: border-box; }
|
|
27
|
+
body.popup-minimal {
|
|
28
|
+
width: 340px;
|
|
29
|
+
min-width: 340px;
|
|
30
|
+
max-width: none;
|
|
31
|
+
min-height: 0;
|
|
32
|
+
margin: 0;
|
|
33
|
+
padding: 0;
|
|
34
|
+
color: var(--popup-text);
|
|
35
|
+
background: var(--popup-bg);
|
|
36
|
+
font: 13px/1.5 "Avenir Next", "Segoe UI", sans-serif;
|
|
37
|
+
animation: none;
|
|
38
|
+
}
|
|
39
|
+
.popup-minimal #popup-shell { display: block; width: 100%; min-width: 0; }
|
|
40
|
+
.popup-minimal .popup-header { display: flex; align-items: center; gap: 12px; padding: 17px 18px 16px; }
|
|
41
|
+
.popup-minimal .popup-icon { display: block; width: 32px; height: 32px; object-fit: contain; flex: 0 0 auto; }
|
|
42
|
+
.popup-minimal .popup-brand { flex: 1; min-width: 0; }
|
|
43
|
+
.popup-minimal .popup-brand h1 { margin: 0; font-size: 14px; font-weight: 500; letter-spacing: -.02em; line-height: 1.45; white-space: nowrap; overflow-wrap: normal; }
|
|
44
|
+
.popup-minimal .connection-toggle {
|
|
45
|
+
appearance: none;
|
|
46
|
+
display: inline-flex;
|
|
47
|
+
align-items: center;
|
|
48
|
+
gap: 5px;
|
|
49
|
+
width: auto;
|
|
50
|
+
min-height: 24px;
|
|
51
|
+
margin: 1px 0 -2px -4px;
|
|
52
|
+
padding: 2px 4px;
|
|
53
|
+
border: 1px solid transparent;
|
|
54
|
+
border-radius: 5px;
|
|
55
|
+
box-shadow: none;
|
|
56
|
+
background: transparent;
|
|
57
|
+
color: var(--popup-muted);
|
|
58
|
+
font: inherit;
|
|
59
|
+
font-size: 11px;
|
|
60
|
+
font-weight: 400;
|
|
61
|
+
line-height: 1.45;
|
|
62
|
+
white-space: nowrap;
|
|
63
|
+
cursor: pointer;
|
|
64
|
+
}
|
|
65
|
+
.popup-minimal .connection-toggle:hover { border-color: var(--popup-border); background: var(--popup-surface); color: var(--popup-text); transform: none; }
|
|
66
|
+
.popup-minimal .connection-chevron { width: 5px; height: 5px; flex: 0 0 auto; margin: -2px 2px 0; border: solid currentColor; border-width: 0 1px 1px 0; transform: rotate(45deg); }
|
|
67
|
+
.popup-minimal .connection-toggle[aria-expanded="true"] .connection-chevron { margin-top: 2px; transform: rotate(225deg); }
|
|
68
|
+
.popup-minimal .status-icon { display: block; width: 5px; height: 5px; min-width: 5px; min-height: 5px; flex: 0 0 auto; border-radius: 50%; background: var(--popup-muted); font-size: 0; box-shadow: none; }
|
|
69
|
+
.popup-minimal .status-icon.compatible { background: var(--popup-green); }
|
|
70
|
+
.popup-minimal .status-icon.update-available { background: var(--popup-warn); }
|
|
71
|
+
.popup-minimal .status-icon.incompatible { background: var(--popup-danger); }
|
|
72
|
+
.popup-minimal .connection-details { padding: 12px 18px; border-top: 1px solid var(--popup-border); background: var(--popup-surface); }
|
|
73
|
+
.popup-minimal #version-pair { display: grid; gap: 8px; margin: 0; font-size: 11px; line-height: 1.45; }
|
|
74
|
+
.popup-minimal #version-pair > div { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
|
|
75
|
+
.popup-minimal #version-pair dt { color: var(--popup-muted); }
|
|
76
|
+
.popup-minimal #version-pair dd { margin: 0; color: var(--popup-text); font-variant-numeric: tabular-nums; white-space: nowrap; }
|
|
77
|
+
.popup-minimal .launcher-setting { display: grid; grid-template-columns: minmax(0, 1fr) 31px; align-items: center; gap: 16px; padding: 15px 18px 17px; border-top: 1px solid var(--popup-border); cursor: pointer; }
|
|
78
|
+
.popup-minimal .launcher-copy { min-width: 0; }
|
|
79
|
+
.popup-minimal .launcher-copy strong { display: block; font-size: 12px; font-weight: 500; line-height: 1.5; }
|
|
80
|
+
.popup-minimal .launcher-copy small { display: block; margin-top: 3px; color: var(--popup-muted); font-size: 11px; line-height: 1.5; }
|
|
81
|
+
.popup-minimal .launcher-toggle {
|
|
82
|
+
appearance: none;
|
|
83
|
+
-webkit-appearance: none;
|
|
84
|
+
position: relative;
|
|
85
|
+
width: 31px;
|
|
86
|
+
height: 19px;
|
|
87
|
+
margin: 0;
|
|
88
|
+
padding: 0;
|
|
89
|
+
flex: 0 0 auto;
|
|
90
|
+
border: 1px solid var(--popup-border);
|
|
91
|
+
border-radius: 20px;
|
|
92
|
+
background: var(--popup-surface);
|
|
93
|
+
cursor: pointer;
|
|
94
|
+
}
|
|
95
|
+
.popup-minimal .launcher-toggle::after { content: ""; position: absolute; top: 2px; left: 2px; width: 13px; height: 13px; border-radius: 50%; background: var(--popup-muted); transition: transform 130ms ease; }
|
|
96
|
+
.popup-minimal .launcher-toggle:checked { border-color: var(--popup-green); background: var(--popup-green); }
|
|
97
|
+
.popup-minimal .launcher-toggle:checked::after { background: var(--popup-on-green); transform: translateX(12px); }
|
|
98
|
+
.popup-minimal .launcher-toggle:disabled { cursor: default; opacity: .5; }
|
|
99
|
+
.popup-minimal .popup-note { margin: 0; padding: 11px 18px; border-top: 1px solid var(--popup-border); color: var(--popup-muted); font-size: 11px; line-height: 1.6; overflow-wrap: anywhere; }
|
|
100
|
+
.popup-minimal .popup-note[role="alert"] { color: var(--popup-danger); }
|
|
101
|
+
.popup-minimal .install { margin: 0; padding: 14px 18px 16px; border: 0; border-top: 1px solid var(--popup-border); border-radius: 0; background: var(--popup-surface); }
|
|
102
|
+
.popup-minimal .install > strong { font-size: 12px; font-weight: 500; }
|
|
103
|
+
.popup-minimal .install p { margin: 6px 0 0; color: var(--popup-muted); font-size: 11px; line-height: 1.6; }
|
|
104
|
+
.popup-minimal .install code { display: block; margin: 10px 0; padding: 9px; max-height: 120px; overflow: auto; border: 1px solid var(--popup-border); border-radius: 6px; color: var(--popup-text); background: var(--popup-bg); white-space: pre-wrap; overflow-wrap: anywhere; font: 11px/1.5 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
|
|
105
|
+
.popup-minimal .copy-command { appearance: none; width: auto; min-height: 29px; margin: 0; padding: 5px 8px; border: 1px solid var(--popup-border); border-radius: 6px; background: var(--popup-bg); color: var(--popup-text); font: inherit; font-size: 11px; font-weight: 500; cursor: pointer; }
|
|
106
|
+
.popup-minimal .copy-command:hover { background: var(--popup-surface); border-color: var(--popup-muted); transform: none; }
|
|
107
|
+
.popup-minimal .copy-command:disabled { opacity: .55; cursor: default; }
|
|
108
|
+
.popup-minimal button:focus-visible, .popup-minimal input:focus-visible { outline: 2px solid var(--popup-green); outline-offset: 3px; }
|
|
109
|
+
.popup-minimal [hidden] { display: none !important; }
|
|
110
|
+
@media (prefers-reduced-motion: reduce) { .popup-minimal .launcher-toggle::after { transition: none; } }
|
|
@@ -34,7 +34,7 @@ function buildAnthropicRequest({ requestBody = {}, launch = {}, historyMessages
|
|
|
34
34
|
model,
|
|
35
35
|
max_tokens: maxTokens,
|
|
36
36
|
messages,
|
|
37
|
-
stream: requestBody.stream !== false
|
|
37
|
+
stream: requestBody.stream !== false && launch.upstreamResponseMode !== 'buffered'
|
|
38
38
|
};
|
|
39
39
|
if (systemParts.length) {
|
|
40
40
|
body.system = launch.anthropicPromptCaching
|
|
@@ -175,7 +175,8 @@ function convertToolChoice(value, context, launch) {
|
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
function applyAnthropicThinking(body, requestBody, launch, maxTokens) {
|
|
178
|
-
|
|
178
|
+
// The captured panel choice wins over a model-generated request default.
|
|
179
|
+
const effort = text(launch.reasoningEffort || requestBody?.reasoning?.effort).toLowerCase();
|
|
179
180
|
if (!effort || ['none', 'off', 'disabled'].includes(effort) || launch.anthropicThinkingMode === 'none') {
|
|
180
181
|
return false;
|
|
181
182
|
}
|
|
@@ -217,8 +218,10 @@ function rectifyAnthropicRequestForRetry(body, errorText) {
|
|
|
217
218
|
return changed;
|
|
218
219
|
}
|
|
219
220
|
if (/budget_tokens|thinking budget|must be less than max_tokens|at least 1024/i.test(message)) {
|
|
221
|
+
// Keep this existing compatibility retry only when its budget fits the
|
|
222
|
+
// caller's maximum. Otherwise expose the original upstream rejection.
|
|
223
|
+
if (!Number.isFinite(Number(body.max_tokens)) || Number(body.max_tokens) < 64000) return false;
|
|
220
224
|
body.thinking = { type: 'enabled', budget_tokens: 32000 };
|
|
221
|
-
body.max_tokens = Math.max(Number(body.max_tokens) || 0, 64000);
|
|
222
225
|
delete body.output_config;
|
|
223
226
|
return true;
|
|
224
227
|
}
|
|
@@ -216,6 +216,7 @@ function appendBlockDelta(state, res, index, delta) {
|
|
|
216
216
|
function closeBlock(state, res, index) {
|
|
217
217
|
const entry = state.blocks.get(index);
|
|
218
218
|
if (!entry || entry.closed) return;
|
|
219
|
+
const args = entry.type === 'tool_use' ? canonicalArguments(entry.arguments) : '';
|
|
219
220
|
entry.closed = true;
|
|
220
221
|
if (entry.type === 'text') {
|
|
221
222
|
const part = { type: 'output_text', text: entry.text, annotations: [] };
|
|
@@ -236,7 +237,6 @@ function closeBlock(state, res, index) {
|
|
|
236
237
|
state.assistantBlocks[index] = block;
|
|
237
238
|
} else {
|
|
238
239
|
entry.item.status = 'completed';
|
|
239
|
-
const args = canonicalArguments(entry.arguments);
|
|
240
240
|
if (entry.kind === 'custom') {
|
|
241
241
|
entry.item.input = unwrapCustomInput(args);
|
|
242
242
|
emit(state, res, 'response.custom_tool_call_input.done', { item_id: entry.item.id, output_index: entry.outputIndex, input: entry.item.input });
|
|
@@ -401,7 +401,11 @@ function reserve(state, item) {
|
|
|
401
401
|
}
|
|
402
402
|
|
|
403
403
|
function canonicalArguments(value) {
|
|
404
|
-
try {
|
|
404
|
+
try {
|
|
405
|
+
return JSON.stringify(JSON.parse(value || '{}'));
|
|
406
|
+
} catch (_error) {
|
|
407
|
+
throw responseError('The provider returned incomplete or invalid JSON tool arguments.');
|
|
408
|
+
}
|
|
405
409
|
}
|
|
406
410
|
|
|
407
411
|
function unwrapCustomInput(value) {
|
|
@@ -13,6 +13,7 @@ const {
|
|
|
13
13
|
const { writeConvertedResponseAsSse } = require('./chatBridgeResponse');
|
|
14
14
|
const { classifyResponsesRoute } = require('./providerBridgeRoutes');
|
|
15
15
|
const { providerError } = require('./providerProfile');
|
|
16
|
+
const { fetchProvider, readProviderText, readProviderJson } = require('./providerHttp');
|
|
16
17
|
const { sanitizeProviderMessage } = require('./providerRedaction');
|
|
17
18
|
const { logDebug } = require('./debugLog');
|
|
18
19
|
const {
|
|
@@ -92,9 +93,13 @@ async function handleRequest({ req, res, launch, clientToken, activeRequests, hi
|
|
|
92
93
|
const requestBody = await readJsonBody(req);
|
|
93
94
|
const previousResponseId = String(requestBody.previous_response_id || '');
|
|
94
95
|
const previous = history.get(previousResponseId);
|
|
95
|
-
const
|
|
96
|
+
const fallbackAllowed = !previousResponseId || previousResponseId === continuationState.responseId;
|
|
97
|
+
const fallbackAnchor = previous || !fallbackAllowed ? [] : continuationState.anchorMessages;
|
|
98
|
+
const continuationAttempts = previous
|
|
99
|
+
? Number(previous.continuationAttempts) || 0
|
|
100
|
+
: fallbackAllowed ? continuationState.attempts : 0;
|
|
96
101
|
const continuing = Boolean(previous?.continuation || fallbackAnchor.length);
|
|
97
|
-
if (continuing &&
|
|
102
|
+
if (continuing && continuationAttempts >= MAX_REASONING_CONTINUATIONS) {
|
|
98
103
|
throw providerError(
|
|
99
104
|
'provider_reasoning_continuation_exhausted',
|
|
100
105
|
'The provider repeatedly interrupted the same reasoning stream. Retry the task or use a different model endpoint.'
|
|
@@ -107,12 +112,12 @@ async function handleRequest({ req, res, launch, clientToken, activeRequests, hi
|
|
|
107
112
|
});
|
|
108
113
|
logDebug('provider.anthropic.request', {
|
|
109
114
|
model: translated.body.model,
|
|
110
|
-
stream:
|
|
115
|
+
stream: translated.body.stream,
|
|
111
116
|
maxTokens: translated.body.max_tokens,
|
|
112
117
|
thinkingType: translated.body.thinking?.type || 'disabled',
|
|
113
118
|
hasPreviousResponse: Boolean(previousResponseId),
|
|
114
119
|
continuing,
|
|
115
|
-
continuationAttempt:
|
|
120
|
+
continuationAttempt: continuationAttempts
|
|
116
121
|
});
|
|
117
122
|
const controller = new AbortController();
|
|
118
123
|
activeRequests.add(controller);
|
|
@@ -130,7 +135,7 @@ async function handleRequest({ req, res, launch, clientToken, activeRequests, hi
|
|
|
130
135
|
res.on('close', onClientClose);
|
|
131
136
|
lifecycle.start();
|
|
132
137
|
try {
|
|
133
|
-
const upstream = await fetchWithRectification(launch, translated.body, controller.signal);
|
|
138
|
+
const upstream = await fetchWithRectification(launch, translated.body, controller.signal, lifecycle.touch);
|
|
134
139
|
lifecycle.touch();
|
|
135
140
|
if (!upstream.response.ok) {
|
|
136
141
|
forwardUpstreamError(upstream.response, upstream.errorText, res, launch.apiKey);
|
|
@@ -152,14 +157,15 @@ async function handleRequest({ req, res, launch, clientToken, activeRequests, hi
|
|
|
152
157
|
const messages = [...baseMessages, ...assistantMessages];
|
|
153
158
|
if (anchored) {
|
|
154
159
|
continuationState.anchorMessages = messages;
|
|
155
|
-
continuationState.attempts
|
|
160
|
+
continuationState.attempts = continuationAttempts + 1;
|
|
156
161
|
continuationState.responseId = converted.response.id;
|
|
157
162
|
} else {
|
|
158
163
|
continuationState.anchorMessages = [];
|
|
159
164
|
continuationState.attempts = 0;
|
|
160
165
|
continuationState.responseId = '';
|
|
161
166
|
}
|
|
162
|
-
rememberHistory(history, converted.response.id, messages, { continuation: anchored
|
|
167
|
+
rememberHistory(history, converted.response.id, messages, { continuation: anchored,
|
|
168
|
+
continuationAttempts: anchored ? continuationAttempts + 1 : 0 });
|
|
163
169
|
const blocks = Array.isArray(converted.assistantBlocks) ? converted.assistantBlocks : [];
|
|
164
170
|
logDebug('provider.anthropic.response', {
|
|
165
171
|
responseId: converted.response.id,
|
|
@@ -185,7 +191,7 @@ async function handleRequest({ req, res, launch, clientToken, activeRequests, hi
|
|
|
185
191
|
recoverInterrupted: lifecycle.recoverInterrupted
|
|
186
192
|
});
|
|
187
193
|
} else {
|
|
188
|
-
const converted = convertAnthropicResponse(await upstream.response.
|
|
194
|
+
const converted = convertAnthropicResponse(await readProviderJson(upstream.response, lifecycle.touch), context);
|
|
189
195
|
writeConvertedResponseAsSse(res, converted, context, remember);
|
|
190
196
|
}
|
|
191
197
|
} else if (contentType.includes('text/event-stream')) {
|
|
@@ -202,7 +208,7 @@ async function handleRequest({ req, res, launch, clientToken, activeRequests, hi
|
|
|
202
208
|
remember(converted);
|
|
203
209
|
sendJson(res, 200, converted.response);
|
|
204
210
|
} else {
|
|
205
|
-
const converted = convertAnthropicResponse(await upstream.response.
|
|
211
|
+
const converted = convertAnthropicResponse(await readProviderJson(upstream.response, lifecycle.touch), context);
|
|
206
212
|
remember(converted);
|
|
207
213
|
sendJson(res, 200, converted.response);
|
|
208
214
|
}
|
|
@@ -224,27 +230,29 @@ async function handleRequest({ req, res, launch, clientToken, activeRequests, hi
|
|
|
224
230
|
}
|
|
225
231
|
}
|
|
226
232
|
|
|
227
|
-
async function fetchWithRectification(launch, body, signal) {
|
|
233
|
+
async function fetchWithRectification(launch, body, signal, onActivity) {
|
|
228
234
|
let requestBody = body;
|
|
229
|
-
let response = await
|
|
235
|
+
let response = await fetchProvider(buildAnthropicMessagesUrl(launch.baseUrl, launch), {
|
|
230
236
|
method: 'POST',
|
|
231
237
|
headers: buildAnthropicHeaders(launch),
|
|
232
238
|
body: JSON.stringify(body),
|
|
233
239
|
signal
|
|
234
|
-
});
|
|
240
|
+
}, launch);
|
|
241
|
+
onActivity();
|
|
235
242
|
if (response.ok) return { response, errorText: '', requestBody };
|
|
236
|
-
let errorText = (await response
|
|
243
|
+
let errorText = (await readProviderText(response, onActivity)).slice(0, MAX_ERROR_BYTES);
|
|
237
244
|
if (response.status === 400) {
|
|
238
245
|
const retryBody = JSON.parse(JSON.stringify(body));
|
|
239
246
|
if (rectifyAnthropicRequestForRetry(retryBody, errorText)) {
|
|
240
247
|
requestBody = retryBody;
|
|
241
|
-
response = await
|
|
248
|
+
response = await fetchProvider(buildAnthropicMessagesUrl(launch.baseUrl, launch), {
|
|
242
249
|
method: 'POST',
|
|
243
250
|
headers: buildAnthropicHeaders(launch),
|
|
244
251
|
body: JSON.stringify(retryBody),
|
|
245
252
|
signal
|
|
246
|
-
});
|
|
247
|
-
|
|
253
|
+
}, launch);
|
|
254
|
+
onActivity();
|
|
255
|
+
errorText = response.ok ? '' : (await readProviderText(response, onActivity)).slice(0, MAX_ERROR_BYTES);
|
|
248
256
|
}
|
|
249
257
|
}
|
|
250
258
|
return { response, errorText, requestBody };
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// This module owns only files and their recovery record. The caller must verify
|
|
4
|
+
// the signed release, bind its authorization and hold the update mutation lock.
|
|
5
|
+
const fs = require('node:fs');
|
|
6
|
+
const path = require('node:path');
|
|
7
|
+
const crypto = require('node:crypto');
|
|
8
|
+
const { validateBootstrapMigrationDescriptor } = require('./bootstrapMigrationContract');
|
|
9
|
+
|
|
10
|
+
const RECORD_SCHEMA = 1;
|
|
11
|
+
const TRANSACTION_ID = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/;
|
|
12
|
+
const MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
13
|
+
|
|
14
|
+
function prepareBootstrapMigration(options, hooks = {}) {
|
|
15
|
+
const descriptor = clone(options.descriptor);
|
|
16
|
+
validateBootstrapMigrationDescriptor(descriptor, { targetVersion: options.targetVersion });
|
|
17
|
+
if (!descriptor.sourceVersions.includes(options.sourceVersion)) fail('source_version_mismatch');
|
|
18
|
+
const transactionId = validTransaction(options.transactionId);
|
|
19
|
+
const backupRoot = absoluteRoot(options.backupRoot);
|
|
20
|
+
const extensionRoot = absoluteRoot(options.extensionRoot);
|
|
21
|
+
const payloadRoot = absoluteRoot(options.payloadRoot);
|
|
22
|
+
if (overlaps(backupRoot, extensionRoot) || overlaps(backupRoot, payloadRoot)
|
|
23
|
+
|| overlaps(extensionRoot, payloadRoot)) fail('roots_overlap');
|
|
24
|
+
ensureDirectory(backupRoot);
|
|
25
|
+
const recordRoot = path.join(backupRoot, transactionId);
|
|
26
|
+
ensureChildDirectory(backupRoot, transactionId);
|
|
27
|
+
const journalPath = path.join(recordRoot, 'state.json');
|
|
28
|
+
const identity = { transactionId, sourceVersion: options.sourceVersion,
|
|
29
|
+
targetVersion: options.targetVersion, extensionRoot, payloadRoot,
|
|
30
|
+
descriptorSha256: hash(JSON.stringify(descriptor)) };
|
|
31
|
+
if (readFileInfo(journalPath)) {
|
|
32
|
+
const saved = loadBootstrapMigration({ backupRoot, transactionId });
|
|
33
|
+
if (Object.entries(identity).some(([key, value]) => saved[key] !== value)) fail('transaction_mismatch');
|
|
34
|
+
return saved;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Verify the entire source and target before writing any recovery material.
|
|
38
|
+
const files = descriptor.files.map(file => {
|
|
39
|
+
const source = readRootFile(extensionRoot, file.path);
|
|
40
|
+
if (source?.sha256 !== file.sourceSha256 && !(source === null && file.sourceSha256 === null)) fail('source_mismatch', file.path);
|
|
41
|
+
const target = readRootFile(payloadRoot, file.path);
|
|
42
|
+
if (!target || target.sha256 !== file.targetSha256) fail('payload_mismatch', file.path);
|
|
43
|
+
return { ...file, sourceMode: source?.mode ?? null, targetMode: source?.mode ?? target.mode };
|
|
44
|
+
});
|
|
45
|
+
ensureChildDirectory(recordRoot, 'files');
|
|
46
|
+
for (const file of files) {
|
|
47
|
+
if (file.sourceSha256 === null) continue;
|
|
48
|
+
const source = readRootFile(extensionRoot, file.path);
|
|
49
|
+
if (!source || source.sha256 !== file.sourceSha256 || source.mode !== file.sourceMode) fail('source_mismatch', file.path);
|
|
50
|
+
const target = childFile(recordRoot, 'files/' + file.path, true);
|
|
51
|
+
atomicWrite(target, source.bytes, 0o600, hooks, 'backup');
|
|
52
|
+
}
|
|
53
|
+
const record = { schemaVersion: RECORD_SCHEMA, ...identity, descriptor,
|
|
54
|
+
migrationId: descriptor.id, backupRoot, recordRoot, journalPath, files,
|
|
55
|
+
sourceDigest: digest(files, 'sourceSha256'), targetDigest: digest(files, 'targetSha256'),
|
|
56
|
+
state: 'prepared', pending: null, completed: [], createdAt: new Date().toISOString() };
|
|
57
|
+
writeRecord(record, hooks);
|
|
58
|
+
return publicPlan(record);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function loadBootstrapMigration({ backupRoot, transactionId }) {
|
|
62
|
+
backupRoot = absoluteRoot(backupRoot);
|
|
63
|
+
transactionId = validTransaction(transactionId);
|
|
64
|
+
const recordRoot = childFile(backupRoot, transactionId);
|
|
65
|
+
const journalPath = childFile(recordRoot, 'state.json');
|
|
66
|
+
const info = readFileInfo(journalPath);
|
|
67
|
+
if (!info) fail('record_missing');
|
|
68
|
+
let record;
|
|
69
|
+
try { record = JSON.parse(info.bytes.toString('utf8')); } catch (_) { fail('record_invalid'); }
|
|
70
|
+
if (!record || record.schemaVersion !== RECORD_SCHEMA || record.transactionId !== transactionId
|
|
71
|
+
|| record.backupRoot !== backupRoot || record.recordRoot !== recordRoot || record.journalPath !== journalPath) fail('record_invalid');
|
|
72
|
+
validateBootstrapMigrationDescriptor(record.descriptor, { targetVersion: record.targetVersion });
|
|
73
|
+
if (!record.descriptor.sourceVersions.includes(record.sourceVersion)
|
|
74
|
+
|| record.migrationId !== record.descriptor.id
|
|
75
|
+
|| record.descriptorSha256 !== hash(JSON.stringify(record.descriptor))
|
|
76
|
+
|| !Array.isArray(record.files) || record.files.length !== record.descriptor.files.length
|
|
77
|
+
|| !['prepared', 'applying', 'applied', 'restoring', 'restored'].includes(record.state)
|
|
78
|
+
|| !Array.isArray(record.completed)) fail('record_invalid');
|
|
79
|
+
const extensionRoot = absoluteRoot(record.extensionRoot);
|
|
80
|
+
const payloadRoot = absoluteRoot(record.payloadRoot);
|
|
81
|
+
if (overlaps(backupRoot, extensionRoot) || overlaps(backupRoot, payloadRoot)
|
|
82
|
+
|| overlaps(extensionRoot, payloadRoot)) fail('roots_overlap');
|
|
83
|
+
for (let index = 0; index < record.files.length; index++) {
|
|
84
|
+
const file = record.files[index];
|
|
85
|
+
const expected = record.descriptor.files[index];
|
|
86
|
+
if (['path', 'sourceSha256', 'targetSha256'].some(key => file[key] !== expected[key])
|
|
87
|
+
|| !validMode(file.targetMode) || (file.sourceSha256 === null ? file.sourceMode !== null : !validMode(file.sourceMode))) fail('record_invalid');
|
|
88
|
+
}
|
|
89
|
+
if (record.sourceDigest !== digest(record.files, 'sourceSha256')
|
|
90
|
+
|| record.targetDigest !== digest(record.files, 'targetSha256')) fail('record_invalid');
|
|
91
|
+
return publicPlan(record);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function applyBootstrapMigration(plan, hooks = {}) {
|
|
95
|
+
const record = reloadPlan(plan);
|
|
96
|
+
if (record.state === 'restoring' || record.state === 'restored') fail('already_restoring');
|
|
97
|
+
verifyKnownFiles(record);
|
|
98
|
+
verifyBackups(record);
|
|
99
|
+
for (const file of record.files) {
|
|
100
|
+
const target = readRootFile(record.payloadRoot, file.path);
|
|
101
|
+
if (!target || target.sha256 !== file.targetSha256) fail('payload_mismatch', file.path);
|
|
102
|
+
}
|
|
103
|
+
if (record.state === 'applied') return verifyBootstrapMigration(record, { expected: 'target' });
|
|
104
|
+
record.state = 'applying';
|
|
105
|
+
writeRecord(record, hooks);
|
|
106
|
+
for (const file of writeOrder(record.files)) {
|
|
107
|
+
record.pending = file.path;
|
|
108
|
+
writeRecord(record, hooks);
|
|
109
|
+
const current = readRootFile(record.extensionRoot, file.path);
|
|
110
|
+
if (!matchesKnown(current, file)) fail('source_mismatch', file.path);
|
|
111
|
+
if (current?.sha256 !== file.targetSha256 || current.mode !== file.targetMode) {
|
|
112
|
+
const target = readRootFile(record.payloadRoot, file.path);
|
|
113
|
+
if (!target || target.sha256 !== file.targetSha256) fail('payload_mismatch', file.path);
|
|
114
|
+
atomicWrite(childFile(record.extensionRoot, file.path, true), target.bytes, file.targetMode, hooks, 'apply');
|
|
115
|
+
}
|
|
116
|
+
verifyFile(record.extensionRoot, file, 'target');
|
|
117
|
+
if (!record.completed.includes(file.path)) record.completed.push(file.path);
|
|
118
|
+
record.pending = null;
|
|
119
|
+
writeRecord(record, hooks);
|
|
120
|
+
}
|
|
121
|
+
record.state = 'applied';
|
|
122
|
+
writeRecord(record, hooks);
|
|
123
|
+
return verifyBootstrapMigration(record, { expected: 'target' });
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function restoreBootstrapMigration(plan, hooks = {}) {
|
|
127
|
+
const record = reloadPlan(plan);
|
|
128
|
+
verifyKnownFiles(record);
|
|
129
|
+
verifyBackups(record);
|
|
130
|
+
if (record.state === 'restored') return verifyBootstrapMigration(record, { expected: 'source' });
|
|
131
|
+
record.state = 'restoring';
|
|
132
|
+
writeRecord(record, hooks);
|
|
133
|
+
// Reverse dependencies: restore HTML/entry users before removing new files.
|
|
134
|
+
for (const file of writeOrder(record.files).reverse()) {
|
|
135
|
+
record.pending = file.path;
|
|
136
|
+
writeRecord(record, hooks);
|
|
137
|
+
const current = readRootFile(record.extensionRoot, file.path);
|
|
138
|
+
if (!matchesKnown(current, file)) fail('source_mismatch', file.path);
|
|
139
|
+
const target = childFile(record.extensionRoot, file.path);
|
|
140
|
+
if (file.sourceSha256 === null) {
|
|
141
|
+
if (current) {
|
|
142
|
+
fs.unlinkSync(target);
|
|
143
|
+
syncDirectory(path.dirname(target));
|
|
144
|
+
step(hooks, 'restore:removed', target);
|
|
145
|
+
}
|
|
146
|
+
} else if (current?.sha256 !== file.sourceSha256 || current.mode !== file.sourceMode) {
|
|
147
|
+
const backup = readRootFile(record.recordRoot, 'files/' + file.path);
|
|
148
|
+
if (!backup || backup.sha256 !== file.sourceSha256) fail('backup_mismatch', file.path);
|
|
149
|
+
atomicWrite(target, backup.bytes, file.sourceMode, hooks, 'restore');
|
|
150
|
+
}
|
|
151
|
+
verifyFile(record.extensionRoot, file, 'source');
|
|
152
|
+
record.completed = record.completed.filter(value => value !== file.path);
|
|
153
|
+
record.pending = null;
|
|
154
|
+
writeRecord(record, hooks);
|
|
155
|
+
}
|
|
156
|
+
record.state = 'restored';
|
|
157
|
+
writeRecord(record, hooks);
|
|
158
|
+
return verifyBootstrapMigration(record, { expected: 'source' });
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function verifyBootstrapMigration(plan, { expected = 'target' } = {}) {
|
|
162
|
+
if (!['source', 'target'].includes(expected)) fail('expectation_invalid');
|
|
163
|
+
const record = reloadPlan(plan);
|
|
164
|
+
for (const file of record.files) verifyFile(record.extensionRoot, file, expected);
|
|
165
|
+
return { transactionId: record.transactionId, migrationId: record.migrationId,
|
|
166
|
+
state: record.state, digest: expected === 'target' ? record.targetDigest : record.sourceDigest,
|
|
167
|
+
targetRevision: record.descriptor.targetRevision, expected };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function readBootstrapMigrationState(plan) { return reloadPlan(plan); }
|
|
171
|
+
|
|
172
|
+
function reloadPlan(plan) {
|
|
173
|
+
if (!plan || typeof plan !== 'object') fail('record_invalid');
|
|
174
|
+
const saved = loadBootstrapMigration(plan);
|
|
175
|
+
for (const key of ['descriptorSha256', 'extensionRoot', 'payloadRoot', 'sourceVersion', 'targetVersion']) {
|
|
176
|
+
if (plan[key] !== saved[key]) fail('transaction_mismatch');
|
|
177
|
+
}
|
|
178
|
+
return saved;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function verifyKnownFiles(record) {
|
|
182
|
+
for (const file of record.files) {
|
|
183
|
+
if (!matchesKnown(readRootFile(record.extensionRoot, file.path), file)) fail('source_mismatch', file.path);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function matchesKnown(current, file) {
|
|
188
|
+
if (current === null) return file.sourceSha256 === null;
|
|
189
|
+
return (current.sha256 === file.sourceSha256 && current.mode === file.sourceMode)
|
|
190
|
+
|| (current.sha256 === file.targetSha256 && current.mode === file.targetMode);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function verifyBackups(record) {
|
|
194
|
+
for (const file of record.files) {
|
|
195
|
+
if (file.sourceSha256 === null) continue;
|
|
196
|
+
const backup = readRootFile(record.recordRoot, 'files/' + file.path);
|
|
197
|
+
if (!backup || backup.sha256 !== file.sourceSha256) fail('backup_mismatch', file.path);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function verifyFile(root, file, expected) {
|
|
202
|
+
const current = readRootFile(root, file.path);
|
|
203
|
+
const expectedHash = file[expected + 'Sha256'];
|
|
204
|
+
if (expectedHash === null ? current !== null : !current || current.sha256 !== expectedHash
|
|
205
|
+
|| current.mode !== file[expected + 'Mode']) fail(expected + '_mismatch', file.path);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function writeOrder(files) {
|
|
209
|
+
const rank = file => file.sourceSha256 === null ? 0 : file.path === 'bootstrap/background.js' ? 3
|
|
210
|
+
: file.path.endsWith('.html') ? 2 : 1;
|
|
211
|
+
return [...files].sort((a, b) => rank(a) - rank(b) || a.path.localeCompare(b.path));
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function writeRecord(record, hooks) {
|
|
215
|
+
record.updatedAt = new Date().toISOString();
|
|
216
|
+
atomicWrite(record.journalPath, JSON.stringify(record, null, 2) + '\n', 0o600, hooks, 'journal');
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function atomicWrite(target, bytes, mode, hooks, phase) {
|
|
220
|
+
try { if (!fs.lstatSync(target).isFile()) fail('path_unsafe'); }
|
|
221
|
+
catch (error) { if (error.code !== 'ENOENT') throw error; }
|
|
222
|
+
const temporary = target + '.migration-' + crypto.randomBytes(8).toString('hex') + '.tmp';
|
|
223
|
+
const fd = fs.openSync(temporary, 'wx', mode);
|
|
224
|
+
try { fs.writeFileSync(fd, bytes); fs.fchmodSync(fd, mode); fs.fsyncSync(fd); }
|
|
225
|
+
finally { fs.closeSync(fd); }
|
|
226
|
+
step(hooks, phase + ':temporary', target);
|
|
227
|
+
fs.renameSync(temporary, target);
|
|
228
|
+
syncDirectory(path.dirname(target));
|
|
229
|
+
step(hooks, phase + ':replaced', target);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function syncDirectory(directory) {
|
|
233
|
+
let fd;
|
|
234
|
+
try { fd = fs.openSync(directory, 'r'); fs.fsyncSync(fd); }
|
|
235
|
+
catch (error) {
|
|
236
|
+
// Windows does not expose POSIX directory fsync through Node. File contents
|
|
237
|
+
// are flushed before rename on all platforms; directory durability is OS-dependent.
|
|
238
|
+
if (process.platform !== 'win32' || !['EPERM', 'EISDIR', 'EINVAL', 'EBADF', 'EACCES'].includes(error.code)) throw error;
|
|
239
|
+
} finally { if (fd !== undefined) fs.closeSync(fd); }
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function childFile(root, relative, createParents = false) {
|
|
243
|
+
if (typeof relative !== 'string' || relative.includes('\\') || relative.split('/').some(part => !part || part === '.' || part === '..')
|
|
244
|
+
|| path.isAbsolute(relative)) fail('path_unsafe');
|
|
245
|
+
assertDirectory(root);
|
|
246
|
+
const parts = relative.split('/');
|
|
247
|
+
let parent = root;
|
|
248
|
+
for (const part of parts.slice(0, -1)) {
|
|
249
|
+
parent = path.join(parent, part);
|
|
250
|
+
if (createParents && !fs.existsSync(parent)) { fs.mkdirSync(parent, { mode: 0o700 }); syncDirectory(path.dirname(parent)); }
|
|
251
|
+
assertDirectory(parent);
|
|
252
|
+
}
|
|
253
|
+
const target = path.join(root, ...parts);
|
|
254
|
+
try { if (fs.lstatSync(target).isSymbolicLink()) fail('path_unsafe'); }
|
|
255
|
+
catch (error) { if (error.code !== 'ENOENT') throw error; }
|
|
256
|
+
return target;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function readRootFile(root, relative) { return readFileInfo(childFile(root, relative)); }
|
|
260
|
+
|
|
261
|
+
function readFileInfo(target) {
|
|
262
|
+
let stat;
|
|
263
|
+
try { stat = fs.lstatSync(target); } catch (error) { if (error.code === 'ENOENT') return null; throw error; }
|
|
264
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > MAX_FILE_BYTES) fail('path_unsafe', target);
|
|
265
|
+
const bytes = fs.readFileSync(target);
|
|
266
|
+
return { bytes, sha256: hash(bytes), mode: stat.mode & 0o777 };
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function ensureDirectory(root) {
|
|
270
|
+
if (!fs.existsSync(root)) {
|
|
271
|
+
ensureDirectory(path.dirname(root));
|
|
272
|
+
fs.mkdirSync(root, { mode: 0o700 });
|
|
273
|
+
syncDirectory(path.dirname(root));
|
|
274
|
+
}
|
|
275
|
+
assertDirectory(root);
|
|
276
|
+
}
|
|
277
|
+
function ensureChildDirectory(root, relative) {
|
|
278
|
+
const directory = childFile(root, relative, true);
|
|
279
|
+
if (!fs.existsSync(directory)) { fs.mkdirSync(directory, { mode: 0o700 }); syncDirectory(path.dirname(directory)); }
|
|
280
|
+
assertDirectory(directory);
|
|
281
|
+
return directory;
|
|
282
|
+
}
|
|
283
|
+
function assertDirectory(value) { if (!fs.lstatSync(value).isDirectory() || fs.lstatSync(value).isSymbolicLink()) fail('path_unsafe'); }
|
|
284
|
+
function absoluteRoot(value) { if (typeof value !== 'string' || !path.isAbsolute(value) || path.normalize(value) !== value) fail('path_unsafe'); return value; }
|
|
285
|
+
function validTransaction(value) { if (typeof value !== 'string' || !TRANSACTION_ID.test(value) || value === '.' || value === '..') fail('transaction_invalid'); return value; }
|
|
286
|
+
function overlaps(a, b) { return a === b || a.startsWith(b + path.sep) || b.startsWith(a + path.sep); }
|
|
287
|
+
function validMode(value) { return Number.isInteger(value) && value >= 0 && value <= 0o777; }
|
|
288
|
+
function digest(files, key) { return hash(JSON.stringify([...files].sort((a, b) => a.path.localeCompare(b.path)).map(file => [file.path, file[key]]))); }
|
|
289
|
+
function hash(value) { return crypto.createHash('sha256').update(value).digest('hex'); }
|
|
290
|
+
function clone(value) { return JSON.parse(JSON.stringify(value)); }
|
|
291
|
+
function publicPlan(record) { return clone(record); }
|
|
292
|
+
function step(hooks, phase, target) { if (typeof hooks.onStep === 'function') hooks.onStep({ phase, path: target }); }
|
|
293
|
+
function fail(reason, file) { const error = new Error('Bootstrap migration ' + reason.replaceAll('_', ' ') + (file ? ': ' + file : '.')); error.code = 'update_bootstrap_' + reason; throw error; }
|
|
294
|
+
|
|
295
|
+
module.exports = { prepareBootstrapMigration, loadBootstrapMigration, applyBootstrapMigration,
|
|
296
|
+
restoreBootstrapMigration, verifyBootstrapMigration, readBootstrapMigrationState };
|