mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-06 23:55:12 +00:00
ci: externalize more channel plugins
This commit is contained in:
@@ -9,6 +9,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Tools: add a platform-level tool descriptor planner for descriptor-first visibility, generic availability checks, and executor references. Thanks @shakkernerd.
|
||||
- Docs/Codex: clarify that ChatGPT/Codex subscription setups should use `openai/gpt-*` with `agentRuntime.id: "codex"` for native Codex runtime, while `openai-codex/*` remains the PI OAuth route. Thanks @pashpashpash.
|
||||
- Plugins/source checkout: load bundled plugins from the `extensions/*` pnpm workspace tree in source checkouts, so plugin-local dependencies and edits are used directly while packaged installs keep using the built runtime tree. Thanks @vincentkoc.
|
||||
- Plugins/beta: prepare Google Chat, LINE, Matrix, and Mattermost for `2026.5.1-beta.2` npm and ClawHub publishing, and keep publishable plugin dist trees out of the core npm package. Thanks @vincentkoc.
|
||||
- Plugins/beta: prepare BlueBubbles, diagnostics Prometheus, Google Meet, Nextcloud Talk, Nostr, Zalo, and Zalo Personal for `2026.5.1-beta.2` npm and ClawHub publishing. Thanks @vincentkoc.
|
||||
- Plugins/beta: prepare diagnostics OpenTelemetry, Discord, Diffs, Lobster, Memory LanceDB, Microsoft Teams, QQ Bot, Voice Call, and WhatsApp for `2026.5.1-beta.1` npm and ClawHub publishing. Thanks @vincentkoc.
|
||||
- Plugins/beta: prepare Brave, Codex, Feishu, Synology Chat, Tlon, and Twitch for `2026.5.1-beta.1` npm and ClawHub publishing. Thanks @vincentkoc.
|
||||
|
||||
@@ -5,7 +5,21 @@ read_when:
|
||||
title: "Google Chat"
|
||||
---
|
||||
|
||||
Status: ready for DMs + spaces via Google Chat API webhooks (HTTP only).
|
||||
Status: downloadable plugin for DMs + spaces via Google Chat API webhooks (HTTP only).
|
||||
|
||||
## Install
|
||||
|
||||
Install Google Chat before configuring the channel:
|
||||
|
||||
```bash
|
||||
openclaw plugins install @openclaw/googlechat
|
||||
```
|
||||
|
||||
Local checkout (when running from a git repo):
|
||||
|
||||
```bash
|
||||
openclaw plugins install ./path/to/local/googlechat-plugin
|
||||
```
|
||||
|
||||
## Quick setup (beginner)
|
||||
|
||||
|
||||
@@ -24,12 +24,12 @@ Text is supported everywhere; media and reactions vary by channel.
|
||||
- [BlueBubbles](/channels/bluebubbles) — **Recommended for iMessage**; uses the BlueBubbles macOS server REST API with full feature support (bundled plugin; edit, unsend, effects, reactions, group management — edit currently broken on macOS 26 Tahoe).
|
||||
- [Discord](/channels/discord) — Discord Bot API + Gateway; supports servers, channels, and DMs.
|
||||
- [Feishu](/channels/feishu) — Feishu/Lark bot via WebSocket (bundled plugin).
|
||||
- [Google Chat](/channels/googlechat) — Google Chat API app via HTTP webhook.
|
||||
- [Google Chat](/channels/googlechat) — Google Chat API app via HTTP webhook (downloadable plugin).
|
||||
- [iMessage (legacy)](/channels/imessage) — Legacy macOS integration via imsg CLI (deprecated, use BlueBubbles for new setups).
|
||||
- [IRC](/channels/irc) — Classic IRC servers; channels + DMs with pairing/allowlist controls.
|
||||
- [LINE](/channels/line) — LINE Messaging API bot (bundled plugin).
|
||||
- [Matrix](/channels/matrix) — Matrix protocol (bundled plugin).
|
||||
- [Mattermost](/channels/mattermost) — Bot API + WebSocket; channels, groups, DMs (bundled plugin).
|
||||
- [LINE](/channels/line) — LINE Messaging API bot (downloadable plugin).
|
||||
- [Matrix](/channels/matrix) — Matrix protocol (downloadable plugin).
|
||||
- [Mattermost](/channels/mattermost) — Bot API + WebSocket; channels, groups, DMs (downloadable plugin).
|
||||
- [Microsoft Teams](/channels/msteams) — Bot Framework; enterprise support (bundled plugin).
|
||||
- [Nextcloud Talk](/channels/nextcloud-talk) — Self-hosted chat via Nextcloud Talk (bundled plugin).
|
||||
- [Nostr](/channels/nostr) — Decentralized DMs via NIP-04 (bundled plugin).
|
||||
|
||||
@@ -11,26 +11,18 @@ LINE connects to OpenClaw via the LINE Messaging API. The plugin runs as a webho
|
||||
receiver on the gateway and uses your channel access token + channel secret for
|
||||
authentication.
|
||||
|
||||
Status: bundled plugin. Direct messages, group chats, media, locations, Flex
|
||||
Status: downloadable plugin. Direct messages, group chats, media, locations, Flex
|
||||
messages, template messages, and quick replies are supported. Reactions and threads
|
||||
are not supported.
|
||||
|
||||
## Bundled plugin
|
||||
## Install
|
||||
|
||||
LINE ships as a bundled plugin in current OpenClaw releases, so normal
|
||||
packaged builds do not need a separate install.
|
||||
|
||||
If you are on an older build or a custom install that excludes LINE, install a
|
||||
current npm package when one is published:
|
||||
Install LINE before configuring the channel:
|
||||
|
||||
```bash
|
||||
openclaw plugins install @openclaw/line
|
||||
```
|
||||
|
||||
If npm reports the OpenClaw-owned package as deprecated or missing, use a
|
||||
current packaged OpenClaw build or a local checkout until the npm package train
|
||||
catches up.
|
||||
|
||||
Local checkout (when running from a git repo):
|
||||
|
||||
```bash
|
||||
|
||||
@@ -6,23 +6,17 @@ read_when:
|
||||
title: "Matrix"
|
||||
---
|
||||
|
||||
Matrix is a bundled channel plugin for OpenClaw.
|
||||
Matrix is a downloadable channel plugin for OpenClaw.
|
||||
It uses the official `matrix-js-sdk` and supports DMs, rooms, threads, media, reactions, polls, location, and E2EE.
|
||||
|
||||
## Bundled plugin
|
||||
## Install
|
||||
|
||||
Current packaged OpenClaw releases ship the Matrix plugin in the box. You do not need to install anything; configuring `channels.matrix.*` (see [Setup](#setup)) is what activates it.
|
||||
|
||||
For older builds or custom installs that exclude Matrix, install a current npm
|
||||
package when one is published:
|
||||
Install Matrix before configuring the channel:
|
||||
|
||||
```bash
|
||||
openclaw plugins install @openclaw/matrix
|
||||
```
|
||||
|
||||
If npm reports the OpenClaw-owned package as deprecated, use a current packaged
|
||||
OpenClaw build or a local checkout until a newer npm package is published.
|
||||
|
||||
From a local checkout:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -7,15 +7,11 @@ title: "Mattermost"
|
||||
sidebarTitle: "Mattermost"
|
||||
---
|
||||
|
||||
Status: bundled plugin (bot token + WebSocket events). Channels, groups, and DMs are supported. Mattermost is a self-hostable team messaging platform; see the official site at [mattermost.com](https://mattermost.com) for product details and downloads.
|
||||
Status: downloadable plugin (bot token + WebSocket events). Channels, groups, and DMs are supported. Mattermost is a self-hostable team messaging platform; see the official site at [mattermost.com](https://mattermost.com) for product details and downloads.
|
||||
|
||||
## Bundled plugin
|
||||
## Install
|
||||
|
||||
<Note>
|
||||
Mattermost ships as a bundled plugin in current OpenClaw releases, so normal packaged builds do not need a separate install.
|
||||
</Note>
|
||||
|
||||
If you are on an older build or a custom install that excludes Mattermost, install a current npm package when one is published:
|
||||
Install Mattermost before configuring the channel:
|
||||
|
||||
<Tabs>
|
||||
<Tab title="npm registry">
|
||||
@@ -30,10 +26,6 @@ If you are on an older build or a custom install that excludes Mattermost, insta
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
If npm reports the OpenClaw-owned package as deprecated, use a current packaged
|
||||
OpenClaw build or the local checkout path until a newer npm package is
|
||||
published.
|
||||
|
||||
Details: [Plugins](/tools/plugin)
|
||||
|
||||
## Quick setup
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
{
|
||||
"name": "@openclaw/googlechat",
|
||||
"version": "2026.4.25",
|
||||
"private": true,
|
||||
"version": "2026.5.1-beta.2",
|
||||
"description": "OpenClaw Google Chat channel plugin",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/openclaw/openclaw"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"gaxios": "7.1.4",
|
||||
@@ -70,6 +73,16 @@
|
||||
"npmSpec": "@openclaw/googlechat",
|
||||
"defaultChoice": "npm",
|
||||
"minHostVersion": ">=2026.4.10"
|
||||
},
|
||||
"compat": {
|
||||
"pluginApi": ">=2026.4.25"
|
||||
},
|
||||
"build": {
|
||||
"openclawVersion": "2026.5.1-beta.2"
|
||||
},
|
||||
"release": {
|
||||
"publishToClawHub": true,
|
||||
"publishToNpm": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
{
|
||||
"name": "@openclaw/line",
|
||||
"version": "2026.4.25",
|
||||
"private": true,
|
||||
"version": "2026.5.1-beta.2",
|
||||
"description": "OpenClaw LINE channel plugin",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/openclaw/openclaw"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@line/bot-sdk": "^11.0.0"
|
||||
@@ -40,6 +43,16 @@
|
||||
"npmSpec": "@openclaw/line",
|
||||
"defaultChoice": "npm",
|
||||
"minHostVersion": ">=2026.4.10"
|
||||
},
|
||||
"compat": {
|
||||
"pluginApi": ">=2026.4.25"
|
||||
},
|
||||
"build": {
|
||||
"openclawVersion": "2026.5.1-beta.2"
|
||||
},
|
||||
"release": {
|
||||
"publishToClawHub": true,
|
||||
"publishToNpm": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
{
|
||||
"name": "@openclaw/matrix",
|
||||
"version": "2026.4.25",
|
||||
"version": "2026.5.1-beta.2",
|
||||
"description": "OpenClaw Matrix channel plugin",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/openclaw/openclaw"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@matrix-org/matrix-sdk-crypto-nodejs": "^0.5.1",
|
||||
@@ -79,6 +83,16 @@
|
||||
"defaultChoice": "npm",
|
||||
"minHostVersion": ">=2026.4.10",
|
||||
"allowInvalidConfigRecovery": true
|
||||
},
|
||||
"compat": {
|
||||
"pluginApi": ">=2026.4.25"
|
||||
},
|
||||
"build": {
|
||||
"openclawVersion": "2026.5.1-beta.2"
|
||||
},
|
||||
"release": {
|
||||
"publishToClawHub": true,
|
||||
"publishToNpm": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
{
|
||||
"name": "@openclaw/mattermost",
|
||||
"version": "2026.4.25",
|
||||
"version": "2026.5.1-beta.2",
|
||||
"description": "OpenClaw Mattermost channel plugin",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/openclaw/openclaw"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"ws": "^8.20.0"
|
||||
@@ -36,6 +40,16 @@
|
||||
"npmSpec": "@openclaw/mattermost",
|
||||
"defaultChoice": "npm",
|
||||
"minHostVersion": ">=2026.4.10"
|
||||
},
|
||||
"compat": {
|
||||
"pluginApi": ">=2026.4.25"
|
||||
},
|
||||
"build": {
|
||||
"openclawVersion": "2026.5.1-beta.2"
|
||||
},
|
||||
"release": {
|
||||
"publishToClawHub": true,
|
||||
"publishToNpm": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
26
package.json
26
package.json
@@ -33,9 +33,35 @@
|
||||
"!dist/plugin-sdk/.tsbuildinfo",
|
||||
"!dist/extensions/node_modules/**",
|
||||
"!dist/extensions/*/node_modules/**",
|
||||
"!dist/extensions/bluebubbles/**",
|
||||
"!dist/extensions/brave/**",
|
||||
"!dist/extensions/codex/**",
|
||||
"!dist/extensions/diagnostics-otel/**",
|
||||
"!dist/extensions/diagnostics-prometheus/**",
|
||||
"!dist/extensions/diffs/**",
|
||||
"!dist/extensions/discord/**",
|
||||
"!dist/extensions/feishu/**",
|
||||
"!dist/extensions/google-meet/**",
|
||||
"!dist/extensions/googlechat/**",
|
||||
"!dist/extensions/line/**",
|
||||
"!dist/extensions/lobster/**",
|
||||
"!dist/extensions/matrix/**",
|
||||
"!dist/extensions/mattermost/**",
|
||||
"!dist/extensions/memory-lancedb/**",
|
||||
"!dist/extensions/msteams/**",
|
||||
"!dist/extensions/nextcloud-talk/**",
|
||||
"!dist/extensions/nostr/**",
|
||||
"!dist/extensions/qqbot/**",
|
||||
"!dist/extensions/qa-channel/**",
|
||||
"!dist/extensions/qa-lab/**",
|
||||
"!dist/extensions/qa-matrix/**",
|
||||
"!dist/extensions/synology-chat/**",
|
||||
"!dist/extensions/tlon/**",
|
||||
"!dist/extensions/twitch/**",
|
||||
"!dist/extensions/voice-call/**",
|
||||
"!dist/extensions/whatsapp/**",
|
||||
"!dist/extensions/zalo/**",
|
||||
"!dist/extensions/zalouser/**",
|
||||
"!dist/plugin-sdk/extensions/qa-channel/**",
|
||||
"!dist/plugin-sdk/extensions/qa-lab/**",
|
||||
"!dist/plugin-sdk/qa-channel.*",
|
||||
|
||||
@@ -187,6 +187,69 @@ describe("package dist inventory", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps publishable externalized bundled plugin dist trees out of the inventory", async () => {
|
||||
await withTempDir({ prefix: "openclaw-dist-inventory-externalized-" }, async (packageRoot) => {
|
||||
const externalizedRuntime = path.join(
|
||||
packageRoot,
|
||||
"dist",
|
||||
"extensions",
|
||||
"external-chat",
|
||||
"index.js",
|
||||
);
|
||||
const bundledRuntime = path.join(
|
||||
packageRoot,
|
||||
"dist",
|
||||
"extensions",
|
||||
"bundled-chat",
|
||||
"index.js",
|
||||
);
|
||||
const externalizedPackageJson = path.join(
|
||||
packageRoot,
|
||||
"extensions",
|
||||
"external-chat",
|
||||
"package.json",
|
||||
);
|
||||
const bundledPackageJson = path.join(
|
||||
packageRoot,
|
||||
"extensions",
|
||||
"bundled-chat",
|
||||
"package.json",
|
||||
);
|
||||
|
||||
await fs.mkdir(path.dirname(externalizedRuntime), { recursive: true });
|
||||
await fs.mkdir(path.dirname(bundledRuntime), { recursive: true });
|
||||
await fs.mkdir(path.dirname(externalizedPackageJson), { recursive: true });
|
||||
await fs.mkdir(path.dirname(bundledPackageJson), { recursive: true });
|
||||
await fs.writeFile(externalizedRuntime, "export {};\n", "utf8");
|
||||
await fs.writeFile(bundledRuntime, "export {};\n", "utf8");
|
||||
await fs.writeFile(
|
||||
externalizedPackageJson,
|
||||
JSON.stringify({
|
||||
name: "@openclaw/external-chat",
|
||||
openclaw: {
|
||||
release: {
|
||||
publishToClawHub: true,
|
||||
publishToNpm: true,
|
||||
},
|
||||
},
|
||||
}),
|
||||
"utf8",
|
||||
);
|
||||
await fs.writeFile(
|
||||
bundledPackageJson,
|
||||
JSON.stringify({
|
||||
name: "@openclaw/bundled-chat",
|
||||
openclaw: {},
|
||||
}),
|
||||
"utf8",
|
||||
);
|
||||
|
||||
await expect(writePackageDistInventory(packageRoot)).resolves.toEqual([
|
||||
"dist/extensions/bundled-chat/index.js",
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it("reports runtime-created install staging dirs during installed dist verification", async () => {
|
||||
await withTempDir({ prefix: "openclaw-dist-inventory-stage-" }, async (packageRoot) => {
|
||||
const realFile = path.join(packageRoot, "dist", "real-AbC123.js");
|
||||
|
||||
@@ -39,6 +39,7 @@ const OMITTED_DIST_SUBTREE_PATTERNS = [
|
||||
new RegExp(`^dist/plugin-sdk/extensions/${LEGACY_QA_LAB_DIR}(?:/|$)`, "u"),
|
||||
] as const;
|
||||
const INSTALL_STAGE_DEBRIS_DIR_PATTERN = /^\.openclaw-install-stage(?:-[^/]+)?$/iu;
|
||||
type ExternalizedBundledExtensionIds = ReadonlySet<string>;
|
||||
|
||||
function normalizeRelativePath(value: string): string {
|
||||
return value.replace(/\\/g, "/");
|
||||
@@ -74,10 +75,86 @@ export function isLegacyPluginDependencyInstallStagePath(relativePath: string):
|
||||
);
|
||||
}
|
||||
|
||||
function isPackagedDistPath(relativePath: string): boolean {
|
||||
function isExternalizedBundledExtensionDistPath(
|
||||
relativePath: string,
|
||||
externalizedExtensionIds: ExternalizedBundledExtensionIds,
|
||||
): boolean {
|
||||
if (externalizedExtensionIds.size === 0) {
|
||||
return false;
|
||||
}
|
||||
const parts = normalizeRelativePath(relativePath).split("/");
|
||||
return (
|
||||
parts.length >= 3 &&
|
||||
parts[0] === "dist" &&
|
||||
parts[1] === "extensions" &&
|
||||
Boolean(parts[2]) &&
|
||||
externalizedExtensionIds.has(parts[2] ?? "")
|
||||
);
|
||||
}
|
||||
|
||||
function isPublishableExternalizedBundledManifest(value: unknown): boolean {
|
||||
if (!value || typeof value !== "object") {
|
||||
return false;
|
||||
}
|
||||
const openclaw = (value as { openclaw?: unknown }).openclaw;
|
||||
if (!openclaw || typeof openclaw !== "object") {
|
||||
return false;
|
||||
}
|
||||
const release = (openclaw as { release?: unknown }).release;
|
||||
if (!release || typeof release !== "object") {
|
||||
return false;
|
||||
}
|
||||
const typedRelease = release as { publishToClawHub?: unknown; publishToNpm?: unknown };
|
||||
return typedRelease.publishToNpm === true || typedRelease.publishToClawHub === true;
|
||||
}
|
||||
|
||||
async function collectExternalizedBundledExtensionIds(
|
||||
packageRoot: string,
|
||||
): Promise<ExternalizedBundledExtensionIds> {
|
||||
const extensionsDir = path.join(packageRoot, "extensions");
|
||||
let entries: import("node:fs").Dirent[];
|
||||
try {
|
||||
entries = await fs.readdir(extensionsDir, { withFileTypes: true });
|
||||
} catch (error) {
|
||||
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
|
||||
return new Set();
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
const ids = new Set<string>();
|
||||
await Promise.all(
|
||||
entries.map(async (entry) => {
|
||||
if (!entry.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
const packageJsonPath = path.join(extensionsDir, entry.name, "package.json");
|
||||
try {
|
||||
const parsed = JSON.parse(await fs.readFile(packageJsonPath, "utf8")) as unknown;
|
||||
if (isPublishableExternalizedBundledManifest(parsed)) {
|
||||
ids.add(entry.name);
|
||||
}
|
||||
} catch (error) {
|
||||
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
|
||||
return;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}),
|
||||
);
|
||||
return ids;
|
||||
}
|
||||
|
||||
function isPackagedDistPath(
|
||||
relativePath: string,
|
||||
externalizedExtensionIds: ExternalizedBundledExtensionIds,
|
||||
): boolean {
|
||||
if (!relativePath.startsWith("dist/")) {
|
||||
return false;
|
||||
}
|
||||
if (isExternalizedBundledExtensionDistPath(relativePath, externalizedExtensionIds)) {
|
||||
return false;
|
||||
}
|
||||
if (isLegacyPluginDependencyDirPath(relativePath)) {
|
||||
return false;
|
||||
}
|
||||
@@ -106,16 +183,24 @@ function isPackagedDistPath(relativePath: string): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
function isOmittedDistSubtree(relativePath: string): boolean {
|
||||
function isOmittedDistSubtree(
|
||||
relativePath: string,
|
||||
externalizedExtensionIds: ExternalizedBundledExtensionIds,
|
||||
): boolean {
|
||||
return (
|
||||
isExternalizedBundledExtensionDistPath(relativePath, externalizedExtensionIds) ||
|
||||
isLegacyPluginDependencyDirPath(relativePath) ||
|
||||
OMITTED_DIST_SUBTREE_PATTERNS.some((pattern) => pattern.test(relativePath))
|
||||
);
|
||||
}
|
||||
|
||||
async function collectRelativeFiles(rootDir: string, baseDir: string): Promise<string[]> {
|
||||
async function collectRelativeFiles(
|
||||
rootDir: string,
|
||||
baseDir: string,
|
||||
externalizedExtensionIds: ExternalizedBundledExtensionIds,
|
||||
): Promise<string[]> {
|
||||
const rootRelativePath = normalizeRelativePath(path.relative(baseDir, rootDir));
|
||||
if (rootRelativePath && isOmittedDistSubtree(rootRelativePath)) {
|
||||
if (rootRelativePath && isOmittedDistSubtree(rootRelativePath, externalizedExtensionIds)) {
|
||||
return [];
|
||||
}
|
||||
try {
|
||||
@@ -134,10 +219,10 @@ async function collectRelativeFiles(rootDir: string, baseDir: string): Promise<s
|
||||
throw new Error(`Unsafe package dist path: ${relativePath}`);
|
||||
}
|
||||
if (entry.isDirectory()) {
|
||||
return await collectRelativeFiles(entryPath, baseDir);
|
||||
return await collectRelativeFiles(entryPath, baseDir, externalizedExtensionIds);
|
||||
}
|
||||
if (entry.isFile()) {
|
||||
return isPackagedDistPath(relativePath) ? [relativePath] : [];
|
||||
return isPackagedDistPath(relativePath, externalizedExtensionIds) ? [relativePath] : [];
|
||||
}
|
||||
return [];
|
||||
}),
|
||||
@@ -152,7 +237,12 @@ async function collectRelativeFiles(rootDir: string, baseDir: string): Promise<s
|
||||
}
|
||||
|
||||
export async function collectPackageDistInventory(packageRoot: string): Promise<string[]> {
|
||||
return await collectRelativeFiles(path.join(packageRoot, "dist"), packageRoot);
|
||||
const externalizedExtensionIds = await collectExternalizedBundledExtensionIds(packageRoot);
|
||||
return await collectRelativeFiles(
|
||||
path.join(packageRoot, "dist"),
|
||||
packageRoot,
|
||||
externalizedExtensionIds,
|
||||
);
|
||||
}
|
||||
|
||||
export async function collectLegacyPluginDependencyStagingDebrisPaths(
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { mkdirSync } from "node:fs";
|
||||
import { mkdirSync, readFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { bundledPluginFile, bundledPluginRoot } from "openclaw/plugin-sdk/test-fixtures";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { collectClawHubPublishablePluginPackages } from "../scripts/lib/plugin-clawhub-release.ts";
|
||||
import {
|
||||
collectPublishablePluginPackages,
|
||||
collectChangedExtensionIdsFromPaths,
|
||||
@@ -155,6 +156,22 @@ describe("collectPublishablePluginPackageErrors", () => {
|
||||
});
|
||||
|
||||
describe("collectPublishablePluginPackages", () => {
|
||||
it("keeps publishable plugin dist trees out of the core npm package files list", () => {
|
||||
const rootPackage = JSON.parse(readFileSync("package.json", "utf8")) as {
|
||||
files?: unknown;
|
||||
};
|
||||
const packageFiles = new Set(Array.isArray(rootPackage.files) ? rootPackage.files : []);
|
||||
const publishablePlugins = [
|
||||
...collectPublishablePluginPackages(),
|
||||
...collectClawHubPublishablePluginPackages(),
|
||||
];
|
||||
const missingExclusions = Array.from(
|
||||
new Set(publishablePlugins.map((plugin) => `!dist/extensions/${plugin.extensionId}/**`)),
|
||||
).filter((entry) => !packageFiles.has(entry));
|
||||
|
||||
expect(missingExclusions).toEqual([]);
|
||||
});
|
||||
|
||||
it("collects publishable npm plugins from extension package manifests", () => {
|
||||
const repoDir = makeTempRepoRoot(tempDirs, "openclaw-plugin-npm-release-");
|
||||
mkdirSync(join(repoDir, "extensions", "demo-plugin"), { recursive: true });
|
||||
|
||||
Reference in New Issue
Block a user