mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
f44c5e2e5e
Use a manifest-first inventory with independent coverage for manifest-only bundled capabilities. Retire the undocumented thread-ownership plugin while Doctor removes stale references. Document Talk voice and persist only provider-scoped voice selection. Closes #121353
83 lines
2.6 KiB
TypeScript
83 lines
2.6 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
assertPluginInventoryCoverage,
|
|
resolvePluginSurface,
|
|
} from "../../scripts/lib/plugin-inventory-doc.mts";
|
|
|
|
describe("resolvePluginSurface", () => {
|
|
it("keeps manifest identifiers as inline code while leaving labels visible", () => {
|
|
expect(
|
|
resolvePluginSurface({
|
|
id: "example",
|
|
channels: ["discord"],
|
|
providers: ["openai"],
|
|
contracts: {
|
|
webSearchProviders: {},
|
|
tools: {},
|
|
},
|
|
dashboard: {
|
|
dataBindings: [{ id: "items.list" }],
|
|
actionVerbs: [{ id: "refresh" }],
|
|
},
|
|
skills: ["example"],
|
|
}),
|
|
).toBe(
|
|
"channels: `discord`; providers: `openai`; contracts: `tools`, `webSearchProviders`; dashboard data bindings: `example.items.list`; dashboard action verbs: `example.refresh`; skills",
|
|
);
|
|
});
|
|
|
|
it("retains the generic fallback", () => {
|
|
expect(resolvePluginSurface({})).toBe("plugin");
|
|
});
|
|
|
|
it("renders only runtime slash command aliases", () => {
|
|
expect(
|
|
resolvePluginSurface({
|
|
commandAliases: [
|
|
{ name: "voice", kind: "runtime-slash" },
|
|
{ name: "internal", kind: "activation-only" },
|
|
],
|
|
}),
|
|
).toBe("commands: `/voice`");
|
|
});
|
|
|
|
it("escapes dashboard plugin owner delimiters and literal escape markers", () => {
|
|
expect(
|
|
resolvePluginSurface({
|
|
id: "dashboard.segmented",
|
|
dashboard: { actionVerbs: [{ id: "refresh" }] },
|
|
}),
|
|
).toBe("dashboard action verbs: `dashboard%2Esegmented.refresh`");
|
|
expect(
|
|
resolvePluginSurface({
|
|
id: "dashboard%2Esegmented",
|
|
dashboard: { dataBindings: [{ id: "refresh" }] },
|
|
}),
|
|
).toBe("dashboard data bindings: `dashboard%252Esegmented.refresh`");
|
|
});
|
|
});
|
|
|
|
describe("assertPluginInventoryCoverage", () => {
|
|
it("detects a manifest directory omitted from the collected source entries", () => {
|
|
expect(() =>
|
|
assertPluginInventoryCoverage(
|
|
[{ dirName: "packaged", id: "packaged" }],
|
|
[
|
|
{ dirName: "manifest-only", id: "manifest-only" },
|
|
{ dirName: "packaged", id: "packaged" },
|
|
],
|
|
),
|
|
).toThrow(/missing dirNames: manifest-only.*missing ids: manifest-only/u);
|
|
});
|
|
|
|
it("detects duplicate ids in the independent manifest enumeration", () => {
|
|
const entries = [
|
|
{ dirName: "one", id: "duplicate" },
|
|
{ dirName: "two", id: "duplicate" },
|
|
];
|
|
expect(() => assertPluginInventoryCoverage(entries, entries)).toThrow(
|
|
"duplicate manifest ids: duplicate",
|
|
);
|
|
});
|
|
});
|