

























@@ -7,11 +7,13 @@ import {
77} from "openclaw/plugin-sdk/plugin-test-contracts";
88import { afterEach, describe, expect, it } from "vitest";
99import {
10+validatePluginsUiDescriptorsResult,
1011validatePluginsUiDescriptorsParams,
1112validateSessionsPluginPatchParams,
1213} from "../../../packages/gateway-protocol/src/index.js";
1314import { loadSessionStore, updateSessionStore, type SessionEntry } from "../../config/sessions.js";
1415import { APPROVALS_SCOPE, READ_SCOPE, WRITE_SCOPE } from "../../gateway/operator-scopes.js";
16+import { pluginHostHookHandlers } from "../../gateway/server-methods/plugin-host-hooks.js";
1517import { buildGatewaySessionRow } from "../../gateway/session-utils.js";
1618import { withTempConfig } from "../../gateway/test-temp-config.js";
1719import { emitAgentEvent, resetAgentEventsForTest } from "../../infra/agent-events.js";
@@ -1892,6 +1894,84 @@ describe("host-hook fixture plugin contract", () => {
18921894).toBe(false);
18931895expect(validatePluginsUiDescriptorsParams({})).toBe(true);
18941896expect(validatePluginsUiDescriptorsParams({ pluginId: "host-hook-fixture" })).toBe(false);
1897+expect(
1898+validatePluginsUiDescriptorsResult({
1899+ok: true,
1900+descriptors: [
1901+{
1902+id: "approval-panel",
1903+pluginId: "host-hook-fixture",
1904+surface: "session",
1905+label: "Approval panel",
1906+},
1907+],
1908+}),
1909+).toBe(true);
1910+expect(
1911+validatePluginsUiDescriptorsResult({
1912+ok: true,
1913+descriptors: [
1914+{
1915+id: "approval-panel",
1916+pluginId: "host-hook-fixture",
1917+surface: "session",
1918+label: "Approval panel",
1919+leakedRegistryField: true,
1920+},
1921+],
1922+}),
1923+).toBe(false);
1924+});
1925+1926+it("projects plugin UI descriptors through the strict gateway result shape", () => {
1927+const { config, registry } = createPluginRegistryFixture();
1928+registerTestPlugin({
1929+ registry,
1930+ config,
1931+record: createPluginRecord({
1932+id: "host-hook-fixture",
1933+name: "Host Hook Fixture",
1934+}),
1935+register(api) {
1936+api.registerControlUiDescriptor({
1937+id: "approval-panel",
1938+surface: "session",
1939+label: "Approval panel",
1940+});
1941+},
1942+});
1943+const descriptorEntry = registry.registry.controlUiDescriptors?.[0];
1944+if (!descriptorEntry) {
1945+throw new Error("expected control UI descriptor registration");
1946+}
1947+Object.assign(descriptorEntry.descriptor, { leakedRegistryField: true });
1948+setActivePluginRegistry(registry.registry);
1949+1950+const calls: Array<[boolean, unknown, unknown]> = [];
1951+void pluginHostHookHandlers["plugins.uiDescriptors"]({
1952+params: {},
1953+respond: (ok: boolean, payload: unknown, error: unknown) => {
1954+calls.push([ok, payload, error]);
1955+},
1956+} as never);
1957+1958+expect(calls).toHaveLength(1);
1959+const [ok, payload, error] = calls[0] ?? [];
1960+expect(ok).toBe(true);
1961+expect(error).toBeUndefined();
1962+expect(validatePluginsUiDescriptorsResult(payload)).toBe(true);
1963+expect(payload).toEqual({
1964+ok: true,
1965+descriptors: [
1966+{
1967+id: "approval-panel",
1968+pluginId: "host-hook-fixture",
1969+pluginName: "Host Hook Fixture",
1970+surface: "session",
1971+label: "Approval panel",
1972+},
1973+],
1974+});
18951975});
1896197618971977it("enforces command requiredScopes for gateway clients and command owners", async () => {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。