mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 11:10:45 +00:00
fix(plugins): hydrate bundled channel config metadata
Hydrate bundled channel schema metadata through opt-in registry schema paths while keeping ordinary manifest registry loads lightweight.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { collectBundledChannelConfigs as collectBundledChannelConfigsImpl } from "../plugins/bundled-channel-config-metadata.js";
|
||||
import { loadPluginManifestRegistry as loadPluginManifestRegistryImpl } from "../plugins/manifest-registry.js";
|
||||
import {
|
||||
collectChannelSchemaMetadata as collectChannelSchemaMetadataImpl,
|
||||
@@ -6,6 +7,7 @@ import {
|
||||
import { buildConfigSchema as buildConfigSchemaImpl } from "./schema.js";
|
||||
|
||||
export const loadPluginManifestRegistry = loadPluginManifestRegistryImpl;
|
||||
export const collectBundledChannelConfigs = collectBundledChannelConfigsImpl;
|
||||
export const collectChannelSchemaMetadata = collectChannelSchemaMetadataImpl;
|
||||
export const collectPluginSchemaMetadata = collectPluginSchemaMetadataImpl;
|
||||
export const buildConfigSchema = buildConfigSchemaImpl;
|
||||
|
||||
@@ -368,6 +368,7 @@ async function loadBundledConfigSchemaResponse(): Promise<ConfigSchemaResponse>
|
||||
cache: false,
|
||||
env,
|
||||
config: {},
|
||||
bundledChannelConfigCollector: runtime.collectBundledChannelConfigs,
|
||||
});
|
||||
logConfigDocBaselineDebug(`loaded ${manifestRegistry.plugins.length} bundled plugin manifests`);
|
||||
const bundledRegistry = {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent-scope.js";
|
||||
import { collectBundledChannelConfigs } from "../plugins/bundled-channel-config-metadata.js";
|
||||
import { loadPluginManifestRegistryForPluginRegistry } from "../plugins/plugin-registry.js";
|
||||
import {
|
||||
collectChannelSchemaMetadata,
|
||||
@@ -16,6 +17,7 @@ function loadManifestRegistry(config: OpenClawConfig, env?: NodeJS.ProcessEnv) {
|
||||
env,
|
||||
workspaceDir,
|
||||
includeDisabled: true,
|
||||
bundledChannelConfigCollector: collectBundledChannelConfigs,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { PluginCandidate } from "./discovery.js";
|
||||
import type { InstalledPluginIndex, InstalledPluginIndexRecord } from "./installed-plugin-index.js";
|
||||
import { extractPluginInstallRecordsFromInstalledPluginIndex } from "./installed-plugin-index.js";
|
||||
import { loadPluginManifestRegistry, type PluginManifestRegistry } from "./manifest-registry.js";
|
||||
import type { BundledChannelConfigCollector } from "./manifest-registry.js";
|
||||
import {
|
||||
DEFAULT_PLUGIN_ENTRY_CANDIDATES,
|
||||
getPackageManifestMetadata,
|
||||
@@ -88,6 +89,7 @@ export function loadPluginManifestRegistryForInstalledIndex(params: {
|
||||
env?: NodeJS.ProcessEnv;
|
||||
pluginIds?: readonly string[];
|
||||
includeDisabled?: boolean;
|
||||
bundledChannelConfigCollector?: BundledChannelConfigCollector;
|
||||
}): PluginManifestRegistry {
|
||||
if (params.pluginIds && params.pluginIds.length === 0) {
|
||||
return { plugins: [], diagnostics: [] };
|
||||
@@ -111,5 +113,8 @@ export function loadPluginManifestRegistryForInstalledIndex(params: {
|
||||
candidates,
|
||||
diagnostics: [...diagnostics],
|
||||
installRecords: extractPluginInstallRecordsFromInstalledPluginIndex(params.index),
|
||||
...(params.bundledChannelConfigCollector
|
||||
? { bundledChannelConfigCollector: params.bundledChannelConfigCollector }
|
||||
: {}),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { collectChannelSchemaMetadata } from "../config/channel-config-metadata.js";
|
||||
import { collectBundledChannelConfigs } from "./bundled-channel-config-metadata.js";
|
||||
import type { PluginCandidate } from "./discovery.js";
|
||||
import {
|
||||
clearPluginManifestRegistryCache,
|
||||
@@ -630,6 +632,107 @@ describe("loadPluginManifestRegistry", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("hydrates bundled channel config metadata from plugin-local config surfaces", () => {
|
||||
const dir = makeTempDir();
|
||||
writeManifest(dir, {
|
||||
id: "alpha",
|
||||
channels: ["alpha"],
|
||||
configSchema: { type: "object" },
|
||||
channelConfigs: {
|
||||
alpha: {
|
||||
schema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
manifestOnly: { type: "boolean" },
|
||||
},
|
||||
},
|
||||
uiHints: {
|
||||
manifestOnly: { help: "manifest hint" },
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
writeTextFile(dir, "index.ts", "export {};\n");
|
||||
writeTextFile(
|
||||
dir,
|
||||
"src/config-schema.js",
|
||||
[
|
||||
"export const AlphaChannelConfigSchema = {",
|
||||
" schema: {",
|
||||
" type: 'object',",
|
||||
" properties: {",
|
||||
" generatedOnly: { type: 'string' },",
|
||||
" },",
|
||||
" additionalProperties: false,",
|
||||
" },",
|
||||
" uiHints: {",
|
||||
" generatedOnly: { label: 'Generated only' },",
|
||||
" },",
|
||||
"};",
|
||||
].join("\n"),
|
||||
);
|
||||
|
||||
const candidate = createPluginCandidate({
|
||||
idHint: "alpha",
|
||||
rootDir: dir,
|
||||
origin: "bundled",
|
||||
packageDir: dir,
|
||||
packageManifest: {
|
||||
channel: {
|
||||
id: "alpha",
|
||||
label: "Alpha",
|
||||
blurb: "Alpha channel",
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(loadRegistry([candidate]).plugins[0]?.channelConfigs?.alpha?.schema).toEqual({
|
||||
type: "object",
|
||||
properties: {
|
||||
manifestOnly: { type: "boolean" },
|
||||
},
|
||||
});
|
||||
|
||||
const registry = loadPluginManifestRegistry({
|
||||
cache: false,
|
||||
bundledChannelConfigCollector: collectBundledChannelConfigs,
|
||||
candidates: [candidate],
|
||||
});
|
||||
|
||||
expect(registry.plugins[0]?.channelConfigs?.alpha).toEqual({
|
||||
schema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
generatedOnly: { type: "string" },
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
label: "Alpha",
|
||||
description: "Alpha channel",
|
||||
uiHints: {
|
||||
generatedOnly: { label: "Generated only" },
|
||||
manifestOnly: { help: "manifest hint" },
|
||||
},
|
||||
});
|
||||
expect(collectChannelSchemaMetadata(registry)).toEqual([
|
||||
{
|
||||
id: "alpha",
|
||||
label: "Alpha",
|
||||
description: "Alpha channel",
|
||||
configSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
generatedOnly: { type: "string" },
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
configUiHints: {
|
||||
generatedOnly: { label: "Generated only" },
|
||||
manifestOnly: { help: "manifest hint" },
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("reports non-bundled providerAuthEnvVars as deprecated compat metadata", () => {
|
||||
const dir = makeTempDir();
|
||||
writeManifest(dir, {
|
||||
|
||||
@@ -158,6 +158,12 @@ export type PluginManifestRegistry = {
|
||||
diagnostics: PluginDiagnostic[];
|
||||
};
|
||||
|
||||
export type BundledChannelConfigCollector = (params: {
|
||||
pluginDir: string;
|
||||
manifest: PluginManifest;
|
||||
packageManifest?: OpenClawPackageManifest;
|
||||
}) => Record<string, PluginManifestChannelConfig> | undefined;
|
||||
|
||||
const registryCache = pluginManifestRegistryCache as Map<
|
||||
string,
|
||||
{ expiresAt: number; registry: PluginManifestRegistry }
|
||||
@@ -293,9 +299,18 @@ function buildRecord(params: {
|
||||
manifestPath: string;
|
||||
schemaCacheKey?: string;
|
||||
configSchema?: Record<string, unknown>;
|
||||
bundledChannelConfigCollector?: BundledChannelConfigCollector;
|
||||
}): PluginManifestRecord {
|
||||
const manifestChannelConfigs =
|
||||
params.candidate.origin === "bundled" && params.bundledChannelConfigCollector
|
||||
? params.bundledChannelConfigCollector({
|
||||
pluginDir: params.candidate.packageDir ?? params.candidate.rootDir,
|
||||
manifest: params.manifest,
|
||||
packageManifest: params.candidate.packageManifest,
|
||||
})
|
||||
: params.manifest.channelConfigs;
|
||||
const channelConfigs = mergePackageChannelMetaIntoChannelConfigs({
|
||||
channelConfigs: params.manifest.channelConfigs,
|
||||
channelConfigs: manifestChannelConfigs,
|
||||
packageChannel: params.candidate.packageManifest?.channel,
|
||||
});
|
||||
const packageChannelCommands = normalizePackageChannelCommands(
|
||||
@@ -542,6 +557,7 @@ export function loadPluginManifestRegistry(
|
||||
candidates?: PluginCandidate[];
|
||||
diagnostics?: PluginDiagnostic[];
|
||||
installRecords?: Record<string, PluginInstallRecord>;
|
||||
bundledChannelConfigCollector?: BundledChannelConfigCollector;
|
||||
} = {},
|
||||
): PluginManifestRegistry {
|
||||
const config = params.config ?? {};
|
||||
@@ -549,7 +565,10 @@ export function loadPluginManifestRegistry(
|
||||
const env = params.env ?? process.env;
|
||||
const cacheKey = buildCacheKey({ workspaceDir: params.workspaceDir, plugins: normalized, env });
|
||||
const cacheEnabled =
|
||||
params.cache !== false && !params.installRecords && shouldUseManifestCache(env);
|
||||
params.cache !== false &&
|
||||
!params.installRecords &&
|
||||
!params.bundledChannelConfigCollector &&
|
||||
shouldUseManifestCache(env);
|
||||
if (cacheEnabled) {
|
||||
const cached = registryCache.get(cacheKey);
|
||||
if (cached && cached.expiresAt > Date.now()) {
|
||||
@@ -659,6 +678,9 @@ export function loadPluginManifestRegistry(
|
||||
manifestPath: manifestRes.manifestPath,
|
||||
schemaCacheKey,
|
||||
configSchema,
|
||||
...(params.bundledChannelConfigCollector
|
||||
? { bundledChannelConfigCollector: params.bundledChannelConfigCollector }
|
||||
: {}),
|
||||
});
|
||||
|
||||
const existing = seenIds.get(manifest.id);
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
import { isInstalledPluginEnabled } from "./installed-plugin-index.js";
|
||||
import { loadPluginManifestRegistryForInstalledIndex } from "./manifest-registry-installed.js";
|
||||
import type {
|
||||
BundledChannelConfigCollector,
|
||||
PluginManifestContractListKey,
|
||||
PluginManifestRecord,
|
||||
PluginManifestRegistry,
|
||||
@@ -25,6 +26,7 @@ export type PluginRegistryContributionOptions = LoadPluginRegistryParams & {
|
||||
export type LoadPluginRegistryManifestParams = LoadPluginRegistryParams & {
|
||||
includeDisabled?: boolean;
|
||||
pluginIds?: readonly string[];
|
||||
bundledChannelConfigCollector?: BundledChannelConfigCollector;
|
||||
};
|
||||
|
||||
export type PluginRegistryContributionKey =
|
||||
@@ -201,6 +203,9 @@ export function loadPluginManifestRegistryForPluginRegistry(
|
||||
env: params.env,
|
||||
pluginIds: params.pluginIds,
|
||||
includeDisabled: params.includeDisabled,
|
||||
...(params.bundledChannelConfigCollector
|
||||
? { bundledChannelConfigCollector: params.bundledChannelConfigCollector }
|
||||
: {}),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user