refactor: unify plugin metadata cache paths

This commit is contained in:
Peter Steinberger
2026-05-02 02:35:14 +01:00
parent 7d89d4997e
commit 82fef597bc
10 changed files with 250 additions and 152 deletions

View File

@@ -1,11 +1,85 @@
import {
listBundledPluginMetadata,
resolveBundledPluginGeneratedPath,
resolveBundledPluginWorkspaceSourcePath,
type BundledPluginMetadata,
} from "./bundled-plugin-metadata.js";
import fs from "node:fs";
import path from "node:path";
import { resolveBundledPluginGeneratedPath } from "./bundled-plugin-metadata.js";
import type { PluginManifestRecord } from "./manifest-registry.js";
import type { OpenClawPackageManifest } from "./manifest.js";
import { loadPluginManifestRegistryForPluginRegistry } from "./plugin-registry.js";
export type BundledChannelPluginMetadata = BundledPluginMetadata;
type BundledChannelEntryPathPair = {
source: string;
built: string;
};
export type BundledChannelPluginMetadata = {
dirName: string;
source: BundledChannelEntryPathPair;
setupSource?: BundledChannelEntryPathPair;
manifest: {
id: string;
channels?: readonly string[];
};
packageManifest?: OpenClawPackageManifest;
rootDir: string;
};
function resolveBundledMetadataEnv(params?: {
rootDir?: string;
scanDir?: string;
}): NodeJS.ProcessEnv | undefined {
const overrideDir = params?.scanDir
? path.resolve(params.scanDir)
: params?.rootDir
? resolveBundledPluginsDirForRoot(params.rootDir)
: undefined;
if (!overrideDir) {
return undefined;
}
return {
...process.env,
OPENCLAW_BUNDLED_PLUGINS_DIR: overrideDir,
OPENCLAW_TEST_TRUST_BUNDLED_PLUGINS_DIR: "1",
};
}
function resolveBundledPluginsDirForRoot(rootDir: string): string | undefined {
const candidates = [
path.join(rootDir, "extensions"),
path.join(rootDir, "dist-runtime", "extensions"),
path.join(rootDir, "dist", "extensions"),
];
return candidates.find((candidate) => fs.existsSync(candidate));
}
function toBundledChannelEntryPair(source: string | undefined): BundledChannelEntryPathPair | null {
if (!source) {
return null;
}
return { source, built: source };
}
function toBundledChannelPluginMetadata(
record: PluginManifestRecord,
): BundledChannelPluginMetadata | null {
if (record.origin !== "bundled") {
return null;
}
const source = toBundledChannelEntryPair(record.source);
if (!source) {
return null;
}
const setupSource = toBundledChannelEntryPair(record.setupSource);
return {
dirName: path.basename(record.rootDir),
source,
...(setupSource ? { setupSource } : {}),
manifest: {
id: record.id,
channels: record.channels,
},
...(record.packageManifest ? { packageManifest: record.packageManifest } : {}),
rootDir: record.rootDir,
};
}
export function listBundledChannelPluginMetadata(params?: {
rootDir?: string;
@@ -13,12 +87,15 @@ export function listBundledChannelPluginMetadata(params?: {
includeChannelConfigs?: boolean;
includeSyntheticChannelConfigs?: boolean;
}): readonly BundledChannelPluginMetadata[] {
return listBundledPluginMetadata(params);
return loadPluginManifestRegistryForPluginRegistry({
env: resolveBundledMetadataEnv(params),
includeDisabled: true,
}).plugins.flatMap((record) => toBundledChannelPluginMetadata(record) ?? []);
}
export function resolveBundledChannelGeneratedPath(
rootDir: string,
entry: BundledPluginMetadata["source"] | BundledPluginMetadata["setupSource"],
entry: BundledChannelPluginMetadata["source"] | BundledChannelPluginMetadata["setupSource"],
pluginDirName?: string,
scanDir?: string,
): string | null {
@@ -30,5 +107,12 @@ export function resolveBundledChannelWorkspacePath(params: {
scanDir?: string;
pluginId: string;
}): string | null {
return resolveBundledPluginWorkspaceSourcePath(params);
return (
listBundledChannelPluginMetadata({
rootDir: params.rootDir,
...(params.scanDir ? { scanDir: params.scanDir } : {}),
includeChannelConfigs: false,
includeSyntheticChannelConfigs: false,
}).find((metadata) => metadata.manifest.id === params.pluginId)?.rootDir ?? null
);
}

View File

@@ -29,7 +29,6 @@ const CURRENT_MODULE_PATH = fileURLToPath(import.meta.url);
const RUNNING_FROM_BUILT_ARTIFACT =
CURRENT_MODULE_PATH.includes(`${path.sep}dist${path.sep}`) ||
CURRENT_MODULE_PATH.includes(`${path.sep}dist-runtime${path.sep}`);
const DEFAULT_ROOT_METADATA_CACHE = new Map<string, readonly BundledPluginMetadata[]>();
type BundledPluginPathPair = {
source: string;
@@ -186,18 +185,6 @@ export function listBundledPluginMetadata(params?: {
const includeChannelConfigs = params?.includeChannelConfigs ?? !RUNNING_FROM_BUILT_ARTIFACT;
const includeSyntheticChannelConfigs =
params?.includeSyntheticChannelConfigs ?? includeChannelConfigs;
const cacheKey =
!params?.rootDir && !scanDir
? JSON.stringify({
resolvedScanDir,
includeChannelConfigs,
includeSyntheticChannelConfigs,
})
: undefined;
const cached = cacheKey ? DEFAULT_ROOT_METADATA_CACHE.get(cacheKey) : undefined;
if (cached) {
return cached;
}
const metadata = Object.freeze(
collectBundledPluginMetadata(
resolvedScanDir,
@@ -205,9 +192,6 @@ export function listBundledPluginMetadata(params?: {
includeSyntheticChannelConfigs,
),
);
if (cacheKey) {
DEFAULT_ROOT_METADATA_CACHE.set(cacheKey, metadata);
}
return metadata;
}

View File

@@ -4,15 +4,20 @@ import type { PluginManifestRegistry } from "./manifest-registry.js";
const mocks = vi.hoisted(() => {
const loadManifestRegistry = vi.fn();
return {
findBundledPluginMetadataById: vi.fn(),
discoverOpenClawPlugins: vi.fn(() => ({ candidates: [], diagnostics: [] })),
loadBundledManifestRegistry: vi.fn(),
loadPluginManifestRegistryForInstalledIndex: loadManifestRegistry,
loadPluginManifestRegistryForPluginRegistry: loadManifestRegistry,
loadPluginRegistrySnapshot: vi.fn(() => ({ plugins: [] })),
};
});
vi.mock("./bundled-plugin-metadata.js", () => ({
findBundledPluginMetadataById: mocks.findBundledPluginMetadataById,
vi.mock("./discovery.js", () => ({
discoverOpenClawPlugins: mocks.discoverOpenClawPlugins,
}));
vi.mock("./manifest-registry.js", () => ({
loadPluginManifestRegistry: mocks.loadBundledManifestRegistry,
}));
vi.mock("./manifest-registry-installed.js", () => ({
@@ -77,14 +82,17 @@ function createPluginRecord(
describe("resolvePluginConfigContractsById", () => {
beforeEach(() => {
mocks.findBundledPluginMetadataById.mockReset();
mocks.discoverOpenClawPlugins.mockReset();
mocks.discoverOpenClawPlugins.mockReturnValue({ candidates: [], diagnostics: [] });
mocks.loadBundledManifestRegistry.mockReset();
mocks.loadBundledManifestRegistry.mockReturnValue(createRegistry([]));
mocks.loadPluginManifestRegistryForInstalledIndex.mockReset();
mocks.loadPluginManifestRegistryForInstalledIndex.mockReturnValue(createRegistry([]));
mocks.loadPluginRegistrySnapshot.mockReset();
mocks.loadPluginRegistrySnapshot.mockReturnValue({ plugins: [] });
});
it("does not fall back to bundled metadata when registry already resolved a plugin without config contracts", () => {
it("does not fall back to bundled registry when registry already resolved a plugin without config contracts", () => {
mocks.loadPluginManifestRegistryForInstalledIndex.mockReturnValue(
createRegistry([
createPluginRecord({
@@ -99,10 +107,10 @@ describe("resolvePluginConfigContractsById", () => {
pluginIds: ["brave"],
}),
).toEqual(new Map());
expect(mocks.findBundledPluginMetadataById).not.toHaveBeenCalled();
expect(mocks.loadBundledManifestRegistry).not.toHaveBeenCalled();
});
it("can hydrate missing contracts from bundled metadata for resolved bundled plugins", () => {
it("can hydrate missing contracts from bundled registry for resolved bundled plugins", () => {
mocks.loadPluginManifestRegistryForInstalledIndex.mockReturnValue(
createRegistry([
createPluginRecord({
@@ -114,15 +122,19 @@ describe("resolvePluginConfigContractsById", () => {
}),
]),
);
mocks.findBundledPluginMetadataById.mockReturnValue({
manifest: {
configContracts: {
secretInputs: {
paths: [{ path: "twilio.authToken", expected: "string" }],
mocks.loadBundledManifestRegistry.mockReturnValue(
createRegistry([
createPluginRecord({
id: "voice-call",
origin: "bundled",
configContracts: {
secretInputs: {
paths: [{ path: "twilio.authToken", expected: "string" }],
},
},
},
},
});
}),
]),
);
expect(
resolvePluginConfigContractsById({
@@ -147,7 +159,7 @@ describe("resolvePluginConfigContractsById", () => {
);
});
it("refreshes stale bundled SecretInput contracts from bundled metadata", () => {
it("refreshes stale bundled SecretInput contracts from bundled registry", () => {
mocks.loadPluginManifestRegistryForInstalledIndex.mockReturnValue(
createRegistry([
createPluginRecord({
@@ -162,18 +174,22 @@ describe("resolvePluginConfigContractsById", () => {
}),
]),
);
mocks.findBundledPluginMetadataById.mockReturnValue({
manifest: {
configContracts: {
secretInputs: {
paths: [
{ path: "twilio.authToken", expected: "string" },
{ path: "realtime.providers.*.apiKey", expected: "string" },
],
mocks.loadBundledManifestRegistry.mockReturnValue(
createRegistry([
createPluginRecord({
id: "voice-call",
origin: "bundled",
configContracts: {
secretInputs: {
paths: [
{ path: "twilio.authToken", expected: "string" },
{ path: "realtime.providers.*.apiKey", expected: "string" },
],
},
},
},
},
});
}),
]),
);
expect(
resolvePluginConfigContractsById({
@@ -210,15 +226,19 @@ describe("resolvePluginConfigContractsById", () => {
}),
]),
);
mocks.findBundledPluginMetadataById.mockReturnValue({
manifest: {
configContracts: {
secretInputs: {
paths: [{ path: "tts.providers.*.apiKey", expected: "string" }],
mocks.loadBundledManifestRegistry.mockReturnValue(
createRegistry([
createPluginRecord({
id: "voice-call",
origin: "bundled",
configContracts: {
secretInputs: {
paths: [{ path: "tts.providers.*.apiKey", expected: "string" }],
},
},
},
},
});
}),
]),
);
expect(
resolvePluginConfigContractsById({
@@ -249,6 +269,6 @@ describe("resolvePluginConfigContractsById", () => {
fallbackToBundledMetadata: false,
}),
).toEqual(new Map());
expect(mocks.findBundledPluginMetadataById).not.toHaveBeenCalled();
expect(mocks.loadBundledManifestRegistry).not.toHaveBeenCalled();
});
});

View File

@@ -1,6 +1,7 @@
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { isRecord } from "../utils.js";
import { findBundledPluginMetadataById } from "./bundled-plugin-metadata.js";
import { discoverOpenClawPlugins } from "./discovery.js";
import { loadPluginManifestRegistry } from "./manifest-registry.js";
import type { PluginManifestConfigContracts } from "./manifest.js";
import type { PluginOrigin } from "./plugin-origin.types.js";
import { loadPluginManifestRegistryForPluginRegistry } from "./plugin-registry.js";
@@ -116,6 +117,32 @@ export function resolvePluginConfigContractsById(params: {
const fallbackBundledPluginIds = new Set(
(params.fallbackBundledPluginIds ?? []).map((pluginId) => pluginId.trim()).filter(Boolean),
);
const bundledContractFallbacks = new Map<string, PluginManifestConfigContracts | undefined>();
const findBundledConfigContracts = (
pluginId: string,
): PluginManifestConfigContracts | undefined => {
if (bundledContractFallbacks.has(pluginId)) {
return bundledContractFallbacks.get(pluginId);
}
const discovery = discoverOpenClawPlugins({
workspaceDir: params.workspaceDir,
env: params.env,
});
const registry = loadPluginManifestRegistry({
config: params.config,
workspaceDir: params.workspaceDir,
env: params.env,
candidates: discovery.candidates.filter((candidate) => candidate.origin === "bundled"),
diagnostics: discovery.diagnostics,
});
for (const plugin of registry.plugins) {
bundledContractFallbacks.set(plugin.id, plugin.configContracts);
}
if (!bundledContractFallbacks.has(pluginId)) {
bundledContractFallbacks.set(pluginId, undefined);
}
return bundledContractFallbacks.get(pluginId);
};
const resolvedPluginOrigins = new Map<string, PluginOrigin>();
const registry = loadPluginManifestRegistryForPluginRegistry({
@@ -146,18 +173,15 @@ export function resolvePluginConfigContractsById(params: {
((params.fallbackToBundledMetadataForResolvedBundled && existing.origin === "bundled") ||
fallbackBundledPluginIds.has(pluginId));
if (shouldHydrateBundledMatch) {
const bundled = findBundledPluginMetadataById(pluginId, {
includeChannelConfigs: false,
includeSyntheticChannelConfigs: false,
});
if (bundled?.manifest.configContracts) {
const bundledConfigContracts = findBundledConfigContracts(pluginId);
if (bundledConfigContracts) {
matches.set(pluginId, {
origin: fallbackBundledPluginIds.has(pluginId) ? "bundled" : existing.origin,
configContracts: {
...bundled.manifest.configContracts,
...bundledConfigContracts,
...existing.configContracts,
...(bundled.manifest.configContracts.secretInputs
? { secretInputs: bundled.manifest.configContracts.secretInputs }
...(bundledConfigContracts.secretInputs
? { secretInputs: bundledConfigContracts.secretInputs }
: {}),
},
});
@@ -175,16 +199,13 @@ export function resolvePluginConfigContractsById(params: {
) {
continue;
}
const bundled = findBundledPluginMetadataById(pluginId, {
includeChannelConfigs: false,
includeSyntheticChannelConfigs: false,
});
if (!bundled?.manifest.configContracts) {
const bundledConfigContracts = findBundledConfigContracts(pluginId);
if (!bundledConfigContracts) {
continue;
}
matches.set(pluginId, {
origin: "bundled",
configContracts: bundled.manifest.configContracts,
configContracts: bundledConfigContracts,
});
}
}

View File

@@ -155,12 +155,13 @@ describe("normalizePluginsConfig", () => {
expect(result.entries.minimax?.enabled).toBe(false);
});
it("reuses the bundled alias scan during one config normalization", async () => {
it("reuses the plugin alias discovery during one config normalization", async () => {
vi.resetModules();
const bundledPluginMetadata = await import("./bundled-plugin-metadata.js");
const listBundledMetadata = vi.spyOn(bundledPluginMetadata, "listBundledPluginMetadata");
const discovery = await import("./discovery.js");
const discoverPlugins = vi.spyOn(discovery, "discoverOpenClawPlugins");
const { normalizePluginsConfig: normalizeFreshPluginsConfig } =
await import("./config-state.js");
discoverPlugins.mockClear();
const result = normalizeFreshPluginsConfig({
allow: ["unknown-plugin-one", "unknown-plugin-two"],
@@ -175,7 +176,7 @@ describe("normalizePluginsConfig", () => {
expect(result.allow).toEqual(["unknown-plugin-one", "unknown-plugin-two"]);
expect(result.deny).toEqual(["unknown-plugin-three"]);
expect(result.entries["unknown-plugin-four"]?.enabled).toBe(true);
expect(listBundledMetadata).toHaveBeenCalledTimes(1);
expect(discoverPlugins).toHaveBeenCalledTimes(1);
});
});

View File

@@ -3,7 +3,6 @@ import {
normalizeOptionalLowercaseString,
normalizeOptionalString,
} from "../shared/string-coerce.js";
import { listBundledPluginMetadata } from "./bundled-plugin-metadata.js";
import {
createEffectiveEnableStateResolver,
createPluginEnableStateResolver,
@@ -21,6 +20,8 @@ import {
type NormalizePluginId,
type NormalizedPluginsConfig as SharedNormalizedPluginsConfig,
} from "./config-normalization-shared.js";
import { discoverOpenClawPlugins } from "./discovery.js";
import { loadPluginManifest } from "./manifest.js";
import type { PluginOrigin } from "./plugin-origin.types.js";
import { defaultSlotIdForKey } from "./slots.js";
@@ -45,36 +46,38 @@ const BUILT_IN_PLUGIN_ALIAS_LOOKUP = new Map<string, string>([
...BUILT_IN_PLUGIN_ALIAS_FALLBACKS.map(([, pluginId]) => [pluginId, pluginId] as const),
]);
let bundledPluginAliasLookup: ReadonlyMap<string, string> | undefined;
function getBundledPluginAliasLookup(): ReadonlyMap<string, string> {
if (bundledPluginAliasLookup) {
return bundledPluginAliasLookup;
}
const lookup = new Map<string, string>();
for (const plugin of listBundledPluginMetadata({ includeChannelConfigs: false })) {
const pluginId = normalizeOptionalLowercaseString(plugin.manifest.id);
if (pluginId) {
lookup.set(pluginId, plugin.manifest.id);
for (const candidate of discoverOpenClawPlugins({}).candidates) {
const manifestResult =
candidate.origin === "bundled" && candidate.bundledManifest
? { ok: true as const, manifest: candidate.bundledManifest }
: loadPluginManifest(candidate.rootDir, candidate.origin !== "bundled");
if (!manifestResult.ok) {
continue;
}
for (const providerId of plugin.manifest.providers ?? []) {
const manifest = manifestResult.manifest;
const pluginId = normalizeOptionalLowercaseString(manifest.id);
if (pluginId) {
lookup.set(pluginId, manifest.id);
}
for (const providerId of manifest.providers ?? []) {
const normalizedProviderId = normalizeOptionalLowercaseString(providerId);
if (normalizedProviderId) {
lookup.set(normalizedProviderId, plugin.manifest.id);
lookup.set(normalizedProviderId, manifest.id);
}
}
for (const legacyPluginId of plugin.manifest.legacyPluginIds ?? []) {
for (const legacyPluginId of manifest.legacyPluginIds ?? []) {
const normalizedLegacyPluginId = normalizeOptionalLowercaseString(legacyPluginId);
if (normalizedLegacyPluginId) {
lookup.set(normalizedLegacyPluginId, plugin.manifest.id);
lookup.set(normalizedLegacyPluginId, manifest.id);
}
}
}
for (const [alias, pluginId] of BUILT_IN_PLUGIN_ALIAS_FALLBACKS) {
lookup.set(alias, pluginId);
}
bundledPluginAliasLookup = lookup;
return bundledPluginAliasLookup;
return lookup;
}
function normalizePluginIdWithLookup(

View File

@@ -135,19 +135,6 @@ function normalizeStringField(value: unknown): string | undefined {
return normalized ? normalized : undefined;
}
function normalizeStringListField(value: unknown): readonly string[] | undefined {
if (!Array.isArray(value)) {
return undefined;
}
const normalized = value
.flatMap((entry) => {
const normalizedEntry = normalizeStringField(entry);
return normalizedEntry ? [normalizedEntry] : [];
})
.filter((entry, index, all) => all.indexOf(entry) === index);
return normalized.length > 0 ? normalized : undefined;
}
function normalizePackageChannel(
channel: PluginPackageChannel | undefined,
): InstalledPluginPackageChannelInfo | undefined {
@@ -155,30 +142,9 @@ function normalizePackageChannel(
if (!id) {
return undefined;
}
const label = normalizeStringField(channel?.label);
const blurb = normalizeStringField(channel?.blurb);
const preferOver = normalizeStringListField(channel?.preferOver);
const commands =
channel?.commands &&
typeof channel.commands === "object" &&
!Array.isArray(channel.commands) &&
(typeof channel.commands.nativeCommandsAutoEnabled === "boolean" ||
typeof channel.commands.nativeSkillsAutoEnabled === "boolean")
? {
...(typeof channel.commands.nativeCommandsAutoEnabled === "boolean"
? { nativeCommandsAutoEnabled: channel.commands.nativeCommandsAutoEnabled }
: {}),
...(typeof channel.commands.nativeSkillsAutoEnabled === "boolean"
? { nativeSkillsAutoEnabled: channel.commands.nativeSkillsAutoEnabled }
: {}),
}
: undefined;
return {
...structuredClone(channel),
id,
...(label ? { label } : {}),
...(blurb ? { blurb } : {}),
...(preferOver ? { preferOver } : {}),
...(commands ? { commands } : {}),
};
}
@@ -240,7 +206,9 @@ export function buildInstalledPluginIndexRecords(params: {
const packageJsonPath = resolvePackageJsonPath(candidate);
const installRecord = params.installRecords[record.id];
const packageInstall = describePackageInstallSource(candidate);
const packageChannel = normalizePackageChannel(candidate?.packageManifest?.channel);
const packageChannel = normalizePackageChannel(
record.packageChannel ?? candidate?.packageManifest?.channel,
);
const manifestHash = resolveManifestHash({ record, diagnostics: params.diagnostics });
const packageJson = resolvePackageJsonRecord({
candidate,

View File

@@ -60,10 +60,7 @@ export type InstalledPluginInstallRecordInfo = Pick<
| "marketplacePlugin"
>;
export type InstalledPluginPackageChannelInfo = Pick<
PluginPackageChannel,
"id" | "label" | "blurb" | "preferOver" | "commands"
>;
export type InstalledPluginPackageChannelInfo = PluginPackageChannel;
export type InstalledPluginIndexRecord = {
pluginId: string;

View File

@@ -104,36 +104,36 @@ function resolveFallbackPluginSource(record: InstalledPluginIndexRecord): string
function resolveInstalledPackageManifest(
record: InstalledPluginIndexRecord,
): OpenClawPackageManifest | undefined {
if (!record.packageChannel) {
return undefined;
}
if (record.packageChannel.commands) {
return { channel: record.packageChannel };
}
const rootDir = resolveInstalledPluginRootDir(record);
const packageJsonPath = record.packageJson?.path
? path.resolve(rootDir, record.packageJson.path)
: undefined;
if (!packageJsonPath) {
return { channel: record.packageChannel };
return record.packageChannel ? { channel: record.packageChannel } : undefined;
}
const relative = path.relative(rootDir, packageJsonPath);
if (relative.startsWith("..") || path.isAbsolute(relative)) {
return { channel: record.packageChannel };
return record.packageChannel ? { channel: record.packageChannel } : undefined;
}
try {
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")) as PackageManifest;
const packageManifest = getPackageManifestMetadata(packageJson);
if (!packageManifest) {
return record.packageChannel ? { channel: record.packageChannel } : undefined;
}
const channel =
record.packageChannel || packageManifest.channel
? {
...record.packageChannel,
...packageManifest.channel,
}
: undefined;
return {
channel: {
...record.packageChannel,
...(packageManifest?.channel?.commands
? { commands: packageManifest.channel.commands }
: {}),
},
...packageManifest,
...(channel ? { channel } : {}),
};
} catch {
return { channel: record.packageChannel };
return record.packageChannel ? { channel: record.packageChannel } : undefined;
}
}

View File

@@ -37,6 +37,8 @@ import {
type PluginManifestProviderRequest,
type PluginManifestQaRunner,
type PluginManifestSetup,
type PluginPackageChannel,
type PluginPackageInstall,
} from "./manifest.js";
import { checkMinHostVersion } from "./min-host-version.js";
import { isPathInside, safeRealpathSync } from "./path-safety.js";
@@ -96,6 +98,9 @@ export type PluginManifestRecord = {
name?: string;
description?: string;
version?: string;
packageName?: string;
packageVersion?: string;
packageDescription?: string;
enabledByDefault?: boolean;
autoEnableWhenConfiguredProviders?: string[];
legacyPluginIds?: string[];
@@ -122,6 +127,9 @@ export type PluginManifestRecord = {
providerAuthChoices?: PluginManifest["providerAuthChoices"];
activation?: PluginManifestActivation;
setup?: PluginManifestSetup;
packageManifest?: OpenClawPackageManifest;
packageChannel?: PluginPackageChannel;
packageInstall?: PluginPackageInstall;
qaRunners?: PluginManifestQaRunner[];
skills: string[];
settingsFiles?: string[];
@@ -269,6 +277,9 @@ function buildRecord(params: {
description:
normalizeOptionalString(params.manifest.description) ?? params.candidate.packageDescription,
version: normalizeOptionalString(params.manifest.version) ?? params.candidate.packageVersion,
packageName: params.candidate.packageName,
packageVersion: params.candidate.packageVersion,
packageDescription: params.candidate.packageDescription,
enabledByDefault: params.manifest.enabledByDefault === true ? true : undefined,
autoEnableWhenConfiguredProviders: params.manifest.autoEnableWhenConfiguredProviders,
legacyPluginIds: params.manifest.legacyPluginIds,
@@ -298,6 +309,9 @@ function buildRecord(params: {
providerAuthChoices: params.manifest.providerAuthChoices,
activation: params.manifest.activation,
setup: params.manifest.setup,
packageManifest: params.candidate.packageManifest,
packageChannel: params.candidate.packageManifest?.channel,
packageInstall: params.candidate.packageManifest?.install,
qaRunners: params.manifest.qaRunners,
skills: params.manifest.skills ?? [],
settingsFiles: [],
@@ -357,6 +371,12 @@ function buildBundleRecord(params: {
name: normalizeOptionalString(params.manifest.name) ?? params.candidate.idHint,
description: normalizeOptionalString(params.manifest.description),
version: normalizeOptionalString(params.manifest.version),
packageName: params.candidate.packageName,
packageVersion: params.candidate.packageVersion,
packageDescription: params.candidate.packageDescription,
packageManifest: params.candidate.packageManifest,
packageChannel: params.candidate.packageManifest?.channel,
packageInstall: params.candidate.packageManifest?.install,
format: "bundle",
bundleFormat: params.candidate.bundleFormat,
bundleCapabilities: params.manifest.capabilities,