fix(release): keep private test helpers out of npm pack

This commit is contained in:
Peter Steinberger
2026-05-28 20:05:04 +01:00
parent 2d8cebba5c
commit a0fcb91670
7 changed files with 41 additions and 18 deletions

View File

@@ -11,7 +11,7 @@
import { readFileSync, existsSync } from "node:fs";
import { resolve, dirname } from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import { pluginSdkSubpaths } from "./lib/plugin-sdk-entries.mjs";
import { publicPluginSdkSubpaths } from "./lib/plugin-sdk-entries.mjs";
const scriptDir = dirname(fileURLToPath(import.meta.url));
const distFile = resolve(scriptDir, "..", "dist", "plugin-sdk", "index.js");
@@ -70,7 +70,7 @@ for (const name of requiredExports) {
}
}
for (const entry of pluginSdkSubpaths) {
for (const entry of publicPluginSdkSubpaths) {
const jsPath = resolve(scriptDir, "..", "dist", "plugin-sdk", `${entry}.js`);
const dtsPath = resolve(scriptDir, "..", "dist", "plugin-sdk", `${entry}.d.ts`);
if (!existsSync(jsPath)) {

View File

@@ -12,6 +12,8 @@ const TOP_LEVEL_PUBLIC_SURFACE_EXTENSIONS = new Set([".ts", ".js", ".mts", ".cts
export const NON_PACKAGED_BUNDLED_PLUGIN_DIRS = new Set(["qa-channel", "qa-lab", "qa-matrix"]);
const EXCLUDED_CORE_BUNDLED_PLUGIN_DIRS = new Set(["qqbot", "whatsapp"]);
const BUNDLED_PLUGIN_BUILD_IDS_ENV = "OPENCLAW_BUNDLED_PLUGIN_BUILD_IDS";
const TOP_LEVEL_PRIVATE_TEST_SURFACE_RE =
/(?:^|[._-])(?:test|spec|test-support|test-helpers|test-fixtures|test-harness|mock-setup)(?:[._-]|$)/u;
const toPosixPath = (value) => value.replaceAll("\\", "/");
function parseBundledPluginBuildIdFilter(env = process.env) {
@@ -88,8 +90,7 @@ export function collectTopLevelPublicSurfaceEntries(pluginDir) {
if (
normalizedName.endsWith(".d.ts") ||
/^config-api\.(?:[cm]?[jt]s)$/u.test(normalizedName) ||
normalizedName.includes(".test.") ||
normalizedName.includes(".spec.") ||
TOP_LEVEL_PRIVATE_TEST_SURFACE_RE.test(normalizedName) ||
normalizedName.includes(".fixture.") ||
normalizedName.includes(".snap")
) {
@@ -117,8 +118,7 @@ function collectTopLevelPublicSurfaceEntriesFromFiles(relativeFiles) {
if (
normalizedName.endsWith(".d.ts") ||
/^config-api\.(?:[cm]?[jt]s)$/u.test(normalizedName) ||
normalizedName.includes(".test.") ||
normalizedName.includes(".spec.") ||
TOP_LEVEL_PRIVATE_TEST_SURFACE_RE.test(normalizedName) ||
normalizedName.includes(".fixture.") ||
normalizedName.includes(".snap")
) {

View File

@@ -6,7 +6,7 @@ export const publicPluginSdkSubpaths: string[];
export const deprecatedPublicPluginSdkEntrypoints: string[];
export const deprecatedBarrelPluginSdkEntrypoints: string[];
export function buildPluginSdkEntrySources(): Record<string, string>;
export function buildPluginSdkEntrySources(entries?: readonly string[]): Record<string, string>;
export function buildPluginSdkPackageExports(): Record<
string,
{

View File

@@ -33,10 +33,8 @@ export const deprecatedBarrelPluginSdkEntrypoints = pluginSdkSubpaths.filter((en
deprecatedBarrelPluginSdkSubpathList.includes(entry),
);
export function buildPluginSdkEntrySources() {
return Object.fromEntries(
pluginSdkEntrypoints.map((entry) => [entry, `src/plugin-sdk/${entry}.ts`]),
);
export function buildPluginSdkEntrySources(entries = pluginSdkEntrypoints) {
return Object.fromEntries(entries.map((entry) => [entry, `src/plugin-sdk/${entry}.ts`]));
}
export function buildPluginSdkPackageExports() {

View File

@@ -2,7 +2,11 @@ import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { build } from "tsdown";
import { buildPluginSdkEntrySources, pluginSdkEntrypoints } from "./lib/plugin-sdk-entries.mjs";
import {
buildPluginSdkEntrySources,
pluginSdkEntrypoints,
publicPluginSdkEntrypoints,
} from "./lib/plugin-sdk-entries.mjs";
const RUNTIME_SHIMS: Partial<Record<string, string>> = {
"webhook-path": [
@@ -67,6 +71,11 @@ function copyFlatDeclarations(fromDir: string, toDir: string): void {
const distPluginSdkDir = path.join(process.cwd(), "dist/plugin-sdk");
const flatDeclarationTempDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-plugin-sdk-dts-"));
const shouldBuildPrivateQaEntries = process.env.OPENCLAW_BUILD_PRIVATE_QA === "1";
const flatDeclarationEntrypoints = shouldBuildPrivateQaEntries
? pluginSdkEntrypoints
: publicPluginSdkEntrypoints;
const flatDeclarationEntrypointSet = new Set(flatDeclarationEntrypoints);
try {
await build({
@@ -74,7 +83,7 @@ try {
config: false,
deps: { neverBundle: (id) => isBareImportSpecifier(id) },
dts: true,
entry: buildPluginSdkEntrySources(),
entry: buildPluginSdkEntrySources(flatDeclarationEntrypoints),
failOnWarn: false,
fixedExtension: false,
format: "esm",
@@ -96,6 +105,10 @@ try {
// The private workspace package keeps source-shaped declaration paths for local
// package-boundary projects, so bridge them back to the packaged flat entries.
for (const entry of pluginSdkEntrypoints) {
if (!flatDeclarationEntrypointSet.has(entry)) {
continue;
}
const packageTypeOut = path.join(
process.cwd(),
`packages/plugin-sdk/dist/src/plugin-sdk/${entry}.d.ts`,

View File

@@ -103,6 +103,12 @@ describe("bundled plugin build entries", () => {
expect(entries["extensions/telegram/telegram-ingress-worker.runtime"]).toBeUndefined();
});
it("keeps top-level bundled plugin test helpers out of public-surface entries", () => {
const entries = listBundledPluginBuildEntries();
expect(entries["extensions/browser/test-support"]).toBeUndefined();
});
it("discovers repo plugin build entries without directory scans", () => {
const payload = expectNoNodeFsScans<{
artifacts: number;

View File

@@ -5,7 +5,11 @@ import {
collectBundledPluginBuildEntries,
NON_PACKAGED_BUNDLED_PLUGIN_DIRS,
} from "./scripts/lib/bundled-plugin-build-entries.mjs";
import { buildPluginSdkEntrySources } from "./scripts/lib/plugin-sdk-entries.mjs";
import {
buildPluginSdkEntrySources,
pluginSdkEntrypoints,
publicPluginSdkEntrypoints,
} from "./scripts/lib/plugin-sdk-entries.mjs";
type InputOptionsFactory = Extract<NonNullable<UserConfig["inputOptions"]>, Function>;
type InputOptionsArg = InputOptionsFactory extends (
@@ -140,6 +144,9 @@ function nodeBuildConfig(config: UserConfig): UserConfig {
const bundledPluginBuildEntries = collectBundledPluginBuildEntries();
const shouldBuildPrivateQaEntries = process.env.OPENCLAW_BUILD_PRIVATE_QA === "1";
const productionPluginSdkEntrypoints = shouldBuildPrivateQaEntries
? pluginSdkEntrypoints
: publicPluginSdkEntrypoints;
function buildBundledHookEntries(): Record<string, string> {
const hooksRoot = path.join(process.cwd(), "src", "hooks", "bundled");
@@ -357,10 +364,9 @@ function buildUnifiedDistEntries(): Record<string, string> {
// Private bundled Codex helper for app-server user MCP config projection.
"plugin-sdk/codex-mcp-projection": "src/plugin-sdk/codex-mcp-projection.ts",
...Object.fromEntries(
Object.entries(buildPluginSdkEntrySources()).map(([entry, source]) => [
`plugin-sdk/${entry}`,
source,
]),
Object.entries(buildPluginSdkEntrySources(productionPluginSdkEntrypoints)).map(
([entry, source]) => [`plugin-sdk/${entry}`, source],
),
),
...(shouldBuildPrivateQaEntries
? {