diff --git a/package.json b/package.json index 86822b23bf1..cc6925725fa 100644 --- a/package.json +++ b/package.json @@ -292,6 +292,7 @@ "moltbot:rpc": "node scripts/run-node.mjs agent --mode rpc --json", "openclaw": "node scripts/run-node.mjs", "openclaw:rpc": "node scripts/run-node.mjs agent --mode rpc --json", + "plugin-sdk:sync-exports": "node scripts/sync-plugin-sdk-exports.mjs", "plugins:sync": "node --import tsx scripts/sync-plugin-versions.ts", "prepack": "pnpm build && pnpm ui:build", "prepare": "command -v git >/dev/null 2>&1 && git rev-parse --is-inside-work-tree >/dev/null 2>&1 && git config core.hooksPath git-hooks || exit 0", diff --git a/scripts/check-plugin-sdk-exports.mjs b/scripts/check-plugin-sdk-exports.mjs index 93fc3fcb545..60c89056ca0 100755 --- a/scripts/check-plugin-sdk-exports.mjs +++ b/scripts/check-plugin-sdk-exports.mjs @@ -11,6 +11,7 @@ import { readFileSync, existsSync } from "node:fs"; import { resolve, dirname } from "node:path"; import { fileURLToPath } from "node:url"; +import { pluginSdkSubpaths } from "./lib/plugin-sdk-entries.mjs"; const __dirname = dirname(fileURLToPath(import.meta.url)); const distFile = resolve(__dirname, "..", "dist", "plugin-sdk", "index.js"); @@ -41,51 +42,6 @@ const exportedNames = exportMatch[1] const exportSet = new Set(exportedNames); -const requiredSubpathEntries = [ - "core", - "compat", - "telegram", - "discord", - "slack", - "signal", - "imessage", - "whatsapp", - "line", - "msteams", - "acpx", - "bluebubbles", - "copilot-proxy", - "device-pair", - "diagnostics-otel", - "diffs", - "feishu", - "googlechat", - "irc", - "llm-task", - "lobster", - "matrix", - "mattermost", - "memory-core", - "memory-lancedb", - "minimax-portal-auth", - "nextcloud-talk", - "nostr", - "open-prose", - "phone-control", - "qwen-portal-auth", - "synology-chat", - "talk-voice", - "test-utils", - "thread-ownership", - "tlon", - "twitch", - "voice-call", - "zalo", - "zalouser", - "account-id", - "keyed-async-queue", -]; - const requiredRuntimeShimEntries = ["root-alias.cjs"]; // Critical functions that channel extension plugins import from openclaw/plugin-sdk. @@ -123,7 +79,7 @@ for (const name of requiredExports) { } } -for (const entry of requiredSubpathEntries) { +for (const entry of pluginSdkSubpaths) { const jsPath = resolve(__dirname, "..", "dist", "plugin-sdk", `${entry}.js`); const dtsPath = resolve(__dirname, "..", "dist", "plugin-sdk", `${entry}.d.ts`); if (!existsSync(jsPath)) { diff --git a/scripts/lib/plugin-sdk-entries.mjs b/scripts/lib/plugin-sdk-entries.mjs new file mode 100644 index 00000000000..ba6c1a5c386 --- /dev/null +++ b/scripts/lib/plugin-sdk-entries.mjs @@ -0,0 +1,78 @@ +export const pluginSdkEntrypoints = [ + "index", + "core", + "compat", + "telegram", + "discord", + "slack", + "signal", + "imessage", + "whatsapp", + "line", + "msteams", + "acpx", + "bluebubbles", + "copilot-proxy", + "device-pair", + "diagnostics-otel", + "diffs", + "feishu", + "googlechat", + "irc", + "llm-task", + "lobster", + "matrix", + "mattermost", + "memory-core", + "memory-lancedb", + "minimax-portal-auth", + "nextcloud-talk", + "nostr", + "open-prose", + "phone-control", + "qwen-portal-auth", + "synology-chat", + "talk-voice", + "test-utils", + "thread-ownership", + "tlon", + "twitch", + "voice-call", + "zalo", + "zalouser", + "account-id", + "keyed-async-queue", +]; + +export const pluginSdkSubpaths = pluginSdkEntrypoints.filter((entry) => entry !== "index"); + +export function buildPluginSdkEntrySources() { + return Object.fromEntries( + pluginSdkEntrypoints.map((entry) => [entry, `src/plugin-sdk/${entry}.ts`]), + ); +} + +export function buildPluginSdkSpecifiers() { + return pluginSdkEntrypoints.map((entry) => + entry === "index" ? "openclaw/plugin-sdk" : `openclaw/plugin-sdk/${entry}`, + ); +} + +export function buildPluginSdkPackageExports() { + return Object.fromEntries( + pluginSdkEntrypoints.map((entry) => [ + entry === "index" ? "./plugin-sdk" : `./plugin-sdk/${entry}`, + { + types: `./dist/plugin-sdk/${entry}.d.ts`, + default: `./dist/plugin-sdk/${entry}.js`, + }, + ]), + ); +} + +export function listPluginSdkDistArtifacts() { + return pluginSdkEntrypoints.flatMap((entry) => [ + `dist/plugin-sdk/${entry}.js`, + `dist/plugin-sdk/${entry}.d.ts`, + ]); +} diff --git a/scripts/release-check.ts b/scripts/release-check.ts index b8e4fa6706b..7eedc970103 100755 --- a/scripts/release-check.ts +++ b/scripts/release-check.ts @@ -10,6 +10,7 @@ import { type BundledExtension, type ExtensionPackageJson as PackageJson, } from "./lib/bundled-extension-manifest.ts"; +import { listPluginSdkDistArtifacts } from "./lib/plugin-sdk-entries.mjs"; import { sparkleBuildFloorsFromShortVersion, type SparkleBuildFloors } from "./sparkle-build.ts"; export { collectBundledExtensionManifestErrors } from "./lib/bundled-extension-manifest.ts"; @@ -20,93 +21,8 @@ type PackResult = { files?: PackFile[]; filename?: string; unpackedSize?: number const requiredPathGroups = [ ["dist/index.js", "dist/index.mjs"], ["dist/entry.js", "dist/entry.mjs"], - "dist/plugin-sdk/index.js", - "dist/plugin-sdk/index.d.ts", - "dist/plugin-sdk/core.js", - "dist/plugin-sdk/core.d.ts", + ...listPluginSdkDistArtifacts(), "dist/plugin-sdk/root-alias.cjs", - "dist/plugin-sdk/compat.js", - "dist/plugin-sdk/compat.d.ts", - "dist/plugin-sdk/telegram.js", - "dist/plugin-sdk/telegram.d.ts", - "dist/plugin-sdk/discord.js", - "dist/plugin-sdk/discord.d.ts", - "dist/plugin-sdk/slack.js", - "dist/plugin-sdk/slack.d.ts", - "dist/plugin-sdk/signal.js", - "dist/plugin-sdk/signal.d.ts", - "dist/plugin-sdk/imessage.js", - "dist/plugin-sdk/imessage.d.ts", - "dist/plugin-sdk/whatsapp.js", - "dist/plugin-sdk/whatsapp.d.ts", - "dist/plugin-sdk/line.js", - "dist/plugin-sdk/line.d.ts", - "dist/plugin-sdk/msteams.js", - "dist/plugin-sdk/msteams.d.ts", - "dist/plugin-sdk/acpx.js", - "dist/plugin-sdk/acpx.d.ts", - "dist/plugin-sdk/bluebubbles.js", - "dist/plugin-sdk/bluebubbles.d.ts", - "dist/plugin-sdk/copilot-proxy.js", - "dist/plugin-sdk/copilot-proxy.d.ts", - "dist/plugin-sdk/device-pair.js", - "dist/plugin-sdk/device-pair.d.ts", - "dist/plugin-sdk/diagnostics-otel.js", - "dist/plugin-sdk/diagnostics-otel.d.ts", - "dist/plugin-sdk/diffs.js", - "dist/plugin-sdk/diffs.d.ts", - "dist/plugin-sdk/feishu.js", - "dist/plugin-sdk/feishu.d.ts", - "dist/plugin-sdk/googlechat.js", - "dist/plugin-sdk/googlechat.d.ts", - "dist/plugin-sdk/irc.js", - "dist/plugin-sdk/irc.d.ts", - "dist/plugin-sdk/llm-task.js", - "dist/plugin-sdk/llm-task.d.ts", - "dist/plugin-sdk/lobster.js", - "dist/plugin-sdk/lobster.d.ts", - "dist/plugin-sdk/matrix.js", - "dist/plugin-sdk/matrix.d.ts", - "dist/plugin-sdk/mattermost.js", - "dist/plugin-sdk/mattermost.d.ts", - "dist/plugin-sdk/memory-core.js", - "dist/plugin-sdk/memory-core.d.ts", - "dist/plugin-sdk/memory-lancedb.js", - "dist/plugin-sdk/memory-lancedb.d.ts", - "dist/plugin-sdk/minimax-portal-auth.js", - "dist/plugin-sdk/minimax-portal-auth.d.ts", - "dist/plugin-sdk/nextcloud-talk.js", - "dist/plugin-sdk/nextcloud-talk.d.ts", - "dist/plugin-sdk/nostr.js", - "dist/plugin-sdk/nostr.d.ts", - "dist/plugin-sdk/open-prose.js", - "dist/plugin-sdk/open-prose.d.ts", - "dist/plugin-sdk/phone-control.js", - "dist/plugin-sdk/phone-control.d.ts", - "dist/plugin-sdk/qwen-portal-auth.js", - "dist/plugin-sdk/qwen-portal-auth.d.ts", - "dist/plugin-sdk/synology-chat.js", - "dist/plugin-sdk/synology-chat.d.ts", - "dist/plugin-sdk/talk-voice.js", - "dist/plugin-sdk/talk-voice.d.ts", - "dist/plugin-sdk/test-utils.js", - "dist/plugin-sdk/test-utils.d.ts", - "dist/plugin-sdk/thread-ownership.js", - "dist/plugin-sdk/thread-ownership.d.ts", - "dist/plugin-sdk/tlon.js", - "dist/plugin-sdk/tlon.d.ts", - "dist/plugin-sdk/twitch.js", - "dist/plugin-sdk/twitch.d.ts", - "dist/plugin-sdk/voice-call.js", - "dist/plugin-sdk/voice-call.d.ts", - "dist/plugin-sdk/zalo.js", - "dist/plugin-sdk/zalo.d.ts", - "dist/plugin-sdk/zalouser.js", - "dist/plugin-sdk/zalouser.d.ts", - "dist/plugin-sdk/account-id.js", - "dist/plugin-sdk/account-id.d.ts", - "dist/plugin-sdk/keyed-async-queue.js", - "dist/plugin-sdk/keyed-async-queue.d.ts", "dist/build-info.json", ]; const forbiddenPrefixes = ["dist/OpenClaw.app/"]; diff --git a/scripts/sync-plugin-sdk-exports.mjs b/scripts/sync-plugin-sdk-exports.mjs new file mode 100644 index 00000000000..cfe2e181259 --- /dev/null +++ b/scripts/sync-plugin-sdk-exports.mjs @@ -0,0 +1,34 @@ +#!/usr/bin/env node + +import fs from "node:fs"; +import path from "node:path"; +import { buildPluginSdkPackageExports } from "./lib/plugin-sdk-entries.mjs"; + +const packageJsonPath = path.join(process.cwd(), "package.json"); +const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")); +const currentExports = packageJson.exports ?? {}; +const syncedPluginSdkExports = buildPluginSdkPackageExports(); + +const nextExports = {}; +let insertedPluginSdkExports = false; +for (const [key, value] of Object.entries(currentExports)) { + if (key.startsWith("./plugin-sdk")) { + if (!insertedPluginSdkExports) { + Object.assign(nextExports, syncedPluginSdkExports); + insertedPluginSdkExports = true; + } + continue; + } + nextExports[key] = value; + if (key === "." && !insertedPluginSdkExports) { + Object.assign(nextExports, syncedPluginSdkExports); + insertedPluginSdkExports = true; + } +} + +if (!insertedPluginSdkExports) { + Object.assign(nextExports, syncedPluginSdkExports); +} + +packageJson.exports = nextExports; +fs.writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`, "utf8"); diff --git a/scripts/write-plugin-sdk-entry-dts.ts b/scripts/write-plugin-sdk-entry-dts.ts index d0331377432..832368bbcd3 100644 --- a/scripts/write-plugin-sdk-entry-dts.ts +++ b/scripts/write-plugin-sdk-entry-dts.ts @@ -1,57 +1,13 @@ import fs from "node:fs"; import path from "node:path"; +import { pluginSdkEntrypoints } from "./lib/plugin-sdk-entries.mjs"; // `tsc` emits declarations under `dist/plugin-sdk/src/plugin-sdk/*` because the source lives // at `src/plugin-sdk/*` and `rootDir` is `.` (repo root, to support cross-src/extensions refs). // // Our package export map points subpath `types` at `dist/plugin-sdk/.d.ts`, so we // generate stable entry d.ts files that re-export the real declarations. -const entrypoints = [ - "index", - "core", - "compat", - "telegram", - "discord", - "slack", - "signal", - "imessage", - "whatsapp", - "line", - "msteams", - "acpx", - "bluebubbles", - "copilot-proxy", - "device-pair", - "diagnostics-otel", - "diffs", - "feishu", - "googlechat", - "irc", - "llm-task", - "lobster", - "matrix", - "mattermost", - "memory-core", - "memory-lancedb", - "minimax-portal-auth", - "nextcloud-talk", - "nostr", - "open-prose", - "phone-control", - "qwen-portal-auth", - "synology-chat", - "talk-voice", - "test-utils", - "thread-ownership", - "tlon", - "twitch", - "voice-call", - "zalo", - "zalouser", - "account-id", - "keyed-async-queue", -] as const; -for (const entry of entrypoints) { +for (const entry of pluginSdkEntrypoints) { const out = path.join(process.cwd(), `dist/plugin-sdk/${entry}.d.ts`); fs.mkdirSync(path.dirname(out), { recursive: true }); // NodeNext: reference the runtime specifier with `.js`, TS will map it to `.d.ts`. diff --git a/src/plugin-sdk/index.test.ts b/src/plugin-sdk/index.test.ts index 8fe13972e11..4e9a8869849 100644 --- a/src/plugin-sdk/index.test.ts +++ b/src/plugin-sdk/index.test.ts @@ -4,68 +4,15 @@ import path from "node:path"; import { pathToFileURL } from "node:url"; import { build } from "tsdown"; import { describe, expect, it } from "vitest"; +import { + buildPluginSdkEntrySources, + buildPluginSdkPackageExports, + buildPluginSdkSpecifiers, + pluginSdkEntrypoints, +} from "../../scripts/lib/plugin-sdk-entries.mjs"; import * as sdk from "./index.js"; -const pluginSdkEntrypoints = [ - "index", - "core", - "compat", - "telegram", - "discord", - "slack", - "signal", - "imessage", - "whatsapp", - "line", - "msteams", - "acpx", - "bluebubbles", - "copilot-proxy", - "device-pair", - "diagnostics-otel", - "diffs", - "feishu", - "googlechat", - "irc", - "llm-task", - "lobster", - "matrix", - "mattermost", - "memory-core", - "memory-lancedb", - "minimax-portal-auth", - "nextcloud-talk", - "nostr", - "open-prose", - "phone-control", - "qwen-portal-auth", - "synology-chat", - "talk-voice", - "test-utils", - "thread-ownership", - "tlon", - "twitch", - "voice-call", - "zalo", - "zalouser", - "account-id", - "keyed-async-queue", -] as const; - -const pluginSdkSpecifiers = pluginSdkEntrypoints.map((entry) => - entry === "index" ? "openclaw/plugin-sdk" : `openclaw/plugin-sdk/${entry}`, -); - -function buildPluginSdkPackageExports() { - return Object.fromEntries( - pluginSdkEntrypoints.map((entry) => [ - entry === "index" ? "./plugin-sdk" : `./plugin-sdk/${entry}`, - { - default: `./dist/plugin-sdk/${entry}.js`, - }, - ]), - ); -} +const pluginSdkSpecifiers = buildPluginSdkSpecifiers(); describe("plugin-sdk exports", () => { it("does not expose runtime modules", () => { @@ -180,9 +127,7 @@ describe("plugin-sdk exports", () => { clean: true, config: false, dts: false, - entry: Object.fromEntries( - pluginSdkEntrypoints.map((entry) => [entry, `src/plugin-sdk/${entry}.ts`]), - ), + entry: buildPluginSdkEntrySources(), env: { NODE_ENV: "production" }, fixedExtension: false, logLevel: "error", @@ -237,4 +182,16 @@ describe("plugin-sdk exports", () => { await fs.rm(fixtureDir, { recursive: true, force: true }); } }); + + it("keeps package.json plugin-sdk exports synced with the manifest", async () => { + const packageJsonPath = path.join(process.cwd(), "package.json"); + const packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf8")) as { + exports?: Record; + }; + const currentPluginSdkExports = Object.fromEntries( + Object.entries(packageJson.exports ?? {}).filter(([key]) => key.startsWith("./plugin-sdk")), + ); + + expect(currentPluginSdkExports).toEqual(buildPluginSdkPackageExports()); + }); }); diff --git a/src/plugin-sdk/subpaths.test.ts b/src/plugin-sdk/subpaths.test.ts index 42d69512925..6b696be7269 100644 --- a/src/plugin-sdk/subpaths.test.ts +++ b/src/plugin-sdk/subpaths.test.ts @@ -9,42 +9,14 @@ import * as slackSdk from "openclaw/plugin-sdk/slack"; import * as telegramSdk from "openclaw/plugin-sdk/telegram"; import * as whatsappSdk from "openclaw/plugin-sdk/whatsapp"; import { describe, expect, it } from "vitest"; +import { pluginSdkSubpaths } from "../../scripts/lib/plugin-sdk-entries.mjs"; -const bundledExtensionSubpathLoaders = [ - { id: "acpx", load: () => import("openclaw/plugin-sdk/acpx") }, - { id: "bluebubbles", load: () => import("openclaw/plugin-sdk/bluebubbles") }, - { id: "copilot-proxy", load: () => import("openclaw/plugin-sdk/copilot-proxy") }, - { id: "device-pair", load: () => import("openclaw/plugin-sdk/device-pair") }, - { id: "diagnostics-otel", load: () => import("openclaw/plugin-sdk/diagnostics-otel") }, - { id: "diffs", load: () => import("openclaw/plugin-sdk/diffs") }, - { id: "feishu", load: () => import("openclaw/plugin-sdk/feishu") }, - { id: "googlechat", load: () => import("openclaw/plugin-sdk/googlechat") }, - { id: "irc", load: () => import("openclaw/plugin-sdk/irc") }, - { id: "llm-task", load: () => import("openclaw/plugin-sdk/llm-task") }, - { id: "lobster", load: () => import("openclaw/plugin-sdk/lobster") }, - { id: "matrix", load: () => import("openclaw/plugin-sdk/matrix") }, - { id: "mattermost", load: () => import("openclaw/plugin-sdk/mattermost") }, - { id: "memory-core", load: () => import("openclaw/plugin-sdk/memory-core") }, - { id: "memory-lancedb", load: () => import("openclaw/plugin-sdk/memory-lancedb") }, - { - id: "minimax-portal-auth", - load: () => import("openclaw/plugin-sdk/minimax-portal-auth"), - }, - { id: "nextcloud-talk", load: () => import("openclaw/plugin-sdk/nextcloud-talk") }, - { id: "nostr", load: () => import("openclaw/plugin-sdk/nostr") }, - { id: "open-prose", load: () => import("openclaw/plugin-sdk/open-prose") }, - { id: "phone-control", load: () => import("openclaw/plugin-sdk/phone-control") }, - { id: "qwen-portal-auth", load: () => import("openclaw/plugin-sdk/qwen-portal-auth") }, - { id: "synology-chat", load: () => import("openclaw/plugin-sdk/synology-chat") }, - { id: "talk-voice", load: () => import("openclaw/plugin-sdk/talk-voice") }, - { id: "test-utils", load: () => import("openclaw/plugin-sdk/test-utils") }, - { id: "thread-ownership", load: () => import("openclaw/plugin-sdk/thread-ownership") }, - { id: "tlon", load: () => import("openclaw/plugin-sdk/tlon") }, - { id: "twitch", load: () => import("openclaw/plugin-sdk/twitch") }, - { id: "voice-call", load: () => import("openclaw/plugin-sdk/voice-call") }, - { id: "zalo", load: () => import("openclaw/plugin-sdk/zalo") }, - { id: "zalouser", load: () => import("openclaw/plugin-sdk/zalouser") }, -] as const; +const importPluginSdkSubpath = (specifier: string) => import(/* @vite-ignore */ specifier); + +const bundledExtensionSubpathLoaders = pluginSdkSubpaths.map((id) => ({ + id, + load: () => importPluginSdkSubpath(`openclaw/plugin-sdk/${id}`), +})); describe("plugin-sdk subpath exports", () => { it("exports compat helpers", () => { diff --git a/tsconfig.plugin-sdk.dts.json b/tsconfig.plugin-sdk.dts.json index 15828b8b7ad..b182b3e30e4 100644 --- a/tsconfig.plugin-sdk.dts.json +++ b/tsconfig.plugin-sdk.dts.json @@ -10,51 +10,6 @@ "rootDir": ".", "tsBuildInfoFile": "dist/plugin-sdk/.tsbuildinfo" }, - "include": [ - "src/plugin-sdk/index.ts", - "src/plugin-sdk/core.ts", - "src/plugin-sdk/compat.ts", - "src/plugin-sdk/telegram.ts", - "src/plugin-sdk/discord.ts", - "src/plugin-sdk/slack.ts", - "src/plugin-sdk/signal.ts", - "src/plugin-sdk/imessage.ts", - "src/plugin-sdk/whatsapp.ts", - "src/plugin-sdk/line.ts", - "src/plugin-sdk/msteams.ts", - "src/plugin-sdk/account-id.ts", - "src/plugin-sdk/keyed-async-queue.ts", - "src/plugin-sdk/acpx.ts", - "src/plugin-sdk/bluebubbles.ts", - "src/plugin-sdk/copilot-proxy.ts", - "src/plugin-sdk/device-pair.ts", - "src/plugin-sdk/diagnostics-otel.ts", - "src/plugin-sdk/diffs.ts", - "src/plugin-sdk/feishu.ts", - "src/plugin-sdk/googlechat.ts", - "src/plugin-sdk/irc.ts", - "src/plugin-sdk/llm-task.ts", - "src/plugin-sdk/lobster.ts", - "src/plugin-sdk/matrix.ts", - "src/plugin-sdk/mattermost.ts", - "src/plugin-sdk/memory-core.ts", - "src/plugin-sdk/memory-lancedb.ts", - "src/plugin-sdk/minimax-portal-auth.ts", - "src/plugin-sdk/nextcloud-talk.ts", - "src/plugin-sdk/nostr.ts", - "src/plugin-sdk/open-prose.ts", - "src/plugin-sdk/phone-control.ts", - "src/plugin-sdk/qwen-portal-auth.ts", - "src/plugin-sdk/synology-chat.ts", - "src/plugin-sdk/talk-voice.ts", - "src/plugin-sdk/test-utils.ts", - "src/plugin-sdk/thread-ownership.ts", - "src/plugin-sdk/tlon.ts", - "src/plugin-sdk/twitch.ts", - "src/plugin-sdk/voice-call.ts", - "src/plugin-sdk/zalo.ts", - "src/plugin-sdk/zalouser.ts", - "src/types/**/*.d.ts" - ], + "include": ["src/plugin-sdk/**/*.ts", "src/types/**/*.d.ts"], "exclude": ["node_modules", "dist", "src/**/*.test.ts"] } diff --git a/tsdown.config.ts b/tsdown.config.ts index b266f660421..80eaae39a4e 100644 --- a/tsdown.config.ts +++ b/tsdown.config.ts @@ -1,6 +1,7 @@ import fs from "node:fs"; import path from "node:path"; import { defineConfig } from "tsdown"; +import { buildPluginSdkEntrySources } from "./scripts/lib/plugin-sdk-entries.mjs"; const env = { NODE_ENV: "production", @@ -58,52 +59,6 @@ function nodeBuildConfig(config: Record) { }; } -const pluginSdkEntrypoints = [ - "index", - "core", - "compat", - "telegram", - "discord", - "slack", - "signal", - "imessage", - "whatsapp", - "line", - "msteams", - "acpx", - "bluebubbles", - "copilot-proxy", - "device-pair", - "diagnostics-otel", - "diffs", - "feishu", - "googlechat", - "irc", - "llm-task", - "lobster", - "matrix", - "mattermost", - "memory-core", - "memory-lancedb", - "minimax-portal-auth", - "nextcloud-talk", - "nostr", - "open-prose", - "phone-control", - "qwen-portal-auth", - "synology-chat", - "talk-voice", - "test-utils", - "thread-ownership", - "tlon", - "twitch", - "voice-call", - "zalo", - "zalouser", - "account-id", - "keyed-async-queue", -] as const; - function listBundledPluginBuildEntries(): Record { const extensionsRoot = path.join(process.cwd(), "extensions"); const entries: Record = {}; @@ -189,7 +144,7 @@ export default defineConfig([ nodeBuildConfig({ // Bundle all plugin-sdk entries in a single build so the bundler can share // common chunks instead of duplicating them per entry (~712MB heap saved). - entry: Object.fromEntries(pluginSdkEntrypoints.map((e) => [e, `src/plugin-sdk/${e}.ts`])), + entry: buildPluginSdkEntrySources(), outDir: "dist/plugin-sdk", }), nodeBuildConfig({ diff --git a/vitest.config.ts b/vitest.config.ts index c45f5f45c25..564065be9e3 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -2,57 +2,13 @@ import os from "node:os"; import path from "node:path"; import { fileURLToPath } from "node:url"; import { defineConfig } from "vitest/config"; +import { pluginSdkSubpaths } from "./scripts/lib/plugin-sdk-entries.mjs"; const repoRoot = path.dirname(fileURLToPath(import.meta.url)); const isCI = process.env.CI === "true" || process.env.GITHUB_ACTIONS === "true"; const isWindows = process.platform === "win32"; const localWorkers = Math.max(4, Math.min(16, os.cpus().length)); const ciWorkers = isWindows ? 2 : 3; -const pluginSdkSubpaths = [ - "account-id", - "core", - "compat", - "telegram", - "discord", - "slack", - "signal", - "imessage", - "whatsapp", - "line", - "msteams", - "acpx", - "bluebubbles", - "copilot-proxy", - "device-pair", - "diagnostics-otel", - "diffs", - "feishu", - "googlechat", - "irc", - "llm-task", - "lobster", - "matrix", - "mattermost", - "memory-core", - "memory-lancedb", - "minimax-portal-auth", - "nextcloud-talk", - "nostr", - "open-prose", - "phone-control", - "qwen-portal-auth", - "synology-chat", - "talk-voice", - "test-utils", - "thread-ownership", - "tlon", - "twitch", - "voice-call", - "zalo", - "zalouser", - "keyed-async-queue", -] as const; - export default defineConfig({ resolve: { // Keep this ordered: the base `openclaw/plugin-sdk` alias is a prefix match.