mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 12:50:42 +00:00
fix: reuse manifest pass for runtime contract owners
This commit is contained in:
@@ -29,6 +29,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Plugins/startup: carry the Gateway `PluginLookUpTable` into deferred channel full-runtime reloads so post-listen startup does not rebuild manifest metadata after the provisional setup-runtime load. Thanks @shakkernerd.
|
||||
- Gateway/startup: extend `OPENCLAW_GATEWAY_STARTUP_TRACE=1` with per-phase event-loop delay plus plugin lookup-table timing and count metrics for installed-index, manifest, startup-plan, and owner-map work, and include the new timing fields in startup benchmark summaries. Thanks @shakkernerd.
|
||||
- Plugins/channels: resolve read-only channel command defaults from one plugin index plus manifest pass instead of reloading plugin metadata while checking candidate plugin enablement. Thanks @shakkernerd.
|
||||
- Plugins/contracts: resolve runtime manifest-contract plugin owners from one plugin index plus manifest pass instead of rebuilding manifest metadata separately for all owners and enabled owners. Thanks @shakkernerd.
|
||||
- Plugins/registry: resolve lookup-table owner maps for providers, CLI backends, setup providers, command aliases, model catalogs, channel configs, and manifest contracts while preserving setup-only CLI backend ownership. Thanks @shakkernerd.
|
||||
- Process/Windows: decode command stdout and stderr from raw bytes with console-codepage awareness, while preserving valid UTF-8 output and multibyte characters split across chunks. Fixes #50519. Thanks @iready, @kevinten10, @zhangyongjie1997, @knightplat-blip, @heiqishi666, and @slepybear.
|
||||
- Bonjour/Windows: hide the bundled mDNS advertiser's Windows ARP shell probe so Gateway startup no longer flashes command-prompt windows. Fixes #70238. Thanks @alexandre-leng, @PratikRai0101, @infinitypacific, and @tomerpeled.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import type { PluginManifestContractListKey } from "./manifest-registry.js";
|
||||
import { loadPluginManifestRegistryForPluginRegistry } from "./plugin-registry.js";
|
||||
import { loadPluginManifestRegistryForInstalledIndex } from "./manifest-registry-installed.js";
|
||||
import type { PluginManifestContractListKey, PluginManifestRecord } from "./manifest-registry.js";
|
||||
import { loadPluginRegistrySnapshot } from "./plugin-registry.js";
|
||||
|
||||
export type ManifestContractRuntimePluginResolution = {
|
||||
pluginIds: string[];
|
||||
@@ -12,7 +13,7 @@ const DEMAND_ONLY_CONTRACT_LOOKUP_OPTIONS = {
|
||||
} as const;
|
||||
|
||||
function hasManifestContractValue(
|
||||
plugin: ReturnType<typeof loadPluginManifestRegistryForPluginRegistry>["plugins"][number],
|
||||
plugin: PluginManifestRecord,
|
||||
contract: PluginManifestContractListKey,
|
||||
value?: string,
|
||||
): boolean {
|
||||
@@ -25,21 +26,22 @@ export function resolveManifestContractRuntimePluginResolution(params: {
|
||||
contract: PluginManifestContractListKey;
|
||||
value?: string;
|
||||
}): ManifestContractRuntimePluginResolution {
|
||||
const allContractPlugins = loadPluginManifestRegistryForPluginRegistry({
|
||||
const index = loadPluginRegistrySnapshot({
|
||||
config: params.cfg,
|
||||
env: process.env,
|
||||
...DEMAND_ONLY_CONTRACT_LOOKUP_OPTIONS,
|
||||
});
|
||||
const allContractPlugins = loadPluginManifestRegistryForInstalledIndex({
|
||||
index,
|
||||
config: params.cfg,
|
||||
env: process.env,
|
||||
includeDisabled: true,
|
||||
...DEMAND_ONLY_CONTRACT_LOOKUP_OPTIONS,
|
||||
}).plugins.filter((plugin) => hasManifestContractValue(plugin, params.contract, params.value));
|
||||
const bundledCompatPluginIds = allContractPlugins
|
||||
.filter((plugin) => plugin.origin === "bundled")
|
||||
.map((plugin) => plugin.id);
|
||||
const enabledPluginIds = new Set(
|
||||
loadPluginManifestRegistryForPluginRegistry({
|
||||
config: params.cfg,
|
||||
env: process.env,
|
||||
...DEMAND_ONLY_CONTRACT_LOOKUP_OPTIONS,
|
||||
}).plugins.map((plugin) => plugin.id),
|
||||
index.plugins.filter((plugin) => plugin.enabled).map((plugin) => plugin.pluginId),
|
||||
);
|
||||
const pluginIds = allContractPlugins
|
||||
.filter((plugin) => plugin.origin === "bundled" || enabledPluginIds.has(plugin.id))
|
||||
|
||||
@@ -8,10 +8,24 @@ type MockManifestRegistry = {
|
||||
diagnostics: unknown[];
|
||||
};
|
||||
|
||||
type MockPluginIndex = {
|
||||
plugins: Array<{
|
||||
pluginId: string;
|
||||
origin: string;
|
||||
enabled: boolean;
|
||||
enabledByDefault?: boolean;
|
||||
}>;
|
||||
diagnostics: unknown[];
|
||||
};
|
||||
|
||||
function createEmptyMockManifestRegistry(): MockManifestRegistry {
|
||||
return { plugins: [], diagnostics: [] };
|
||||
}
|
||||
|
||||
function createMockPluginIndex(plugins: MockPluginIndex["plugins"]): MockPluginIndex {
|
||||
return { plugins, diagnostics: [] };
|
||||
}
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
resolveRuntimePluginRegistry: vi.fn<(params?: unknown) => PluginRegistry | undefined>(
|
||||
() => undefined,
|
||||
@@ -19,6 +33,7 @@ const mocks = vi.hoisted(() => ({
|
||||
loadPluginManifestRegistry: vi.fn<(params?: Record<string, unknown>) => MockManifestRegistry>(
|
||||
() => createEmptyMockManifestRegistry(),
|
||||
),
|
||||
loadPluginRegistrySnapshot: vi.fn<() => MockPluginIndex>(() => createMockPluginIndex([])),
|
||||
withBundledPluginAllowlistCompat: vi.fn(
|
||||
({ config }: { config?: OpenClawConfig; pluginIds: string[] }) => config,
|
||||
),
|
||||
@@ -35,7 +50,11 @@ vi.mock("./loader.js", () => ({
|
||||
}));
|
||||
|
||||
vi.mock("./plugin-registry.js", () => ({
|
||||
loadPluginManifestRegistryForPluginRegistry: mocks.loadPluginManifestRegistry,
|
||||
loadPluginRegistrySnapshot: mocks.loadPluginRegistrySnapshot,
|
||||
}));
|
||||
|
||||
vi.mock("./manifest-registry-installed.js", () => ({
|
||||
loadPluginManifestRegistryForInstalledIndex: mocks.loadPluginManifestRegistry,
|
||||
}));
|
||||
|
||||
vi.mock("./bundled-compat.js", () => ({
|
||||
@@ -61,6 +80,7 @@ describe("migration provider runtime", () => {
|
||||
vi.clearAllMocks();
|
||||
mocks.resolveRuntimePluginRegistry.mockReturnValue(createEmptyPluginRegistry());
|
||||
mocks.loadPluginManifestRegistry.mockReturnValue(createEmptyMockManifestRegistry());
|
||||
mocks.loadPluginRegistrySnapshot.mockReturnValue(createMockPluginIndex([]));
|
||||
const runtime = await import("./migration-provider-runtime.js");
|
||||
resolvePluginMigrationProvider = runtime.resolvePluginMigrationProvider;
|
||||
resolvePluginMigrationProviders = runtime.resolvePluginMigrationProviders;
|
||||
@@ -82,6 +102,20 @@ describe("migration provider runtime", () => {
|
||||
mocks.resolveRuntimePluginRegistry.mockImplementation((params?: unknown) =>
|
||||
params === undefined ? active : loaded,
|
||||
);
|
||||
mocks.loadPluginRegistrySnapshot.mockReturnValue(
|
||||
createMockPluginIndex([
|
||||
{
|
||||
pluginId: "external-migration",
|
||||
origin: "installed",
|
||||
enabled: true,
|
||||
},
|
||||
{
|
||||
pluginId: "disabled-external-migration",
|
||||
origin: "installed",
|
||||
enabled: false,
|
||||
},
|
||||
]),
|
||||
);
|
||||
mocks.loadPluginManifestRegistry.mockImplementation((params?: Record<string, unknown>) => ({
|
||||
diagnostics: [],
|
||||
plugins: params?.includeDisabled
|
||||
@@ -109,11 +143,20 @@ describe("migration provider runtime", () => {
|
||||
const resolved = resolvePluginMigrationProvider({ providerId: "external-import", cfg });
|
||||
|
||||
expect(resolved).toBe(provider);
|
||||
expect(mocks.loadPluginRegistrySnapshot).toHaveBeenCalledWith({
|
||||
config: cfg,
|
||||
env: process.env,
|
||||
preferPersisted: false,
|
||||
});
|
||||
expect(mocks.loadPluginManifestRegistry).toHaveBeenCalledWith({
|
||||
index: expect.objectContaining({
|
||||
plugins: expect.arrayContaining([
|
||||
expect.objectContaining({ pluginId: "external-migration" }),
|
||||
]),
|
||||
}),
|
||||
config: cfg,
|
||||
env: process.env,
|
||||
includeDisabled: true,
|
||||
preferPersisted: false,
|
||||
});
|
||||
expect(mocks.resolveRuntimePluginRegistry).toHaveBeenCalledWith();
|
||||
expect(mocks.resolveRuntimePluginRegistry).toHaveBeenCalledWith({
|
||||
@@ -136,30 +179,41 @@ describe("migration provider runtime", () => {
|
||||
mocks.resolveRuntimePluginRegistry.mockImplementation((params?: unknown) =>
|
||||
params === undefined ? active : loaded,
|
||||
);
|
||||
mocks.loadPluginManifestRegistry.mockImplementation((params?: Record<string, unknown>) => {
|
||||
if (params?.preferPersisted !== false) {
|
||||
return createEmptyMockManifestRegistry();
|
||||
}
|
||||
return {
|
||||
diagnostics: [],
|
||||
plugins: [
|
||||
{
|
||||
id: "migrate-hermes",
|
||||
origin: "bundled",
|
||||
contracts: { migrationProviders: ["hermes"] },
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
mocks.loadPluginRegistrySnapshot.mockReturnValue(
|
||||
createMockPluginIndex([
|
||||
{
|
||||
pluginId: "migrate-hermes",
|
||||
origin: "bundled",
|
||||
enabled: true,
|
||||
},
|
||||
]),
|
||||
);
|
||||
mocks.loadPluginManifestRegistry.mockImplementation(() => ({
|
||||
diagnostics: [],
|
||||
plugins: [
|
||||
{
|
||||
id: "migrate-hermes",
|
||||
origin: "bundled",
|
||||
contracts: { migrationProviders: ["hermes"] },
|
||||
},
|
||||
],
|
||||
}));
|
||||
|
||||
const resolved = resolvePluginMigrationProvider({ providerId: "hermes" });
|
||||
|
||||
expect(resolved).toBe(provider);
|
||||
expect(mocks.loadPluginRegistrySnapshot).toHaveBeenCalledWith({
|
||||
config: undefined,
|
||||
env: process.env,
|
||||
preferPersisted: false,
|
||||
});
|
||||
expect(mocks.loadPluginManifestRegistry).toHaveBeenCalledWith({
|
||||
index: expect.objectContaining({
|
||||
plugins: [expect.objectContaining({ pluginId: "migrate-hermes" })],
|
||||
}),
|
||||
config: undefined,
|
||||
env: process.env,
|
||||
includeDisabled: true,
|
||||
preferPersisted: false,
|
||||
});
|
||||
expect(mocks.resolveRuntimePluginRegistry).toHaveBeenCalledWith({
|
||||
onlyPluginIds: ["migrate-hermes"],
|
||||
@@ -187,6 +241,15 @@ describe("migration provider runtime", () => {
|
||||
mocks.resolveRuntimePluginRegistry.mockImplementation((params?: unknown) =>
|
||||
params === undefined ? active : loaded,
|
||||
);
|
||||
mocks.loadPluginRegistrySnapshot.mockReturnValue(
|
||||
createMockPluginIndex([
|
||||
{
|
||||
pluginId: "external-migration",
|
||||
origin: "installed",
|
||||
enabled: true,
|
||||
},
|
||||
]),
|
||||
);
|
||||
mocks.loadPluginManifestRegistry.mockImplementation((params?: Record<string, unknown>) => ({
|
||||
diagnostics: [],
|
||||
plugins: params?.includeDisabled
|
||||
|
||||
Reference in New Issue
Block a user