11import fs from "node:fs" ;
22import path from "node:path" ;
33import { afterAll , afterEach , describe , expect , it , vi } from "vitest" ;
4+ import { setCurrentPluginMetadataSnapshot } from "../plugins/current-plugin-metadata-snapshot.js" ;
5+ import { resolveInstalledPluginIndexPolicyHash } from "../plugins/installed-plugin-index-policy.js" ;
6+ import type { PluginManifestRegistry } from "../plugins/manifest-registry.js" ;
7+ import type { PluginMetadataSnapshot } from "../plugins/plugin-metadata-snapshot.js" ;
48import {
59 applyPluginAutoEnable ,
610 detectPluginAutoEnableCandidates ,
@@ -58,6 +62,53 @@ vi.mock("../plugins/setup-registry.js", () => ({
5862
5963const env = makeIsolatedEnv ( ) ;
6064
65+ function createPluginMetadataSnapshot ( params : {
66+ config ?: OpenClawConfig ;
67+ manifestRegistry : PluginManifestRegistry ;
68+ workspaceDir ?: string ;
69+ } ) : PluginMetadataSnapshot {
70+ const policyHash = resolveInstalledPluginIndexPolicyHash ( params . config ) ;
71+ return {
72+ policyHash,
73+ ...( params . workspaceDir ? { workspaceDir : params . workspaceDir } : { } ) ,
74+ index : {
75+ version : 1 ,
76+ hostContractVersion : "test" ,
77+ compatRegistryVersion : "test" ,
78+ migrationVersion : 1 ,
79+ policyHash,
80+ generatedAtMs : 1 ,
81+ installRecords : { } ,
82+ plugins : [ ] ,
83+ diagnostics : [ ] ,
84+ } ,
85+ registryDiagnostics : [ ] ,
86+ manifestRegistry : params . manifestRegistry ,
87+ plugins : params . manifestRegistry . plugins ,
88+ diagnostics : params . manifestRegistry . diagnostics ,
89+ byPluginId : new Map ( params . manifestRegistry . plugins . map ( ( plugin ) => [ plugin . id , plugin ] ) ) ,
90+ normalizePluginId : ( pluginId ) => pluginId ,
91+ owners : {
92+ channels : new Map ( ) ,
93+ channelConfigs : new Map ( ) ,
94+ providers : new Map ( ) ,
95+ modelCatalogProviders : new Map ( ) ,
96+ cliBackends : new Map ( ) ,
97+ setupProviders : new Map ( ) ,
98+ commandAliases : new Map ( ) ,
99+ contracts : new Map ( ) ,
100+ } ,
101+ metrics : {
102+ registrySnapshotMs : 0 ,
103+ manifestRegistryMs : 0 ,
104+ ownerMapsMs : 0 ,
105+ totalMs : 0 ,
106+ indexPluginCount : 0 ,
107+ manifestPluginCount : params . manifestRegistry . plugins . length ,
108+ } ,
109+ } ;
110+ }
111+
61112afterAll ( ( ) => {
62113 resetPluginAutoEnableTestState ( ) ;
63114} ) ;
@@ -84,6 +135,39 @@ describe("applyPluginAutoEnable core", () => {
84135 ] ) ;
85136 } ) ;
86137
138+ it ( "reuses policy-compatible current manifest registry when runtime config differs" , ( ) => {
139+ const manifestRegistry = makeRegistry ( [ { id : "custom-chat" , channels : [ "custom-chat" ] } ] ) ;
140+ const snapshotConfig : OpenClawConfig = { plugins : { allow : [ "existing" ] } } ;
141+ setCurrentPluginMetadataSnapshot (
142+ createPluginMetadataSnapshot ( {
143+ config : snapshotConfig ,
144+ manifestRegistry,
145+ workspaceDir : "/tmp/workspace" ,
146+ } ) ,
147+ {
148+ config : snapshotConfig ,
149+ workspaceDir : "/tmp/workspace" ,
150+ } ,
151+ ) ;
152+
153+ const result = applyPluginAutoEnable ( {
154+ config : {
155+ plugins : {
156+ allow : [ "existing" ] ,
157+ entries : {
158+ "custom-chat" : { config : { token : "x" } } ,
159+ } ,
160+ } ,
161+ } ,
162+ env,
163+ } ) ;
164+
165+ expect ( result . config . plugins ?. allow ) . toContain ( "custom-chat" ) ;
166+ expect ( result . changes ) . toContain (
167+ "custom-chat plugin config present, added to plugin allowlist." ,
168+ ) ;
169+ } ) ;
170+
87171 it ( "formats typed provider-auth candidates into stable reasons" , ( ) => {
88172 expect (
89173 resolvePluginAutoEnableCandidateReason ( {
0 commit comments