Plugins: add host-owned CLI and service storage
This commit is contained in:
parent
542d17de04
commit
daad214a3a
@ -25,7 +25,9 @@ import type {
|
||||
ExtensionHostToolRegistration,
|
||||
} from "./runtime-registrations.js";
|
||||
import {
|
||||
addExtensionHostCliRegistration,
|
||||
addExtensionHostHttpRoute,
|
||||
addExtensionHostServiceRegistration,
|
||||
replaceExtensionHostHttpRoute,
|
||||
setExtensionHostGatewayHandler,
|
||||
} from "./runtime-registry.js";
|
||||
@ -131,7 +133,7 @@ export function addExtensionCliRegistration(params: {
|
||||
entry: ExtensionHostCliRegistration;
|
||||
}): void {
|
||||
params.record.cliCommands.push(...params.commands);
|
||||
params.registry.cliRegistrars.push(params.entry as PluginCliRegistration);
|
||||
addExtensionHostCliRegistration(params.registry, params.entry as PluginCliRegistration);
|
||||
}
|
||||
|
||||
export function addExtensionServiceRegistration(params: {
|
||||
@ -141,7 +143,7 @@ export function addExtensionServiceRegistration(params: {
|
||||
entry: ExtensionHostServiceRegistration;
|
||||
}): void {
|
||||
params.record.services.push(params.serviceId);
|
||||
params.registry.services.push(params.entry as PluginServiceRegistration);
|
||||
addExtensionHostServiceRegistration(params.registry, params.entry as PluginServiceRegistration);
|
||||
}
|
||||
|
||||
export function addExtensionCommandRegistration(params: {
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { createEmptyPluginRegistry } from "../plugins/registry.js";
|
||||
import {
|
||||
addExtensionHostCliRegistration,
|
||||
addExtensionHostHttpRoute,
|
||||
addExtensionHostServiceRegistration,
|
||||
getExtensionHostGatewayHandlers,
|
||||
hasExtensionHostRuntimeEntries,
|
||||
listExtensionHostCliRegistrations,
|
||||
@ -46,6 +48,26 @@ describe("extension host runtime registry accessors", () => {
|
||||
handler: vi.fn(),
|
||||
});
|
||||
expect(hasExtensionHostRuntimeEntries(gatewayRegistry)).toBe(true);
|
||||
|
||||
const cliRegistry = createEmptyPluginRegistry();
|
||||
addExtensionHostCliRegistration(cliRegistry, {
|
||||
pluginId: "cli-demo",
|
||||
source: "test",
|
||||
commands: ["demo"],
|
||||
register: () => undefined,
|
||||
});
|
||||
expect(hasExtensionHostRuntimeEntries(cliRegistry)).toBe(true);
|
||||
|
||||
const serviceRegistry = createEmptyPluginRegistry();
|
||||
addExtensionHostServiceRegistration(serviceRegistry, {
|
||||
pluginId: "svc-demo",
|
||||
source: "test",
|
||||
service: {
|
||||
id: "svc-demo",
|
||||
start: () => undefined,
|
||||
},
|
||||
});
|
||||
expect(hasExtensionHostRuntimeEntries(serviceRegistry)).toBe(true);
|
||||
});
|
||||
|
||||
it("returns stable empty views for missing registries", () => {
|
||||
@ -74,7 +96,7 @@ describe("extension host runtime registry accessors", () => {
|
||||
},
|
||||
}),
|
||||
});
|
||||
registry.services.push({
|
||||
addExtensionHostServiceRegistration(registry, {
|
||||
pluginId: "svc-demo",
|
||||
source: "test",
|
||||
service: {
|
||||
@ -82,7 +104,7 @@ describe("extension host runtime registry accessors", () => {
|
||||
start: () => undefined,
|
||||
},
|
||||
});
|
||||
registry.cliRegistrars.push({
|
||||
addExtensionHostCliRegistration(registry, {
|
||||
pluginId: "cli-demo",
|
||||
source: "test",
|
||||
commands: ["demo"],
|
||||
@ -104,8 +126,8 @@ describe("extension host runtime registry accessors", () => {
|
||||
});
|
||||
|
||||
expect(listExtensionHostToolRegistrations(registry)).toBe(registry.tools);
|
||||
expect(listExtensionHostServiceRegistrations(registry)).toBe(registry.services);
|
||||
expect(listExtensionHostCliRegistrations(registry)).toBe(registry.cliRegistrars);
|
||||
expect(listExtensionHostServiceRegistrations(registry)).toEqual(registry.services);
|
||||
expect(listExtensionHostCliRegistrations(registry)).toEqual(registry.cliRegistrars);
|
||||
expect(listExtensionHostHttpRoutes(registry)).toEqual(registry.httpRoutes);
|
||||
expect(getExtensionHostGatewayHandlers(registry)).toEqual(registry.gatewayHandlers);
|
||||
expect(getExtensionHostGatewayHandlers(registry)["demo.echo"]).toBe(handler);
|
||||
@ -141,4 +163,30 @@ describe("extension host runtime registry accessors", () => {
|
||||
expect(registry.httpRoutes[0]?.handler).toBe(secondHandler);
|
||||
expect(getExtensionHostGatewayHandlers(registry)).toEqual(registry.gatewayHandlers);
|
||||
});
|
||||
|
||||
it("keeps legacy CLI and service mirrors synchronized with host-owned state", () => {
|
||||
const registry = createEmptyPluginRegistry();
|
||||
const service = {
|
||||
id: "svc-demo",
|
||||
start: () => undefined,
|
||||
};
|
||||
const register = () => undefined;
|
||||
|
||||
addExtensionHostServiceRegistration(registry, {
|
||||
pluginId: "svc-demo",
|
||||
source: "test",
|
||||
service,
|
||||
});
|
||||
addExtensionHostCliRegistration(registry, {
|
||||
pluginId: "cli-demo",
|
||||
source: "test",
|
||||
commands: ["demo"],
|
||||
register,
|
||||
});
|
||||
|
||||
expect(listExtensionHostServiceRegistrations(registry)).toEqual(registry.services);
|
||||
expect(listExtensionHostCliRegistrations(registry)).toEqual(registry.cliRegistrars);
|
||||
expect(registry.services[0]?.service).toBe(service);
|
||||
expect(registry.cliRegistrars[0]?.register).toBe(register);
|
||||
});
|
||||
});
|
||||
|
||||
@ -17,6 +17,10 @@ const EMPTY_GATEWAY_HANDLERS: Readonly<GatewayRequestHandlers> = Object.freeze({
|
||||
const EXTENSION_HOST_RUNTIME_REGISTRY_STATE = Symbol.for("openclaw.extensionHostRuntimeRegistry");
|
||||
|
||||
type ExtensionHostRuntimeRegistryState = {
|
||||
cliRegistrars: PluginCliRegistration[];
|
||||
legacyCliRegistrars: PluginCliRegistration[];
|
||||
services: PluginServiceRegistration[];
|
||||
legacyServices: PluginServiceRegistration[];
|
||||
httpRoutes: PluginHttpRouteRegistration[];
|
||||
legacyHttpRoutes: PluginHttpRouteRegistration[];
|
||||
gatewayHandlers: GatewayRequestHandlers;
|
||||
@ -25,7 +29,7 @@ type ExtensionHostRuntimeRegistryState = {
|
||||
|
||||
type RuntimeRegistryBackedPluginRegistry = Pick<
|
||||
PluginRegistry,
|
||||
"httpRoutes" | "gatewayHandlers"
|
||||
"cliRegistrars" | "services" | "httpRoutes" | "gatewayHandlers"
|
||||
> & {
|
||||
[EXTENSION_HOST_RUNTIME_REGISTRY_STATE]?: ExtensionHostRuntimeRegistryState;
|
||||
};
|
||||
@ -41,8 +45,16 @@ function ensureExtensionHostRuntimeRegistryState(
|
||||
registry.httpRoutes = legacyHttpRoutes;
|
||||
const legacyGatewayHandlers = registry.gatewayHandlers ?? {};
|
||||
registry.gatewayHandlers = legacyGatewayHandlers;
|
||||
const legacyCliRegistrars = registry.cliRegistrars ?? [];
|
||||
registry.cliRegistrars = legacyCliRegistrars;
|
||||
const legacyServices = registry.services ?? [];
|
||||
registry.services = legacyServices;
|
||||
|
||||
const state: ExtensionHostRuntimeRegistryState = {
|
||||
cliRegistrars: [...legacyCliRegistrars],
|
||||
legacyCliRegistrars,
|
||||
services: [...legacyServices],
|
||||
legacyServices,
|
||||
httpRoutes: [...legacyHttpRoutes],
|
||||
legacyHttpRoutes,
|
||||
gatewayHandlers: { ...legacyGatewayHandlers },
|
||||
@ -52,6 +64,14 @@ function ensureExtensionHostRuntimeRegistryState(
|
||||
return state;
|
||||
}
|
||||
|
||||
function syncLegacyCliRegistrars(state: ExtensionHostRuntimeRegistryState): void {
|
||||
state.legacyCliRegistrars.splice(0, state.legacyCliRegistrars.length, ...state.cliRegistrars);
|
||||
}
|
||||
|
||||
function syncLegacyServices(state: ExtensionHostRuntimeRegistryState): void {
|
||||
state.legacyServices.splice(0, state.legacyServices.length, ...state.services);
|
||||
}
|
||||
|
||||
function syncLegacyHttpRoutes(state: ExtensionHostRuntimeRegistryState): void {
|
||||
state.legacyHttpRoutes.splice(0, state.legacyHttpRoutes.length, ...state.httpRoutes);
|
||||
}
|
||||
@ -94,8 +114,8 @@ export function hasExtensionHostRuntimeEntries(
|
||||
registry.providers.length > 0 ||
|
||||
Object.keys(getExtensionHostGatewayHandlers(registry)).length > 0 ||
|
||||
listExtensionHostHttpRoutes(registry).length > 0 ||
|
||||
registry.cliRegistrars.length > 0 ||
|
||||
registry.services.length > 0 ||
|
||||
listExtensionHostCliRegistrations(registry).length > 0 ||
|
||||
listExtensionHostServiceRegistrations(registry).length > 0 ||
|
||||
registry.commands.length > 0 ||
|
||||
registry.hooks.length > 0 ||
|
||||
registry.typedHooks.length > 0
|
||||
@ -115,15 +135,29 @@ export function listExtensionHostToolRegistrations(
|
||||
}
|
||||
|
||||
export function listExtensionHostServiceRegistrations(
|
||||
registry: Pick<PluginRegistry, "services"> | null | undefined,
|
||||
registry:
|
||||
| Pick<PluginRegistry, "cliRegistrars" | "services" | "httpRoutes" | "gatewayHandlers">
|
||||
| null
|
||||
| undefined,
|
||||
): readonly PluginServiceRegistration[] {
|
||||
return registry?.services ?? EMPTY_SERVICES;
|
||||
if (!registry) {
|
||||
return EMPTY_SERVICES;
|
||||
}
|
||||
return ensureExtensionHostRuntimeRegistryState(registry as RuntimeRegistryBackedPluginRegistry)
|
||||
.services;
|
||||
}
|
||||
|
||||
export function listExtensionHostCliRegistrations(
|
||||
registry: Pick<PluginRegistry, "cliRegistrars"> | null | undefined,
|
||||
registry:
|
||||
| Pick<PluginRegistry, "cliRegistrars" | "services" | "httpRoutes" | "gatewayHandlers">
|
||||
| null
|
||||
| undefined,
|
||||
): readonly PluginCliRegistration[] {
|
||||
return registry?.cliRegistrars ?? EMPTY_CLI_REGISTRARS;
|
||||
if (!registry) {
|
||||
return EMPTY_CLI_REGISTRARS;
|
||||
}
|
||||
return ensureExtensionHostRuntimeRegistryState(registry as RuntimeRegistryBackedPluginRegistry)
|
||||
.cliRegistrars;
|
||||
}
|
||||
|
||||
export function listExtensionHostHttpRoutes(
|
||||
@ -147,7 +181,7 @@ export function getExtensionHostGatewayHandlers(
|
||||
}
|
||||
|
||||
export function addExtensionHostHttpRoute(
|
||||
registry: Pick<PluginRegistry, "httpRoutes" | "gatewayHandlers">,
|
||||
registry: Pick<PluginRegistry, "cliRegistrars" | "services" | "httpRoutes" | "gatewayHandlers">,
|
||||
entry: PluginHttpRouteRegistration,
|
||||
): void {
|
||||
const state = ensureExtensionHostRuntimeRegistryState(
|
||||
@ -158,7 +192,7 @@ export function addExtensionHostHttpRoute(
|
||||
}
|
||||
|
||||
export function replaceExtensionHostHttpRoute(params: {
|
||||
registry: Pick<PluginRegistry, "httpRoutes" | "gatewayHandlers">;
|
||||
registry: Pick<PluginRegistry, "cliRegistrars" | "services" | "httpRoutes" | "gatewayHandlers">;
|
||||
index: number;
|
||||
entry: PluginHttpRouteRegistration;
|
||||
}): void {
|
||||
@ -170,7 +204,7 @@ export function replaceExtensionHostHttpRoute(params: {
|
||||
}
|
||||
|
||||
export function removeExtensionHostHttpRoute(
|
||||
registry: Pick<PluginRegistry, "httpRoutes" | "gatewayHandlers">,
|
||||
registry: Pick<PluginRegistry, "cliRegistrars" | "services" | "httpRoutes" | "gatewayHandlers">,
|
||||
entry: PluginHttpRouteRegistration,
|
||||
): void {
|
||||
const state = ensureExtensionHostRuntimeRegistryState(
|
||||
@ -185,7 +219,7 @@ export function removeExtensionHostHttpRoute(
|
||||
}
|
||||
|
||||
export function setExtensionHostGatewayHandler(params: {
|
||||
registry: Pick<PluginRegistry, "httpRoutes" | "gatewayHandlers">;
|
||||
registry: Pick<PluginRegistry, "cliRegistrars" | "services" | "httpRoutes" | "gatewayHandlers">;
|
||||
method: string;
|
||||
handler: GatewayRequestHandlers[string];
|
||||
}): void {
|
||||
@ -195,3 +229,25 @@ export function setExtensionHostGatewayHandler(params: {
|
||||
state.gatewayHandlers[params.method] = params.handler;
|
||||
syncLegacyGatewayHandlers(state);
|
||||
}
|
||||
|
||||
export function addExtensionHostCliRegistration(
|
||||
registry: Pick<PluginRegistry, "cliRegistrars" | "services" | "httpRoutes" | "gatewayHandlers">,
|
||||
entry: PluginCliRegistration,
|
||||
): void {
|
||||
const state = ensureExtensionHostRuntimeRegistryState(
|
||||
registry as RuntimeRegistryBackedPluginRegistry,
|
||||
);
|
||||
state.cliRegistrars.push(entry);
|
||||
syncLegacyCliRegistrars(state);
|
||||
}
|
||||
|
||||
export function addExtensionHostServiceRegistration(
|
||||
registry: Pick<PluginRegistry, "cliRegistrars" | "services" | "httpRoutes" | "gatewayHandlers">,
|
||||
entry: PluginServiceRegistration,
|
||||
): void {
|
||||
const state = ensureExtensionHostRuntimeRegistryState(
|
||||
registry as RuntimeRegistryBackedPluginRegistry,
|
||||
);
|
||||
state.services.push(entry);
|
||||
syncLegacyServices(state);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user