From e39e258d0cf5db0d0a7ea4a51107f4d58cd13bfa Mon Sep 17 00:00:00 2001 From: Tuyen Date: Thu, 19 Mar 2026 00:36:54 +0700 Subject: [PATCH] Build: isolate optional bundled clusters --- extensions/discord/src/directory-live.test.ts | 4 +- extensions/nostr/api.ts | 1 - extensions/tlon/api.ts | 1 - extensions/whatsapp/src/shared.ts | 15 +++++- scripts/audit-plugin-sdk-seams.mjs | 53 +++++++++++++++++++ scripts/lib/optional-bundled-clusters.d.mts | 6 +++ tsconfig.json | 19 ++++++- 7 files changed, 92 insertions(+), 7 deletions(-) create mode 100644 scripts/lib/optional-bundled-clusters.d.mts diff --git a/extensions/discord/src/directory-live.test.ts b/extensions/discord/src/directory-live.test.ts index 36f1f821795..adc4898dff2 100644 --- a/extensions/discord/src/directory-live.test.ts +++ b/extensions/discord/src/directory-live.test.ts @@ -1,6 +1,6 @@ +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import type { DirectoryConfigParams } from "openclaw/plugin-sdk/directory-runtime"; import { beforeEach, describe, expect, it, vi } from "vitest"; -import type { OpenClawConfig } from "../../../src/config/config.js"; -import type { DirectoryConfigParams } from "../../../src/plugin-sdk/directory-runtime.js"; import { listDiscordDirectoryGroupsLive, listDiscordDirectoryPeersLive } from "./directory-live.js"; function makeParams(overrides: Partial = {}): DirectoryConfigParams { diff --git a/extensions/nostr/api.ts b/extensions/nostr/api.ts index 2de81f11142..3f3d64cc3bf 100644 --- a/extensions/nostr/api.ts +++ b/extensions/nostr/api.ts @@ -1,2 +1 @@ export * from "openclaw/plugin-sdk/nostr"; -export * from "./setup-api.js"; diff --git a/extensions/tlon/api.ts b/extensions/tlon/api.ts index bccfa85fbac..5364c68f07d 100644 --- a/extensions/tlon/api.ts +++ b/extensions/tlon/api.ts @@ -1,2 +1 @@ export * from "openclaw/plugin-sdk/tlon"; -export * from "./setup-api.js"; diff --git a/extensions/whatsapp/src/shared.ts b/extensions/whatsapp/src/shared.ts index 5fa27f42030..3888cdc36d3 100644 --- a/extensions/whatsapp/src/shared.ts +++ b/extensions/whatsapp/src/shared.ts @@ -167,5 +167,18 @@ export function createWhatsAppPluginBase(params: { }, setup: params.setup, groups: params.groups, - }); + }) as Pick< + ChannelPlugin, + | "id" + | "meta" + | "setupWizard" + | "capabilities" + | "reload" + | "gatewayMethods" + | "configSchema" + | "config" + | "security" + | "setup" + | "groups" + >; } diff --git a/scripts/audit-plugin-sdk-seams.mjs b/scripts/audit-plugin-sdk-seams.mjs index 67e27c036f4..28b0f6649d2 100644 --- a/scripts/audit-plugin-sdk-seams.mjs +++ b/scripts/audit-plugin-sdk-seams.mjs @@ -25,6 +25,30 @@ function normalizePath(filePath) { return path.relative(repoRoot, filePath).split(path.sep).join("/"); } +function readDefaultTsconfigFiles() { + const tsconfigPath = path.join(repoRoot, "tsconfig.json"); + const readTsConfigFile = (filePath) => ts.sys.readFile(filePath); + const parsedConfig = ts.readConfigFile(tsconfigPath, readTsConfigFile); + if (parsedConfig.error) { + throw new Error(ts.flattenDiagnosticMessageText(parsedConfig.error.messageText, "\n")); + } + const resolvedConfig = ts.parseJsonConfigFileContent( + parsedConfig.config, + ts.sys, + repoRoot, + undefined, + tsconfigPath, + ); + if (resolvedConfig.errors.length > 0) { + throw new Error( + resolvedConfig.errors + .map((error) => ts.flattenDiagnosticMessageText(error.messageText, "\n")) + .join("\n"), + ); + } + return new Set(resolvedConfig.fileNames.map((fileName) => normalizePath(fileName))); +} + function isCodeFile(fileName) { return /\.(ts|tsx|mts|cts|js|jsx|mjs|cjs)$/.test(fileName); } @@ -337,8 +361,30 @@ function packageClusterMeta(relativePackagePath) { }; } +function workspaceSourcePrefix(relativePackagePath) { + if (relativePackagePath === "ui/package.json") { + return "ui/"; + } + const cluster = relativePackagePath.split("/")[1]; + return `extensions/${cluster}/`; +} + function classifyMissingPackageCluster(params) { if (optionalBundledClusterSet.has(params.cluster)) { + if (!params.defaultGraphReachable) { + if (params.cluster === "ui") { + return { + decision: "optional", + reason: + "Private UI workspace is excluded from the default tsconfig graph, so repo-wide check/build does not require UI-only packages by default.", + }; + } + return { + decision: "optional", + reason: + "Workspace package is excluded from the default tsconfig graph, so repo-wide check/build does not require its plugin-local dependencies by default.", + }; + } if (params.cluster === "ui") { return { decision: "optional", @@ -375,6 +421,7 @@ async function buildMissingPackages() { ]); const pluginSdkEntrySources = await walkCodeFiles(path.join(repoRoot, "src", "plugin-sdk")); + const defaultTsconfigFiles = readDefaultTsconfigFiles(); const pluginSdkReachability = new Map(); for (const filePath of pluginSdkEntrySources) { const source = await fs.readFile(filePath, "utf8"); @@ -403,6 +450,9 @@ async function buildMissingPackages() { continue; } const meta = packageClusterMeta(relativePackagePath); + const defaultGraphIncludedFileCount = [...defaultTsconfigFiles].filter((filePath) => + filePath.startsWith(workspaceSourcePrefix(relativePackagePath)), + ).length; const rootDependencyMirrorAllowlist = ( pkg.openclaw?.releaseChecks?.rootDependencyMirrorAllowlist ?? [] ).toSorted(compareStrings); @@ -411,12 +461,15 @@ async function buildMissingPackages() { ); const classification = classifyMissingPackageCluster({ cluster: meta.cluster, + defaultGraphReachable: defaultGraphIncludedFileCount > 0, pluginSdkEntries, }); output.push({ cluster: meta.cluster, decision: classification.decision, decisionReason: classification.reason, + defaultGraphIncludedFileCount, + defaultGraphStatus: defaultGraphIncludedFileCount > 0 ? "included" : "excluded", packageName: pkg.name ?? meta.packageName, packagePath: relativePackagePath, npmSpec: pkg.openclaw?.install?.npmSpec ?? null, diff --git a/scripts/lib/optional-bundled-clusters.d.mts b/scripts/lib/optional-bundled-clusters.d.mts new file mode 100644 index 00000000000..42640bd1772 --- /dev/null +++ b/scripts/lib/optional-bundled-clusters.d.mts @@ -0,0 +1,6 @@ +export const optionalBundledClusters: string[]; +export const optionalBundledClusterSet: Set; +export const OPTIONAL_BUNDLED_BUILD_ENV: string; +export function isOptionalBundledCluster(cluster: string): boolean; +export function shouldIncludeOptionalBundledClusters(env?: NodeJS.ProcessEnv): boolean; +export function shouldBuildBundledCluster(cluster: string, env?: NodeJS.ProcessEnv): boolean; diff --git a/tsconfig.json b/tsconfig.json index bc6439e921f..0438b5a610d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,6 +23,21 @@ "openclaw/plugin-sdk/account-id": ["./src/plugin-sdk/account-id.ts"] } }, - "include": ["src/**/*", "ui/**/*", "extensions/**/*"], - "exclude": ["node_modules", "dist"] + "include": ["src/**/*", "extensions/**/*"], + "exclude": [ + "node_modules", + "dist", + "ui", + "extensions/acpx", + "extensions/diagnostics-otel", + "extensions/diffs", + "extensions/googlechat", + "extensions/matrix", + "extensions/memory-lancedb", + "extensions/msteams", + "extensions/nostr", + "extensions/tlon", + "extensions/twitch", + "extensions/zalouser" + ] }