Vendor OpenClaw source as Adolf fork baseline
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled
Adolf is a fork/vendored clone of github.com/openclaw/openclaw (v2026.6.11), free to diverge. Tree copied sans upstream .git; upstream remote added for future syncs. Node pinned to 24 (.nvmrc); engines already require >=22.19. Preserves docs/ARCHITECTURE.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
This commit is contained in:
343
test/official-channel-catalog.test.ts
Normal file
343
test/official-channel-catalog.test.ts
Normal file
@@ -0,0 +1,343 @@
|
||||
// Official channel catalog tests validate catalog metadata and entries.
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { bundledPluginRoot } from "openclaw/plugin-sdk/test-fixtures";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import {
|
||||
buildOfficialChannelCatalog,
|
||||
OFFICIAL_CHANNEL_CATALOG_RELATIVE_PATH,
|
||||
writeOfficialChannelCatalog,
|
||||
} from "../scripts/write-official-channel-catalog.mjs";
|
||||
import { describePluginInstallSource } from "../src/plugins/install-source-info.js";
|
||||
import { cleanupTempDirs, makeTempRepoRoot, writeJsonFile } from "./helpers/temp-repo.js";
|
||||
|
||||
const tempDirs: string[] = [];
|
||||
|
||||
type OfficialChannelCatalogEntry = ReturnType<
|
||||
typeof buildOfficialChannelCatalog
|
||||
>["entries"][number];
|
||||
type OfficialChannelInstall = NonNullable<
|
||||
NonNullable<OfficialChannelCatalogEntry["openclaw"]>["install"]
|
||||
>;
|
||||
|
||||
function makeRepoRoot(prefix: string): string {
|
||||
return makeTempRepoRoot(tempDirs, prefix);
|
||||
}
|
||||
|
||||
function writeJson(filePath: string, value: unknown): void {
|
||||
writeJsonFile(filePath, value);
|
||||
}
|
||||
|
||||
function requireInstall(entry: OfficialChannelCatalogEntry | undefined): OfficialChannelInstall {
|
||||
const install = entry?.openclaw?.install;
|
||||
if (!install) {
|
||||
throw new Error("expected official channel install config");
|
||||
}
|
||||
return install;
|
||||
}
|
||||
|
||||
function requireNpmInstallSource(source: ReturnType<typeof describePluginInstallSource>) {
|
||||
if (!source.npm) {
|
||||
throw new Error("expected npm install source");
|
||||
}
|
||||
return source.npm;
|
||||
}
|
||||
|
||||
function findCatalogEntry(
|
||||
entries: OfficialChannelCatalogEntry[],
|
||||
predicate: (entry: OfficialChannelCatalogEntry) => boolean,
|
||||
): OfficialChannelCatalogEntry {
|
||||
const entry = entries.find(predicate);
|
||||
if (!entry) {
|
||||
throw new Error("expected official channel catalog entry");
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
function summarizeCatalogEntry(entry: OfficialChannelCatalogEntry) {
|
||||
return {
|
||||
name: entry.name,
|
||||
description: entry.description,
|
||||
source: entry.source,
|
||||
plugin: entry.openclaw?.plugin,
|
||||
channel: entry.openclaw?.channel,
|
||||
install: entry.openclaw?.install,
|
||||
};
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
cleanupTempDirs(tempDirs);
|
||||
});
|
||||
|
||||
describe("buildOfficialChannelCatalog", () => {
|
||||
it("includes publishable official channel plugins and skips non-publishable entries", () => {
|
||||
const repoRoot = makeRepoRoot("openclaw-official-channel-catalog-");
|
||||
writeJson(path.join(repoRoot, "extensions", "whatsapp", "package.json"), {
|
||||
name: "@openclaw/whatsapp",
|
||||
version: "2026.3.23",
|
||||
description: "OpenClaw WhatsApp channel plugin",
|
||||
openclaw: {
|
||||
channel: {
|
||||
id: "whatsapp",
|
||||
label: "WhatsApp",
|
||||
selectionLabel: "WhatsApp (QR link)",
|
||||
detailLabel: "WhatsApp Web",
|
||||
docsPath: "/channels/whatsapp",
|
||||
blurb: "works with your own number; recommend a separate phone + eSIM.",
|
||||
},
|
||||
install: {
|
||||
clawhubSpec: "clawhub:@openclaw/whatsapp",
|
||||
npmSpec: "@openclaw/whatsapp",
|
||||
localPath: bundledPluginRoot("whatsapp"),
|
||||
defaultChoice: "clawhub",
|
||||
},
|
||||
release: {
|
||||
publishToNpm: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
writeJson(path.join(repoRoot, "extensions", "local-only", "package.json"), {
|
||||
name: "@openclaw/local-only",
|
||||
openclaw: {
|
||||
channel: {
|
||||
id: "local-only",
|
||||
label: "Local Only",
|
||||
selectionLabel: "Local Only",
|
||||
docsPath: "/channels/local-only",
|
||||
blurb: "dev only",
|
||||
},
|
||||
install: {
|
||||
localPath: bundledPluginRoot("local-only"),
|
||||
},
|
||||
release: {
|
||||
publishToNpm: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const entries = buildOfficialChannelCatalog({ repoRoot }).entries;
|
||||
|
||||
expect(
|
||||
summarizeCatalogEntry(
|
||||
findCatalogEntry(entries, (entry) => entry.name === "@wecom/wecom-openclaw-plugin"),
|
||||
),
|
||||
).toEqual({
|
||||
name: "@wecom/wecom-openclaw-plugin",
|
||||
description: "OpenClaw WeCom channel plugin by the Tencent WeCom team.",
|
||||
source: "external",
|
||||
plugin: {
|
||||
id: "wecom-openclaw-plugin",
|
||||
label: "WeCom",
|
||||
},
|
||||
channel: {
|
||||
id: "wecom",
|
||||
label: "WeCom",
|
||||
selectionLabel: "WeCom(企业微信)",
|
||||
detailLabel: "WeCom",
|
||||
docsLabel: "wecom",
|
||||
docsPath: "/plugins/community#wecom",
|
||||
blurb: "Enterprise messaging and documents, scheduling, task tools.",
|
||||
order: 45,
|
||||
aliases: ["qywx", "wework", "enterprise-wechat"],
|
||||
},
|
||||
install: {
|
||||
npmSpec: "@wecom/wecom-openclaw-plugin@2026.5.7",
|
||||
defaultChoice: "npm",
|
||||
expectedIntegrity:
|
||||
"sha512-TCkP9as00WfEhgFWG8YL/rcmaWGIshAki2HQh83nTRccGfVBCoGjrEboTTqq3yDmK9koWTV11zi8u8A4dNtvug==",
|
||||
},
|
||||
});
|
||||
expect(
|
||||
summarizeCatalogEntry(
|
||||
findCatalogEntry(entries, (entry) => entry.name === "openclaw-plugin-yuanbao"),
|
||||
),
|
||||
).toEqual({
|
||||
name: "openclaw-plugin-yuanbao",
|
||||
description: "OpenClaw Yuanbao channel plugin by the Tencent Yuanbao team.",
|
||||
source: "external",
|
||||
plugin: {
|
||||
id: "openclaw-plugin-yuanbao",
|
||||
label: "Yuanbao",
|
||||
},
|
||||
channel: {
|
||||
id: "yuanbao",
|
||||
label: "Yuanbao",
|
||||
selectionLabel: "Yuanbao (元宝)",
|
||||
detailLabel: "Yuanbao",
|
||||
docsLabel: "yuanbao",
|
||||
docsPath: "/plugins/community#yuanbao",
|
||||
blurb: "Tencent Yuanbao AI assistant conversation channel.",
|
||||
order: 85,
|
||||
aliases: ["yuanbao", "yb", "tencent-yuanbao", "元宝"],
|
||||
},
|
||||
install: {
|
||||
npmSpec: "openclaw-plugin-yuanbao@2.15.0",
|
||||
defaultChoice: "npm",
|
||||
expectedIntegrity:
|
||||
"sha512-3GD+mf3EjTSUTOAREjTHAyp/deXdpgqB+q+xE0b19Qtat4ADhUV1mHDwFkVCRqTCBY5ATFKtKcipoDejqFj/+w==",
|
||||
},
|
||||
});
|
||||
expect(
|
||||
summarizeCatalogEntry(
|
||||
findCatalogEntry(entries, (entry) => entry.name === "@openclaw/whatsapp"),
|
||||
),
|
||||
).toEqual({
|
||||
name: "@openclaw/whatsapp",
|
||||
description: "OpenClaw WhatsApp channel plugin",
|
||||
source: "official",
|
||||
plugin: undefined,
|
||||
channel: {
|
||||
id: "whatsapp",
|
||||
label: "WhatsApp",
|
||||
selectionLabel: "WhatsApp (QR link)",
|
||||
detailLabel: "WhatsApp Web",
|
||||
docsLabel: "whatsapp",
|
||||
docsPath: "/channels/whatsapp",
|
||||
blurb: "works with your own number; recommend a separate phone + eSIM.",
|
||||
systemImage: "message",
|
||||
},
|
||||
install: {
|
||||
clawhubSpec: "clawhub:@openclaw/whatsapp",
|
||||
npmSpec: "@openclaw/whatsapp",
|
||||
defaultChoice: "clawhub",
|
||||
minHostVersion: ">=2026.4.25",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps third-party official external catalog npm sources exactly pinned", () => {
|
||||
const repoRoot = makeRepoRoot("openclaw-official-channel-catalog-policy-");
|
||||
const entries = buildOfficialChannelCatalog({ repoRoot }).entries.filter(
|
||||
(entry) => entry.source === "external" && !entry.name?.startsWith("@openclaw/"),
|
||||
);
|
||||
|
||||
expect(entries.length).toBeGreaterThan(0);
|
||||
for (const entry of entries) {
|
||||
const installSource = describePluginInstallSource(requireInstall(entry));
|
||||
expect(installSource.warnings).toStrictEqual([]);
|
||||
expect(requireNpmInstallSource(installSource).pinState).toBe("exact-with-integrity");
|
||||
}
|
||||
});
|
||||
|
||||
it("allows official OpenClaw channel npm specs without integrity during launch", () => {
|
||||
const repoRoot = makeRepoRoot("openclaw-official-channel-catalog-openclaw-policy-");
|
||||
const twitch = buildOfficialChannelCatalog({ repoRoot }).entries.find(
|
||||
(entry) => entry.openclaw?.channel?.id === "twitch",
|
||||
);
|
||||
|
||||
expect({
|
||||
name: twitch?.name,
|
||||
install: twitch?.openclaw?.install,
|
||||
}).toEqual({
|
||||
name: "@openclaw/twitch",
|
||||
install: {
|
||||
npmSpec: "@openclaw/twitch",
|
||||
defaultChoice: "npm",
|
||||
minHostVersion: ">=2026.4.10",
|
||||
},
|
||||
});
|
||||
const installSource = describePluginInstallSource(requireInstall(twitch));
|
||||
expect(requireNpmInstallSource(installSource).pinState).toBe("floating-without-integrity");
|
||||
expect(installSource.warnings).toEqual(["npm-spec-floating", "npm-spec-missing-integrity"]);
|
||||
});
|
||||
|
||||
it("preserves ClawHub specs when generating publishable channel catalog entries", () => {
|
||||
const repoRoot = makeRepoRoot("openclaw-official-channel-catalog-clawhub-");
|
||||
writeJson(path.join(repoRoot, "extensions", "storepack-chat", "package.json"), {
|
||||
name: "@openclaw/storepack-chat",
|
||||
openclaw: {
|
||||
channel: {
|
||||
id: "storepack-chat",
|
||||
label: "Storepack Chat",
|
||||
selectionLabel: "Storepack Chat",
|
||||
docsPath: "/channels/storepack-chat",
|
||||
blurb: "storepack-first channel",
|
||||
},
|
||||
install: {
|
||||
clawhubSpec: "clawhub:@openclaw/storepack-chat",
|
||||
npmSpec: "@openclaw/storepack-chat",
|
||||
defaultChoice: "clawhub",
|
||||
},
|
||||
release: {
|
||||
publishToNpm: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const entry = buildOfficialChannelCatalog({ repoRoot }).entries.find(
|
||||
(candidate) => candidate.openclaw?.channel?.id === "storepack-chat",
|
||||
);
|
||||
|
||||
expect(requireInstall(entry)).toEqual({
|
||||
clawhubSpec: "clawhub:@openclaw/storepack-chat",
|
||||
npmSpec: "@openclaw/storepack-chat",
|
||||
defaultChoice: "clawhub",
|
||||
});
|
||||
});
|
||||
|
||||
it("writes the official catalog under dist", () => {
|
||||
const repoRoot = makeRepoRoot("openclaw-official-channel-catalog-write-");
|
||||
writeJson(path.join(repoRoot, "extensions", "whatsapp", "package.json"), {
|
||||
name: "@openclaw/whatsapp",
|
||||
openclaw: {
|
||||
channel: {
|
||||
id: "whatsapp",
|
||||
label: "WhatsApp",
|
||||
selectionLabel: "WhatsApp",
|
||||
docsPath: "/channels/whatsapp",
|
||||
blurb: "wa",
|
||||
},
|
||||
install: {
|
||||
npmSpec: "@openclaw/whatsapp",
|
||||
},
|
||||
release: {
|
||||
publishToNpm: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
writeOfficialChannelCatalog({ repoRoot });
|
||||
|
||||
const outputPath = path.join(repoRoot, OFFICIAL_CHANNEL_CATALOG_RELATIVE_PATH);
|
||||
expect(fs.existsSync(outputPath)).toBe(true);
|
||||
const entries = JSON.parse(fs.readFileSync(outputPath, "utf8")).entries;
|
||||
expect(entries.map((entry: { name?: string }) => entry.name)).toContain(
|
||||
"@wecom/wecom-openclaw-plugin",
|
||||
);
|
||||
expect(entries.map((entry: { name?: string }) => entry.name)).toContain(
|
||||
"openclaw-plugin-yuanbao",
|
||||
);
|
||||
const whatsappEntry = findCatalogEntry(
|
||||
entries,
|
||||
(entry: { openclaw?: { channel?: { id?: string } } }) =>
|
||||
entry.openclaw?.channel?.id === "whatsapp",
|
||||
);
|
||||
expect(summarizeCatalogEntry(whatsappEntry)).toEqual({
|
||||
name: "@openclaw/whatsapp",
|
||||
description: "OpenClaw WhatsApp channel plugin",
|
||||
source: "official",
|
||||
plugin: undefined,
|
||||
channel: {
|
||||
id: "whatsapp",
|
||||
label: "WhatsApp",
|
||||
selectionLabel: "WhatsApp (QR link)",
|
||||
detailLabel: "WhatsApp Web",
|
||||
docsLabel: "whatsapp",
|
||||
docsPath: "/channels/whatsapp",
|
||||
blurb: "works with your own number; recommend a separate phone + eSIM.",
|
||||
systemImage: "message",
|
||||
},
|
||||
install: {
|
||||
clawhubSpec: "clawhub:@openclaw/whatsapp",
|
||||
npmSpec: "@openclaw/whatsapp",
|
||||
defaultChoice: "clawhub",
|
||||
minHostVersion: ">=2026.4.25",
|
||||
},
|
||||
});
|
||||
const whatsappEntries = entries.filter(
|
||||
(entry: { openclaw?: { channel?: { id?: string } } }) =>
|
||||
entry.openclaw?.channel?.id === "whatsapp",
|
||||
);
|
||||
expect(whatsappEntries).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user