refactor: remove dead plugin loader exports (#105937)

* refactor(plugins): trim activation and contract exports

* test(plugins): restore fixture cleanup

* refactor(plugins): trim install and loader exports

* test(plugins): fully reset loader caches

* refactor(plugins): trim metadata and catalog exports

* test(plugins): preserve catalog trust coverage

* refactor(plugins): trim provider and plugin exports

* refactor(plugins): trim runtime and tool exports

* test(plugins): update dead-export consumers

* test(plugins): remove empty dead-export suites

* refactor(plugins): align exports with split registry

* refactor(plugins): trim drifted loader exports

* style(plugins): format test fixtures

* refactor(scripts): use supported plugin APIs

* refactor(plugins): finish dead export cleanup

* chore(deadcode): refresh export baseline

* test(cli): mock production memory state

* chore(deadcode): sync latest export baseline

* fix(tests): keep plugin fixtures inside core

* chore(deadcode): refresh rebased export baseline

* chore(deadcode): sync current ratchets

* fix(plugins): retain reserved slot invariant

* fix(plugins): preserve dead-export invariants

* test(plugins): use neutral catalog query fixture

* test(plugins): satisfy catalog lint

* test(plugins): preserve integrity drift coverage

* fix(ci): register skill experience live proof
This commit is contained in:
Peter Steinberger
2026-07-13 01:29:33 -07:00
committed by GitHub
parent 8c740891e1
commit 98e3f729bc
342 changed files with 1758 additions and 9707 deletions
-536
View File
@@ -3046,549 +3046,13 @@ export const KNIP_UNUSED_EXPORT_BASELINE = [
"src/plugin-state/plugin-state-store.sqlite.ts: seedPluginStateDatabaseEntriesForTests",
"src/plugin-state/plugin-state-store.sqlite.ts: setMaxPluginStateEntriesPerPluginForTests",
"src/plugin-state/plugin-state-store.ts: clearPluginStateStoreForTests",
"src/plugins/activation-context.ts: BundledPluginCompatibleActivationInputs",
"src/plugins/activation-context.ts: BundledPluginCompatibleLoadValues",
"src/plugins/activation-context.ts: PluginActivationCompatConfig",
"src/plugins/activation-context.ts: PluginActivationInputs",
"src/plugins/activation-planner.ts: PluginActivationPlanEntry",
"src/plugins/activation-planner.ts: PluginActivationPlannerHintReason",
"src/plugins/activation-planner.ts: PluginActivationPlannerManifestReason",
"src/plugins/activation-planner.ts: PluginActivationPlannerReason",
"src/plugins/activation-planner.ts: PluginActivationPlannerTrigger",
"src/plugins/agent-tool-result-middleware-loader.ts: __testing",
"src/plugins/agent-tool-result-middleware-loader.ts: testing",
"src/plugins/agent-tool-result-middleware.ts: normalizeAgentToolResultMiddlewareHarnesses",
"src/plugins/api-builder.ts: BuildPluginApiParams",
"src/plugins/api-lifecycle.ts: PluginApiLifecyclePolicy",
"src/plugins/api-lifecycle.ts: PluginApiMethodName",
"src/plugins/bundle-commands.ts: ClaudeBundleCommandSpec",
"src/plugins/bundle-config-shared.ts: BundleServerRuntimeSupport",
"src/plugins/bundle-lsp.ts: BundleLspConfig",
"src/plugins/bundle-lsp.ts: BundleLspRuntimeSupport",
"src/plugins/bundle-manifest.ts: BundleManifestLoadResult",
"src/plugins/bundle-manifest.ts: BundlePluginManifest",
"src/plugins/bundle-mcp.ts: BundleMcpRuntimeSupport",
"src/plugins/bundle-mcp.ts: EnabledBundleMcpConfigResult",
"src/plugins/bundled-capability-runtime.ts: buildVitestCapabilityShimAliasMap",
"src/plugins/bundled-channel-runtime.ts: resolveBundledChannelWorkspacePath",
"src/plugins/bundled-dir.ts: setBundledPluginsDirOverrideForTest",
"src/plugins/bundled-dir.ts: SourceCheckoutDependencyDiagnostic",
"src/plugins/bundled-load-path-aliases.ts: BundledPluginLoadPathAlias",
"src/plugins/bundled-load-path-aliases.ts: BundledPluginLoadPathAliasKind",
"src/plugins/bundled-load-path-aliases.ts: LegacyBundledPluginPath",
"src/plugins/bundled-load-path-aliases.ts: PackagedBundledPluginPath",
"src/plugins/bundled-plugin-metadata.ts: BundledPluginMetadata",
"src/plugins/bundled-plugin-startup-metadata.ts: BundledPluginStartupMetadata",
"src/plugins/bundled-sources.ts: BundledPluginLookup",
"src/plugins/clawhub.ts: ClawHubInstallErrorCode",
"src/plugins/clawhub.ts: formatClawHubSpecifier",
"src/plugins/cli-backend.types.ts: CliBackendToolAvailability",
"src/plugins/cli-backends.runtime.ts: PluginCliBackendEntry",
"src/plugins/cli-gateway-nodes-runtime.ts: resolvePluginCliNodeInvokeGatewayTimeoutMs",
"src/plugins/command-registration.ts: CommandRegistrationResult",
"src/plugins/command-registration.ts: RegisteredPluginCommand",
"src/plugins/command-specs.ts: PluginCommandEntrySpec",
"src/plugins/compaction-provider.ts: CompactionProviderSummarizationInstructions",
"src/plugins/compaction-provider.ts: RegisteredCompactionProvider",
"src/plugins/compat/registry.ts: isPluginCompatCode",
"src/plugins/compat/registry.ts: KnownPluginCompatRecord",
"src/plugins/compat/registry.ts: listDeprecatedPluginCompatRecords",
"src/plugins/compat/registry.ts: PLUGIN_COMPAT_RECORDS",
"src/plugins/compat/types.ts: PluginCompatOwner",
"src/plugins/compat/types.ts: PluginCompatStatus",
"src/plugins/config-activation-shared.ts: PluginActivationCause",
"src/plugins/config-activation-shared.ts: PluginActivationDecision",
"src/plugins/config-activation-shared.ts: PluginExplicitSelectionCause",
"src/plugins/config-contract-matches.ts: PluginConfigContractMatch",
"src/plugins/config-contracts.ts: PluginConfigContractMatch",
"src/plugins/config-contracts.ts: PluginConfigContractMetadata",
"src/plugins/config-policy.ts: isBundledChannelEnabledByChannelConfig",
"src/plugins/config-policy.ts: NormalizedPluginsConfig",
"src/plugins/config-policy.ts: PluginActivationSource",
"src/plugins/config-policy.ts: PluginActivationState",
"src/plugins/config-policy.ts: resolvePluginActivationState",
"src/plugins/contracts/inventory/bundled-capability-metadata.ts: buildBundledPluginContractSnapshot",
"src/plugins/contracts/inventory/bundled-capability-metadata.ts: BUNDLED_AUTO_ENABLE_PROVIDER_PLUGIN_IDS",
"src/plugins/contracts/inventory/bundled-capability-metadata.ts: BUNDLED_LEGACY_PLUGIN_ID_ALIASES",
"src/plugins/contracts/inventory/bundled-capability-metadata.ts: BundledCapabilityManifest",
"src/plugins/contracts/inventory/bundled-capability-metadata.ts: hasBundledPluginContractSnapshotCapabilities",
"src/plugins/contracts/inventory/bundled-capability-metadata.ts: resolveBundledContractSnapshotPluginIds",
"src/plugins/contracts/registry.ts: providerContractPluginIds",
"src/plugins/contracts/registry.ts: requireProviderContractProvider",
"src/plugins/conversation-binding.ts: __testing",
"src/plugins/conversation-binding.ts: testing",
"src/plugins/current-plugin-metadata-snapshot.ts: resolvePluginMetadataControlPlaneFingerprint",
"src/plugins/default-enablement.ts: PluginDefaultEnablement",
"src/plugins/dependency-denylist.ts: blockedInstallDependencyPackageNames",
"src/plugins/dependency-denylist.ts: BlockedManifestDependencyFinding",
"src/plugins/doctor-contract-registry.ts: clearPluginDoctorContractRegistryCache",
"src/plugins/doctor-contract-registry.ts: PluginDoctorStateMigrationEntry",
"src/plugins/doctor-contract-registry.ts: setPluginDoctorContractRegistryModuleLoaderFactoryForTest",
"src/plugins/embedding-provider-runtime.ts: EmbeddingInput",
"src/plugins/embedding-provider-runtime.ts: EmbeddingProviderCallOptions",
"src/plugins/embedding-provider-runtime.ts: EmbeddingProviderCreateOptions",
"src/plugins/embedding-provider-runtime.ts: EmbeddingProviderCreateResult",
"src/plugins/embedding-provider-runtime.ts: EmbeddingProviderRuntime",
"src/plugins/embedding-provider-runtime.ts: listRegisteredEmbeddingProviders",
"src/plugins/embedding-provider-runtime.ts: RegisteredEmbeddingProvider",
"src/plugins/embedding-providers.ts: getEmbeddingProvider",
"src/plugins/embedding-providers.ts: listEmbeddingProviders",
"src/plugins/embedding-providers.ts: restoreEmbeddingProviders",
"src/plugins/externalized-bundled-plugins.ts: ExternalizedBundledPluginPreferredSource",
"src/plugins/gateway-startup-plugin-ids.ts: ConfiguredMemoryEmbeddingStartupProviderOwner",
"src/plugins/gateway-startup-plugin-ids.ts: MemoryEmbeddingStartupProviderSource",
"src/plugins/git-install.ts: GitPluginInstallResult",
"src/plugins/git-install.ts: GitPluginResolution",
"src/plugins/git-install.ts: ParsedGitPluginSpec",
"src/plugins/hardlink-policy.ts: isNixStorePluginRoot",
"src/plugins/hook-agent-context.ts: resolveAgentHookChannelId",
"src/plugins/hook-decision-types.ts: BLOCK_MESSAGE_PREFIX",
"src/plugins/hook-decision-types.ts: HookDecision",
"src/plugins/hook-decision-types.ts: HookDecisionBlock",
"src/plugins/hook-decision-types.ts: HookDecisionPass",
"src/plugins/hook-decision-types.ts: mergeHookDecisions",
"src/plugins/hook-registry.types.ts: PluginLegacyHookRegistration",
"src/plugins/hook-runner-global-state.ts: HookRunnerGlobalState",
"src/plugins/hooks.ts: HookFailurePolicy",
"src/plugins/hooks.ts: HookRunnerLogger",
"src/plugins/hooks.ts: HookRunnerOptions",
"src/plugins/hooks.ts: PluginHookAfterCompactionEvent",
"src/plugins/hooks.ts: PluginHookAfterToolCallEvent",
"src/plugins/hooks.ts: PluginHookAgentContext",
"src/plugins/hooks.ts: PluginHookAgentEndEvent",
"src/plugins/hooks.ts: PluginHookBeforeAgentFinalizeEvent",
"src/plugins/hooks.ts: PluginHookBeforeAgentFinalizeResult",
"src/plugins/hooks.ts: PluginHookBeforeAgentReplyEvent",
"src/plugins/hooks.ts: PluginHookBeforeAgentReplyResult",
"src/plugins/hooks.ts: PluginHookBeforeAgentRunEvent",
"src/plugins/hooks.ts: PluginHookBeforeAgentStartEvent",
"src/plugins/hooks.ts: PluginHookBeforeAgentStartResult",
"src/plugins/hooks.ts: PluginHookBeforeCompactionEvent",
"src/plugins/hooks.ts: PluginHookBeforeDispatchContext",
"src/plugins/hooks.ts: PluginHookBeforeDispatchEvent",
"src/plugins/hooks.ts: PluginHookBeforeDispatchResult",
"src/plugins/hooks.ts: PluginHookBeforeInstallContext",
"src/plugins/hooks.ts: PluginHookBeforeInstallEvent",
"src/plugins/hooks.ts: PluginHookBeforeInstallResult",
"src/plugins/hooks.ts: PluginHookBeforeMessageWriteEvent",
"src/plugins/hooks.ts: PluginHookBeforeMessageWriteResult",
"src/plugins/hooks.ts: PluginHookBeforeModelResolveEvent",
"src/plugins/hooks.ts: PluginHookBeforeModelResolveResult",
"src/plugins/hooks.ts: PluginHookBeforePromptBuildEvent",
"src/plugins/hooks.ts: PluginHookBeforePromptBuildResult",
"src/plugins/hooks.ts: PluginHookBeforeResetEvent",
"src/plugins/hooks.ts: PluginHookBeforeToolCallEvent",
"src/plugins/hooks.ts: PluginHookBeforeToolCallResult",
"src/plugins/hooks.ts: PluginHookCronChangedEvent",
"src/plugins/hooks.ts: PluginHookCronReconciledContext",
"src/plugins/hooks.ts: PluginHookCronReconciledEvent",
"src/plugins/hooks.ts: PluginHookGatewayContext",
"src/plugins/hooks.ts: PluginHookGatewayCronDeliveryStatus",
"src/plugins/hooks.ts: PluginHookGatewayCronJobState",
"src/plugins/hooks.ts: PluginHookGatewayCronRunStatus",
"src/plugins/hooks.ts: PluginHookGatewayStartEvent",
"src/plugins/hooks.ts: PluginHookGatewayStopEvent",
"src/plugins/hooks.ts: PluginHookInboundClaimContext",
"src/plugins/hooks.ts: PluginHookInboundClaimEvent",
"src/plugins/hooks.ts: PluginHookInboundClaimResult",
"src/plugins/hooks.ts: PluginHookLlmInputEvent",
"src/plugins/hooks.ts: PluginHookLlmOutputEvent",
"src/plugins/hooks.ts: PluginHookMessageContext",
"src/plugins/hooks.ts: PluginHookMessageReceivedEvent",
"src/plugins/hooks.ts: PluginHookMessageSendingEvent",
"src/plugins/hooks.ts: PluginHookMessageSendingResult",
"src/plugins/hooks.ts: PluginHookMessageSentEvent",
"src/plugins/hooks.ts: PluginHookModelCallEndedEvent",
"src/plugins/hooks.ts: PluginHookModelCallStartedEvent",
"src/plugins/hooks.ts: PluginHookReplyDispatchContext",
"src/plugins/hooks.ts: PluginHookReplyDispatchEvent",
"src/plugins/hooks.ts: PluginHookReplyDispatchResult",
"src/plugins/hooks.ts: PluginHookReplyPayload",
"src/plugins/hooks.ts: PluginHookReplyPayloadSendingContext",
"src/plugins/hooks.ts: PluginHookReplyPayloadSendingEvent",
"src/plugins/hooks.ts: PluginHookReplyPayloadSendingResult",
"src/plugins/hooks.ts: PluginHookResolveExecEnvContext",
"src/plugins/hooks.ts: PluginHookResolveExecEnvEvent",
"src/plugins/hooks.ts: PluginHookSessionContext",
"src/plugins/hooks.ts: PluginHookSessionEndEvent",
"src/plugins/hooks.ts: PluginHookSessionStartEvent",
"src/plugins/hooks.ts: PluginHookSubagentContext",
"src/plugins/hooks.ts: PluginHookSubagentDeliveryTargetEvent",
"src/plugins/hooks.ts: PluginHookSubagentDeliveryTargetResult",
"src/plugins/hooks.ts: PluginHookSubagentEndedEvent",
"src/plugins/hooks.ts: PluginHookSubagentSpawnedEvent",
"src/plugins/hooks.ts: PluginHookSubagentSpawningEvent",
"src/plugins/hooks.ts: PluginHookSubagentSpawningResult",
"src/plugins/hooks.ts: PluginHookToolContext",
"src/plugins/hooks.ts: PluginHookToolResultPersistContext",
"src/plugins/hooks.ts: PluginHookToolResultPersistEvent",
"src/plugins/hooks.ts: PluginHookToolResultPersistResult",
"src/plugins/hooks.ts: PluginTargetedInboundClaimOutcome",
"src/plugins/host-hook-attachments.ts: attachmentProbeFs",
"src/plugins/host-hook-attachments.ts: resolveAttachmentDelivery",
"src/plugins/host-hook-attachments.ts: resolveSessionAttachmentThreadId",
"src/plugins/host-hook-cleanup.ts: clearPluginOwnedSessionState",
"src/plugins/host-hook-cleanup.ts: PluginHostCleanupFailure",
"src/plugins/host-hook-cleanup.ts: PluginHostCleanupResult",
"src/plugins/host-hook-json.ts: PluginJsonPrimitive",
"src/plugins/host-hook-json.ts: PluginJsonValueLimits",
"src/plugins/host-hook-runtime.ts: listPluginSessionSchedulerJobs",
"src/plugins/host-hook-runtime.ts: PLUGIN_TERMINAL_EVENT_CLEANUP_WAIT_MS",
"src/plugins/host-hook-scheduled-turns.ts: buildPluginSchedulerCronName",
"src/plugins/host-hook-state.ts: clearPluginOwnedSessionState",
"src/plugins/host-hook-state.ts: drainPluginNextTurnInjections",
"src/plugins/host-hooks.ts: PluginControlUiTabGroup",
"src/plugins/host-hooks.ts: PluginJsonPrimitive",
"src/plugins/host-hooks.ts: PluginNextTurnInjectionPlacement",
"src/plugins/host-hooks.ts: PluginSessionAttachmentFile",
"src/plugins/host-hooks.ts: PluginSessionExtensionProjectionContext",
"src/plugins/host-hooks.ts: PluginToolPolicyDecision",
"src/plugins/host-tool-param-parsers.ts: HostToolDerivationOptions",
"src/plugins/host-tool-param-parsers.ts: HostToolDerivedParams",
"src/plugins/install-channel-specs.ts: ChannelInstallSpecs",
"src/plugins/install-policy-context.ts: BeforeInstallHookPayloadParams",
"src/plugins/install-security-scan.ts: PackageExecutableScanMetadata",
"src/plugins/install-security-scan.ts: PluginInstallRequestKind",
"src/plugins/install-source-info.ts: DescribePluginInstallSourceOptions",
"src/plugins/install-source-info.ts: PluginInstallClawHubSourceInfo",
"src/plugins/install-source-info.ts: PluginInstallLocalSourceInfo",
"src/plugins/install-source-info.ts: PluginInstallNpmPinState",
"src/plugins/install-source-info.ts: PluginInstallNpmSourceInfo",
"src/plugins/install-source-info.ts: PluginInstallSourceWarning",
"src/plugins/install.ts: installPluginFromDir",
"src/plugins/install.ts: PluginInstallErrorCode",
"src/plugins/install.ts: PluginNpmIntegrityDriftParams",
"src/plugins/installed-plugin-index-record-cache.ts: InstallRecordsCacheEntry",
"src/plugins/installed-plugin-index-store.ts: InstalledPluginIndexStoreState",
"src/plugins/installed-plugin-index.ts: CONFIG_PATH_ACTIVATION_COMPAT_CODE",
"src/plugins/installed-plugin-index.ts: InstalledPluginPackageChannelInfo",
"src/plugins/installed-plugin-index.ts: InstalledPluginStartupInfo",
"src/plugins/installed-plugin-index.ts: listEnabledInstalledPluginRecords",
"src/plugins/interactive-registry.ts: clearPluginInteractiveHandlerRegistrations",
"src/plugins/legacy-npm-declaration.ts: LegacyNpmPluginDeclaration",
"src/plugins/loader-cache-state.ts: PluginLoadReentryError",
"src/plugins/loader-channel-setup.ts: BundledRuntimeChannelRegistration",
"src/plugins/loader-provenance.ts: PluginProvenanceIndex",
"src/plugins/loader.ts: __testing",
"src/plugins/loader.ts: clearPluginLoaderCache",
"src/plugins/loader.ts: PluginLoadReentryError",
"src/plugins/loader.ts: testing",
"src/plugins/management-service.ts: derivePluginCategory",
"src/plugins/management-service.ts: ManagedPluginCatalog",
"src/plugins/management-service.ts: ManagedPluginCatalogEntry",
"src/plugins/management-service.ts: ManagedPluginInstallRequest",
"src/plugins/management-service.ts: overlayBundledOfficialPluginCatalogMetadata",
"src/plugins/manifest-command-aliases.ts: PluginManifestCommandAliasKind",
"src/plugins/manifest-contract-runtime.ts: ManifestContractRuntimePluginResolution",
"src/plugins/manifest-contribution-ids.ts: listManifestContributionIds",
"src/plugins/manifest-contribution-ids.ts: ListManifestContributionIdsParams",
"src/plugins/manifest-registry.ts: __testing",
"src/plugins/manifest-registry.ts: testing",
"src/plugins/manifest-tool-availability.ts: ManifestAuthAvailabilitySignal",
"src/plugins/manifest-tool-availability.ts: ManifestConfigAvailabilitySignal",
"src/plugins/manifest.ts: clearPluginManifestLoadCache",
"src/plugins/manifest.ts: ManifestKey",
"src/plugins/manifest.ts: MAX_PLUGIN_MANIFEST_BYTES",
"src/plugins/manifest.ts: OpenClawPackageCompat",
"src/plugins/manifest.ts: OpenClawPackageSetupFeatures",
"src/plugins/manifest.ts: OpenClawPackageStartup",
"src/plugins/manifest.ts: PluginManifestCapabilityProviderModeConfigSignal",
"src/plugins/manifest.ts: PluginManifestConfigLiteral",
"src/plugins/manifest.ts: PluginManifestDangerousConfigFlag",
"src/plugins/manifest.ts: PluginManifestDefaultPlatform",
"src/plugins/manifest.ts: PluginManifestLoadResult",
"src/plugins/manifest.ts: PluginManifestMediaUnderstandingCapability",
"src/plugins/manifest.ts: PluginManifestModelIdPrefixRule",
"src/plugins/manifest.ts: PluginManifestOnboardingScope",
"src/plugins/manifest.ts: PluginManifestProviderAuthChoice",
"src/plugins/manifest.ts: PluginManifestProviderBaseUrlGuard",
"src/plugins/manifest.ts: PluginManifestProviderRequestProvider",
"src/plugins/manifest.ts: PluginManifestSecretInputContracts",
"src/plugins/manifest.ts: PluginManifestSecretInputPath",
"src/plugins/manifest.ts: PluginManifestSetupProvider",
"src/plugins/manifest.ts: PluginManifestSetupProviderAuthEvidence",
"src/plugins/manifest.ts: PluginPackageChannelCliOption",
"src/plugins/marketplace.ts: MarketplaceInstallResult",
"src/plugins/marketplace.ts: MarketplaceManifest",
"src/plugins/marketplace.ts: MarketplacePluginEntry",
"src/plugins/marketplace.ts: MarketplacePluginListResult",
"src/plugins/marketplace.ts: MarketplaceShortcutResolution",
"src/plugins/memory-embedding-providers.ts: restoreMemoryEmbeddingProviders",
"src/plugins/memory-state.ts: MemoryPluginCapabilityRegistration",
"src/plugins/memory-state.ts: MemoryPluginPublicArtifactContentType",
"src/plugins/memory-state.ts: MemoryPromptSupplementRegistration",
"src/plugins/memory-state.ts: MemoryRuntimeBackendConfig",
"src/plugins/memory-state.ts: MemoryRuntimeQmdConfig",
"src/plugins/memory-state.ts: registerMemoryFlushPlanResolver",
"src/plugins/memory-state.ts: registerMemoryPromptSection",
"src/plugins/memory-state.ts: registerMemoryRuntime",
"src/plugins/min-host-version.ts: MIN_HOST_VERSION_FORMAT",
"src/plugins/min-host-version.ts: MinHostVersionCheckResult",
"src/plugins/min-host-version.ts: MinHostVersionRequirement",
"src/plugins/official-external-plugin-catalog-envelope.ts: createOfficialExternalPluginCatalogEnvelopePayload",
"src/plugins/official-external-plugin-catalog-envelope.ts: createOfficialExternalPluginCatalogEnvelopeSigningInput",
"src/plugins/official-external-plugin-catalog-envelope.ts: OFFICIAL_EXTERNAL_PLUGIN_CATALOG_FEED_PAYLOAD_TYPE",
"src/plugins/official-external-plugin-catalog-envelope.ts: OfficialExternalPluginCatalogEnvelopeSignature",
"src/plugins/official-external-plugin-catalog-envelope.ts: OfficialExternalPluginCatalogEnvelopeVerificationResult",
"src/plugins/official-external-plugin-catalog-envelope.ts: OfficialExternalPluginCatalogSignedEnvelope",
"src/plugins/official-external-plugin-catalog-envelope.ts: OfficialExternalPluginCatalogTrustedSigningKey",
"src/plugins/official-external-plugin-catalog-snapshot-store.ts: HostedOfficialExternalPluginCatalogSnapshotStoreOptions",
"src/plugins/official-external-plugin-catalog.ts: createInMemoryHostedOfficialExternalPluginCatalogSnapshotStore",
"src/plugins/official-external-plugin-catalog.ts: DEFAULT_OFFICIAL_EXTERNAL_PLUGIN_CATALOG_CLAWHUB_SOURCE_REF",
"src/plugins/official-external-plugin-catalog.ts: DEFAULT_OFFICIAL_EXTERNAL_PLUGIN_CATALOG_FEED_PROFILE",
"src/plugins/official-external-plugin-catalog.ts: DEFAULT_OFFICIAL_EXTERNAL_PLUGIN_CATALOG_FEED_URL",
"src/plugins/official-external-plugin-catalog.ts: DEFAULT_OFFICIAL_EXTERNAL_PLUGIN_CATALOG_NPM_SOURCE_REF",
"src/plugins/official-external-plugin-catalog.ts: filterOfficialExternalPluginCatalogEntriesBySourceRefs",
"src/plugins/official-external-plugin-catalog.ts: loadHostedOfficialExternalPluginCatalogEntries",
"src/plugins/official-external-plugin-catalog.ts: OfficialExternalPluginCatalogFeedProfile",
"src/plugins/official-external-plugin-catalog.ts: OfficialExternalPluginCatalogFeedSigningKey",
"src/plugins/official-external-plugin-catalog.ts: OfficialExternalPluginCatalogFeedVerification",
"src/plugins/official-external-plugin-catalog.ts: OfficialExternalPluginCatalogInstallCandidate",
"src/plugins/official-external-plugin-catalog.ts: OfficialExternalPluginCatalogManifest",
"src/plugins/official-external-plugin-catalog.ts: OfficialExternalPluginCatalogProfileConfig",
"src/plugins/official-external-plugin-catalog.ts: OfficialExternalPluginCatalogSourceProfile",
"src/plugins/official-external-plugin-catalog.ts: OfficialExternalProviderCatalogProvider",
"src/plugins/official-external-plugin-catalog.ts: parseOfficialExternalPluginCatalogEntries",
"src/plugins/official-external-plugin-catalog.ts: resolveOfficialExternalPluginCatalogProfileConfigFromConfig",
"src/plugins/official-external-plugin-catalog.ts: validateOfficialExternalPluginCatalogEntrySourceRefs",
"src/plugins/openai-compatible-embedding-provider.ts: createOpenAICompatibleEmbeddingProvider",
"src/plugins/openai-compatible-embedding-provider.ts: OPENAI_COMPATIBLE_EMBEDDING_PROVIDER_ID",
"src/plugins/openai-compatible-embedding-provider.ts: OpenAICompatibleEmbeddingClient",
"src/plugins/package-compat.ts: PackagePluginApiRangeResult",
"src/plugins/plugin-cache-primitives.ts: ConfigScopedPromiseLoader",
"src/plugins/plugin-control-plane-context.ts: PluginControlPlaneContext",
"src/plugins/plugin-control-plane-context.ts: PluginDiscoveryContext",
"src/plugins/plugin-control-plane-context.ts: resolvePluginControlPlaneContext",
"src/plugins/plugin-control-plane-context.ts: ResolvePluginDiscoveryContextParams",
"src/plugins/plugin-control-plane-context.ts: resolvePluginDiscoveryFingerprint",
"src/plugins/plugin-load-profile.ts: PluginLoadProfileExtras",
"src/plugins/plugin-load-profile.ts: PluginLoadProfiler",
"src/plugins/plugin-load-profile.ts: PluginLoadProfileScope",
"src/plugins/plugin-lookup-table.ts: clearPluginLookUpTableMemoForTest",
"src/plugins/plugin-lookup-table.ts: LoadPluginLookUpTableParams",
"src/plugins/plugin-lookup-table.ts: PluginLookUpTableMetrics",
"src/plugins/plugin-module-loader-cache.ts: PluginModuleLoader",
"src/plugins/plugin-module-loader-cache.ts: PluginModuleLoaderCacheEntry",
"src/plugins/plugin-module-loader-cache.ts: PluginModuleLoaderStatsSnapshot",
"src/plugins/plugin-module-loader-cache.ts: resolvePluginModuleLoaderCacheEntry",
"src/plugins/plugin-module-loader-cache.ts: ResolvePluginModuleLoaderCacheEntryParams",
"src/plugins/plugin-registration-transaction.ts: PluginRegistrationTransaction",
"src/plugins/plugin-registry-contributions.ts: ListPluginContributionIdsParams",
"src/plugins/plugin-registry-contributions.ts: LoadPluginRegistryManifestParams",
"src/plugins/plugin-registry-contributions.ts: PluginLookUpTable",
"src/plugins/plugin-registry-contributions.ts: PluginRegistryContributionOptions",
"src/plugins/plugin-registry-contributions.ts: PluginRegistryIdNormalizerOptions",
"src/plugins/plugin-registry-contributions.ts: ResolveManifestContractOwnerPluginIdParams",
"src/plugins/plugin-registry-contributions.ts: ResolveManifestContractPluginIdsByCompatibilityRuntimePathParams",
"src/plugins/plugin-registry-contributions.ts: ResolveManifestContractPluginIdsParams",
"src/plugins/plugin-registry-contributions.ts: ResolvePluginContributionOwnersParams",
"src/plugins/plugin-registry-contributions.ts: ResolveProviderOwnersParams",
"src/plugins/plugin-registry-snapshot.ts: DISABLE_PERSISTED_PLUGIN_REGISTRY_ENV",
"src/plugins/plugin-registry-snapshot.ts: GetPluginRecordParams",
"src/plugins/plugin-registry-snapshot.ts: listPluginRecords",
"src/plugins/plugin-registry-snapshot.ts: PluginRegistryInspection",
"src/plugins/plugin-registry-snapshot.ts: PluginRegistrySnapshotDiagnosticCode",
"src/plugins/plugin-registry-snapshot.ts: PluginRegistrySnapshotResult",
"src/plugins/plugin-sdk-native-resolver.ts: InstallOpenClawPluginSdkNativeResolverOptions",
"src/plugins/plugin-sdk-native-resolver.ts: resetOpenClawPluginSdkNativeResolverForTest",
"src/plugins/plugin-version-drift.ts: PluginVersionDriftEntry",
"src/plugins/provider-auth-choice.ts: __testing",
"src/plugins/provider-auth-choice.ts: applyAuthChoicePluginProvider",
"src/plugins/provider-auth-choice.ts: ApplyProviderAuthChoiceParams",
"src/plugins/provider-auth-choice.ts: ApplyProviderAuthChoiceResult",
"src/plugins/provider-auth-choice.ts: PluginProviderAuthChoiceOptions",
"src/plugins/provider-auth-choice.ts: testing",
"src/plugins/provider-auth-choices.ts: ProviderOnboardAuthFlag (providerAuthChoices)",
"src/plugins/provider-auth-choices.ts: resolveManifestProviderOnboardAuthFlags (providerAuthChoices)",
"src/plugins/provider-auth-input.ts: extractEnvVarFromSourceLabel",
"src/plugins/provider-auth-input.ts: maybeApplyApiKeyFromOption",
"src/plugins/provider-auth-input.ts: resolveRefFallbackInput",
"src/plugins/provider-auth-input.ts: SecretInputModePromptCopy",
"src/plugins/provider-auth-input.ts: SecretRefSetupPromptCopy",
"src/plugins/provider-auth-mode.ts: SecretInputModePromptCopy",
"src/plugins/provider-auth-token.ts: ANTHROPIC_SETUP_TOKEN_PREFIX",
"src/plugins/provider-catalog-result.ts: ProviderCatalogResultProjection",
"src/plugins/provider-discovery.ts: resolveInstalledPluginProviderContributionIds",
"src/plugins/provider-discovery.ts: ResolveInstalledPluginProviderContributionIdsParams",
"src/plugins/provider-discovery.ts: ResolveRuntimePluginDiscoveryProvidersParams",
"src/plugins/provider-hook-runtime.ts: ProviderRuntimePluginHandleParams",
"src/plugins/provider-hook-runtime.ts: ProviderRuntimePluginLookupParams",
"src/plugins/provider-model-compat.ts: shouldOmitEmptyArrayItems",
"src/plugins/provider-oauth-flow.ts: OAuthPrompt",
"src/plugins/provider-openai-chatgpt-oauth-tls.ts: OpenAIOAuthTlsPreflightResult",
"src/plugins/provider-runtime.runtime.ts: buildProviderMissingAuthMessageWithPlugin",
"src/plugins/provider-thinking.types.ts: ProviderThinkingLevel",
"src/plugins/provider-thinking.types.ts: ProviderThinkingLevelId",
"src/plugins/provider-thinking.types.ts: ProviderThinkingModelCompat",
"src/plugins/provider-wizard.ts: ProviderWizardOption (providerWizard)",
"src/plugins/providers.ts: __testing",
"src/plugins/providers.ts: ProviderRefOwnership",
"src/plugins/providers.ts: testing",
"src/plugins/providers.ts: UsageHookProviderPluginContract",
"src/plugins/public-surface-loader.ts: resetBundledPluginPublicArtifactLoaderForTest",
"src/plugins/public-surface-runtime.ts: normalizeBundledPluginDirName",
"src/plugins/register-plugin-cli-command-groups.ts: PluginCliCommandGroupEntry",
"src/plugins/register-plugin-cli-command-groups.ts: PluginCliCommandGroupMode",
"src/plugins/registry-types.ts: OpenClawPluginApi",
"src/plugins/registry-types.ts: OpenClawPluginHookOptions",
"src/plugins/registry-types.ts: OpenClawPluginHttpRouteParams",
"src/plugins/registry-types.ts: OpenClawPluginNodeHostCommand",
"src/plugins/registry-types.ts: OpenClawPluginToolContext",
"src/plugins/registry-types.ts: PluginAgentEventSubscriptionRegistryRegistration",
"src/plugins/registry-types.ts: PluginAgentHarnessRegistration",
"src/plugins/registry-types.ts: PluginChannelSetupRegistration",
"src/plugins/registry-types.ts: PluginCliBackendRegistration",
"src/plugins/registry-types.ts: PluginCliRegistration",
"src/plugins/registry-types.ts: PluginCodexAppServerExtensionFactoryRegistration",
"src/plugins/registry-types.ts: PluginControlUiDescriptorRegistryRegistration",
"src/plugins/registry-types.ts: PluginConversationBindingResolvedHandlerRegistration",
"src/plugins/registry-types.ts: PluginEmbeddingProviderRegistration",
"src/plugins/registry-types.ts: PluginHookHandlerMap",
"src/plugins/registry-types.ts: PluginHookRegistration",
"src/plugins/registry-types.ts: PluginHostedMediaResolverRegistration",
"src/plugins/registry-types.ts: PluginImageGenerationProviderRegistration",
"src/plugins/registry-types.ts: PluginInteractiveHandlerRegistryRegistration",
"src/plugins/registry-types.ts: PluginMediaUnderstandingProviderRegistration",
"src/plugins/registry-types.ts: PluginMemoryEmbeddingProviderRegistration",
"src/plugins/registry-types.ts: PluginMigrationProviderRegistration",
"src/plugins/registry-types.ts: PluginModelCatalogProviderRegistration",
"src/plugins/registry-types.ts: PluginMusicGenerationProviderRegistration",
"src/plugins/registry-types.ts: PluginNodeInvokePolicyRegistration",
"src/plugins/registry-types.ts: PluginProviderRegistration",
"src/plugins/registry-types.ts: PluginRealtimeTranscriptionProviderRegistration",
"src/plugins/registry-types.ts: PluginRealtimeVoiceProviderRegistration",
"src/plugins/registry-types.ts: PluginRegistrationMode",
"src/plugins/registry-types.ts: PluginReloadRegistration",
"src/plugins/registry-types.ts: PluginRuntimeLifecycleRegistryRegistration",
"src/plugins/registry-types.ts: PluginSecurityAuditCollectorRegistration",
"src/plugins/registry-types.ts: PluginSessionCatalogRegistration",
"src/plugins/registry-types.ts: PluginSessionExtensionRegistryRegistration",
"src/plugins/registry-types.ts: PluginSessionSchedulerJobRegistryRegistration",
"src/plugins/registry-types.ts: PluginSpeechProviderRegistration",
"src/plugins/registry-types.ts: PluginToolMetadataRegistryRegistration",
"src/plugins/registry-types.ts: PluginTranscriptsSourceProviderRegistration",
"src/plugins/registry-types.ts: PluginVideoGenerationProviderRegistration",
"src/plugins/registry-types.ts: PluginWebFetchProviderRegistration",
"src/plugins/registry-types.ts: PluginWebSearchProviderRegistration",
"src/plugins/registry.ts: PluginAgentHarnessRegistration",
"src/plugins/registry.ts: PluginChannelRegistration",
"src/plugins/registry.ts: PluginChannelSetupRegistration",
"src/plugins/registry.ts: PluginCliBackendRegistration",
"src/plugins/registry.ts: PluginCliRegistration",
"src/plugins/registry.ts: PluginCommandRegistration",
"src/plugins/registry.ts: PluginControlUiDescriptorRegistryRegistration",
"src/plugins/registry.ts: PluginConversationBindingResolvedHandlerRegistration",
"src/plugins/registry.ts: PluginHookRegistration",
"src/plugins/registry.ts: PluginHostedMediaResolverRegistration",
"src/plugins/registry.ts: PluginImageGenerationProviderRegistration",
"src/plugins/registry.ts: PluginMediaUnderstandingProviderRegistration",
"src/plugins/registry.ts: PluginMemoryEmbeddingProviderRegistration",
"src/plugins/registry.ts: PluginMusicGenerationProviderRegistration",
"src/plugins/registry.ts: PluginNodeHostCommandRegistration",
"src/plugins/registry.ts: PluginProviderRegistration",
"src/plugins/registry.ts: PluginRealtimeTranscriptionProviderRegistration",
"src/plugins/registry.ts: PluginRealtimeVoiceProviderRegistration",
"src/plugins/registry.ts: PluginRegistryParams",
"src/plugins/registry.ts: PluginReloadRegistration",
"src/plugins/registry.ts: PluginRuntimeLifecycleRegistryRegistration",
"src/plugins/registry.ts: PluginSecurityAuditCollectorRegistration",
"src/plugins/registry.ts: PluginServiceRegistration",
"src/plugins/registry.ts: PluginSessionExtensionRegistryRegistration",
"src/plugins/registry.ts: PluginSpeechProviderRegistration",
"src/plugins/registry.ts: PluginTextTransformsRegistration",
"src/plugins/registry.ts: PluginToolMetadataRegistryRegistration",
"src/plugins/registry.ts: PluginToolRegistration",
"src/plugins/registry.ts: PluginTrustedToolPolicyRegistryRegistration",
"src/plugins/registry.ts: PluginVideoGenerationProviderRegistration",
"src/plugins/registry.ts: PluginWebFetchProviderRegistration",
"src/plugins/registry.ts: PluginWebSearchProviderRegistration",
"src/plugins/registry.ts: PluginWorkerProviderRegistration",
"src/plugins/roots.ts: PluginCacheInputs",
"src/plugins/runtime-channel-state.ts: PLUGIN_REGISTRY_STATE",
"src/plugins/runtime-state.ts: getActivePluginChannelRegistryFromState",
"src/plugins/runtime-state.ts: RuntimeTrackedPluginRegistry",
"src/plugins/runtime/gateway-bindings.ts: clearGatewaySubagentRuntime",
"src/plugins/runtime/gateway-request-scope.ts: PluginRuntimeGatewayRequestScope",
"src/plugins/runtime/gateway-request-scope.ts: PluginRuntimePluginScope",
"src/plugins/runtime/index.ts: clearGatewaySubagentRuntime",
"src/plugins/runtime/index.ts: createPluginRuntime",
"src/plugins/runtime/index.ts: CreatePluginRuntimeOptions",
"src/plugins/runtime/index.ts: setGatewayNodesRuntime",
"src/plugins/runtime/index.ts: setGatewaySubagentRuntime",
"src/plugins/runtime/load-context.ts: PluginRuntimeLoadContextOptions",
"src/plugins/runtime/load-context.ts: PluginRuntimeResolvedLoadValues",
"src/plugins/runtime/native-deps.ts: NativeDependencyHintParams",
"src/plugins/runtime/runtime-plugin-boundary.ts: resolvePluginRuntimeRecord",
"src/plugins/runtime/runtime-taskflow.types.ts: BoundTaskFlowCancelResult",
"src/plugins/runtime/runtime-taskflow.types.ts: BoundTaskFlowTaskRunResult",
"src/plugins/runtime/runtime-taskflow.types.ts: ManagedTaskFlowCreateParams",
"src/plugins/runtime/runtime-taskflow.types.ts: ManagedTaskFlowMutationErrorCode",
"src/plugins/runtime/runtime-tasks.types.ts: TaskFlowView",
"src/plugins/runtime/runtime-tasks.types.ts: TaskRunAggregateSummary",
"src/plugins/runtime/runtime-tasks.types.ts: TaskRunDetail",
"src/plugins/runtime/runtime-tasks.types.ts: TaskRunView",
"src/plugins/runtime/types-channel.ts: PluginRuntimeChannelContextEvent",
"src/plugins/runtime/types-channel.ts: PluginRuntimeChannelContextKey",
"src/plugins/runtime/types-channel.ts: PluginRuntimeChannelContextRegistry",
"src/plugins/runtime/types-channel.ts: RuntimeThreadBindingLifecycleRecord",
"src/plugins/runtime/types-core.ts: DeepReadonly",
"src/plugins/runtime/types-core.ts: HeartbeatRunResult",
"src/plugins/runtime/types-core.ts: PluginRuntimeThinkingPolicy",
"src/plugins/runtime/types-core.ts: PluginRuntimeThinkingPolicyLevel",
"src/plugins/runtime/types-core.ts: PluginRuntimeThinkingPolicyRequest",
"src/plugins/runtime/types-core.ts: RuntimeRequestHeartbeatNowOptions",
"src/plugins/runtime/types-core.ts: RuntimeRequestHeartbeatOptions",
"src/plugins/runtime/types.ts: PluginManagedWorktree",
"src/plugins/runtime/types.ts: RuntimeNodeInvokeParams",
"src/plugins/runtime/types.ts: RuntimeNodeListParams",
"src/plugins/runtime/types.ts: RuntimeNodeListResult",
"src/plugins/runtime/types.ts: SubagentDeleteSessionParams",
"src/plugins/runtime/types.ts: SubagentGetSessionMessagesParams",
"src/plugins/runtime/types.ts: SubagentGetSessionMessagesResult",
"src/plugins/runtime/types.ts: SubagentGetSessionParams",
"src/plugins/runtime/types.ts: SubagentGetSessionResult",
"src/plugins/runtime/types.ts: SubagentWaitParams",
"src/plugins/runtime/types.ts: SubagentWaitResult",
"src/plugins/sdk-alias.ts: isBundledPluginExtensionPath",
"src/plugins/sdk-alias.ts: LoaderModuleResolveParams",
"src/plugins/sdk-alias.ts: normalizeJitiAliasTargetPath",
"src/plugins/sdk-alias.ts: resolvePluginLoaderJitiFsCacheDir",
"src/plugins/sdk-alias.ts: resolvePluginLoaderJitiFsCacheOption",
"src/plugins/session-entry-slot-keys.ts: _AssertAllSessionEntryKeysAreReserved",
"src/plugins/setup-registry.runtime.ts: testing",
"src/plugins/setup-registry.ts: clearPluginSetupRegistryCache",
"src/plugins/setup-registry.ts: PluginSetupRegistryDiagnosticCode",
"src/plugins/setup-registry.ts: setPluginSetupRegistryModuleLoaderFactoryForTest",
"src/plugins/slots.ts: normalizeKinds",
"src/plugins/slots.ts: slotKeysForPluginKind",
"src/plugins/slots.ts: SlotSelectionResult",
"src/plugins/source-display.ts: formatPluginSourceForTable",
"src/plugins/source-display.ts: PluginSourceRoots",
"src/plugins/source-display.ts: resolvePluginSourceRoots",
"src/plugins/status-dependencies-core.ts: PluginDependencyEntry",
"src/plugins/tools.ts: PluginToolMeta",
"src/plugins/tools.ts: resetPluginToolDescriptorCache",
"src/plugins/tools.ts: resetPluginToolFactoryCache",
"src/plugins/trusted-tool-policy.ts: TrustedToolPolicyDiagnosticEntry",
"src/plugins/uninstall.ts: createEmptyUninstallActions",
"src/plugins/uninstall.ts: PluginUninstallPlanResult",
"src/plugins/uninstall.ts: resolveUninstallDirectoryTarget",
"src/plugins/uninstall.ts: UninstallActions",
"src/plugins/uninstall.ts: uninstallPlugin",
"src/plugins/uninstall.ts: UninstallPluginParams",
"src/plugins/uninstall.ts: UninstallPluginResult",
"src/plugins/update.ts: PluginChannelSyncResult",
"src/plugins/update.ts: PluginChannelSyncSummary",
"src/plugins/update.ts: PluginUpdateLogger",
"src/plugins/update.ts: PluginUpdateStatus",
"src/plugins/update.ts: PluginUpdateSummary",
"src/plugins/web-provider-resolution-shared.ts: WebProviderCandidateResolution",
"src/plugins/web-provider-resolution-shared.ts: WebProviderConfigKey",
"src/plugins/web-provider-resolution-shared.ts: WebProviderContract",
"src/plugins/web-provider-runtime-shared.ts: ResolvePluginWebProvidersParams",
"src/plugins/web-provider-types.ts: WebFetchProviderConfiguredCredentialFallback",
"src/plugins/web-provider-types.ts: WebSearchProviderConfiguredCredentialFallback",
"src/plugins/worker-provider-registry.ts: listWorkerProviderRegistrations",
"src/process/command-queue.ts: CommandLaneTaskTimeoutError",
"src/process/command-queue.ts: resetCommandQueueStateForTest",
"src/process/gateway-work-admission.ts: tryBeginGatewayIndependentRootWorkAdmission",
+11 -8
View File
@@ -1,8 +1,5 @@
// Bundled Extension Manifest script supports OpenClaw repository automation.
import {
MIN_HOST_VERSION_FORMAT,
parseMinHostVersionRequirement,
} from "../../src/plugins/min-host-version.ts";
import { checkMinHostVersion } from "../../src/plugins/min-host-version.ts";
import { isRecord } from "../../src/utils.js";
export type ExtensionPackageJson = {
@@ -38,11 +35,17 @@ export function collectBundledExtensionManifestErrors(extensions: BundledExtensi
`bundled extension '${extension.id}' manifest invalid | openclaw.install.npmSpec must be a non-empty string`,
);
}
const minHostVersionError =
install?.minHostVersion === undefined ||
parseMinHostVersionRequirement(install.minHostVersion)
const minHostVersionCheck =
install?.minHostVersion === undefined
? null
: MIN_HOST_VERSION_FORMAT;
: checkMinHostVersion({
currentVersion: "0.0.0",
minHostVersion: install.minHostVersion,
});
const minHostVersionError =
minHostVersionCheck && !minHostVersionCheck.ok && minHostVersionCheck.kind === "invalid"
? minHostVersionCheck.error
: null;
if (minHostVersionError) {
errors.push(`bundled extension '${extension.id}' manifest invalid | ${minHostVersionError}`);
}
+2 -15
View File
@@ -6,9 +6,8 @@ import { fileURLToPath, pathToFileURL } from "node:url";
import type { createJiti } from "jiti";
import { buildChannelConfigSchema } from "../src/channels/plugins/config-schema.js";
import {
buildPluginLoaderAliasMap,
buildPluginLoaderJitiOptions,
resolvePluginSdkAliasFile,
resolvePluginSdkScopedAliasMap,
} from "../src/plugins/sdk-alias.js";
type CreateJiti = typeof createJiti;
@@ -152,19 +151,7 @@ export async function loadChannelConfigSurfaceModule(
};
const loadViaJiti = (candidatePath: string) => {
const resolvedPath = path.resolve(candidatePath);
const pluginSdkAlias = resolvePluginSdkAliasFile({
srcFile: "root-alias.cjs",
distFile: "root-alias.cjs",
modulePath: resolvedPath,
pluginSdkResolution: "src",
});
const aliasMap = {
...(pluginSdkAlias ? { "openclaw/plugin-sdk": pluginSdkAlias } : {}),
...resolvePluginSdkScopedAliasMap({
modulePath: resolvedPath,
pluginSdkResolution: "src",
}),
};
const aliasMap = buildPluginLoaderAliasMap(resolvedPath, "", undefined, "src");
const jiti = loadCreateJitiLoaderFactory()(import.meta.url, {
...buildPluginLoaderJitiOptions(aliasMap),
interopDefault: true,
+4 -4
View File
@@ -1,5 +1,4 @@
#!/usr/bin/env node
// Plugin Boundary Report script supports OpenClaw repository automation.
import { spawnSync } from "node:child_process";
import { existsSync, lstatSync, readdirSync, readFileSync } from "node:fs";
import { join, relative, resolve } from "node:path";
@@ -10,7 +9,7 @@ import {
reservedBundledPluginSdkEntrypoints,
supportedBundledFacadeSdkEntrypoints,
} from "../src/plugin-sdk/entrypoints.ts";
import { PLUGIN_COMPAT_RECORDS } from "../src/plugins/compat/registry.ts";
import { listPluginCompatRecords } from "../src/plugins/compat/registry.ts";
import type { PluginCompatRecord } from "../src/plugins/compat/types.ts";
const REPO_ROOT = process.cwd();
@@ -374,7 +373,8 @@ function collectCompatDebt(
today = new Date(),
options: { includeReferenceFiles?: boolean } = {},
): CompatDebtRecord[] {
return PLUGIN_COMPAT_RECORDS.filter((record) => record.status === "deprecated")
return listPluginCompatRecords()
.filter((record) => record.status === "deprecated")
.map((record) => {
const tokens = extractCompatTokens(record);
const references =
@@ -389,7 +389,7 @@ function collectCompatDebt(
owner: record.owner,
status: record.status,
removeAfter: record.removeAfter,
replacement: record.replacement,
replacement: record.replacement as string,
docsPath: record.docsPath,
surfaces: record.surfaces,
tokens,
@@ -15,7 +15,7 @@ import {
initializeGlobalHookRunner,
resetGlobalHookRunner,
} from "../plugins/hook-runner-global.js";
import { addTestHook, createMockPluginRegistry } from "../plugins/hooks.test-helpers.js";
import { addTestHook, createMockPluginRegistry } from "../plugins/hooks.test-fixtures.js";
import { patchPluginSessionExtension } from "../plugins/host-hook-state.js";
import { createEmptyPluginRegistry } from "../plugins/registry.js";
import { setActivePluginRegistry } from "../plugins/runtime.js";
@@ -18,7 +18,7 @@ import {
initializeGlobalHookRunner,
resetGlobalHookRunner,
} from "../plugins/hook-runner-global.js";
import { createMockPluginRegistry } from "../plugins/hooks.test-helpers.js";
import { createMockPluginRegistry } from "../plugins/hooks.test-fixtures.js";
import "./test-helpers/fast-bash-tools.js";
import "./test-helpers/fast-coding-tools.js";
import "./test-helpers/fast-openclaw-tools.js";
@@ -1,281 +0,0 @@
/** E2E proof for CLI runner bundle-MCP subprocess execution. */
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import type { OpenClawConfig } from "../config/config.js";
import type { CliBackendConfig } from "../config/types.js";
import { captureEnv, deleteTestEnvValue, setTestEnvValue } from "../test-utils/env.js";
import {
writeBundleProbeMcpServer,
writeClaudeBundle,
writeFakeClaudeCli,
writeFakeClaudeLiveCli,
} from "./bundle-mcp.test-harness.js";
import type {
CliPreparedBackend,
PreparedCliRunContext,
RunCliAgentParams,
} from "./cli-runner/types.js";
// This e2e spins a real stdio MCP server plus a spawned CLI process. Keep the
// proof focused on bundle MCP config generation and subprocess execution; the
// full runCliAgent prepare graph has dedicated unit coverage and is expensive
// in cold Linux workers.
const E2E_TIMEOUT_MS = 30_000;
type BundleMcpFixture = {
config: OpenClawConfig;
envSnapshot: ReturnType<typeof captureEnv>;
fakeClaudePath: string;
fakeClaudePidPath?: string;
pluginRoot: string;
sessionFile: string;
tempHome: string;
workspaceDir: string;
};
function isProcessAlive(pid: number): boolean {
try {
process.kill(pid, 0);
return true;
} catch (error) {
if ((error as NodeJS.ErrnoException).code === "ESRCH") {
return false;
}
throw error;
}
}
async function resetBundleMcpPluginState() {
// Bundle MCP setup caches plugin discovery; reset between temp plugin roots.
const { resetPluginLoaderTestStateForTest } = await import("../plugins/loader.test-fixtures.js");
const { clearPluginSetupRegistryCache } = await import("../plugins/setup-registry.js");
resetPluginLoaderTestStateForTest();
clearPluginSetupRegistryCache();
}
async function createBundleMcpFixture(params: {
liveSession?: boolean;
tempPrefix: string;
}): Promise<BundleMcpFixture> {
// Fixture creates a real temp plugin + MCP server + fake CLI binary, but keeps
// it isolated from persisted plugin registry state.
await resetBundleMcpPluginState();
const envSnapshot = captureEnv([
"HOME",
"USERPROFILE",
"OPENCLAW_HOME",
"OPENCLAW_STATE_DIR",
"OPENCLAW_DISABLE_PERSISTED_PLUGIN_REGISTRY",
]);
const tempHome = await fs.mkdtemp(path.join(os.tmpdir(), params.tempPrefix));
setTestEnvValue("HOME", tempHome);
setTestEnvValue("USERPROFILE", tempHome);
deleteTestEnvValue("OPENCLAW_HOME");
deleteTestEnvValue("OPENCLAW_STATE_DIR");
setTestEnvValue("OPENCLAW_DISABLE_PERSISTED_PLUGIN_REGISTRY", "1");
const workspaceDir = path.join(tempHome, "workspace");
const sessionFile = path.join(tempHome, "session.jsonl");
const binDir = path.join(tempHome, "bin");
const serverScriptPath = path.join(tempHome, "mcp", "bundle-probe.mjs");
const fakeClaudePath = path.join(
binDir,
params.liveSession ? "fake-live-claude.mjs" : "fake-claude.mjs",
);
const fakeClaudePidPath = params.liveSession
? path.join(tempHome, "fake-live-claude.pid")
: undefined;
const pluginRoot = path.join(tempHome, ".openclaw", "extensions", "bundle-probe");
await fs.mkdir(workspaceDir, { recursive: true });
await writeBundleProbeMcpServer(serverScriptPath);
if (params.liveSession) {
await writeFakeClaudeLiveCli({ filePath: fakeClaudePath, pidPath: fakeClaudePidPath });
} else {
await writeFakeClaudeCli(fakeClaudePath);
}
await writeClaudeBundle({ pluginRoot, serverScriptPath });
const config: OpenClawConfig = {
agents: {
defaults: {
workspace: workspaceDir,
},
},
plugins: {
load: { paths: [pluginRoot] },
entries: {
"bundle-probe": { enabled: true },
},
},
};
return {
config,
envSnapshot,
fakeClaudePath,
...(fakeClaudePidPath ? { fakeClaudePidPath } : {}),
pluginRoot,
sessionFile,
tempHome,
workspaceDir,
};
}
function buildTestBackend(params: {
commandPath: string;
liveSession?: "claude-stdio";
}): CliBackendConfig {
return {
command: "node",
args: [params.commandPath],
input: "stdin",
output: "jsonl",
clearEnv: [],
...(params.liveSession ? { liveSession: params.liveSession } : {}),
};
}
async function prepareBundleMcpExecutionContext(params: {
backend: CliBackendConfig;
config: OpenClawConfig;
model: string;
prompt: string;
runId: string;
sessionFile: string;
sessionId: string;
workspaceDir: string;
}): Promise<PreparedCliRunContext> {
// Exercise bundle MCP config preparation while bypassing unrelated full
// runCliAgent context assembly.
const { prepareCliBundleMcpConfig } = await import("./cli-runner/bundle-mcp.js");
const preparedBackend = (await prepareCliBundleMcpConfig({
enabled: true,
mode: "claude-config-file",
backend: params.backend,
workspaceDir: params.workspaceDir,
config: params.config,
})) as CliPreparedBackend;
const runParams: RunCliAgentParams = {
sessionId: params.sessionId,
sessionFile: params.sessionFile,
workspaceDir: params.workspaceDir,
config: params.config,
prompt: params.prompt,
provider: "claude-cli",
model: params.model,
timeoutMs: 20_000,
runId: params.runId,
};
return {
params: runParams,
started: Date.now(),
workspaceDir: params.workspaceDir,
cwd: params.workspaceDir,
backendResolved: {
id: "claude-cli",
config: params.backend,
bundleMcp: true,
bundleMcpMode: "claude-config-file",
},
preparedBackend,
reusableCliSession: { mode: "none" },
hadSessionFile: false,
contextEngineConfig: params.config,
modelId: params.model,
normalizedModel: params.model,
systemPrompt: "Bundle MCP e2e test prompt.",
systemPromptReport: {} as PreparedCliRunContext["systemPromptReport"],
claudeSkillsPluginArgs: [],
bootstrapPromptWarningLines: [],
authEpochVersion: 1,
};
}
async function cleanupFixture(fixture: BundleMcpFixture): Promise<void> {
await fs.rm(fixture.tempHome, { recursive: true, force: true });
fixture.envSnapshot.restore();
}
afterEach(async () => {
await resetBundleMcpPluginState();
});
describe("CLI bundle MCP e2e", () => {
it(
"routes enabled bundle MCP config into the claude-cli backend and executes the tool",
{ timeout: E2E_TIMEOUT_MS },
async () => {
const { executePreparedCliRun } = await import("./cli-runner/execute.js");
const fixture = await createBundleMcpFixture({
tempPrefix: "openclaw-cli-bundle-mcp-",
});
const context = await prepareBundleMcpExecutionContext({
backend: buildTestBackend({ commandPath: fixture.fakeClaudePath }),
config: fixture.config,
model: "test-bundle",
prompt: "Use your configured MCP tools and report the bundle probe text.",
runId: "bundle-mcp-e2e",
sessionFile: fixture.sessionFile,
sessionId: "session:test",
workspaceDir: fixture.workspaceDir,
});
try {
const result = await executePreparedCliRun(context);
expect(result.text).toContain("BUNDLE MCP OK FROM-BUNDLE");
} finally {
await context.preparedBackend.cleanup?.();
await cleanupFixture(fixture);
}
},
);
it(
"exits one-shot Claude live-session runs and closes the live process",
{ timeout: E2E_TIMEOUT_MS },
async () => {
const { executePreparedCliRun } = await import("./cli-runner/execute.js");
const { closeClaudeLiveSessionForContext } =
await import("./cli-runner/claude-live-session.js");
const fixture = await createBundleMcpFixture({
liveSession: true,
tempPrefix: "openclaw-cli-live-cleanup-",
});
const context = await prepareBundleMcpExecutionContext({
backend: buildTestBackend({
commandPath: fixture.fakeClaudePath,
liveSession: "claude-stdio",
}),
config: fixture.config,
model: "test-live-bundle",
prompt: "Use your configured MCP tools and report the bundle probe text.",
runId: "bundle-mcp-live-cleanup-e2e",
sessionFile: fixture.sessionFile,
sessionId: "session:test-live-cleanup",
workspaceDir: fixture.workspaceDir,
});
try {
const result = await executePreparedCliRun(context);
await closeClaudeLiveSessionForContext(context);
expect(result.text).toContain("LIVE BUNDLE MCP OK FROM-BUNDLE");
expect(fixture.fakeClaudePidPath).toBeDefined();
const fakeClaudePid = Number.parseInt(
await fs.readFile(fixture.fakeClaudePidPath!, "utf-8"),
10,
);
expect(Number.isFinite(fakeClaudePid)).toBe(true);
expect(isProcessAlive(fakeClaudePid)).toBe(false);
} finally {
await closeClaudeLiveSessionForContext(context);
await context.preparedBackend.cleanup?.();
await cleanupFixture(fixture);
}
},
);
});
+4 -1
View File
@@ -22,7 +22,10 @@ import type {
McpLoopbackRequestContext,
} from "../../gateway/mcp-grant-store.js";
import { getGlobalHookRunner } from "../../plugins/hook-runner-global.js";
import { clearMemoryPluginState, registerMemoryPromptSection } from "../../plugins/memory-state.js";
import {
clearMemoryPluginState,
registerMemoryPromptSection,
} from "../../plugins/memory-state.test-fixtures.js";
import { setActivePluginRegistry } from "../../plugins/runtime.js";
import {
createChannelTestPluginBase,
@@ -22,7 +22,7 @@ import {
initializeGlobalHookRunner,
resetGlobalHookRunner,
} from "../../../plugins/hook-runner-global.js";
import { createHookRunnerWithRegistry } from "../../../plugins/hooks.test-helpers.js";
import { createHookRunnerWithRegistry } from "../../../plugins/hooks.test-fixtures.js";
import { withEnvAsync } from "../../../test-utils/env.js";
import { wrapStreamFnWithDiagnosticModelCallEvents } from "./attempt.model-diagnostic-events.js";
@@ -14,7 +14,7 @@ import { buildMemorySystemPromptAddition } from "../../../context-engine/delegat
import {
clearMemoryPluginState,
registerMemoryPromptSection,
} from "../../../plugins/memory-state.js";
} from "../../../plugins/memory-state.test-fixtures.js";
import {
addSubagentRunForTests,
leasePendingAgentSteeringItems,
@@ -1,7 +1,10 @@
// Embedded system prompt tests cover prompt assembly for provider guidance,
// delegation mode, workspace-only safety, memory sections, and active processes.
import { afterEach, describe, expect, it, vi } from "vitest";
import { clearMemoryPluginState, registerMemoryPromptSection } from "../../plugins/memory-state.js";
import {
clearMemoryPluginState,
registerMemoryPromptSection,
} from "../../plugins/memory-state.test-fixtures.js";
import type { AgentSession } from "../sessions/index.js";
import { applySystemPromptToSession, buildEmbeddedSystemPrompt } from "./system-prompt.js";
@@ -3,7 +3,7 @@
import { describe, expect, it, vi } from "vitest";
import { createInlineCodeState } from "../../packages/markdown-core/src/code-spans.js";
import { createHookRunner } from "../plugins/hooks.js";
import { createMockPluginRegistry, TEST_PLUGIN_AGENT_CTX } from "../plugins/hooks.test-helpers.js";
import { createMockPluginRegistry, TEST_PLUGIN_AGENT_CTX } from "../plugins/hooks.test-fixtures.js";
import { handleAgentEnd, handleAgentStart } from "./embedded-agent-subscribe.handlers.lifecycle.js";
import type { EmbeddedAgentSubscribeContext } from "./embedded-agent-subscribe.handlers.types.js";
+1 -1
View File
@@ -12,7 +12,7 @@ import {
initializeGlobalHookRunner,
resetGlobalHookRunner,
} from "../../plugins/hook-runner-global.js";
import { createMockPluginRegistry } from "../../plugins/hooks.test-helpers.js";
import { createMockPluginRegistry } from "../../plugins/hooks.test-fixtures.js";
import { patchPluginSessionExtension } from "../../plugins/host-hook-state.js";
import { createEmptyPluginRegistry } from "../../plugins/registry-empty.js";
import { setActivePluginRegistry } from "../../plugins/runtime.js";
@@ -3,7 +3,7 @@ import {
initializeGlobalHookRunner,
resetGlobalHookRunner,
} from "../../plugins/hook-runner-global.js";
import { createMockPluginRegistry } from "../../plugins/hooks.test-helpers.js";
import { createMockPluginRegistry } from "../../plugins/hooks.test-fixtures.js";
import { resolveAgentHarnessBeforePromptBuildResult } from "./prompt-compaction-hook-helpers.js";
afterEach(() => {
-114
View File
@@ -14,13 +14,9 @@ import { resetLogger, setLoggerOverride } from "../logging/logger.js";
import { createWarnLogCapture } from "../logging/test-helpers/warn-log-capture.js";
import {
clearCurrentPluginMetadataSnapshot,
resolvePluginMetadataControlPlaneFingerprint,
setCurrentPluginMetadataSnapshot,
} from "../plugins/current-plugin-metadata-snapshot.js";
import { resolveInstalledPluginIndexPolicyHash } from "../plugins/installed-plugin-index-policy.js";
import type { InstalledPluginIndex } from "../plugins/installed-plugin-index.js";
import { loadPluginMetadataSnapshot } from "../plugins/plugin-metadata-snapshot.js";
import type { PluginMetadataSnapshot } from "../plugins/plugin-metadata-snapshot.types.js";
import { CommandLaneTaskTimeoutError } from "../process/command-queue.js";
import { AUTH_STORE_VERSION } from "./auth-profiles/constants.js";
import type { AuthProfileStore } from "./auth-profiles/types.js";
@@ -229,68 +225,6 @@ function setDefaultPluginMetadataSnapshot(): void {
});
}
function createModelNormalizerSnapshot(params: {
manifestHash: string;
prefix: string;
}): PluginMetadataSnapshot {
// Builds a process-stable plugin metadata snapshot with one model normalizer
// so fallback can prove manifest-policy cache invalidation.
const policyHash = resolveInstalledPluginIndexPolicyHash({});
const index: InstalledPluginIndex = {
version: 1,
hostContractVersion: "test-host",
compatRegistryVersion: "test-compat",
migrationVersion: 1,
policyHash,
generatedAtMs: 0,
installRecords: {},
plugins: [
{
pluginId: "fallback-normalizer",
manifestPath: `/tmp/fallback-normalizer-${params.manifestHash}/openclaw.plugin.json`,
manifestHash: params.manifestHash,
source: `/tmp/fallback-normalizer-${params.manifestHash}/index.ts`,
rootDir: `/tmp/fallback-normalizer-${params.manifestHash}`,
origin: "global",
enabled: true,
startup: {
sidecar: false,
memory: false,
deferConfiguredChannelFullLoadUntilAfterListen: false,
agentHarnesses: [],
},
compat: [],
},
],
diagnostics: [],
};
return {
policyHash,
configFingerprint: resolvePluginMetadataControlPlaneFingerprint(
{},
{
env: process.env,
index,
policyHash,
},
),
index,
registryDiagnostics: [],
plugins: [
{
id: "fallback-normalizer",
modelIdNormalization: {
providers: {
demo: {
prefixWhenBare: params.prefix,
},
},
},
},
],
} as unknown as PluginMetadataSnapshot;
}
afterEach(resetModelFallbackTestState);
beforeEach(() => {
@@ -3129,54 +3063,6 @@ describe("runWithModelFallback", () => {
).toEqual([{ provider: "ollama", model: "llama3" }]);
});
it("does not reuse fallback candidate cache entries across manifest normalization snapshots", () => {
const cfg = makeCfg({
agents: {
defaults: {
model: {
fallbacks: [],
},
},
},
});
try {
setCurrentPluginMetadataSnapshot(
createModelNormalizerSnapshot({
manifestHash: "alpha",
prefix: "alpha",
}),
{ config: {}, env: process.env },
);
expect(
testing.resolveFallbackCandidates({
cfg,
provider: "demo",
model: "demo-model",
fallbacksOverride: [],
}),
).toEqual([{ provider: "demo", model: "alpha/demo-model" }]);
setCurrentPluginMetadataSnapshot(
createModelNormalizerSnapshot({
manifestHash: "bravo",
prefix: "bravo",
}),
{ config: {}, env: process.env },
);
expect(
testing.resolveFallbackCandidates({
cfg,
provider: "demo",
model: "demo-model",
fallbacksOverride: [],
}),
).toEqual([{ provider: "demo", model: "bravo/demo-model" }]);
} finally {
setDefaultPluginMetadataSnapshot();
}
});
it("defaults provider/model when missing (regression #946)", () => {
const cfg = makeCfg({
agents: {
+1 -74
View File
@@ -1,82 +1,9 @@
// Verifies model-selection CLI provider detection from plugin metadata.
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { describe, expect, it } from "vitest";
import type { OpenClawConfig } from "../config/types.js";
import {
clearCurrentPluginMetadataSnapshot,
resolvePluginMetadataControlPlaneFingerprint,
setCurrentPluginMetadataSnapshot,
} from "../plugins/current-plugin-metadata-snapshot.js";
import { resolveInstalledPluginIndexPolicyHash } from "../plugins/installed-plugin-index-policy.js";
import type { InstalledPluginIndex } from "../plugins/installed-plugin-index.js";
import type { PluginMetadataSnapshot } from "../plugins/plugin-metadata-snapshot.js";
import { testing as setupRegistryRuntimeTesting } from "../plugins/setup-registry.runtime.js";
import { isCliProvider } from "./model-selection-cli.js";
function setCliBackendMetadataSnapshot(cliBackends: string[]) {
// Builds a minimal current plugin metadata snapshot so isCliProvider can use
// descriptor metadata without loading setup runtime modules.
const policyHash = resolveInstalledPluginIndexPolicyHash({});
const index: InstalledPluginIndex = {
version: 1,
hostContractVersion: "test-host",
compatRegistryVersion: "test-compat",
migrationVersion: 1,
policyHash,
generatedAtMs: 0,
installRecords: {},
plugins: [
{
pluginId: "anthropic",
manifestPath: "/tmp/anthropic/openclaw.plugin.json",
manifestHash: "test-manifest",
source: "/tmp/anthropic/index.ts",
rootDir: "/tmp/anthropic",
origin: "bundled",
enabled: true,
startup: {
sidecar: false,
memory: false,
deferConfiguredChannelFullLoadUntilAfterListen: false,
agentHarnesses: [],
},
compat: [],
},
],
diagnostics: [],
};
const snapshot = {
policyHash,
configFingerprint: resolvePluginMetadataControlPlaneFingerprint(
{},
{
env: process.env,
index,
policyHash,
},
),
index,
plugins: [
{
id: "anthropic",
origin: "bundled",
cliBackends,
},
],
} as unknown as PluginMetadataSnapshot;
setCurrentPluginMetadataSnapshot(snapshot, { config: {}, env: process.env });
}
describe("isCliProvider", () => {
beforeEach(() => {
setupRegistryRuntimeTesting.resetDescriptorCache();
setCliBackendMetadataSnapshot(["claude-cli"]);
});
afterEach(() => {
clearCurrentPluginMetadataSnapshot();
setupRegistryRuntimeTesting.resetDescriptorCache();
});
it("returns true for setup-registered cli backends", () => {
expect(isCliProvider("claude-cli", {} as OpenClawConfig)).toBe(true);
});
@@ -2,7 +2,6 @@
import path from "node:path";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { setBundledPluginsDirOverrideForTest } from "../plugins/bundled-dir.js";
import {
clearCurrentPluginMetadataSnapshot,
getCurrentPluginMetadataSnapshot,
@@ -170,7 +169,7 @@ describe("optional media tool factory planning", () => {
workflow: { "1": { inputs: {} } },
promptNodeId: "1",
});
setBundledPluginsDirOverrideForTest(path.join(process.cwd(), "extensions"));
vi.stubEnv("OPENCLAW_BUNDLED_PLUGINS_DIR", path.join(process.cwd(), "extensions"));
legacyComfyToolNames = (
await createOpenClawToolsForTest({
config,
@@ -181,7 +180,7 @@ describe("optional media tool factory planning", () => {
clearCurrentPluginMetadataSnapshot();
resetPluginRuntimeStateForTest();
clearSecretsRuntimeSnapshot();
setBundledPluginsDirOverrideForTest(undefined);
vi.unstubAllEnvs();
});
beforeEach(() => {
@@ -193,7 +192,6 @@ describe("optional media tool factory planning", () => {
clearCurrentPluginMetadataSnapshot();
resetPluginRuntimeStateForTest();
clearSecretsRuntimeSnapshot();
setBundledPluginsDirOverrideForTest(undefined);
vi.unstubAllEnvs();
});
@@ -238,7 +236,7 @@ describe("optional media tool factory planning", () => {
it("does not plan media factories from workspace-scoped metadata without workspace context", () => {
// Workspace snapshots are process-local facts and must not leak to unrelated runs.
const config: OpenClawConfig = {};
setBundledPluginsDirOverrideForTest("/nonexistent/bundled/plugins");
vi.stubEnv("OPENCLAW_DISABLE_BUNDLED_PLUGINS", "1");
installSnapshot(
config,
[
@@ -1,92 +0,0 @@
// Verifies runtime plugin loading can reuse a compatible gateway startup registry.
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { createEmptyPluginRegistry } from "../plugins/registry-empty.js";
import type { PluginRegistry } from "../plugins/registry-types.js";
import { resetPluginRuntimeStateForTest, setActivePluginRegistry } from "../plugins/runtime.js";
const mocks = vi.hoisted(() => ({
getCurrentPluginMetadataSnapshot: vi.fn(),
loadOpenClawPlugins: vi.fn<typeof import("../plugins/loader.js").loadOpenClawPlugins>(),
}));
vi.mock("../plugins/current-plugin-metadata-snapshot.js", () => ({
getCurrentPluginMetadataSnapshot: mocks.getCurrentPluginMetadataSnapshot,
}));
vi.mock("../plugins/loader.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../plugins/loader.js")>();
return {
...actual,
loadOpenClawPlugins: (...args: Parameters<typeof mocks.loadOpenClawPlugins>) =>
mocks.loadOpenClawPlugins(...args),
};
});
const [{ ensureRuntimePluginsLoaded }, { clearPluginLoaderCache, testing }] = await Promise.all([
import("./runtime-plugins.js"),
import("../plugins/loader.js"),
]);
function createRegistryWithPlugin(pluginId: string): PluginRegistry {
// Minimal active registry carrying just enough plugin identity for reuse checks.
const registry = createEmptyPluginRegistry();
registry.plugins.push({
id: pluginId,
status: "loaded",
} as never);
return registry;
}
beforeEach(() => {
clearPluginLoaderCache();
resetPluginRuntimeStateForTest();
mocks.getCurrentPluginMetadataSnapshot.mockReset();
mocks.loadOpenClawPlugins.mockReset();
});
afterEach(() => {
clearPluginLoaderCache();
resetPluginRuntimeStateForTest();
});
describe("ensureRuntimePluginsLoaded registry reuse", () => {
it("reuses the compatible gateway startup registry on the dispatch caller path", () => {
// Matching cache key plus gateway-bindable mode means no second plugin load.
const config = { plugins: { allow: ["telegram"] } };
const activeRegistry = createRegistryWithPlugin("telegram");
activeRegistry.coreGatewayMethodNames = ["sessions.get", "sessions.list"];
const startupLoadOptions = {
config,
activationSourceConfig: config,
autoEnabledReasons: {},
workspaceDir: "/tmp/workspace",
onlyPluginIds: ["telegram"],
coreGatewayMethodNames: ["sessions.get", "sessions.list"],
runtimeOptions: {
allowGatewaySubagentBinding: true,
},
preferBuiltPluginArtifacts: true,
};
const { cacheKey } = testing.resolvePluginLoadCacheContext(startupLoadOptions);
setActivePluginRegistry(activeRegistry, cacheKey, "gateway-bindable", "/tmp/workspace");
mocks.getCurrentPluginMetadataSnapshot.mockReturnValue({
startup: {
pluginIds: ["telegram"],
},
});
mocks.loadOpenClawPlugins.mockImplementation(() => {
throw new Error("dispatch should reuse the active gateway startup registry");
});
ensureRuntimePluginsLoaded({
config,
workspaceDir: "/tmp/workspace",
});
expect(mocks.getCurrentPluginMetadataSnapshot).toHaveBeenCalledWith({
config,
workspaceDir: "/tmp/workspace",
});
expect(mocks.loadOpenClawPlugins).not.toHaveBeenCalled();
});
});
+4 -1
View File
@@ -1,7 +1,10 @@
// System prompt memory tests cover opt-out behavior when context engines own
// memory prompt assembly for a run.
import { afterEach, describe, expect, it } from "vitest";
import { clearMemoryPluginState, registerMemoryPromptSection } from "../plugins/memory-state.js";
import {
clearMemoryPluginState,
registerMemoryPromptSection,
} from "../plugins/memory-state.test-fixtures.js";
import { buildAgentSystemPrompt } from "./system-prompt.js";
describe("buildAgentSystemPrompt memory guidance", () => {
@@ -6,7 +6,7 @@
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { clearPluginLoaderCache } from "../../plugins/loader.js";
import { clearPluginLoaderCache } from "../../plugins/loader.test-fixtures.js";
import { createEmptyPluginRegistry } from "../../plugins/registry.js";
import { setActivePluginRegistry } from "../../plugins/runtime.js";
@@ -5,7 +5,7 @@ import { clearRuntimeAuthProfileStoreSnapshots } from "../agents/auth-profiles.j
import { clearSessionStoreCacheForTest } from "../config/sessions.js";
import { resetSystemEventsForTest } from "../infra/system-events.js";
import { createEmptyPluginRegistry } from "../plugins/registry-empty.js";
import type { PluginProviderRegistration } from "../plugins/registry.js";
import type { PluginRegistry } from "../plugins/registry.js";
import { resetPluginRuntimeStateForTest, setActivePluginRegistry } from "../plugins/runtime.js";
import type { ProviderPlugin } from "../plugins/types.js";
import { resetSkillsRefreshForTest } from "../skills/runtime/refresh.js";
@@ -22,6 +22,8 @@ import {
runReplyAgentMock,
} from "./reply.directive.directive-behavior.e2e-mocks.js";
type PluginProviderRegistration = PluginRegistry["providers"][number];
const DEFAULT_TEST_MODEL_CATALOG: Array<{
id: string;
name: string;
@@ -8,7 +8,7 @@ import {
clearMemoryPluginState,
registerMemoryCapability,
type MemoryFlushPlanResolver,
} from "../../plugins/memory-state.js";
} from "../../plugins/memory-state.test-fixtures.js";
import {
runPreflightCompactionIfNeeded,
setAgentRunnerMemoryTestDeps,
@@ -12,7 +12,7 @@ import {
clearMemoryPluginState,
registerMemoryCapability,
type MemoryFlushPlanResolver,
} from "../../plugins/memory-state.js";
} from "../../plugins/memory-state.test-fixtures.js";
import type { TemplateContext } from "../templating.js";
import type { ReplyPayload } from "../types.js";
import {
@@ -24,7 +24,7 @@ import {
clearMemoryPluginState,
registerMemoryCapability,
type MemoryFlushPlanResolver,
} from "../../plugins/memory-state.js";
} from "../../plugins/memory-state.test-fixtures.js";
import { GatewayDrainingError } from "../../process/command-queue.js";
import { getReplyPayloadMetadata, type ReplyPayload } from "../reply-payload.js";
import type { TemplateContext } from "../templating.js";
@@ -4,7 +4,7 @@ import type { OpenClawConfig } from "../../config/config.js";
import { clearPluginCommands, registerPluginCommand } from "../../plugins/commands.js";
import { createPluginRegistry } from "../../plugins/registry.js";
import type { PluginRuntime } from "../../plugins/runtime/types.js";
import { createBundledPluginRecord } from "../../plugins/status.test-helpers.js";
import { createBundledPluginRecord } from "../../plugins/status.test-fixtures.js";
import type { PluginCommandContext, PluginCommandHandler } from "../../plugins/types.js";
import type { MsgContext } from "../templating.js";
import { createDiagnosticsCommandHandler } from "./commands-diagnostics.js";
@@ -1,7 +1,7 @@
// Tests dispatch-from-config reply dispatch integration and final payload routing.
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { clearAgentHarnesses } from "../../agents/harness/registry.js";
import type { PluginHookReplyDispatchResult } from "../../plugins/hooks.js";
import type { PluginHookReplyDispatchResult } from "../../plugins/hooks.test-fixtures.js";
import { createInternalHookEventPayload } from "../../test-utils/internal-hook-event-payload.js";
import { withReplyDispatcher } from "../dispatch-dispatcher.js";
import { setReplyPayloadMetadata } from "../reply-payload.js";
@@ -6,8 +6,8 @@ import type { StuckSessionRecoveryOutcome } from "../../logging/diagnostic-sessi
import type {
PluginHookBeforeDispatchResult,
PluginHookReplyDispatchResult,
PluginTargetedInboundClaimOutcome,
} from "../../plugins/hooks.js";
} from "../../plugins/hook-types.js";
import type { createHookRunner } from "../../plugins/hooks.js";
import { setActivePluginRegistry } from "../../plugins/runtime.js";
import {
createChannelTestPluginBase,
@@ -25,6 +25,9 @@ type AbortResult = {
rejectionReason?: "finalizing";
stoppedSubagents?: number;
};
type PluginTargetedInboundClaimOutcome = Awaited<
ReturnType<ReturnType<typeof createHookRunner>["runInboundClaimForPluginOutcome"]>
>;
const mocks = vi.hoisted(() => ({
isRoutableChannel: vi.fn((_channel: string | undefined) => true),
@@ -23,7 +23,7 @@ import type {
AcpRuntimeTurnInput,
} from "../../plugin-sdk/acp-runtime.js";
import { clearPluginCommands, registerPluginCommand } from "../../plugins/commands.js";
import type { PluginTargetedInboundClaimOutcome } from "../../plugins/hooks.js";
import type { PluginTargetedInboundClaimOutcome } from "../../plugins/hooks.test-fixtures.js";
import { setActivePluginRegistry } from "../../plugins/runtime.js";
import {
interruptSessionWorkAdmissions,
@@ -6,11 +6,8 @@
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import { resolveBundledChannelWorkspacePath } from "../../../../plugins/bundled-channel-runtime.js";
import {
resolvePluginRuntimeModulePath,
resolvePluginRuntimeRecord,
} from "../../../../plugins/runtime/runtime-plugin-boundary.js";
import { listBundledChannelPluginMetadata } from "../../../../plugins/bundled-channel-runtime.js";
import { resolvePluginRuntimeModulePath } from "../../../../plugins/runtime/runtime-plugin-boundary.js";
const REPO_ROOT = fileURLToPath(new URL("../../../../../", import.meta.url));
@@ -19,10 +16,11 @@ function resolveBundledChannelWorkspaceArtifactPath(
entryBaseName: string,
): string | null {
const normalizedEntryBaseName = entryBaseName.replace(/\.(?:[cm]?js|ts)$/u, "");
const pluginRoot = resolveBundledChannelWorkspacePath({
const pluginRoot = listBundledChannelPluginMetadata({
rootDir: REPO_ROOT,
pluginId,
});
includeChannelConfigs: false,
includeSyntheticChannelConfigs: false,
}).find((metadata) => metadata.manifest.id === pluginId)?.rootDir;
if (!pluginRoot) {
return null;
}
@@ -37,15 +35,19 @@ function resolveBundledChannelWorkspaceArtifactPath(
function resolveBundledChannelContractArtifactUrl(pluginId: string, entryBaseName: string): string {
const normalizedEntryBaseName = entryBaseName.replace(/\.(?:[cm]?js|ts)$/u, "");
const record = resolvePluginRuntimeRecord(pluginId, () => {
throw new Error(`missing bundled channel plugin '${pluginId}'`);
});
if (!record) {
const metadata = listBundledChannelPluginMetadata({
rootDir: REPO_ROOT,
includeChannelConfigs: false,
includeSyntheticChannelConfigs: false,
}).find((entry) => entry.manifest.id === pluginId);
if (!metadata) {
throw new Error(`missing bundled channel plugin '${pluginId}'`);
}
const modulePath =
resolvePluginRuntimeModulePath(record, normalizedEntryBaseName) ??
resolveBundledChannelWorkspaceArtifactPath(pluginId, entryBaseName);
resolvePluginRuntimeModulePath(
{ rootDir: metadata.rootDir, source: metadata.source.built },
normalizedEntryBaseName,
) ?? resolveBundledChannelWorkspaceArtifactPath(pluginId, entryBaseName);
if (!modulePath) {
throw new Error(`missing ${entryBaseName} for bundled channel plugin '${pluginId}'`);
}
+14 -21
View File
@@ -5,7 +5,6 @@ import { vi } from "vitest";
import { getRuntimeConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import type { PluginInstallRecord } from "../config/types.plugins.js";
import { createEmptyUninstallActions } from "../plugins/uninstall.js";
import type { CliMockOutputRuntime } from "./test-runtime-capture.js";
type UnknownMock = Mock<(...args: unknown[]) => unknown>;
@@ -27,6 +26,20 @@ type UpdateNpmInstalledHookPacksFn =
(typeof import("../hooks/update.js"))["updateNpmInstalledHookPacks"];
type PluginInstallRecordMap = Record<string, PluginInstallRecord>;
function createEmptyUninstallActions() {
return {
entry: false,
install: false,
allowlist: false,
denylist: false,
loadPath: false,
memorySlot: false,
contextEngineSlot: false,
channelConfig: false,
directory: false,
};
}
let mockInstalledPluginIndexInstallRecords: PluginInstallRecordMap = {};
function clonePluginInstallRecords(records: PluginInstallRecordMap): PluginInstallRecordMap {
@@ -77,7 +90,6 @@ export const clearPluginRegistryLoadCache: UnknownMock = vi.fn();
export const applyExclusiveSlotSelection: UnknownMock = vi.fn();
export const planPluginUninstall: UnknownMock = vi.fn();
export const applyPluginUninstallDirectoryRemoval: AsyncUnknownMock = vi.fn();
const uninstallPlugin: AsyncUnknownMock = vi.fn();
export const updateNpmInstalledPlugins: Mock<UpdateNpmInstalledPluginsFn> = vi.fn();
export const updateNpmInstalledHookPacks: Mock<UpdateNpmInstalledHookPacksFn> = vi.fn();
export const promptYesNo: AsyncUnknownMock = vi.fn();
@@ -482,18 +494,6 @@ vi.mock("../plugins/uninstall.js", async (importOriginal) => {
applyPluginUninstallDirectoryRemoval,
...args,
)) as (typeof import("../plugins/uninstall.js"))["applyPluginUninstallDirectoryRemoval"],
uninstallPlugin: ((
...args: Parameters<(typeof import("../plugins/uninstall.js"))["uninstallPlugin"]>
) =>
invokeMock<
Parameters<(typeof import("../plugins/uninstall.js"))["uninstallPlugin"]>,
ReturnType<(typeof import("../plugins/uninstall.js"))["uninstallPlugin"]>
>(uninstallPlugin, ...args)) as (typeof import("../plugins/uninstall.js"))["uninstallPlugin"],
resolveUninstallDirectoryTarget: ({
installRecord,
}: {
installRecord?: { installPath?: string; sourcePath?: string };
}) => installRecord?.installPath ?? installRecord?.sourcePath ?? null,
};
});
@@ -732,7 +732,6 @@ export function resetPluginsCliTestState() {
applyExclusiveSlotSelection.mockReset();
planPluginUninstall.mockReset();
applyPluginUninstallDirectoryRemoval.mockReset();
uninstallPlugin.mockReset();
updateNpmInstalledPlugins.mockReset();
updateNpmInstalledHookPacks.mockReset();
promptText.mockReset();
@@ -860,12 +859,6 @@ export function resetPluginsCliTestState() {
directoryRemoved: false,
warnings: [],
});
uninstallPlugin.mockResolvedValue({
ok: true,
config: {} as OpenClawConfig,
warnings: [],
actions: createEmptyUninstallActions(),
});
updateNpmInstalledPlugins.mockResolvedValue({
outcomes: [],
changed: false,
+1 -1
View File
@@ -1,7 +1,7 @@
// Plugins CLI list tests cover plugin listing output and installed-state formatting.
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { createPluginRecord } from "../plugins/status.test-helpers.js";
import { createPluginRecord } from "../plugins/status.test-fixtures.js";
import {
buildPluginDiagnosticsReport,
buildPluginInspectReport,
+1 -1
View File
@@ -1,6 +1,6 @@
// Plugin list format tests cover installed plugin table and JSON formatting.
import { describe, expect, it } from "vitest";
import { createPluginRecord } from "../plugins/status.test-helpers.js";
import { createPluginRecord } from "../plugins/status.test-fixtures.js";
import { formatPluginLine } from "./plugins-list-format.js";
describe("formatPluginLine", () => {
+1 -1
View File
@@ -1,7 +1,7 @@
// Plugin location bridge tests cover CLI plugin path bridging between install surfaces.
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { InstalledPluginStartupInfo } from "../plugins/installed-plugin-index-types.js";
import type { InstalledPluginIndex } from "../plugins/installed-plugin-index.js";
import type { InstalledPluginStartupInfo } from "../plugins/installed-plugin-index.js";
import type { PluginManifestRegistry } from "../plugins/manifest-registry.js";
const readPersistedInstalledPluginIndexMock = vi.fn();
+1 -1
View File
@@ -32,7 +32,7 @@ import {
resetAgentEventsForTest,
resetAgentRunContextForTest,
} from "../infra/agent-events.js";
import type { PluginProviderRegistration } from "../plugins/registry.js";
import type { PluginProviderRegistration } from "../plugins/registry.test-fixtures.js";
import { resetPluginRuntimeStateForTest, setActivePluginRegistry } from "../plugins/runtime.js";
import type { RuntimeEnv } from "../runtime.js";
import { AGENT_HARNESS_SESSION_KEY_RESERVED_MESSAGE } from "../sessions/agent-harness-session-key.js";
+4 -1
View File
@@ -2,7 +2,6 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { AuthProfileStore } from "../agents/auth-profiles.js";
import type { ProviderAuthChoiceMetadata } from "../plugins/provider-auth-choices.js";
import type { ProviderWizardOption } from "../plugins/provider-wizard.js";
import {
buildAuthChoiceGroups,
buildAuthChoiceOptions,
@@ -10,6 +9,10 @@ import {
} from "./auth-choice-options.js";
import { formatStaticAuthChoiceChoicesForCli } from "./auth-choice-options.static.js";
type ProviderWizardOption = ReturnType<
(typeof import("../plugins/provider-wizard.js"))["resolveProviderWizardOptions"]
>[number];
const resolveManifestProviderAuthChoices = vi.hoisted(() =>
vi.fn<() => ProviderAuthChoiceMetadata[]>(() => []),
);
@@ -3,7 +3,6 @@ import { expectDefined } from "@openclaw/normalization-core";
import { beforeEach, describe, expect, it, vi } from "vitest";
import {
applyAuthChoiceLoadedPluginProvider,
applyAuthChoicePluginProvider,
runProviderPluginAuthMethod,
} from "../plugins/provider-auth-choice.js";
import type { ProviderPlugin } from "../plugins/types.js";
@@ -678,131 +677,4 @@ describe("applyAuthChoiceLoadedPluginProvider", () => {
"openai/gpt-5.2": {},
});
});
it("returns an agent-scoped override for plugin auth choices when default model application is deferred", async () => {
const provider = buildProvider();
resolvePluginProviders.mockReturnValue([provider]);
const note = vi.fn(async () => {});
const result = await applyAuthChoicePluginProvider(
buildParams({
authChoice: `provider-plugin:${LOCAL_PROVIDER_ID}:${LOCAL_AUTH_METHOD_ID}`,
agentId: "worker",
setDefaultModel: false,
prompter: {
note,
} as unknown as ApplyAuthChoiceParams["prompter"],
}),
{
authChoice: `provider-plugin:${LOCAL_PROVIDER_ID}:${LOCAL_AUTH_METHOD_ID}`,
pluginId: LOCAL_PROVIDER_ID,
providerId: LOCAL_PROVIDER_ID,
methodId: LOCAL_AUTH_METHOD_ID,
label: LOCAL_PROVIDER_LABEL,
},
);
expect(result?.agentModelOverride).toBe(LOCAL_DEFAULT_MODEL);
expect(result?.config.plugins).toEqual({
entries: {
[LOCAL_PROVIDER_ID]: {
enabled: true,
},
},
});
expect(runProviderModelSelectedHook).not.toHaveBeenCalled();
expect(note).toHaveBeenCalledWith(
`Default model set to ${LOCAL_DEFAULT_MODEL} for agent "worker".`,
"Model configured",
);
});
it("preserves the existing primary model for plugin auth choices that patch defaults", async () => {
const provider = buildProviderWithDefaultModelPatch();
resolvePluginProviders.mockReturnValue([provider]);
const note = vi.fn(async () => {});
const result = await applyAuthChoicePluginProvider(
buildParams({
authChoice: `provider-plugin:${LOCAL_PROVIDER_ID}:${LOCAL_AUTH_METHOD_ID}`,
config: {
agents: {
defaults: {
model: { primary: EXISTING_DEFAULT_MODEL },
models: {
[EXISTING_DEFAULT_MODEL]: { alias: "Bedrock" },
},
},
},
},
prompter: {
note,
} as unknown as ApplyAuthChoiceParams["prompter"],
preserveExistingDefaultModel: true,
}),
{
authChoice: `provider-plugin:${LOCAL_PROVIDER_ID}:${LOCAL_AUTH_METHOD_ID}`,
pluginId: LOCAL_PROVIDER_ID,
providerId: LOCAL_PROVIDER_ID,
methodId: LOCAL_AUTH_METHOD_ID,
label: LOCAL_PROVIDER_LABEL,
},
);
expect(result?.config.agents?.defaults?.model).toEqual({
primary: EXISTING_DEFAULT_MODEL,
});
expect(result?.config.agents?.defaults?.models).toEqual({
[EXISTING_DEFAULT_MODEL]: { alias: "Bedrock" },
[LOCAL_DEFAULT_MODEL]: { alias: "Local default" },
});
expect(result?.config.plugins).toEqual({
entries: {
[LOCAL_PROVIDER_ID]: {
enabled: true,
},
},
});
expect(runProviderModelSelectedHook).not.toHaveBeenCalled();
expect(note).toHaveBeenCalledWith(
`Kept existing default model ${EXISTING_DEFAULT_MODEL}; ${LOCAL_DEFAULT_MODEL} is available.`,
"Model configured",
);
});
it("stops early when the plugin is disabled in config", async () => {
const note = vi.fn(async () => {});
const result = await applyAuthChoicePluginProvider(
buildParams({
config: {
plugins: {
enabled: false,
},
},
prompter: {
note,
} as unknown as ApplyAuthChoiceParams["prompter"],
}),
{
authChoice: LOCAL_PROVIDER_ID,
pluginId: LOCAL_PROVIDER_ID,
providerId: LOCAL_PROVIDER_ID,
label: LOCAL_PROVIDER_LABEL,
},
);
expect(result).toEqual({
config: {
plugins: {
enabled: false,
},
},
});
expect(resolvePluginProviders).not.toHaveBeenCalled();
expect(note).toHaveBeenCalledWith(
"Local Provider plugin is disabled (plugins disabled).",
LOCAL_PROVIDER_LABEL,
);
});
});
+7 -85
View File
@@ -6,7 +6,6 @@ import { resolveAgentDir } from "../agents/agent-scope.js";
import type { OpenClawConfig } from "../config/config.js";
import { resolveAgentModelPrimaryValue } from "../config/model-input.js";
import type { ModelProviderConfig } from "../config/types.models.js";
import { testing as providerAuthChoiceTesting } from "../plugins/provider-auth-choice.js";
import * as providerAuthChoices from "../plugins/provider-auth-choices.js";
import type { ProviderAuthMethod, ProviderAuthResult, ProviderPlugin } from "../plugins/types.js";
import type { WizardPrompter } from "../wizard/prompts.js";
@@ -47,6 +46,13 @@ vi.mock("../plugins/provider-install-catalog.js", () => ({
resolveProviderInstallCatalogEntry: vi.fn(() => undefined),
}));
vi.mock("../plugins/provider-auth-choice.runtime.js", () => ({
resolvePluginProviders,
resolvePluginSetupProvider: () => undefined,
resolveProviderPluginChoice,
runProviderModelSelectedHook,
}));
vi.mock("./auth-choice.apply.api-providers.js", () => {
const normalizeProviderIdLocal = (value: string) => value.trim().toLowerCase();
const resolveChoiceByKind = (params: {
@@ -673,18 +679,9 @@ describe("applyAuthChoice", () => {
authTestRoot = (await setupAuthTestEnv("openclaw-auth-")).stateDir;
defaultProviderPlugins = await createDefaultProviderPlugins();
resolvePluginProviders.mockReturnValue(defaultProviderPlugins);
providerAuthChoiceTesting.setDepsForTest({
loadPluginProviderRuntime: async () => ({
resolvePluginProviders,
resolvePluginSetupProvider: () => undefined,
resolveProviderPluginChoice,
runProviderModelSelectedHook,
}),
});
});
afterAll(async () => {
providerAuthChoiceTesting.resetDepsForTest();
if (authTestRoot) {
await fs.rm(authTestRoot, { recursive: true, force: true });
}
@@ -1117,81 +1114,6 @@ describe("applyAuthChoice", () => {
);
});
it("enables the owning plugin for manifest provider auth choices", async () => {
await setupTempState();
const provider = createFixedChoiceProvider({
providerId: "github-copilot",
label: "GitHub Copilot",
choiceId: "github-copilot-github",
method: {
id: "github",
label: "GitHub Copilot",
kind: "token",
run: vi.fn(
async (): Promise<ProviderAuthResult> => ({
profiles: [
{
profileId: "github-copilot:github",
credential: {
type: "token",
provider: "github-copilot",
token: "gho_copilot_test",
},
},
],
defaultModel: "github-copilot/claude-opus-4.7",
}),
),
},
});
const manifestSpy = vi
.spyOn(providerAuthChoices, "resolveManifestProviderAuthChoice")
.mockReturnValue({
pluginId: "github-copilot",
providerId: "github-copilot",
methodId: "github",
choiceId: "github-copilot-github",
choiceLabel: "GitHub Copilot",
});
providerAuthChoiceTesting.setDepsForTest({
loadPluginProviderRuntime: async () => ({
resolvePluginProviders,
resolvePluginSetupProvider: () => provider,
resolveProviderPluginChoice,
runProviderModelSelectedHook,
}),
});
try {
const result = await applyAuthChoice({
authChoice: "github-copilot-github",
config: { plugins: { entries: { "github-copilot": { enabled: false } } } },
prompter: createPrompter({}),
runtime: createExitThrowingRuntime(),
setDefaultModel: true,
preserveExistingDefaultModel: true,
});
expect(result.config.plugins?.entries?.["github-copilot"]).toEqual({ enabled: true });
expectAuthProfileConfig(result, "github-copilot:github", {
provider: "github-copilot",
mode: "token",
});
expect(resolveAgentModelPrimaryValue(result.config.agents?.defaults?.model)).toBe(
"github-copilot/claude-opus-4.7",
);
} finally {
manifestSpy.mockRestore();
providerAuthChoiceTesting.setDepsForTest({
loadPluginProviderRuntime: async () => ({
resolvePluginProviders,
resolvePluginSetupProvider: () => undefined,
resolveProviderPluginChoice,
runProviderModelSelectedHook,
}),
});
}
});
it("uses explicit env for plugin auth resolution instead of host env", async () => {
await setupTempState();
process.env.OPENAI_API_KEY = "sk-openai-host"; // pragma: allowlist secret
+1 -1
View File
@@ -1,7 +1,7 @@
// Config validation tests cover config snapshot validation and command error handling.
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { PluginCompatibilityNotice } from "../plugins/status.js";
import { createCompatibilityNotice } from "../plugins/status.test-helpers.js";
import { createCompatibilityNotice } from "../plugins/status.test-fixtures.js";
import { requireValidConfigSnapshot } from "./config-validation.js";
const { readConfigFileSnapshot, buildPluginCompatibilitySnapshotNotices } = vi.hoisted(() => ({
+1 -1
View File
@@ -8,7 +8,7 @@ import {
createPluginLoadResult,
createPluginRecord,
createTypedHook,
} from "../plugins/status.test-helpers.js";
} from "../plugins/status.test-fixtures.js";
import {
collectWorkspaceStatusHealthFindings,
noteWorkspaceStatus,
+1 -1
View File
@@ -5,7 +5,7 @@ import path from "node:path";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { ChannelAccountSnapshot } from "../channels/plugins/types.js";
import type { ChannelPlugin } from "../channels/plugins/types.js";
import { createPluginRecord } from "../plugins/status.test-helpers.js";
import { createPluginRecord } from "../plugins/status.test-fixtures.js";
import { MAX_TIMER_TIMEOUT_MS } from "../shared/number-coercion.js";
import type { HealthSummary } from "./health.js";
+1 -1
View File
@@ -2,7 +2,7 @@
import type { Mock } from "vitest";
import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from "vitest";
import type { PluginCompatibilityNotice } from "../plugins/status.js";
import { createCompatibilityNotice } from "../plugins/status.test-helpers.js";
import { createCompatibilityNotice } from "../plugins/status.test-fixtures.js";
import { captureEnv, deleteTestEnvValue, setTestEnvValue } from "../test-utils/env.js";
let envSnapshot: ReturnType<typeof captureEnv>;
+1 -25
View File
@@ -1,8 +1,5 @@
// Verifies pruning-related config defaults and migrations.
import path from "node:path";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { setBundledPluginsDirOverrideForTest } from "../plugins/bundled-dir.js";
import { resetBundledPluginPublicArtifactLoaderForTest } from "../plugins/public-surface-loader.js";
import { describe, expect, it } from "vitest";
import type { OpenClawConfig } from "./config.js";
import { applyProviderConfigDefaultsForConfig } from "./provider-policy.js";
@@ -17,27 +14,6 @@ function applyAnthropicDefaultsForTest(config: OpenClawConfig) {
}
describe("config pruning defaults", () => {
beforeAll(() => {
setBundledPluginsDirOverrideForTest(path.resolve(import.meta.dirname, "../../extensions"));
// Provider public artifacts are process-stable. Keep their one-time load out of assertions.
applyAnthropicDefaultsForTest({ agents: { defaults: {} } });
});
beforeEach(() => {
setBundledPluginsDirOverrideForTest(path.resolve(import.meta.dirname, "../../extensions"));
resetBundledPluginPublicArtifactLoaderForTest();
vi.stubEnv(
"OPENCLAW_BUNDLED_PLUGINS_DIR",
path.resolve(import.meta.dirname, "../../extensions"),
);
});
afterEach(() => {
setBundledPluginsDirOverrideForTest(undefined);
resetBundledPluginPublicArtifactLoaderForTest();
vi.unstubAllEnvs();
});
it("does not enable contextPruning by default", () => {
const cfg = applyAnthropicDefaultsForTest({ agents: { defaults: {} } });
+1 -14
View File
@@ -1,9 +1,7 @@
// Covers best-effort config IO reads and warning behavior.
import fs from "node:fs/promises";
import path from "node:path";
import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from "vitest";
import { afterEach, describe, expect, it, vi } from "vitest";
import { executeSqliteQueryTakeFirstSync, getNodeSqliteKysely } from "../infra/kysely-sync.js";
import { setBundledPluginsDirOverrideForTest } from "../plugins/bundled-dir.js";
import type { DB as OpenClawStateKyselyDatabase } from "../state/openclaw-state-db.generated.js";
import {
closeOpenClawStateDatabaseForTest,
@@ -16,7 +14,6 @@ import {
readConfigFileSnapshot,
readSourceConfigBestEffort,
} from "./config.js";
import { applyProviderConfigDefaultsForConfig } from "./provider-policy.js";
import { withTempHome, writeOpenClawConfig } from "./test-helpers.js";
type ConfigHealthDatabase = Pick<OpenClawStateKyselyDatabase, "config_health_entries">;
@@ -34,20 +31,10 @@ function readConfigHealthRow(env: NodeJS.ProcessEnv, configPath: string) {
}
describe("readBestEffortConfig", () => {
beforeAll(() => {
setBundledPluginsDirOverrideForTest(path.resolve(import.meta.dirname, "../../extensions"));
// Materialized reads use the process-stable provider policy cache.
applyProviderConfigDefaultsForConfig({ provider: "anthropic", config: {}, env: {} });
});
afterEach(() => {
closeOpenClawStateDatabaseForTest();
});
afterAll(() => {
setBundledPluginsDirOverrideForTest(undefined);
});
it("can read snapshots without updating config observation state", async () => {
await withTempHome(async (home) => {
const configPath = await writeOpenClawConfig(home, {
@@ -1,122 +0,0 @@
// Verifies plugin auto-enable prefer-over precedence rules.
import fs from "node:fs";
import path from "node:path";
import { afterEach, describe, expect, it, vi } from "vitest";
import type { PluginManifestRegistry } from "../plugins/manifest-registry.js";
import { cleanupTrackedTempDirs } from "../plugins/test-helpers/fs-fixtures.js";
vi.mock("../plugins/bundled-dir.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../plugins/bundled-dir.js")>();
return {
...actual,
resolveBundledPluginsDir: (env: NodeJS.ProcessEnv = process.env) =>
env.OPENCLAW_BUNDLED_PLUGINS_DIR,
};
});
const tempDirs: string[] = [];
function makeTempDir(): string {
const trustedRoot = path.resolve("dist-runtime", "extensions");
fs.mkdirSync(trustedRoot, { recursive: true });
const dir = fs.mkdtempSync(path.join(trustedRoot, ".openclaw-plugin-prefer-over-"));
tempDirs.push(dir);
return dir;
}
function writeBundledChannelPackage(rootDir: string, channelId: string): void {
const pluginDir = path.join(rootDir, channelId);
fs.mkdirSync(pluginDir, { recursive: true });
fs.writeFileSync(
path.join(pluginDir, "package.json"),
JSON.stringify({
openclaw: {
channel: {
id: channelId,
label: "Cache Drift",
selectionLabel: "Cache Drift",
docsPath: `/channels/${channelId}`,
blurb: "Cache drift fixture",
},
},
}),
"utf-8",
);
fs.writeFileSync(
path.join(pluginDir, "openclaw.plugin.json"),
JSON.stringify({
id: channelId,
configSchema: { type: "object" },
channels: [channelId],
}),
"utf-8",
);
fs.writeFileSync(
path.join(pluginDir, "index.js"),
"export default { register() {} };\n",
"utf-8",
);
}
const EMPTY_MANIFEST_REGISTRY: PluginManifestRegistry = {
plugins: [],
diagnostics: [],
};
async function setBundledPluginsDirFixture(dir: string | undefined): Promise<void> {
const { setBundledPluginsDirOverrideForTest } = await import("../plugins/bundled-dir.js");
setBundledPluginsDirOverrideForTest(dir);
}
afterEach(async () => {
await setBundledPluginsDirFixture(undefined);
vi.unstubAllEnvs();
vi.resetModules();
cleanupTrackedTempDirs(tempDirs);
});
describe("plugin auto-enable preferOver", () => {
it("tolerates bundled channel id metadata drift during auto-enable", async () => {
vi.resetModules();
const rootDir = makeTempDir();
const channelId = "cache-drift-channel";
writeBundledChannelPackage(rootDir, channelId);
vi.stubEnv("OPENCLAW_BUNDLED_PLUGINS_DIR", rootDir);
await setBundledPluginsDirFixture(rootDir);
const { normalizeChatChannelId } = await import("../channels/ids.js");
expect(normalizeChatChannelId(channelId)).toBe(channelId);
vi.stubEnv("OPENCLAW_BUNDLED_PLUGINS_DIR", path.join(rootDir, "missing"));
await setBundledPluginsDirFixture(undefined);
const { materializePluginAutoEnableCandidates } = await import("./plugin-auto-enable.js");
const result = materializePluginAutoEnableCandidates({
config: {
channels: {
[channelId]: { token: "configured" },
fallback: { token: "configured" },
},
},
candidates: [
{
pluginId: channelId,
kind: "channel-configured",
channelId,
},
{
pluginId: "fallback",
kind: "channel-configured",
channelId: "fallback",
},
],
env: {
OPENCLAW_STATE_DIR: path.join(rootDir, "state"),
OPENCLAW_BUNDLED_PLUGINS_DIR: path.join(rootDir, "missing"),
},
manifestRegistry: EMPTY_MANIFEST_REGISTRY,
});
expect(result.config.channels?.[channelId]?.enabled).toBe(true);
});
});
@@ -3,9 +3,9 @@ import path from "node:path";
import { clearCurrentPluginMetadataSnapshot } from "../plugins/current-plugin-metadata-snapshot.js";
import { resolveInstalledPluginIndexPolicyHash } from "../plugins/installed-plugin-index-policy.js";
import type { PluginManifestRegistry } from "../plugins/manifest-registry.js";
import { clearPluginMetadataLifecycleCaches } from "../plugins/plugin-metadata-lifecycle.js";
import type { PluginMetadataSnapshot } from "../plugins/plugin-metadata-snapshot.js";
import type { PluginOrigin } from "../plugins/plugin-origin.types.js";
import { clearPluginSetupRegistryCache } from "../plugins/setup-registry.js";
import { cleanupTrackedTempDirs, makeTrackedTempDir } from "../plugins/test-helpers/fs-fixtures.js";
import type { OpenClawConfig } from "./types.openclaw.js";
@@ -14,7 +14,7 @@ const tempDirs: string[] = [];
/** Clears auto-enable plugin caches and temp dirs between tests. */
export function resetPluginAutoEnableTestState(): void {
clearCurrentPluginMetadataSnapshot();
clearPluginSetupRegistryCache();
clearPluginMetadataLifecycleCaches();
cleanupTrackedTempDirs(tempDirs);
}
+2 -2
View File
@@ -3,13 +3,13 @@ import fs from "node:fs/promises";
import path from "node:path";
import { withTempHome as withTempHomeBase } from "openclaw/plugin-sdk/test-env";
import { resetPluginLoaderTestStateForTest } from "../plugins/loader.test-fixtures.js";
import { clearPluginSetupRegistryCache } from "../plugins/setup-registry.js";
import { clearPluginMetadataLifecycleCaches } from "../plugins/plugin-metadata-lifecycle.js";
import { resetConfigRuntimeState, type OpenClawConfig } from "./config.js";
function resetConfigTestRuntimeState(): void {
resetConfigRuntimeState();
resetPluginLoaderTestStateForTest();
clearPluginSetupRegistryCache();
clearPluginMetadataLifecycleCaches();
}
export async function withTempHome<T>(fn: (home: string) => Promise<T>): Promise<T> {
+4 -1
View File
@@ -3,7 +3,10 @@ import type { AgentMessage } from "openclaw/plugin-sdk/agent-core";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import type { MemoryCitationsMode } from "../config/types.memory.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { clearMemoryPluginState, registerMemoryPromptSection } from "../plugins/memory-state.js";
import {
clearMemoryPluginState,
registerMemoryPromptSection,
} from "../plugins/memory-state.test-fixtures.js";
// ---------------------------------------------------------------------------
// We dynamically import the registry so we can get a fresh module per test
// group when needed. For most groups we use the shared singleton directly.
@@ -6,7 +6,7 @@ import { runEmbeddedAgent } from "../agents/embedded-agent.js";
import { loadModelCatalog } from "../agents/model-catalog.js";
import { BASE_THINKING_LEVELS } from "../auto-reply/thinking.shared.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import type { PluginProviderRegistration } from "../plugins/registry.js";
import type { PluginProviderRegistration } from "../plugins/registry.test-fixtures.js";
import { resetPluginRuntimeStateForTest, setActivePluginRegistry } from "../plugins/runtime.js";
import { createTestRegistry } from "../test-utils/channel-plugins.js";
import {
+1 -1
View File
@@ -14,7 +14,7 @@ import {
getRuntimeConfig,
} from "../config/config.js";
import { isTruthyEnvValue } from "../infra/env.js";
import { clearPluginLoaderCache } from "../plugins/loader.js";
import { clearPluginLoaderCache } from "../plugins/loader.test-fixtures.js";
import {
pinActivePluginChannelRegistry,
releasePinnedPluginChannelRegistry,
@@ -21,7 +21,7 @@ import { loadSessionStore } from "../config/sessions/store.js";
import type { SessionEntry } from "../config/sessions/types.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { isTruthyEnvValue } from "../infra/env.js";
import { clearPluginLoaderCache } from "../plugins/loader.js";
import { clearPluginLoaderCache } from "../plugins/loader.test-fixtures.js";
import { resetPluginRuntimeStateForTest } from "../plugins/runtime.js";
import { setTestEnvValue } from "../test-utils/env.js";
import { sleep } from "../utils.js";
+1 -1
View File
@@ -13,7 +13,7 @@ import { isTruthyEnvValue } from "../infra/env.js";
import { getSessionBindingService } from "../infra/outbound/session-binding-service.js";
import { findBundledPluginMetadataById } from "../plugins/bundled-plugin-metadata.js";
import { pluginCommands } from "../plugins/command-registry-state.js";
import { clearPluginLoaderCache } from "../plugins/loader.js";
import { clearPluginLoaderCache } from "../plugins/loader.test-fixtures.js";
import {
pinActivePluginChannelRegistry,
releasePinnedPluginChannelRegistry,
@@ -62,7 +62,6 @@ import { isTruthyEnvValue } from "../infra/env.js";
import type { ModelRegistry } from "../llm/model-registry.js";
import { normalizeGoogleModelId } from "../plugin-sdk/google-model-id.js";
import { resolveProviderThinkingProfile } from "../plugins/provider-runtime.js";
import type { ProviderThinkingModelCompat } from "../plugins/provider-thinking.types.js";
import { DEFAULT_AGENT_ID } from "../routing/session-key.js";
import { stripAssistantInternalScaffolding } from "../shared/text/assistant-visible-text.js";
import { findFinalTagMatches, stripFinalTags } from "../shared/text/final-tags.js";
@@ -70,6 +69,11 @@ import { deleteTestEnvValue, setTestEnvValue } from "../test-utils/env.js";
import { getFreePort, isPortFree } from "../test-utils/ports.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js";
import { GatewayClient } from "./client.js";
type ProviderThinkingModelCompat = {
thinkingFormat?: string;
supportedReasoningEfforts?: readonly string[] | null;
};
import {
hasExpectedSingleNonce,
hasExpectedToolNonce,
+1 -1
View File
@@ -17,7 +17,7 @@ import { clearSessionStoreCacheForTest } from "../config/sessions/store.js";
import type { GatewayAuthConfig, GatewayTailscaleConfig } from "../config/types.gateway.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { resetAgentRunContextForTest } from "../infra/agent-events.js";
import { clearGatewaySubagentRuntime } from "../plugins/runtime/index.js";
import { clearGatewaySubagentRuntime } from "../plugins/runtime/gateway-bindings.test-fixtures.js";
import { captureEnv, deleteTestEnvValue, setTestEnvValue } from "../test-utils/env.js";
import { startGatewayServer } from "./server.js";
import {
@@ -9,7 +9,7 @@ import { clearConfigCache, clearRuntimeConfigSnapshot } from "../config/config.j
import { clearSessionStoreCacheForTest } from "../config/sessions/store.js";
import { resetAgentRunContextForTest } from "../infra/agent-events.js";
import { PROXY_ENV_KEYS } from "../infra/net/proxy-env.js";
import { clearGatewaySubagentRuntime } from "../plugins/runtime/index.js";
import { clearGatewaySubagentRuntime } from "../plugins/runtime/gateway-bindings.test-fixtures.js";
import { captureEnv, deleteTestEnvValue, setTestEnvValue } from "../test-utils/env.js";
import { startGatewayServer } from "./server.js";
import { getFreeGatewayPort } from "./test-helpers.e2e.js";
@@ -4,7 +4,7 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { createBundledBrowserPluginFixture } from "../../test/helpers/browser-bundled-plugin-fixture.js";
import type { OpenClawConfig } from "../config/config.js";
import { clearPluginLoaderCache } from "../plugins/loader.js";
import { clearPluginLoaderCache } from "../plugins/loader.test-fixtures.js";
import { resetPluginRuntimeStateForTest } from "../plugins/runtime.js";
import { loadGatewayStartupPlugins } from "./server-plugin-bootstrap.js";
@@ -3,7 +3,7 @@
*/
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import type { PluginRuntimeGatewayRequestScope } from "../plugins/runtime/gateway-request-scope.js";
import type { PluginRuntimeGatewayRequestScope } from "../plugins/runtime/gateway-request-scope.test-fixtures.js";
import type { GatewayRequestContext, GatewayRequestOptions } from "./server-methods/types.js";
type HandleGatewayRequestOptions = GatewayRequestOptions & {
+4 -3
View File
@@ -5,7 +5,8 @@ import { createPluginRecord } from "../plugins/loader-records.js";
import type { PluginLookUpTable } from "../plugins/plugin-lookup-table.js";
import { createEmptyPluginRegistry } from "../plugins/registry-empty.js";
import type { PluginRegistry } from "../plugins/registry.js";
import type { PluginRuntimeGatewayRequestScope } from "../plugins/runtime/gateway-request-scope.js";
import { clearGatewaySubagentRuntime } from "../plugins/runtime/gateway-bindings.test-fixtures.js";
import type { PluginRuntimeGatewayRequestScope } from "../plugins/runtime/gateway-request-scope.test-fixtures.js";
import type { PluginRuntime } from "../plugins/runtime/types.js";
import type { PluginDiagnostic } from "../plugins/types.js";
import type { GatewayRequestContext, GatewayRequestOptions } from "./server-methods/types.js";
@@ -381,7 +382,7 @@ beforeEach(() => {
pluginRuntimeLoaderLogger.error.mockClear();
pluginRuntimeLoaderLogger.debug.mockClear();
handleGatewayRequest.mockReset();
runtimeModule.clearGatewaySubagentRuntime();
clearGatewaySubagentRuntime();
handleGatewayRequest.mockImplementation(async (opts: HandleGatewayRequestOptions) => {
switch (opts.req.method) {
case "agent":
@@ -404,7 +405,7 @@ beforeEach(() => {
afterEach(() => {
serverPluginsModule.clearFallbackGatewayContext();
runtimeModule.clearGatewaySubagentRuntime();
clearGatewaySubagentRuntime();
runtimeRegistryModule.resetPluginRuntimeStateForTest();
});
@@ -15,7 +15,7 @@ import {
releasePinnedPluginSessionExtensionRegistry,
setActivePluginRegistry,
} from "../plugins/runtime.js";
import { createPluginRecord } from "../plugins/status.test-helpers.js";
import { createPluginRecord } from "../plugins/status.test-fixtures.js";
import { buildGatewaySessionRow } from "./session-utils.js";
import { embeddedRunMock, rpcReq, testState, writeSessionStore } from "./test-helpers.js";
import {
+1 -1
View File
@@ -36,7 +36,7 @@ import { __testing as restartTesting } from "../infra/restart.js";
import { drainSystemEvents, peekSystemEvents } from "../infra/system-events.js";
import { rawDataToString } from "../infra/ws.js";
import { resetLogger, setLoggerOverride } from "../logging.js";
import { clearGatewaySubagentRuntime } from "../plugins/runtime/gateway-bindings.js";
import { clearGatewaySubagentRuntime } from "../plugins/runtime/gateway-bindings.test-fixtures.js";
import { resetGatewayWorkAdmission } from "../process/gateway-work-admission.js";
import {
DEFAULT_AGENT_ID,
+1 -1
View File
@@ -16,7 +16,7 @@ import type { OpenClawConfig } from "../../config/config.js";
import type { SessionTranscriptAppendResult } from "../../config/sessions/transcript.js";
import * as mediaCapabilityModule from "../../media/read-capability.js";
import { createHookRunner } from "../../plugins/hooks.js";
import { addTestHook } from "../../plugins/hooks.test-helpers.js";
import { addTestHook } from "../../plugins/hooks.test-fixtures.js";
import { createEmptyPluginRegistry } from "../../plugins/registry.js";
import {
pinActivePluginChannelRegistry,
+1 -1
View File
@@ -12,7 +12,7 @@ import {
initializeGlobalHookRunner,
resetGlobalHookRunner,
} from "../plugins/hook-runner-global.js";
import { createMockPluginRegistry } from "../plugins/hooks.test-helpers.js";
import { createMockPluginRegistry } from "../plugins/hooks.test-fixtures.js";
import { PluginApprovalResolutions } from "../plugins/types.js";
import { createPluginToolsMcpHandlers } from "./plugin-tools-handlers.js";
@@ -8,7 +8,7 @@ import {
withBundledPluginEnablementCompat,
withBundledPluginVitestCompat,
} from "../plugins/bundled-compat.js";
import { testing as loaderTesting } from "../plugins/loader.js";
import { resolvePluginRegistryLoadCacheKey } from "../plugins/loader.js";
import { loadPluginManifestRegistry } from "../plugins/manifest-registry.js";
import { createEmptyPluginRegistry } from "../plugins/registry.js";
import { setActivePluginRegistry } from "../plugins/runtime.js";
@@ -92,7 +92,7 @@ function setCompatibleActiveMediaUnderstandingRegistry(
pluginIds,
env: process.env,
});
const { cacheKey } = loaderTesting.resolvePluginLoadCacheContext({
const cacheKey = resolvePluginRegistryLoadCacheKey({
config: compatibleConfig,
env: process.env,
});
+1 -1
View File
@@ -4,7 +4,7 @@ import {
initializeGlobalHookRunner,
resetGlobalHookRunner,
} from "../plugins/hook-runner-global.js";
import { createMockPluginRegistry } from "../plugins/hooks.test-helpers.js";
import { createMockPluginRegistry } from "../plugins/hooks.test-fixtures.js";
import { issuePairingChallenge } from "./pairing-challenge.js";
describe("issuePairingChallenge", () => {
+1 -1
View File
@@ -6,7 +6,7 @@ import {
initializeGlobalHookRunner,
resetGlobalHookRunner,
} from "../plugins/hook-runner-global.js";
import { createMockPluginRegistry } from "../plugins/hooks.test-helpers.js";
import { createMockPluginRegistry } from "../plugins/hooks.test-fixtures.js";
import type { PluginRuntime } from "../plugins/runtime/types.js";
import {
createChannelPairingChallengeIssuer,
-3
View File
@@ -4,7 +4,6 @@ import path from "node:path";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { clearRuntimeConfigSnapshot, setRuntimeConfigSnapshot } from "../config/config.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { setBundledPluginsDirOverrideForTest } from "../plugins/bundled-dir.js";
import { createPluginActivationSource, normalizePluginsConfig } from "../plugins/config-state.js";
import {
clearCurrentPluginMetadataSnapshot,
@@ -72,7 +71,6 @@ function createBundledPluginDir(prefix: string, marker: string): string {
function useBundledPluginDirOverrideForTest(dir: string): void {
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = dir;
setBundledPluginsDirOverrideForTest(dir);
}
function createThrowingPluginDir(prefix: string): string {
@@ -102,7 +100,6 @@ afterEach(() => {
clearRuntimeConfigSnapshot();
clearCurrentPluginMetadataSnapshot();
resetFacadeRuntimeStateForTest();
setBundledPluginsDirOverrideForTest(undefined);
vi.doUnmock("../plugins/manifest-registry.js");
if (originalBundledPluginsDir === undefined) {
delete process.env.OPENCLAW_BUNDLED_PLUGINS_DIR;
+1 -1
View File
@@ -9,7 +9,7 @@ import {
clearMemoryPluginState,
registerMemoryCapability,
registerMemoryPromptSection,
} from "../plugins/memory-state.js";
} from "../plugins/memory-state.test-fixtures.js";
import * as memoryCoreAlias from "./memory-core.js";
import {
buildActiveMemoryPromptSection,
+4 -4
View File
@@ -14,7 +14,7 @@ import {
import { getCurrentPluginMetadataSnapshot } from "./current-plugin-metadata-snapshot.js";
import type { PluginDiscoveryResult } from "./discovery.js";
export type PluginActivationCompatConfig = {
type PluginActivationCompatConfig = {
enablementPluginIds?: readonly string[];
vitestPluginIds?: readonly string[];
};
@@ -24,7 +24,7 @@ export type PluginActivationBundledCompatMode = {
vitest?: boolean;
};
export type PluginActivationInputs = {
type PluginActivationInputs = {
rawConfig?: OpenClawConfig;
config?: OpenClawConfig;
normalized: NormalizedPluginsConfig;
@@ -33,11 +33,11 @@ export type PluginActivationInputs = {
autoEnabledReasons: Record<string, string[]>;
};
export type BundledPluginCompatibleActivationInputs = PluginActivationInputs & {
type BundledPluginCompatibleActivationInputs = PluginActivationInputs & {
compatPluginIds: string[];
};
export type BundledPluginCompatibleLoadValues = Pick<
type BundledPluginCompatibleLoadValues = Pick<
BundledPluginCompatibleActivationInputs,
"rawConfig" | "config" | "activationSourceConfig" | "autoEnabledReasons" | "compatPluginIds"
>;
+5 -5
View File
@@ -17,7 +17,7 @@ import { loadPluginManifestRegistryForPluginRegistry } from "./plugin-registry-c
import { createPluginIdScopeSet, normalizePluginIdScope } from "./plugin-scope.js";
/** Runtime surface that can request a lazily activated plugin owner. */
export type PluginActivationPlannerTrigger =
type PluginActivationPlannerTrigger =
| { kind: "command"; command: string }
| { kind: "provider"; provider: string }
| { kind: "agentHarness"; runtime: string }
@@ -25,7 +25,7 @@ export type PluginActivationPlannerTrigger =
| { kind: "route"; route: string }
| { kind: "capability"; capability: PluginManifestActivationCapability };
export type PluginActivationPlannerHintReason =
type PluginActivationPlannerHintReason =
| "activation-agent-harness-hint"
| "activation-capability-hint"
| "activation-channel-hint"
@@ -33,7 +33,7 @@ export type PluginActivationPlannerHintReason =
| "activation-provider-hint"
| "activation-route-hint";
export type PluginActivationPlannerManifestReason =
type PluginActivationPlannerManifestReason =
| "manifest-channel-owner"
| "manifest-command-alias"
| "manifest-hook-owner"
@@ -41,11 +41,11 @@ export type PluginActivationPlannerManifestReason =
| "manifest-setup-provider-owner"
| "manifest-tool-contract";
export type PluginActivationPlannerReason =
type PluginActivationPlannerReason =
| PluginActivationPlannerHintReason
| PluginActivationPlannerManifestReason;
export type PluginActivationPlanEntry = {
type PluginActivationPlanEntry = {
pluginId: string;
origin: PluginOrigin;
reasons: readonly PluginActivationPlannerReason[];
+1 -35
View File
@@ -4,7 +4,7 @@ import {
getLoadedRuntimePluginRegistry,
listLoadedRuntimePluginIdsAcrossSurfaces,
} from "./active-runtime-registry.js";
import { testing, clearPluginLoaderCache } from "./loader.js";
import { clearPluginLoaderCache } from "./loader.test-fixtures.js";
import { createEmptyPluginRegistry } from "./registry-empty.js";
import type { PluginRegistry } from "./registry-types.js";
import { resetPluginRuntimeStateForTest, setActivePluginRegistry } from "./runtime.js";
@@ -149,38 +149,4 @@ describe("getLoadedRuntimePluginRegistry", () => {
}),
).toBeUndefined();
});
it("validates full loader cache compatibility when load options are provided", () => {
const registry = createRegistryWithPlugin("demo");
const loadOptions = {
config: {
plugins: {
allow: ["demo"],
},
},
onlyPluginIds: ["demo"],
workspaceDir: "/tmp/ws",
};
const { cacheKey } = testing.resolvePluginLoadCacheContext(loadOptions);
setActivePluginRegistry(registry, cacheKey, "default", "/tmp/ws");
expect(
getLoadedRuntimePluginRegistry({
loadOptions,
}),
).toBe(registry);
expect(
getLoadedRuntimePluginRegistry({
loadOptions: {
...loadOptions,
config: {
plugins: {
allow: ["other"],
},
},
},
}),
).toBeUndefined();
});
});
@@ -205,8 +205,3 @@ export async function loadAgentToolResultMiddlewaresForRuntime(params: {
return listAgentToolResultMiddlewares(params.runtime);
}
}
export const testing = {
listMiddlewareOwnerPluginIds,
};
export { testing as __testing };
@@ -54,11 +54,6 @@ export function normalizeAgentToolResultMiddlewareRuntimes(
}
return normalized;
}
/** @deprecated Use normalizeAgentToolResultMiddlewareRuntimes. */
export const normalizeAgentToolResultMiddlewareHarnesses =
normalizeAgentToolResultMiddlewareRuntimes;
export function normalizeAgentToolResultMiddlewareRuntimeIds(
runtimes: readonly string[] | undefined,
): AgentToolResultMiddlewareRuntime[] {
+1 -1
View File
@@ -4,7 +4,7 @@ import { attachPluginApiFacades, type OpenClawPluginApiWithoutFacades } from "./
import type { PluginRuntime } from "./runtime/types.js";
import type { OpenClawPluginApi, PluginLogger } from "./types.js";
export type BuildPluginApiParams = {
type BuildPluginApiParams = {
id: string;
name: string;
version?: string;
+2 -2
View File
@@ -9,10 +9,10 @@ type FunctionPropertyNames<T> = Extract<
>;
/** Names of plugin API methods exposed on the OpenClaw plugin API. */
export type PluginApiMethodName = FunctionPropertyNames<OpenClawPluginApi>;
type PluginApiMethodName = FunctionPropertyNames<OpenClawPluginApi>;
/** Lifecycle policy for whether a plugin API method can be called after registration. */
export type PluginApiLifecyclePolicy = {
type PluginApiLifecyclePolicy = {
phase: "registration" | "runtime";
lateCallable: boolean;
};
+1 -1
View File
@@ -24,7 +24,7 @@ import {
} from "./config-state.js";
import { loadPluginManifestRegistryForPluginRegistry } from "./plugin-registry-contributions.js";
export type ClaudeBundleCommandSpec = {
type ClaudeBundleCommandSpec = {
pluginId: string;
rawName: string;
description: string;
+1 -1
View File
@@ -12,7 +12,7 @@ type ReadBundleJsonResult =
| { ok: true; raw: Record<string, unknown> }
| { ok: false; error: string };
export type BundleServerRuntimeSupport = {
type BundleServerRuntimeSupport = {
hasSupportedServer: boolean;
supportedServerNames: string[];
unsupportedServerNames: string[];
+2 -2
View File
@@ -22,12 +22,12 @@ import type { PluginBundleFormat } from "./manifest-types.js";
export type BundleLspServerConfig = Record<string, unknown>;
/** Merged LSP config contributed by enabled plugin bundles. */
export type BundleLspConfig = {
type BundleLspConfig = {
lspServers: Record<string, BundleLspServerConfig>;
};
/** Runtime support summary for bundle-declared LSP servers. */
export type BundleLspRuntimeSupport = {
type BundleLspRuntimeSupport = {
hasStdioServer: boolean;
supportedServerNames: string[];
unsupportedServerNames: string[];
+5 -1
View File
@@ -9,13 +9,17 @@ import {
detectBundleManifestFormat,
loadBundleManifest,
} from "./bundle-manifest.js";
import type { BundlePluginManifest } from "./bundle-manifest.js";
import {
cleanupTrackedTempDirs,
makeTrackedTempDir,
mkdirSafeDir,
} from "./test-helpers/fs-fixtures.js";
type BundlePluginManifest = Extract<
ReturnType<typeof loadBundleManifest>,
{ ok: true }
>["manifest"];
type ReadonlyBundleManifestExpectation = Omit<
BundlePluginManifest,
"capabilities" | "hooks" | "settingsFiles" | "skills"
+2 -2
View File
@@ -24,7 +24,7 @@ export const CLAUDE_BUNDLE_MANIFEST_RELATIVE_PATH = ".claude-plugin/plugin.json"
export const CURSOR_BUNDLE_MANIFEST_RELATIVE_PATH = ".cursor-plugin/plugin.json";
/** Normalized bundle manifest shape consumed by plugin discovery. */
export type BundlePluginManifest = {
type BundlePluginManifest = {
id: string;
name?: string;
description?: string;
@@ -38,7 +38,7 @@ export type BundlePluginManifest = {
capabilities: string[];
};
export type BundleManifestLoadResult =
type BundleManifestLoadResult =
| { ok: true; manifest: BundlePluginManifest; manifestPath: string }
| { ok: false; error: string; manifestPath: string };
+2 -2
View File
@@ -32,11 +32,11 @@ export type BundleMcpDiagnostic = {
message: string;
};
export type EnabledBundleMcpConfigResult = {
type EnabledBundleMcpConfigResult = {
config: BundleMcpConfig;
diagnostics: BundleMcpDiagnostic[];
};
export type BundleMcpRuntimeSupport = {
type BundleMcpRuntimeSupport = {
hasSupportedStdioServer: boolean;
supportedServerNames: string[];
unsupportedServerNames: string[];
@@ -1,21 +1,10 @@
// Verifies bundled capability metadata emitted by plugins.
import fs from "node:fs";
import path from "node:path";
import { expectDefined } from "@openclaw/normalization-core";
import { describe, expect, it } from "vitest";
import { expectNoReaddirSyncDuring } from "../test-utils/fs-scan-assertions.js";
import { listGitTrackedFiles, toRepoRelativePath } from "../test-utils/repo-files.js";
import { normalizeBundledPluginStringList } from "./bundled-plugin-scan.js";
import {
BUNDLED_AUTO_ENABLE_PROVIDER_PLUGIN_IDS,
BUNDLED_LEGACY_PLUGIN_ID_ALIASES,
BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS,
buildBundledPluginContractSnapshot,
hasBundledPluginContractSnapshotCapabilities,
} from "./contracts/inventory/bundled-capability-metadata.js";
import { pluginTestRepoRoot as repoRoot } from "./generated-plugin-test-helpers.js";
import type { OpenClawPackageManifest } from "./manifest.js";
import type { PluginManifest } from "./manifest.js";
function listGitExtensionPackagePaths(extensionsDir: string): string[] | null {
const relativeDir = toRepoRelativePath(repoRoot, extensionsDir);
@@ -45,24 +34,6 @@ function listExtensionPackagePaths(extensionsDir: string): string[] {
.filter((packagePath) => fs.existsSync(packagePath));
}
function readManifestRecords(): PluginManifest[] {
const extensionsDir = path.join(repoRoot, "extensions");
return listExtensionPackagePaths(extensionsDir)
.filter((packagePath) => {
const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf-8")) as {
openclaw?: OpenClawPackageManifest;
};
return normalizeBundledPluginStringList(packageJson.openclaw?.extensions).length > 0;
})
.map(
(packagePath) =>
JSON.parse(
fs.readFileSync(path.join(path.dirname(packagePath), "openclaw.plugin.json"), "utf-8"),
) as PluginManifest,
)
.toSorted((left, right) => left.id.localeCompare(right.id));
}
describe("bundled capability metadata", () => {
it("lists bundled extension packages from git without scanning extension dirs", () => {
const extensionsDir = path.join(repoRoot, "extensions");
@@ -73,69 +44,4 @@ describe("bundled capability metadata", () => {
expect(packagePaths.every((file) => file.endsWith("package.json"))).toBe(true);
});
});
it("keeps contract snapshots aligned with bundled plugin manifests", () => {
const expected = readManifestRecords()
.map(buildBundledPluginContractSnapshot)
.filter(hasBundledPluginContractSnapshotCapabilities)
.toSorted((left, right) => left.pluginId.localeCompare(right.pluginId));
expect(BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS).toEqual(expected);
expect(
BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS.find((entry) => entry.pluginId === "migrate-hermes"),
).toEqual({
pluginId: "migrate-hermes",
cliBackendIds: [],
providerIds: [],
providerEnvVars: {},
workerProviderIds: [],
embeddingProviderIds: [],
speechProviderIds: [],
realtimeTranscriptionProviderIds: [],
realtimeVoiceProviderIds: [],
mediaUnderstandingProviderIds: [],
transcriptSourceProviderIds: [],
documentExtractorIds: [],
imageGenerationProviderIds: [],
videoGenerationProviderIds: [],
musicGenerationProviderIds: [],
webContentExtractorIds: [],
webFetchProviderIds: [],
webSearchProviderIds: [],
migrationProviderIds: ["hermes"],
toolNames: [],
});
});
it("keeps lightweight alias maps aligned with bundled plugin manifests", () => {
const manifests = readManifestRecords();
const expectedLegacyAliases = Object.fromEntries(
manifests
.flatMap((manifest) =>
(manifest.legacyPluginIds ?? []).map((legacyPluginId) => [legacyPluginId, manifest.id]),
)
.toSorted(([left], [right]) =>
expectDefined(left, "left test invariant").localeCompare(
expectDefined(right, "right test invariant"),
),
),
);
const expectedAutoEnableProviderPluginIds = Object.fromEntries(
manifests
.flatMap((manifest) =>
(manifest.autoEnableWhenConfiguredProviders ?? []).map((providerId) => [
providerId,
manifest.id,
]),
)
.toSorted(([left], [right]) =>
expectDefined(left, "left test invariant").localeCompare(
expectDefined(right, "right test invariant"),
),
),
);
expect(BUNDLED_LEGACY_PLUGIN_ID_ALIASES).toEqual(expectedLegacyAliases);
expect(BUNDLED_AUTO_ENABLE_PROVIDER_PLUGIN_IDS).toEqual(expectedAutoEnableProviderPluginIds);
});
});
@@ -1,22 +0,0 @@
// Verifies bundled capability runtime registration from plugin metadata.
import { describe, expect, it } from "vitest";
import { buildVitestCapabilityShimAliasMap } from "./bundled-capability-runtime.js";
describe("buildVitestCapabilityShimAliasMap", () => {
it("keeps scoped and unscoped capability shim aliases aligned", () => {
const aliasMap = buildVitestCapabilityShimAliasMap();
expect(aliasMap["openclaw/plugin-sdk/config-runtime"]).toBe(
aliasMap["@openclaw/plugin-sdk/config-runtime"],
);
expect(aliasMap["openclaw/plugin-sdk/media-runtime"]).toBe(
aliasMap["@openclaw/plugin-sdk/media-runtime"],
);
expect(aliasMap["openclaw/plugin-sdk/provider-onboard"]).toBe(
aliasMap["@openclaw/plugin-sdk/provider-onboard"],
);
expect(aliasMap["openclaw/plugin-sdk/speech-core"]).toBe(
aliasMap["@openclaw/plugin-sdk/speech-core"],
);
});
});
+1 -1
View File
@@ -53,7 +53,7 @@ const CAPABILITY_VITEST_SHIM_ALIASES = [
},
] as const;
export function buildVitestCapabilityShimAliasMap(): Record<string, string> {
function buildVitestCapabilityShimAliasMap(): Record<string, string> {
return Object.fromEntries(
CAPABILITY_VITEST_SHIM_ALIASES.flatMap(({ subpath, target }) => {
const targetPath = fileURLToPath(target);
@@ -6,7 +6,6 @@ import { afterEach, describe, expect, it } from "vitest";
import {
listBundledChannelPluginMetadata,
resolveBundledChannelGeneratedPath,
resolveBundledChannelWorkspacePath,
} from "./bundled-channel-runtime.js";
const tempRoots: string[] = [];
@@ -24,15 +23,6 @@ afterEach(() => {
});
describe("bundled channel runtime metadata", () => {
it("preserves explicit empty bundled roots", () => {
const tempRoot = createTempRoot();
expect(listBundledChannelPluginMetadata({ rootDir: tempRoot })).toStrictEqual([]);
expect(resolveBundledChannelWorkspacePath({ rootDir: tempRoot, pluginId: "telegram" })).toBe(
null,
);
});
it("preserves explicit missing bundled scan roots", () => {
const tempRoot = createTempRoot();
const missingScanDir = path.join(tempRoot, "missing-extensions");
-16
View File
@@ -120,19 +120,3 @@ export function resolveBundledChannelGeneratedPath(
): string | null {
return resolveBundledPluginGeneratedPath(rootDir, entry, pluginDirName, scanDir);
}
/** Resolves the source workspace path for a bundled channel plugin id. */
export function resolveBundledChannelWorkspacePath(params: {
rootDir: string;
scanDir?: string;
pluginId: string;
}): string | null {
return (
listBundledChannelPluginMetadata({
rootDir: params.rootDir,
...(params.scanDir ? { scanDir: params.scanDir } : {}),
includeChannelConfigs: false,
includeSyntheticChannelConfigs: false,
}).find((metadata) => metadata.manifest.id === params.pluginId)?.rootDir ?? null
);
}
+1 -15
View File
@@ -11,11 +11,10 @@ import { resolveUserPath } from "../utils.js";
const DISABLED_BUNDLED_PLUGINS_DIR = path.join(os.tmpdir(), "openclaw-empty-bundled-plugins");
const TEST_TRUST_BUNDLED_PLUGINS_DIR_ENV = "OPENCLAW_TEST_TRUST_BUNDLED_PLUGINS_DIR";
let bundledPluginsDirOverrideForTest: string | undefined;
const bundledPluginsDirCache = new Map<string, string | undefined>();
/** Diagnostic emitted when source-checkout bundled plugins lack dependency installs. */
export type SourceCheckoutDependencyDiagnostic = {
type SourceCheckoutDependencyDiagnostic = {
source: string;
message: string;
};
@@ -210,7 +209,6 @@ function createBundledPluginsDirCacheKey(env: NodeJS.ProcessEnv): string {
openClawHome: env.OPENCLAW_HOME ?? "",
home: env.HOME ?? "",
userProfile: env.USERPROFILE ?? "",
testOverride: bundledPluginsDirOverrideForTest ?? "",
});
}
@@ -219,10 +217,6 @@ function resolveBundledPluginsDirUncached(env: NodeJS.ProcessEnv): string | unde
return resolveDisabledBundledPluginsDir();
}
if (bundledPluginsDirOverrideForTest) {
return bundledPluginsDirOverrideForTest;
}
const override = env.OPENCLAW_BUNDLED_PLUGINS_DIR?.trim();
let rejectedExistingOverride: string | null = null;
if (override) {
@@ -309,11 +303,3 @@ export function resolveBundledPluginsDir(env: NodeJS.ProcessEnv = process.env):
bundledPluginsDirCache.set(cacheKey, resolved);
return resolved;
}
export function setBundledPluginsDirOverrideForTest(dir: string | undefined): void {
if (process.env.VITEST !== "true" && process.env.NODE_ENV !== "test") {
throw new Error("setBundledPluginsDirOverrideForTest is only available in tests");
}
bundledPluginsDirOverrideForTest = dir;
bundledPluginsDirCache.clear();
}
+4 -4
View File
@@ -3,23 +3,23 @@ import path from "node:path";
import { isPathInside } from "./path-safety.js";
/** Alias class for current packaged paths and legacy bundled extension paths. */
export type BundledPluginLoadPathAliasKind = "current" | "legacy";
type BundledPluginLoadPathAliasKind = "current" | "legacy";
/** Load path alias used while resolving bundled plugins across package layouts. */
export type BundledPluginLoadPathAlias = {
type BundledPluginLoadPathAlias = {
kind: BundledPluginLoadPathAliasKind;
path: string;
};
/** Parsed path metadata for a bundled plugin in a packaged dist root. */
export type PackagedBundledPluginPath = {
type PackagedBundledPluginPath = {
packageRoot: string;
bundledRoot: string;
bundledLeaf: string;
};
/** Parsed path metadata for a bundled plugin in the legacy extensions root. */
export type LegacyBundledPluginPath = {
type LegacyBundledPluginPath = {
packageRoot: string;
legacyRoot: string;
bundledLeaf: string;
+2 -1
View File
@@ -7,11 +7,12 @@ import { expectNoReaddirSyncDuring } from "../test-utils/fs-scan-assertions.js";
import { listGitTrackedFiles, toRepoRelativePath } from "../test-utils/repo-files.js";
import { collectBundledChannelConfigs } from "./bundled-channel-config-metadata.js";
import {
type BundledPluginMetadata,
listBundledPluginMetadata,
resolveBundledPluginGeneratedPath,
resolveBundledPluginRepoEntryPath,
} from "./bundled-plugin-metadata.js";
type BundledPluginMetadata = ReturnType<typeof listBundledPluginMetadata>[number];
import { resolveGatewayStartupPluginIdsFromRegistry } from "./gateway-startup-plugin-ids.js";
import {
createGeneratedPluginTempRoot,
+1 -1
View File
@@ -39,7 +39,7 @@ type BundledPluginPathPair = {
};
/** Metadata collected from a bundled plugin package and manifest. */
export type BundledPluginMetadata = {
type BundledPluginMetadata = {
dirName: string;
idHint: string;
source: BundledPluginPathPair;
@@ -8,7 +8,7 @@ import { resolveBundledPluginsDir } from "./bundled-dir.js";
const DOCTOR_CONTRACT_BASENAMES = ["doctor-contract-api", "contract-api"] as const;
const MODULE_EXTENSIONS = ["js", "cjs", "mjs", "ts", "cts", "mts"] as const;
export type BundledPluginStartupMetadata = {
type BundledPluginStartupMetadata = {
hasDoctorContract: boolean;
};
+1 -3
View File
@@ -13,9 +13,7 @@ export type BundledPluginSource = {
requiresConfig?: boolean;
};
export type BundledPluginLookup =
| { kind: "npmSpec"; value: string }
| { kind: "pluginId"; value: string };
type BundledPluginLookup = { kind: "npmSpec"; value: string } | { kind: "pluginId"; value: string };
export function findBundledPluginSourceInMap(params: {
bundled: ReadonlyMap<string, BundledPluginSource>;
+1 -7
View File
@@ -60,8 +60,7 @@ vi.mock("../infra/archive.js", async () => {
const { ClawHubRequestError } = await import("../infra/clawhub.js");
type ClawHubResolvedArtifact = import("../infra/clawhub.js").ClawHubResolvedArtifact;
type ClawHubRiskAcknowledgementRequest = import("./clawhub.js").ClawHubRiskAcknowledgementRequest;
const { CLAWHUB_INSTALL_ERROR_CODE, formatClawHubSpecifier, installPluginFromClawHub } =
await import("./clawhub.js");
const { CLAWHUB_INSTALL_ERROR_CODE, installPluginFromClawHub } = await import("./clawhub.js");
const DEMO_ARCHIVE_INTEGRITY = "sha256-qerEjGEpvES2+Tyan0j2xwDRkbcnmh4ZFfKN9vWbsa8=";
const DEMO_ARCHIVE_SHA256 = "a9eac48c6129bc44b6f93c9a9f48f6c700d191b7279a1e1915f28df6f59bb1af";
@@ -370,11 +369,6 @@ describe("installPluginFromClawHub", () => {
});
});
it("formats clawhub specifiers", () => {
expect(formatClawHubSpecifier({ name: "demo" })).toBe("clawhub:demo");
expect(formatClawHubSpecifier({ name: "demo", version: "1.2.3" })).toBe("clawhub:demo@1.2.3");
});
it("installs a ClawHub plugin through the archive installer", async () => {
const logger = createLoggerSpies();
const result = await installPluginFromClawHub({
+2 -2
View File
@@ -57,7 +57,7 @@ import {
} from "./install.js";
export { CLAWHUB_INSTALL_ERROR_CODE };
export type { ClawHubInstallErrorCode, ClawHubRiskAcknowledgementRequest };
export type { ClawHubRiskAcknowledgementRequest };
type PluginInstallLogger = {
info?: (message: string) => void;
@@ -331,7 +331,7 @@ function resolveTopLevelLegacyArchiveVerification(
return integrity ? { kind: "archive-integrity", integrity } : null;
}
export function formatClawHubSpecifier(params: { name: string; version?: string }): string {
function formatClawHubSpecifier(params: { name: string; version?: string }): string {
return `clawhub:${params.name}${params.version ? `@${params.version}` : ""}`;
}
+1 -1
View File
@@ -54,7 +54,7 @@ export type CliBackendThinkingLevel =
export type CliBackendExecutionMode = "agent" | "side-question";
/** Host-isolated tool grant for a CLI run with every native tool disabled. */
export type CliBackendToolAvailability = {
type CliBackendToolAvailability = {
native: readonly [];
/** MCP tools already isolated by the host transport that may be auto-approved. */
mcp: readonly string[];
+1 -1
View File
@@ -3,7 +3,7 @@ import { getActiveRuntimePluginRegistry } from "./active-runtime-registry.js";
import type { CliBackendPlugin } from "./cli-backend.types.js";
/** Runtime CLI backend registration with owning plugin id. */
export type PluginCliBackendEntry = CliBackendPlugin & {
type PluginCliBackendEntry = CliBackendPlugin & {
pluginId: string;
};
+1 -16
View File
@@ -1,10 +1,7 @@
/** Tests plugin CLI node Gateway runtime timeout and invocation behavior. */
import { MAX_TIMER_TIMEOUT_MS } from "@openclaw/normalization-core/number-coercion";
import { beforeEach, describe, expect, it, vi } from "vitest";
import {
createPluginCliGatewayNodesRuntime,
resolvePluginCliNodeInvokeGatewayTimeoutMs,
} from "./cli-gateway-nodes-runtime.js";
import { createPluginCliGatewayNodesRuntime } from "./cli-gateway-nodes-runtime.js";
import { withPluginRuntimePluginScope } from "./runtime/gateway-request-scope.js";
const callGatewayMock = vi.fn();
@@ -76,15 +73,3 @@ describe("createPluginCliGatewayNodesRuntime", () => {
);
});
});
describe("resolvePluginCliNodeInvokeGatewayTimeoutMs", () => {
it("preserves absent and non-positive timeout behavior", () => {
expect(resolvePluginCliNodeInvokeGatewayTimeoutMs(undefined)).toBeUndefined();
expect(resolvePluginCliNodeInvokeGatewayTimeoutMs(0)).toBeUndefined();
expect(resolvePluginCliNodeInvokeGatewayTimeoutMs(-1)).toBeUndefined();
});
it("adds gateway grace for normal positive timeouts", () => {
expect(resolvePluginCliNodeInvokeGatewayTimeoutMs(10_000)).toBe(15_000);
});
});
+1 -1
View File
@@ -11,7 +11,7 @@ import { getPluginRuntimeGatewayRequestScope } from "./runtime/gateway-request-s
import type { PluginRuntime } from "./runtime/types.js";
/** Adds Gateway timer grace for plugin CLI node invoke calls. */
export function resolvePluginCliNodeInvokeGatewayTimeoutMs(
function resolvePluginCliNodeInvokeGatewayTimeoutMs(
timeoutMs: number | undefined,
): number | undefined {
return typeof timeoutMs === "number" && Number.isFinite(timeoutMs) && timeoutMs > 0
@@ -3,7 +3,7 @@ import path from "node:path";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { createBundledBrowserPluginFixture } from "../../test/helpers/browser-bundled-plugin-fixture.js";
import type { OpenClawConfig } from "../config/config.js";
import { clearPluginLoaderCache, loadOpenClawPlugins } from "./loader.js";
import { clearPluginLoaderCache, loadOpenClawPlugins } from "./loader.test-fixtures.js";
import { resetPluginRuntimeStateForTest } from "./runtime.js";
function resetPluginState() {
+1 -3
View File
@@ -12,7 +12,6 @@ import {
clearPluginCommandsForPlugin,
isPluginCommandRegistryLocked,
pluginCommands,
type RegisteredPluginCommand,
} from "./command-registry-state.js";
import {
AGENT_PROMPT_SURFACE_KINDS,
@@ -79,7 +78,7 @@ function getAgentPromptSurfaces(): Set<string> {
}
/** Result returned when a plugin command registration succeeds or fails validation. */
export type CommandRegistrationResult = {
type CommandRegistrationResult = {
ok: boolean;
error?: string;
};
@@ -388,4 +387,3 @@ export function registerPluginCommand(
}
export { clearPluginCommands, clearPluginCommandsForPlugin };
export type { RegisteredPluginCommand };
+1 -1
View File
@@ -15,7 +15,7 @@ type PluginCommandSpecOptions = {
config?: OpenClawConfig;
};
export type PluginCommandEntrySpec = {
type PluginCommandEntrySpec = {
name: string;
description: string;
acceptsArgs: boolean;
+1 -1
View File
@@ -16,7 +16,7 @@ import {
import { createPluginRegistry } from "./registry.js";
import { setActivePluginRegistry } from "./runtime.js";
import type { PluginRuntime } from "./runtime/types.js";
import { createBundledPluginRecord } from "./status.test-helpers.js";
import { createBundledPluginRecord } from "./status.test-fixtures.js";
const completionMocks = vi.hoisted(() => ({
prepareSimpleCompletionModelForAgent: vi.fn(),

Some files were not shown because too many files have changed in this diff Show More