mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 14:30:45 +00:00
build: remove private QA package compat shims
This commit is contained in:
@@ -1,2 +1,2 @@
|
|||||||
fd941e0485a92ebb8256cf2256330b58c2d5bd94189f4a05d7394353ef7bed88 plugin-sdk-api-baseline.json
|
21914ef8c5840e0defc36d571834dc28a92d6d5ca2d42a088c33b4de681e836a plugin-sdk-api-baseline.json
|
||||||
11ef8362518a0d9f221dc1958b25db46956d1916f278b53e52199bf6c2cbc65b plugin-sdk-api-baseline.jsonl
|
3f22e6af0dad3433d25d996802d7436a3cc0e68bc86ecaf813a22e2b4e5333eb plugin-sdk-api-baseline.jsonl
|
||||||
|
|||||||
14
package.json
14
package.json
@@ -37,14 +37,20 @@
|
|||||||
"!dist/extensions/qa-channel/**",
|
"!dist/extensions/qa-channel/**",
|
||||||
"!dist/extensions/qa-lab/**",
|
"!dist/extensions/qa-lab/**",
|
||||||
"!dist/extensions/qa-matrix/**",
|
"!dist/extensions/qa-matrix/**",
|
||||||
|
"!dist/plugin-sdk/extensions/qa-channel/**",
|
||||||
"!dist/plugin-sdk/extensions/qa-lab/**",
|
"!dist/plugin-sdk/extensions/qa-lab/**",
|
||||||
|
"!dist/plugin-sdk/qa-channel.*",
|
||||||
|
"!dist/plugin-sdk/qa-channel-protocol.*",
|
||||||
"!dist/plugin-sdk/qa-lab.*",
|
"!dist/plugin-sdk/qa-lab.*",
|
||||||
"!dist/plugin-sdk/qa-runtime.*",
|
"!dist/plugin-sdk/qa-runtime.*",
|
||||||
|
"!dist/plugin-sdk/src/plugin-sdk/qa-channel.d.ts",
|
||||||
|
"!dist/plugin-sdk/src/plugin-sdk/qa-channel-protocol.d.ts",
|
||||||
"!dist/plugin-sdk/src/plugin-sdk/qa-lab.d.ts",
|
"!dist/plugin-sdk/src/plugin-sdk/qa-lab.d.ts",
|
||||||
"!dist/plugin-sdk/src/plugin-sdk/qa-runtime.d.ts",
|
"!dist/plugin-sdk/src/plugin-sdk/qa-runtime.d.ts",
|
||||||
"!dist/qa-runtime-*.js",
|
"!dist/qa-runtime-*.js",
|
||||||
"docs/",
|
"docs/",
|
||||||
"!docs/.generated/**",
|
"!docs/.generated/**",
|
||||||
|
"!docs/channels/qa-channel.md",
|
||||||
"patches/",
|
"patches/",
|
||||||
"skills/",
|
"skills/",
|
||||||
"scripts/npm-runner.mjs",
|
"scripts/npm-runner.mjs",
|
||||||
@@ -1044,14 +1050,6 @@
|
|||||||
"types": "./dist/plugin-sdk/nostr.d.ts",
|
"types": "./dist/plugin-sdk/nostr.d.ts",
|
||||||
"default": "./dist/plugin-sdk/nostr.js"
|
"default": "./dist/plugin-sdk/nostr.js"
|
||||||
},
|
},
|
||||||
"./plugin-sdk/qa-channel": {
|
|
||||||
"types": "./dist/plugin-sdk/qa-channel.d.ts",
|
|
||||||
"default": "./dist/plugin-sdk/qa-channel.js"
|
|
||||||
},
|
|
||||||
"./plugin-sdk/qa-channel-protocol": {
|
|
||||||
"types": "./dist/plugin-sdk/qa-channel-protocol.d.ts",
|
|
||||||
"default": "./dist/plugin-sdk/qa-channel-protocol.js"
|
|
||||||
},
|
|
||||||
"./plugin-sdk/provider-auth": {
|
"./plugin-sdk/provider-auth": {
|
||||||
"types": "./dist/plugin-sdk/provider-auth.d.ts",
|
"types": "./dist/plugin-sdk/provider-auth.d.ts",
|
||||||
"default": "./dist/plugin-sdk/provider-auth.js"
|
"default": "./dist/plugin-sdk/provider-auth.js"
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
import { spawnSync } from "node:child_process";
|
import { spawnSync } from "node:child_process";
|
||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
|
|
||||||
const INVENTORY_COMPAT_MISSING_ENTRIES = new Set(["dist/extensions/qa-channel/runtime-api.js"]);
|
|
||||||
|
|
||||||
function usage() {
|
function usage() {
|
||||||
return "Usage: node scripts/check-openclaw-package-tarball.mjs <openclaw.tgz>";
|
return "Usage: node scripts/check-openclaw-package-tarball.mjs <openclaw.tgz>";
|
||||||
}
|
}
|
||||||
@@ -77,9 +75,6 @@ if (entrySet.has("dist/postinstall-inventory.json")) {
|
|||||||
} else {
|
} else {
|
||||||
for (const inventoryEntry of inventory) {
|
for (const inventoryEntry of inventory) {
|
||||||
const normalizedEntry = inventoryEntry.replace(/\\/gu, "/");
|
const normalizedEntry = inventoryEntry.replace(/\\/gu, "/");
|
||||||
if (INVENTORY_COMPAT_MISSING_ENTRIES.has(normalizedEntry)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!entrySet.has(normalizedEntry)) {
|
if (!entrySet.has(normalizedEntry)) {
|
||||||
errors.push(`inventory references missing tar entry ${normalizedEntry}`);
|
errors.push(`inventory references missing tar entry ${normalizedEntry}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,16 @@ function readEntrypoints() {
|
|||||||
return new Set(entrypoints.filter((entry) => entry !== "index"));
|
return new Set(entrypoints.filter((entry) => entry !== "index"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function readPrivateLocalOnlySubpaths() {
|
||||||
|
const subpaths = JSON.parse(
|
||||||
|
readFileSync(
|
||||||
|
path.join(repoRoot, "scripts/lib/plugin-sdk-private-local-only-subpaths.json"),
|
||||||
|
"utf8",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return new Set(subpaths.filter((entry) => typeof entry === "string" && !entry.includes("/")));
|
||||||
|
}
|
||||||
|
|
||||||
function parsePluginSdkSubpath(specifier) {
|
function parsePluginSdkSubpath(specifier) {
|
||||||
if (!specifier.startsWith("openclaw/plugin-sdk/")) {
|
if (!specifier.startsWith("openclaw/plugin-sdk/")) {
|
||||||
return null;
|
return null;
|
||||||
@@ -51,6 +61,7 @@ function compareEntries(left, right) {
|
|||||||
async function collectViolations() {
|
async function collectViolations() {
|
||||||
const entrypoints = readEntrypoints();
|
const entrypoints = readEntrypoints();
|
||||||
const exports = readPackageExports();
|
const exports = readPackageExports();
|
||||||
|
const privateLocalOnlySubpaths = readPrivateLocalOnlySubpaths();
|
||||||
const files = (await collectTypeScriptFilesFromRoots(scanRoots, { includeTests: true })).toSorted(
|
const files = (await collectTypeScriptFilesFromRoots(scanRoots, { includeTests: true })).toSorted(
|
||||||
(left, right) =>
|
(left, right) =>
|
||||||
normalizeRepoPath(repoRoot, left).localeCompare(normalizeRepoPath(repoRoot, right)),
|
normalizeRepoPath(repoRoot, left).localeCompare(normalizeRepoPath(repoRoot, right)),
|
||||||
@@ -72,6 +83,9 @@ async function collectViolations() {
|
|||||||
if (!subpath) {
|
if (!subpath) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (privateLocalOnlySubpaths.has(subpath)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const missingFrom = [];
|
const missingFrom = [];
|
||||||
if (!entrypoints.has(subpath)) {
|
if (!entrypoints.has(subpath)) {
|
||||||
|
|||||||
@@ -246,8 +246,6 @@
|
|||||||
"native-command-registry",
|
"native-command-registry",
|
||||||
"nextcloud-talk",
|
"nextcloud-talk",
|
||||||
"nostr",
|
"nostr",
|
||||||
"qa-channel",
|
|
||||||
"qa-channel-protocol",
|
|
||||||
"provider-auth",
|
"provider-auth",
|
||||||
"provider-auth-runtime",
|
"provider-auth-runtime",
|
||||||
"provider-auth-api-key",
|
"provider-auth-api-key",
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
["qa-lab", "qa-runtime"]
|
["qa-channel", "qa-channel-protocol", "qa-lab", "qa-runtime"]
|
||||||
|
|||||||
@@ -74,6 +74,11 @@ const FORBIDDEN_PACKED_PATH_RULES = [
|
|||||||
describe: (packedPath: string) =>
|
describe: (packedPath: string) =>
|
||||||
`npm package must not include generated docs artifact "${packedPath}".`,
|
`npm package must not include generated docs artifact "${packedPath}".`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
prefix: "docs/channels/qa-channel.md",
|
||||||
|
describe: (packedPath: string) =>
|
||||||
|
`npm package must not include private QA channel docs "${packedPath}".`,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
prefix: "dist/extensions/qa-channel/",
|
prefix: "dist/extensions/qa-channel/",
|
||||||
describe: (packedPath: string) =>
|
describe: (packedPath: string) =>
|
||||||
@@ -84,11 +89,26 @@ const FORBIDDEN_PACKED_PATH_RULES = [
|
|||||||
describe: (packedPath: string) =>
|
describe: (packedPath: string) =>
|
||||||
`npm package must not include private QA lab artifact "${packedPath}".`,
|
`npm package must not include private QA lab artifact "${packedPath}".`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
prefix: "dist/plugin-sdk/extensions/qa-channel/",
|
||||||
|
describe: (packedPath: string) =>
|
||||||
|
`npm package must not include private QA channel type artifact "${packedPath}".`,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
prefix: "dist/plugin-sdk/extensions/qa-lab/",
|
prefix: "dist/plugin-sdk/extensions/qa-lab/",
|
||||||
describe: (packedPath: string) =>
|
describe: (packedPath: string) =>
|
||||||
`npm package must not include private QA lab type artifact "${packedPath}".`,
|
`npm package must not include private QA lab type artifact "${packedPath}".`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
prefix: "dist/plugin-sdk/qa-channel.",
|
||||||
|
describe: (packedPath: string) =>
|
||||||
|
`npm package must not include private QA channel SDK artifact "${packedPath}".`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prefix: "dist/plugin-sdk/qa-channel-protocol.",
|
||||||
|
describe: (packedPath: string) =>
|
||||||
|
`npm package must not include private QA channel SDK artifact "${packedPath}".`,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
prefix: "dist/qa-runtime-",
|
prefix: "dist/qa-runtime-",
|
||||||
describe: (packedPath: string) =>
|
describe: (packedPath: string) =>
|
||||||
@@ -103,6 +123,8 @@ const FORBIDDEN_PACKED_PATH_RULES = [
|
|||||||
const FORBIDDEN_PRIVATE_QA_CONTENT_MARKERS = [
|
const FORBIDDEN_PRIVATE_QA_CONTENT_MARKERS = [
|
||||||
"//#region extensions/qa-lab/",
|
"//#region extensions/qa-lab/",
|
||||||
"qa-channel/runtime-api.js",
|
"qa-channel/runtime-api.js",
|
||||||
|
"qa-channel.js",
|
||||||
|
"qa-channel-protocol.js",
|
||||||
"qa-lab/cli.js",
|
"qa-lab/cli.js",
|
||||||
"qa-lab/runtime-api.js",
|
"qa-lab/runtime-api.js",
|
||||||
] as const;
|
] as const;
|
||||||
@@ -559,9 +581,6 @@ export function collectForbiddenPackedContentErrors(
|
|||||||
const textPathPattern = /\.(?:[cm]?js|d\.ts|json|md|mjs|cjs)$/u;
|
const textPathPattern = /\.(?:[cm]?js|d\.ts|json|md|mjs|cjs)$/u;
|
||||||
const errors: string[] = [];
|
const errors: string[] = [];
|
||||||
for (const packedPath of paths) {
|
for (const packedPath of paths) {
|
||||||
if (packedPath === PACKAGE_DIST_INVENTORY_RELATIVE_PATH) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (
|
if (
|
||||||
!FORBIDDEN_PRIVATE_QA_CONTENT_SCAN_PREFIXES.some((prefix) => packedPath.startsWith(prefix))
|
!FORBIDDEN_PRIVATE_QA_CONTENT_SCAN_PREFIXES.some((prefix) => packedPath.startsWith(prefix))
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
closeSync,
|
closeSync,
|
||||||
existsSync,
|
existsSync,
|
||||||
lstatSync,
|
lstatSync,
|
||||||
mkdirSync,
|
|
||||||
openSync,
|
openSync,
|
||||||
readdirSync,
|
readdirSync,
|
||||||
readFileSync,
|
readFileSync,
|
||||||
@@ -35,18 +34,6 @@ const DISABLE_POSTINSTALL_ENV = "OPENCLAW_DISABLE_BUNDLED_PLUGIN_POSTINSTALL";
|
|||||||
const DISABLE_PLUGIN_REGISTRY_MIGRATION_ENV = "OPENCLAW_DISABLE_PLUGIN_REGISTRY_MIGRATION";
|
const DISABLE_PLUGIN_REGISTRY_MIGRATION_ENV = "OPENCLAW_DISABLE_PLUGIN_REGISTRY_MIGRATION";
|
||||||
const EAGER_BUNDLED_PLUGIN_DEPS_ENV = "OPENCLAW_EAGER_BUNDLED_PLUGIN_DEPS";
|
const EAGER_BUNDLED_PLUGIN_DEPS_ENV = "OPENCLAW_EAGER_BUNDLED_PLUGIN_DEPS";
|
||||||
const DIST_INVENTORY_PATH = "dist/postinstall-inventory.json";
|
const DIST_INVENTORY_PATH = "dist/postinstall-inventory.json";
|
||||||
const LEGACY_QA_CHANNEL_DIR = ["qa", "channel"].join("-");
|
|
||||||
const LEGACY_QA_LAB_DIR = ["qa", "lab"].join("-");
|
|
||||||
const LEGACY_UPDATE_COMPAT_SIDECARS = [
|
|
||||||
{
|
|
||||||
path: `dist/extensions/${LEGACY_QA_CHANNEL_DIR}/runtime-api.js`,
|
|
||||||
content: "export {};\n",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: `dist/extensions/${LEGACY_QA_LAB_DIR}/runtime-api.js`,
|
|
||||||
content: "export {};\n",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const BAILEYS_MEDIA_FILE = join(
|
const BAILEYS_MEDIA_FILE = join(
|
||||||
"node_modules",
|
"node_modules",
|
||||||
"@whiskeysockets",
|
"@whiskeysockets",
|
||||||
@@ -329,29 +316,6 @@ export function pruneInstalledPackageDist(params = {}) {
|
|||||||
return removed;
|
return removed;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function restoreLegacyUpdaterCompatSidecars(params = {}) {
|
|
||||||
const packageRoot = params.packageRoot ?? DEFAULT_PACKAGE_ROOT;
|
|
||||||
const writeFile = params.writeFileSync ?? writeFileSync;
|
|
||||||
const makeDirectory = params.mkdirSync ?? mkdirSync;
|
|
||||||
const log = params.log ?? console;
|
|
||||||
const restored = [];
|
|
||||||
|
|
||||||
for (const sidecar of LEGACY_UPDATE_COMPAT_SIDECARS) {
|
|
||||||
// Older npm updater builds verify these exact sidecars after npm has
|
|
||||||
// already replaced the package, so generate them independently of prune
|
|
||||||
// results.
|
|
||||||
const sidecarPath = join(packageRoot, sidecar.path);
|
|
||||||
makeDirectory(dirname(sidecarPath), { recursive: true });
|
|
||||||
writeFile(sidecarPath, sidecar.content, "utf8");
|
|
||||||
restored.push(sidecar.path);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (restored.length > 0) {
|
|
||||||
log.log(`[postinstall] restored legacy updater compat sidecars: ${restored.join(", ")}`);
|
|
||||||
}
|
|
||||||
return restored;
|
|
||||||
}
|
|
||||||
|
|
||||||
function dependencySentinelPath(depName) {
|
function dependencySentinelPath(depName) {
|
||||||
return join("node_modules", ...depName.split("/"), "package.json");
|
return join("node_modules", ...depName.split("/"), "package.json");
|
||||||
}
|
}
|
||||||
@@ -781,7 +745,7 @@ export function runBundledPluginPostinstall(params = {}) {
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const prunedDistFiles = pruneInstalledPackageDist({
|
pruneInstalledPackageDist({
|
||||||
packageRoot,
|
packageRoot,
|
||||||
existsSync: pathExists,
|
existsSync: pathExists,
|
||||||
readFileSync: params.readFileSync,
|
readFileSync: params.readFileSync,
|
||||||
@@ -789,13 +753,6 @@ export function runBundledPluginPostinstall(params = {}) {
|
|||||||
rmSync: params.rmSync,
|
rmSync: params.rmSync,
|
||||||
log,
|
log,
|
||||||
});
|
});
|
||||||
restoreLegacyUpdaterCompatSidecars({
|
|
||||||
packageRoot,
|
|
||||||
removedFiles: prunedDistFiles,
|
|
||||||
mkdirSync: params.mkdirSync,
|
|
||||||
writeFileSync: params.writeFileSync,
|
|
||||||
log,
|
|
||||||
});
|
|
||||||
if (
|
if (
|
||||||
!shouldRunBundledPluginPostinstall({
|
!shouldRunBundledPluginPostinstall({
|
||||||
env,
|
env,
|
||||||
|
|||||||
@@ -79,19 +79,27 @@ const forbiddenPrefixes = [
|
|||||||
"dist/OpenClaw.app/",
|
"dist/OpenClaw.app/",
|
||||||
"dist/extensions/qa-channel/",
|
"dist/extensions/qa-channel/",
|
||||||
"dist/extensions/qa-lab/",
|
"dist/extensions/qa-lab/",
|
||||||
|
"dist/plugin-sdk/extensions/qa-channel/",
|
||||||
"dist/plugin-sdk/extensions/qa-lab/",
|
"dist/plugin-sdk/extensions/qa-lab/",
|
||||||
|
"dist/plugin-sdk/qa-channel.",
|
||||||
|
"dist/plugin-sdk/qa-channel-protocol.",
|
||||||
"dist/plugin-sdk/qa-lab.",
|
"dist/plugin-sdk/qa-lab.",
|
||||||
"dist/plugin-sdk/qa-runtime.",
|
"dist/plugin-sdk/qa-runtime.",
|
||||||
|
"dist/plugin-sdk/src/plugin-sdk/qa-channel.d.ts",
|
||||||
|
"dist/plugin-sdk/src/plugin-sdk/qa-channel-protocol.d.ts",
|
||||||
"dist/plugin-sdk/src/plugin-sdk/qa-lab.d.ts",
|
"dist/plugin-sdk/src/plugin-sdk/qa-lab.d.ts",
|
||||||
"dist/plugin-sdk/src/plugin-sdk/qa-runtime.d.ts",
|
"dist/plugin-sdk/src/plugin-sdk/qa-runtime.d.ts",
|
||||||
"dist/qa-runtime-",
|
"dist/qa-runtime-",
|
||||||
"dist/plugin-sdk/.tsbuildinfo",
|
"dist/plugin-sdk/.tsbuildinfo",
|
||||||
"docs/.generated/",
|
"docs/.generated/",
|
||||||
|
"docs/channels/qa-channel.md",
|
||||||
"qa/",
|
"qa/",
|
||||||
];
|
];
|
||||||
const forbiddenPrivateQaContentMarkers = [
|
const forbiddenPrivateQaContentMarkers = [
|
||||||
"//#region extensions/qa-lab/",
|
"//#region extensions/qa-lab/",
|
||||||
"qa-channel/runtime-api.js",
|
"qa-channel/runtime-api.js",
|
||||||
|
"qa-channel.js",
|
||||||
|
"qa-channel-protocol.js",
|
||||||
"qa-lab/cli.js",
|
"qa-lab/cli.js",
|
||||||
"qa-lab/runtime-api.js",
|
"qa-lab/runtime-api.js",
|
||||||
] as const;
|
] as const;
|
||||||
@@ -602,9 +610,6 @@ export function collectForbiddenPackContentPaths(
|
|||||||
const textPathPattern = /\.(?:[cm]?js|d\.ts|json|md|mjs|cjs)$/u;
|
const textPathPattern = /\.(?:[cm]?js|d\.ts|json|md|mjs|cjs)$/u;
|
||||||
return [...paths]
|
return [...paths]
|
||||||
.filter((packedPath) => {
|
.filter((packedPath) => {
|
||||||
if (packedPath === PACKAGE_DIST_INVENTORY_RELATIVE_PATH) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!forbiddenPrivateQaContentScanPrefixes.some((prefix) => packedPath.startsWith(prefix))) {
|
if (!forbiddenPrivateQaContentScanPrefixes.some((prefix) => packedPath.startsWith(prefix))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
#!/usr/bin/env -S node --import tsx
|
|
||||||
|
|
||||||
import fs from "node:fs";
|
|
||||||
import path from "node:path";
|
|
||||||
import { NPM_UPDATE_COMPAT_SIDECARS } from "../src/infra/npm-update-compat-sidecars.ts";
|
|
||||||
|
|
||||||
for (const entry of NPM_UPDATE_COMPAT_SIDECARS) {
|
|
||||||
fs.mkdirSync(path.dirname(entry.path), { recursive: true });
|
|
||||||
fs.writeFileSync(entry.path, entry.content, "utf8");
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
const LEGACY_QA_CHANNEL_DIR = ["qa", "channel"].join("-");
|
|
||||||
const LEGACY_QA_LAB_DIR = ["qa", "lab"].join("-");
|
|
||||||
|
|
||||||
type NpmUpdateCompatSidecar = {
|
|
||||||
path: string;
|
|
||||||
content: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const EMPTY_RUNTIME_SIDECAR = "export {};\n";
|
|
||||||
|
|
||||||
export const NPM_UPDATE_COMPAT_SIDECARS = [
|
|
||||||
{
|
|
||||||
path: `dist/extensions/${LEGACY_QA_CHANNEL_DIR}/runtime-api.js`,
|
|
||||||
content: EMPTY_RUNTIME_SIDECAR,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: `dist/extensions/${LEGACY_QA_LAB_DIR}/runtime-api.js`,
|
|
||||||
content: EMPTY_RUNTIME_SIDECAR,
|
|
||||||
},
|
|
||||||
] as const satisfies readonly NpmUpdateCompatSidecar[];
|
|
||||||
|
|
||||||
export const NPM_UPDATE_COMPAT_SIDECAR_PATHS = new Set<string>(
|
|
||||||
NPM_UPDATE_COMPAT_SIDECARS.map((entry) => entry.path),
|
|
||||||
);
|
|
||||||
|
|
||||||
export const NPM_UPDATE_OMITTED_BUNDLED_PLUGIN_ROOTS = new Set<string>([
|
|
||||||
`dist/extensions/${LEGACY_QA_CHANNEL_DIR}`,
|
|
||||||
`dist/extensions/${LEGACY_QA_LAB_DIR}`,
|
|
||||||
"dist/extensions/qa-matrix",
|
|
||||||
]);
|
|
||||||
@@ -21,7 +21,6 @@ describe("package dist inventory", () => {
|
|||||||
|
|
||||||
await expect(writePackageDistInventory(packageRoot)).resolves.toEqual([
|
await expect(writePackageDistInventory(packageRoot)).resolves.toEqual([
|
||||||
"dist/current-BR6xv1a1.js",
|
"dist/current-BR6xv1a1.js",
|
||||||
"dist/extensions/qa-channel/runtime-api.js",
|
|
||||||
]);
|
]);
|
||||||
await expect(collectPackageDistInventoryErrors(packageRoot)).resolves.toEqual([]);
|
await expect(collectPackageDistInventoryErrors(packageRoot)).resolves.toEqual([]);
|
||||||
|
|
||||||
@@ -65,6 +64,18 @@ describe("package dist inventory", () => {
|
|||||||
"index.js",
|
"index.js",
|
||||||
);
|
);
|
||||||
const omittedQaLabPluginSdk = path.join(packageRoot, "dist", "plugin-sdk", "qa-lab.js");
|
const omittedQaLabPluginSdk = path.join(packageRoot, "dist", "plugin-sdk", "qa-lab.js");
|
||||||
|
const omittedQaChannelPluginSdk = path.join(
|
||||||
|
packageRoot,
|
||||||
|
"dist",
|
||||||
|
"plugin-sdk",
|
||||||
|
"qa-channel.js",
|
||||||
|
);
|
||||||
|
const omittedQaChannelProtocolPluginSdk = path.join(
|
||||||
|
packageRoot,
|
||||||
|
"dist",
|
||||||
|
"plugin-sdk",
|
||||||
|
"qa-channel-protocol.js",
|
||||||
|
);
|
||||||
const omittedQaLabTypes = path.join(
|
const omittedQaLabTypes = path.join(
|
||||||
packageRoot,
|
packageRoot,
|
||||||
"dist",
|
"dist",
|
||||||
@@ -135,6 +146,8 @@ describe("package dist inventory", () => {
|
|||||||
await fs.writeFile(omittedQaLabChunk, "export {};\n", "utf8");
|
await fs.writeFile(omittedQaLabChunk, "export {};\n", "utf8");
|
||||||
await fs.writeFile(omittedQaMatrixChunk, "export {};\n", "utf8");
|
await fs.writeFile(omittedQaMatrixChunk, "export {};\n", "utf8");
|
||||||
await fs.writeFile(omittedQaLabPluginSdk, "export {};\n", "utf8");
|
await fs.writeFile(omittedQaLabPluginSdk, "export {};\n", "utf8");
|
||||||
|
await fs.writeFile(omittedQaChannelPluginSdk, "export {};\n", "utf8");
|
||||||
|
await fs.writeFile(omittedQaChannelProtocolPluginSdk, "export {};\n", "utf8");
|
||||||
await fs.writeFile(omittedQaLabTypes, "export {};\n", "utf8");
|
await fs.writeFile(omittedQaLabTypes, "export {};\n", "utf8");
|
||||||
await fs.writeFile(omittedQaRuntimeChunk, "export {};\n", "utf8");
|
await fs.writeFile(omittedQaRuntimeChunk, "export {};\n", "utf8");
|
||||||
await fs.writeFile(omittedRuntimeDepsStamp, "{}\n", "utf8");
|
await fs.writeFile(omittedRuntimeDepsStamp, "{}\n", "utf8");
|
||||||
@@ -150,9 +163,7 @@ describe("package dist inventory", () => {
|
|||||||
);
|
);
|
||||||
await fs.writeFile(omittedMap, "{}", "utf8");
|
await fs.writeFile(omittedMap, "{}", "utf8");
|
||||||
|
|
||||||
await expect(writePackageDistInventory(packageRoot)).resolves.toEqual([
|
await expect(writePackageDistInventory(packageRoot)).resolves.toEqual([]);
|
||||||
"dist/extensions/qa-channel/runtime-api.js",
|
|
||||||
]);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,29 @@
|
|||||||
import fs from "node:fs/promises";
|
import fs from "node:fs/promises";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { NPM_UPDATE_COMPAT_SIDECAR_PATHS } from "./npm-update-compat-sidecars.js";
|
|
||||||
|
|
||||||
export const PACKAGE_DIST_INVENTORY_RELATIVE_PATH = "dist/postinstall-inventory.json";
|
export const PACKAGE_DIST_INVENTORY_RELATIVE_PATH = "dist/postinstall-inventory.json";
|
||||||
const LEGACY_QA_CHANNEL_DIR = ["qa", "channel"].join("-");
|
const LEGACY_QA_CHANNEL_DIR = ["qa", "channel"].join("-");
|
||||||
const LEGACY_QA_LAB_DIR = ["qa", "lab"].join("-");
|
const LEGACY_QA_LAB_DIR = ["qa", "lab"].join("-");
|
||||||
const LEGACY_VERIFIER_COMPAT_INVENTORY_PATHS = [
|
|
||||||
`dist/extensions/${LEGACY_QA_CHANNEL_DIR}/runtime-api.js`,
|
|
||||||
];
|
|
||||||
const OMITTED_QA_EXTENSION_PREFIXES = [
|
const OMITTED_QA_EXTENSION_PREFIXES = [
|
||||||
`dist/extensions/${LEGACY_QA_CHANNEL_DIR}/`,
|
`dist/extensions/${LEGACY_QA_CHANNEL_DIR}/`,
|
||||||
`dist/extensions/${LEGACY_QA_LAB_DIR}/`,
|
`dist/extensions/${LEGACY_QA_LAB_DIR}/`,
|
||||||
"dist/extensions/qa-matrix/",
|
"dist/extensions/qa-matrix/",
|
||||||
];
|
];
|
||||||
const OMITTED_PRIVATE_QA_PLUGIN_SDK_PREFIXES = [`dist/plugin-sdk/extensions/${LEGACY_QA_LAB_DIR}/`];
|
const OMITTED_PRIVATE_QA_PLUGIN_SDK_PREFIXES = [
|
||||||
|
`dist/plugin-sdk/extensions/${LEGACY_QA_CHANNEL_DIR}/`,
|
||||||
|
`dist/plugin-sdk/extensions/${LEGACY_QA_LAB_DIR}/`,
|
||||||
|
];
|
||||||
const OMITTED_PRIVATE_QA_PLUGIN_SDK_FILES = new Set([
|
const OMITTED_PRIVATE_QA_PLUGIN_SDK_FILES = new Set([
|
||||||
|
`dist/plugin-sdk/${LEGACY_QA_CHANNEL_DIR}.d.ts`,
|
||||||
|
`dist/plugin-sdk/${LEGACY_QA_CHANNEL_DIR}.js`,
|
||||||
|
`dist/plugin-sdk/${LEGACY_QA_CHANNEL_DIR}-protocol.d.ts`,
|
||||||
|
`dist/plugin-sdk/${LEGACY_QA_CHANNEL_DIR}-protocol.js`,
|
||||||
`dist/plugin-sdk/${LEGACY_QA_LAB_DIR}.d.ts`,
|
`dist/plugin-sdk/${LEGACY_QA_LAB_DIR}.d.ts`,
|
||||||
`dist/plugin-sdk/${LEGACY_QA_LAB_DIR}.js`,
|
`dist/plugin-sdk/${LEGACY_QA_LAB_DIR}.js`,
|
||||||
"dist/plugin-sdk/qa-runtime.d.ts",
|
"dist/plugin-sdk/qa-runtime.d.ts",
|
||||||
"dist/plugin-sdk/qa-runtime.js",
|
"dist/plugin-sdk/qa-runtime.js",
|
||||||
|
`dist/plugin-sdk/src/plugin-sdk/${LEGACY_QA_CHANNEL_DIR}.d.ts`,
|
||||||
|
`dist/plugin-sdk/src/plugin-sdk/${LEGACY_QA_CHANNEL_DIR}-protocol.d.ts`,
|
||||||
`dist/plugin-sdk/src/plugin-sdk/${LEGACY_QA_LAB_DIR}.d.ts`,
|
`dist/plugin-sdk/src/plugin-sdk/${LEGACY_QA_LAB_DIR}.d.ts`,
|
||||||
"dist/plugin-sdk/src/plugin-sdk/qa-runtime.d.ts",
|
"dist/plugin-sdk/src/plugin-sdk/qa-runtime.d.ts",
|
||||||
]);
|
]);
|
||||||
@@ -28,6 +33,7 @@ const OMITTED_DIST_SUBTREE_PATTERNS = [
|
|||||||
/^dist\/extensions\/[^/]+\/node_modules(?:\/|$)/u,
|
/^dist\/extensions\/[^/]+\/node_modules(?:\/|$)/u,
|
||||||
/^dist\/extensions\/[^/]+\/\.openclaw-runtime-deps-[^/]+(?:\/|$)/u,
|
/^dist\/extensions\/[^/]+\/\.openclaw-runtime-deps-[^/]+(?:\/|$)/u,
|
||||||
/^dist\/extensions\/qa-matrix(?:\/|$)/u,
|
/^dist\/extensions\/qa-matrix(?:\/|$)/u,
|
||||||
|
new RegExp(`^dist/plugin-sdk/extensions/${LEGACY_QA_CHANNEL_DIR}(?:/|$)`, "u"),
|
||||||
new RegExp(`^dist/plugin-sdk/extensions/${LEGACY_QA_LAB_DIR}(?:/|$)`, "u"),
|
new RegExp(`^dist/plugin-sdk/extensions/${LEGACY_QA_LAB_DIR}(?:/|$)`, "u"),
|
||||||
] as const;
|
] as const;
|
||||||
const INSTALL_STAGE_DEBRIS_DIR_PATTERN = /^\.openclaw-install-stage(?:-[^/]+)?$/iu;
|
const INSTALL_STAGE_DEBRIS_DIR_PATTERN = /^\.openclaw-install-stage(?:-[^/]+)?$/iu;
|
||||||
@@ -67,9 +73,6 @@ function isPackagedDistPath(relativePath: string): boolean {
|
|||||||
if (relativePath === "dist/plugin-sdk/.tsbuildinfo") {
|
if (relativePath === "dist/plugin-sdk/.tsbuildinfo") {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (LEGACY_VERIFIER_COMPAT_INVENTORY_PATHS.includes(relativePath)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (
|
if (
|
||||||
OMITTED_PRIVATE_QA_PLUGIN_SDK_PREFIXES.some((prefix) => relativePath.startsWith(prefix)) ||
|
OMITTED_PRIVATE_QA_PLUGIN_SDK_PREFIXES.some((prefix) => relativePath.startsWith(prefix)) ||
|
||||||
OMITTED_PRIVATE_QA_PLUGIN_SDK_FILES.has(relativePath) ||
|
OMITTED_PRIVATE_QA_PLUGIN_SDK_FILES.has(relativePath) ||
|
||||||
@@ -219,12 +222,9 @@ export async function assertNoBundledRuntimeDepsStagingDebris(packageRoot: strin
|
|||||||
|
|
||||||
export async function writePackageDistInventory(packageRoot: string): Promise<string[]> {
|
export async function writePackageDistInventory(packageRoot: string): Promise<string[]> {
|
||||||
await assertNoBundledRuntimeDepsStagingDebris(packageRoot);
|
await assertNoBundledRuntimeDepsStagingDebris(packageRoot);
|
||||||
const inventory = [
|
const inventory = [...new Set(await collectPackageDistInventory(packageRoot))].toSorted(
|
||||||
...new Set([
|
(left, right) => left.localeCompare(right),
|
||||||
...(await collectPackageDistInventory(packageRoot)),
|
);
|
||||||
...LEGACY_VERIFIER_COMPAT_INVENTORY_PATHS,
|
|
||||||
]),
|
|
||||||
].toSorted((left, right) => left.localeCompare(right));
|
|
||||||
const inventoryPath = path.join(packageRoot, PACKAGE_DIST_INVENTORY_RELATIVE_PATH);
|
const inventoryPath = path.join(packageRoot, PACKAGE_DIST_INVENTORY_RELATIVE_PATH);
|
||||||
await fs.mkdir(path.dirname(inventoryPath), { recursive: true });
|
await fs.mkdir(path.dirname(inventoryPath), { recursive: true });
|
||||||
await fs.writeFile(inventoryPath, `${JSON.stringify(inventory, null, 2)}\n`, "utf8");
|
await fs.writeFile(inventoryPath, `${JSON.stringify(inventory, null, 2)}\n`, "utf8");
|
||||||
@@ -269,9 +269,6 @@ export async function collectPackageDistInventoryErrors(packageRoot: string): Pr
|
|||||||
|
|
||||||
for (const relativePath of expectedFiles) {
|
for (const relativePath of expectedFiles) {
|
||||||
if (!actualSet.has(relativePath)) {
|
if (!actualSet.has(relativePath)) {
|
||||||
if (NPM_UPDATE_COMPAT_SIDECAR_PATHS.has(relativePath)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
errors.push(`missing packaged dist file ${relativePath}`);
|
errors.push(`missing packaged dist file ${relativePath}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { bundledDistPluginFile } from "../../test/helpers/bundled-plugin-paths.j
|
|||||||
import { BUNDLED_RUNTIME_SIDECAR_PATHS } from "../plugins/runtime-sidecar-paths.js";
|
import { BUNDLED_RUNTIME_SIDECAR_PATHS } from "../plugins/runtime-sidecar-paths.js";
|
||||||
import { withTempDir } from "../test-helpers/temp-dir.js";
|
import { withTempDir } from "../test-helpers/temp-dir.js";
|
||||||
import { captureEnv } from "../test-utils/env.js";
|
import { captureEnv } from "../test-utils/env.js";
|
||||||
import { NPM_UPDATE_COMPAT_SIDECAR_PATHS } from "./npm-update-compat-sidecars.js";
|
|
||||||
import {
|
import {
|
||||||
PACKAGE_DIST_INVENTORY_RELATIVE_PATH,
|
PACKAGE_DIST_INVENTORY_RELATIVE_PATH,
|
||||||
writePackageDistInventory,
|
writePackageDistInventory,
|
||||||
@@ -39,14 +38,6 @@ async function writeGlobalPackageJson(packageRoot: string, version = "1.0.0") {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function writeCompatSidecars(packageRoot: string) {
|
|
||||||
for (const relativePath of NPM_UPDATE_COMPAT_SIDECAR_PATHS) {
|
|
||||||
const absolutePath = path.join(packageRoot, relativePath);
|
|
||||||
await fs.mkdir(path.dirname(absolutePath), { recursive: true });
|
|
||||||
await fs.writeFile(absolutePath, "export {};\n", "utf-8");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function writeBundledPluginPackageJson(
|
async function writeBundledPluginPackageJson(
|
||||||
packageRoot: string,
|
packageRoot: string,
|
||||||
pluginId: string,
|
pluginId: string,
|
||||||
@@ -399,7 +390,6 @@ describe("update global helpers", () => {
|
|||||||
it("checks installed dist against the packaged inventory", async () => {
|
it("checks installed dist against the packaged inventory", async () => {
|
||||||
await withTempDir({ prefix: "openclaw-update-global-pkg-" }, async (packageRoot) => {
|
await withTempDir({ prefix: "openclaw-update-global-pkg-" }, async (packageRoot) => {
|
||||||
await writeGlobalPackageJson(packageRoot);
|
await writeGlobalPackageJson(packageRoot);
|
||||||
await writeCompatSidecars(packageRoot);
|
|
||||||
for (const relativePath of BUNDLED_RUNTIME_SIDECAR_PATHS) {
|
for (const relativePath of BUNDLED_RUNTIME_SIDECAR_PATHS) {
|
||||||
const absolutePath = path.join(packageRoot, relativePath);
|
const absolutePath = path.join(packageRoot, relativePath);
|
||||||
await fs.mkdir(path.dirname(absolutePath), { recursive: true });
|
await fs.mkdir(path.dirname(absolutePath), { recursive: true });
|
||||||
@@ -428,7 +418,6 @@ describe("update global helpers", () => {
|
|||||||
it("ignores bundled plugin install stages during installed dist verification", async () => {
|
it("ignores bundled plugin install stages during installed dist verification", async () => {
|
||||||
await withTempDir({ prefix: "openclaw-update-global-plugin-stage-" }, async (packageRoot) => {
|
await withTempDir({ prefix: "openclaw-update-global-plugin-stage-" }, async (packageRoot) => {
|
||||||
await writeGlobalPackageJson(packageRoot);
|
await writeGlobalPackageJson(packageRoot);
|
||||||
await writeCompatSidecars(packageRoot);
|
|
||||||
await fs.mkdir(path.join(packageRoot, "dist", "extensions", "brave"), { recursive: true });
|
await fs.mkdir(path.join(packageRoot, "dist", "extensions", "brave"), { recursive: true });
|
||||||
await writePackageDistInventory(packageRoot);
|
await writePackageDistInventory(packageRoot);
|
||||||
|
|
||||||
@@ -456,7 +445,6 @@ describe("update global helpers", () => {
|
|||||||
it("does not require private QA sidecars when the inventory is missing", async () => {
|
it("does not require private QA sidecars when the inventory is missing", async () => {
|
||||||
await withTempDir({ prefix: "openclaw-update-global-legacy-" }, async (packageRoot) => {
|
await withTempDir({ prefix: "openclaw-update-global-legacy-" }, async (packageRoot) => {
|
||||||
await writeGlobalPackageJson(packageRoot);
|
await writeGlobalPackageJson(packageRoot);
|
||||||
await writeCompatSidecars(packageRoot);
|
|
||||||
|
|
||||||
await expect(collectInstalledGlobalPackageErrors({ packageRoot })).resolves.toEqual([]);
|
await expect(collectInstalledGlobalPackageErrors({ packageRoot })).resolves.toEqual([]);
|
||||||
});
|
});
|
||||||
@@ -467,7 +455,6 @@ describe("update global helpers", () => {
|
|||||||
{ prefix: "openclaw-update-global-missing-inventory-new-" },
|
{ prefix: "openclaw-update-global-missing-inventory-new-" },
|
||||||
async (packageRoot) => {
|
async (packageRoot) => {
|
||||||
await writeGlobalPackageJson(packageRoot, "2026.4.15");
|
await writeGlobalPackageJson(packageRoot, "2026.4.15");
|
||||||
await writeCompatSidecars(packageRoot);
|
|
||||||
|
|
||||||
await expect(collectInstalledGlobalPackageErrors({ packageRoot })).resolves.toContain(
|
await expect(collectInstalledGlobalPackageErrors({ packageRoot })).resolves.toContain(
|
||||||
`missing package dist inventory ${PACKAGE_DIST_INVENTORY_RELATIVE_PATH}`,
|
`missing package dist inventory ${PACKAGE_DIST_INVENTORY_RELATIVE_PATH}`,
|
||||||
@@ -511,7 +498,6 @@ describe("update global helpers", () => {
|
|||||||
{ prefix: "openclaw-update-global-critical-sidecars-" },
|
{ prefix: "openclaw-update-global-critical-sidecars-" },
|
||||||
async (packageRoot) => {
|
async (packageRoot) => {
|
||||||
await writeGlobalPackageJson(packageRoot, "2026.4.15");
|
await writeGlobalPackageJson(packageRoot, "2026.4.15");
|
||||||
await writeCompatSidecars(packageRoot);
|
|
||||||
await writeBundledPluginPackageJson(packageRoot, "matrix", "@openclaw/matrix");
|
await writeBundledPluginPackageJson(packageRoot, "matrix", "@openclaw/matrix");
|
||||||
await writePackageDistInventory(packageRoot);
|
await writePackageDistInventory(packageRoot);
|
||||||
|
|
||||||
@@ -527,7 +513,6 @@ describe("update global helpers", () => {
|
|||||||
{ prefix: "openclaw-update-global-stale-private-qa-" },
|
{ prefix: "openclaw-update-global-stale-private-qa-" },
|
||||||
async (packageRoot) => {
|
async (packageRoot) => {
|
||||||
await writeGlobalPackageJson(packageRoot, "2026.4.15");
|
await writeGlobalPackageJson(packageRoot, "2026.4.15");
|
||||||
await writeCompatSidecars(packageRoot);
|
|
||||||
await writeBundledPluginPackageJson(packageRoot, "qa-lab", "@openclaw/qa-lab");
|
await writeBundledPluginPackageJson(packageRoot, "qa-lab", "@openclaw/qa-lab");
|
||||||
await writePackageDistInventory(packageRoot);
|
await writePackageDistInventory(packageRoot);
|
||||||
|
|
||||||
|
|||||||
@@ -5,10 +5,6 @@ import path from "node:path";
|
|||||||
import { BUNDLED_RUNTIME_SIDECAR_PATHS } from "../plugins/runtime-sidecar-paths.js";
|
import { BUNDLED_RUNTIME_SIDECAR_PATHS } from "../plugins/runtime-sidecar-paths.js";
|
||||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||||
import { pathExists } from "../utils.js";
|
import { pathExists } from "../utils.js";
|
||||||
import {
|
|
||||||
NPM_UPDATE_COMPAT_SIDECAR_PATHS,
|
|
||||||
NPM_UPDATE_OMITTED_BUNDLED_PLUGIN_ROOTS,
|
|
||||||
} from "./npm-update-compat-sidecars.js";
|
|
||||||
import {
|
import {
|
||||||
collectPackageDistInventory,
|
collectPackageDistInventory,
|
||||||
PACKAGE_DIST_INVENTORY_RELATIVE_PATH,
|
PACKAGE_DIST_INVENTORY_RELATIVE_PATH,
|
||||||
@@ -46,6 +42,11 @@ const NPM_GLOBAL_INSTALL_OMIT_OPTIONAL_FLAGS = [
|
|||||||
...NPM_GLOBAL_INSTALL_QUIET_FLAGS,
|
...NPM_GLOBAL_INSTALL_QUIET_FLAGS,
|
||||||
] as const;
|
] as const;
|
||||||
const FIRST_PACKAGED_DIST_INVENTORY_VERSION = { major: 2026, minor: 4, patch: 15 };
|
const FIRST_PACKAGED_DIST_INVENTORY_VERSION = { major: 2026, minor: 4, patch: 15 };
|
||||||
|
const OMITTED_PRIVATE_QA_BUNDLED_PLUGIN_ROOTS = new Set([
|
||||||
|
"dist/extensions/qa-channel",
|
||||||
|
"dist/extensions/qa-lab",
|
||||||
|
"dist/extensions/qa-matrix",
|
||||||
|
]);
|
||||||
|
|
||||||
function normalizePackageTarget(value: string): string {
|
function normalizePackageTarget(value: string): string {
|
||||||
return value.trim();
|
return value.trim();
|
||||||
@@ -187,25 +188,18 @@ async function collectInstalledPackageDistErrors(params: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function collectLegacyInstalledPackageDistPaths(packageRoot: string): Promise<string[]> {
|
async function collectLegacyInstalledPackageDistPaths(packageRoot: string): Promise<string[]> {
|
||||||
const expectedFiles = new Set(NPM_UPDATE_COMPAT_SIDECAR_PATHS);
|
return await collectCriticalInstalledPackageDistPaths(packageRoot);
|
||||||
for (const relativePath of await collectCriticalInstalledPackageDistPaths(packageRoot)) {
|
|
||||||
expectedFiles.add(relativePath);
|
|
||||||
}
|
|
||||||
return [...expectedFiles].toSorted((left, right) => left.localeCompare(right));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function collectCriticalInstalledPackageDistPaths(packageRoot: string): Promise<string[]> {
|
async function collectCriticalInstalledPackageDistPaths(packageRoot: string): Promise<string[]> {
|
||||||
const expectedFiles = new Set<string>();
|
const expectedFiles = new Set<string>();
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
BUNDLED_RUNTIME_SIDECAR_PATHS.map(async (relativePath) => {
|
BUNDLED_RUNTIME_SIDECAR_PATHS.map(async (relativePath) => {
|
||||||
if (NPM_UPDATE_COMPAT_SIDECAR_PATHS.has(relativePath)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const pluginRoot = resolveBundledPluginRoot(relativePath);
|
const pluginRoot = resolveBundledPluginRoot(relativePath);
|
||||||
if (pluginRoot === null) {
|
if (pluginRoot === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (NPM_UPDATE_OMITTED_BUNDLED_PLUGIN_ROOTS.has(pluginRoot)) {
|
if (OMITTED_PRIVATE_QA_BUNDLED_PLUGIN_ROOTS.has(pluginRoot)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
@@ -239,18 +233,12 @@ async function collectInstalledPathErrors(params: {
|
|||||||
? actualSet.has(relativePath)
|
? actualSet.has(relativePath)
|
||||||
: await pathExists(path.join(params.packageRoot, relativePath));
|
: await pathExists(path.join(params.packageRoot, relativePath));
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
if (NPM_UPDATE_COMPAT_SIDECAR_PATHS.has(relativePath)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
errors.push(params.missingMessage(relativePath));
|
errors.push(params.missingMessage(relativePath));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (actualSet !== null && params.unexpectedMessage) {
|
if (actualSet !== null && params.unexpectedMessage) {
|
||||||
const expectedSet = new Set(params.expectedFiles);
|
const expectedSet = new Set(params.expectedFiles);
|
||||||
for (const relativePath of params.actualFiles ?? []) {
|
for (const relativePath of params.actualFiles ?? []) {
|
||||||
if (NPM_UPDATE_COMPAT_SIDECAR_PATHS.has(relativePath)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!expectedSet.has(relativePath)) {
|
if (!expectedSet.has(relativePath)) {
|
||||||
errors.push(params.unexpectedMessage(relativePath));
|
errors.push(params.unexpectedMessage(relativePath));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -354,6 +354,8 @@ describe("plugin-sdk subpath exports", () => {
|
|||||||
"lobster",
|
"lobster",
|
||||||
"pairing-access",
|
"pairing-access",
|
||||||
"provider-model-definitions",
|
"provider-model-definitions",
|
||||||
|
"qa-channel",
|
||||||
|
"qa-channel-protocol",
|
||||||
"reply-prefix",
|
"reply-prefix",
|
||||||
"secret-input-schema",
|
"secret-input-schema",
|
||||||
"signal-core",
|
"signal-core",
|
||||||
|
|||||||
@@ -333,16 +333,26 @@ describe("collectForbiddenPackedPathErrors", () => {
|
|||||||
"dist/extensions/qa-channel/package.json",
|
"dist/extensions/qa-channel/package.json",
|
||||||
"dist/extensions/qa-lab/runtime-api.js",
|
"dist/extensions/qa-lab/runtime-api.js",
|
||||||
"dist/extensions/qa-lab/src/cli.js",
|
"dist/extensions/qa-lab/src/cli.js",
|
||||||
|
"dist/plugin-sdk/extensions/qa-channel/api.d.ts",
|
||||||
"dist/plugin-sdk/extensions/qa-lab/cli.d.ts",
|
"dist/plugin-sdk/extensions/qa-lab/cli.d.ts",
|
||||||
|
"dist/plugin-sdk/qa-channel.js",
|
||||||
|
"dist/plugin-sdk/qa-channel-protocol.d.ts",
|
||||||
"dist/qa-runtime-B9LDtssJ.js",
|
"dist/qa-runtime-B9LDtssJ.js",
|
||||||
|
"docs/channels/qa-channel.md",
|
||||||
|
"docs/refactor/qa.md",
|
||||||
"qa/scenarios/index.md",
|
"qa/scenarios/index.md",
|
||||||
]),
|
]),
|
||||||
).toEqual([
|
).toEqual([
|
||||||
'npm package must not include private QA channel artifact "dist/extensions/qa-channel/package.json".',
|
'npm package must not include private QA channel artifact "dist/extensions/qa-channel/package.json".',
|
||||||
'npm package must not include private QA channel artifact "dist/extensions/qa-channel/runtime-api.js".',
|
'npm package must not include private QA channel artifact "dist/extensions/qa-channel/runtime-api.js".',
|
||||||
|
'npm package must not include private QA channel docs "docs/channels/qa-channel.md".',
|
||||||
|
'npm package must not include private QA channel SDK artifact "dist/plugin-sdk/qa-channel-protocol.d.ts".',
|
||||||
|
'npm package must not include private QA channel SDK artifact "dist/plugin-sdk/qa-channel.js".',
|
||||||
|
'npm package must not include private QA channel type artifact "dist/plugin-sdk/extensions/qa-channel/api.d.ts".',
|
||||||
'npm package must not include private QA lab artifact "dist/extensions/qa-lab/runtime-api.js".',
|
'npm package must not include private QA lab artifact "dist/extensions/qa-lab/runtime-api.js".',
|
||||||
'npm package must not include private QA lab artifact "dist/extensions/qa-lab/src/cli.js".',
|
'npm package must not include private QA lab artifact "dist/extensions/qa-lab/src/cli.js".',
|
||||||
'npm package must not include private QA lab type artifact "dist/plugin-sdk/extensions/qa-lab/cli.d.ts".',
|
'npm package must not include private QA lab type artifact "dist/plugin-sdk/extensions/qa-lab/cli.d.ts".',
|
||||||
|
'npm package must not include private QA refactor docs "docs/refactor/qa.md".',
|
||||||
'npm package must not include private QA runtime chunk "dist/qa-runtime-B9LDtssJ.js".',
|
'npm package must not include private QA runtime chunk "dist/qa-runtime-B9LDtssJ.js".',
|
||||||
'npm package must not include private QA suite artifact "qa/scenarios/index.md".',
|
'npm package must not include private QA suite artifact "qa/scenarios/index.md".',
|
||||||
]);
|
]);
|
||||||
@@ -380,7 +390,7 @@ describe("collectForbiddenPackedPathErrors", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it("allows legacy QA compatibility paths in the generated dist inventory", () => {
|
it("rejects private QA paths in the generated dist inventory", () => {
|
||||||
const rootDir = mkdtempSync(join(tmpdir(), "openclaw-pack-inventory-"));
|
const rootDir = mkdtempSync(join(tmpdir(), "openclaw-pack-inventory-"));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -393,7 +403,9 @@ describe("collectForbiddenPackedPathErrors", () => {
|
|||||||
|
|
||||||
expect(
|
expect(
|
||||||
collectForbiddenPackedContentErrors([PACKAGE_DIST_INVENTORY_RELATIVE_PATH], rootDir),
|
collectForbiddenPackedContentErrors([PACKAGE_DIST_INVENTORY_RELATIVE_PATH], rootDir),
|
||||||
).toEqual([]);
|
).toEqual([
|
||||||
|
'npm package must not include private QA lab marker "qa-lab/runtime-api.js" in "dist/postinstall-inventory.json".',
|
||||||
|
]);
|
||||||
} finally {
|
} finally {
|
||||||
rmSync(rootDir, { recursive: true, force: true });
|
rmSync(rootDir, { recursive: true, force: true });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -451,19 +451,29 @@ describe("collectForbiddenPackPaths", () => {
|
|||||||
"dist/index.js",
|
"dist/index.js",
|
||||||
"dist/extensions/qa-channel/runtime-api.js",
|
"dist/extensions/qa-channel/runtime-api.js",
|
||||||
"dist/extensions/qa-lab/runtime-api.js",
|
"dist/extensions/qa-lab/runtime-api.js",
|
||||||
|
"dist/plugin-sdk/extensions/qa-channel/api.d.ts",
|
||||||
"dist/plugin-sdk/extensions/qa-lab/cli.d.ts",
|
"dist/plugin-sdk/extensions/qa-lab/cli.d.ts",
|
||||||
|
"dist/plugin-sdk/qa-channel.js",
|
||||||
|
"dist/plugin-sdk/qa-channel-protocol.d.ts",
|
||||||
"dist/plugin-sdk/qa-lab.js",
|
"dist/plugin-sdk/qa-lab.js",
|
||||||
"dist/plugin-sdk/qa-runtime.js",
|
"dist/plugin-sdk/qa-runtime.js",
|
||||||
"dist/qa-runtime-B9LDtssJ.js",
|
"dist/qa-runtime-B9LDtssJ.js",
|
||||||
|
"docs/channels/qa-channel.md",
|
||||||
|
"docs/refactor/qa.md",
|
||||||
"qa/scenarios/index.md",
|
"qa/scenarios/index.md",
|
||||||
]),
|
]),
|
||||||
).toEqual([
|
).toEqual([
|
||||||
"dist/extensions/qa-channel/runtime-api.js",
|
"dist/extensions/qa-channel/runtime-api.js",
|
||||||
"dist/extensions/qa-lab/runtime-api.js",
|
"dist/extensions/qa-lab/runtime-api.js",
|
||||||
|
"dist/plugin-sdk/extensions/qa-channel/api.d.ts",
|
||||||
"dist/plugin-sdk/extensions/qa-lab/cli.d.ts",
|
"dist/plugin-sdk/extensions/qa-lab/cli.d.ts",
|
||||||
|
"dist/plugin-sdk/qa-channel-protocol.d.ts",
|
||||||
|
"dist/plugin-sdk/qa-channel.js",
|
||||||
"dist/plugin-sdk/qa-lab.js",
|
"dist/plugin-sdk/qa-lab.js",
|
||||||
"dist/plugin-sdk/qa-runtime.js",
|
"dist/plugin-sdk/qa-runtime.js",
|
||||||
"dist/qa-runtime-B9LDtssJ.js",
|
"dist/qa-runtime-B9LDtssJ.js",
|
||||||
|
"docs/channels/qa-channel.md",
|
||||||
|
"docs/refactor/qa.md",
|
||||||
"qa/scenarios/index.md",
|
"qa/scenarios/index.md",
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
@@ -488,7 +498,7 @@ describe("collectForbiddenPackPaths", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it("allows legacy QA compatibility paths in the generated dist inventory", () => {
|
it("blocks private QA paths in the generated dist inventory", () => {
|
||||||
const tempRoot = mkdtempSync(join(tmpdir(), "openclaw-release-inventory-"));
|
const tempRoot = mkdtempSync(join(tmpdir(), "openclaw-release-inventory-"));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -501,7 +511,7 @@ describe("collectForbiddenPackPaths", () => {
|
|||||||
|
|
||||||
expect(
|
expect(
|
||||||
collectForbiddenPackContentPaths([PACKAGE_DIST_INVENTORY_RELATIVE_PATH], tempRoot),
|
collectForbiddenPackContentPaths([PACKAGE_DIST_INVENTORY_RELATIVE_PATH], tempRoot),
|
||||||
).toEqual([]);
|
).toEqual([PACKAGE_DIST_INVENTORY_RELATIVE_PATH]);
|
||||||
} finally {
|
} finally {
|
||||||
rmSync(tempRoot, { recursive: true, force: true });
|
rmSync(tempRoot, { recursive: true, force: true });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,7 @@ import {
|
|||||||
pruneBundledPluginSourceNodeModules,
|
pruneBundledPluginSourceNodeModules,
|
||||||
runBundledPluginPostinstall,
|
runBundledPluginPostinstall,
|
||||||
runPluginRegistryPostinstallMigration,
|
runPluginRegistryPostinstallMigration,
|
||||||
restoreLegacyUpdaterCompatSidecars,
|
|
||||||
} from "../../scripts/postinstall-bundled-plugins.mjs";
|
} from "../../scripts/postinstall-bundled-plugins.mjs";
|
||||||
import { NPM_UPDATE_COMPAT_SIDECARS } from "../../src/infra/npm-update-compat-sidecars.ts";
|
|
||||||
import { writePackageDistInventory } from "../../src/infra/package-dist-inventory.ts";
|
import { writePackageDistInventory } from "../../src/infra/package-dist-inventory.ts";
|
||||||
import { createScriptTestHarness } from "./test-helpers.js";
|
import { createScriptTestHarness } from "./test-helpers.js";
|
||||||
|
|
||||||
@@ -396,7 +394,7 @@ describe("bundled plugin postinstall", () => {
|
|||||||
await expect(fs.stat(staleFile)).rejects.toMatchObject({ code: "ENOENT" });
|
await expect(fs.stat(staleFile)).rejects.toMatchObject({ code: "ENOENT" });
|
||||||
});
|
});
|
||||||
|
|
||||||
it("restores only postinstall-generated QA compat sidecars after pruning old installs", async () => {
|
it("prunes stale private QA files without restoring compat sidecars", async () => {
|
||||||
const packageRoot = await createTempDirAsync("openclaw-packaged-install-qa-compat-");
|
const packageRoot = await createTempDirAsync("openclaw-packaged-install-qa-compat-");
|
||||||
const currentFile = path.join(packageRoot, "dist", "entry.js");
|
const currentFile = path.join(packageRoot, "dist", "entry.js");
|
||||||
const stalePackage = path.join(packageRoot, "dist", "extensions", "qa-lab", "package.json");
|
const stalePackage = path.join(packageRoot, "dist", "extensions", "qa-lab", "package.json");
|
||||||
@@ -422,10 +420,8 @@ describe("bundled plugin postinstall", () => {
|
|||||||
await expect(fs.stat(stalePackage)).rejects.toMatchObject({ code: "ENOENT" });
|
await expect(fs.stat(stalePackage)).rejects.toMatchObject({ code: "ENOENT" });
|
||||||
await expect(fs.stat(staleManifest)).rejects.toMatchObject({ code: "ENOENT" });
|
await expect(fs.stat(staleManifest)).rejects.toMatchObject({ code: "ENOENT" });
|
||||||
await expect(
|
await expect(
|
||||||
fs.readFile(path.join(packageRoot, "dist", "extensions", "qa-channel", "runtime-api.js"), {
|
fs.stat(path.join(packageRoot, "dist", "extensions", "qa-channel", "runtime-api.js")),
|
||||||
encoding: "utf8",
|
).rejects.toMatchObject({ code: "ENOENT" });
|
||||||
}),
|
|
||||||
).resolves.toBe("export {};\n");
|
|
||||||
await expect(
|
await expect(
|
||||||
fs.stat(path.join(packageRoot, "dist", "extensions", "qa-channel", "package.json")),
|
fs.stat(path.join(packageRoot, "dist", "extensions", "qa-channel", "package.json")),
|
||||||
).rejects.toMatchObject({ code: "ENOENT" });
|
).rejects.toMatchObject({ code: "ENOENT" });
|
||||||
@@ -433,26 +429,8 @@ describe("bundled plugin postinstall", () => {
|
|||||||
fs.stat(path.join(packageRoot, "dist", "extensions", "qa-channel", "openclaw.plugin.json")),
|
fs.stat(path.join(packageRoot, "dist", "extensions", "qa-channel", "openclaw.plugin.json")),
|
||||||
).rejects.toMatchObject({ code: "ENOENT" });
|
).rejects.toMatchObject({ code: "ENOENT" });
|
||||||
await expect(
|
await expect(
|
||||||
fs.readFile(path.join(packageRoot, "dist", "extensions", "qa-lab", "runtime-api.js"), {
|
fs.stat(path.join(packageRoot, "dist", "extensions", "qa-lab", "runtime-api.js")),
|
||||||
encoding: "utf8",
|
).rejects.toMatchObject({ code: "ENOENT" });
|
||||||
}),
|
|
||||||
).resolves.toBe("export {};\n");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("keeps postinstall QA compat sidecars aligned with update verification metadata", async () => {
|
|
||||||
const packageRoot = await createTempDirAsync("openclaw-packaged-install-qa-compat-");
|
|
||||||
|
|
||||||
const restored = restoreLegacyUpdaterCompatSidecars({
|
|
||||||
packageRoot,
|
|
||||||
log: { log: vi.fn(), warn: vi.fn() },
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(restored).toEqual(NPM_UPDATE_COMPAT_SIDECARS.map((sidecar) => sidecar.path));
|
|
||||||
for (const sidecar of NPM_UPDATE_COMPAT_SIDECARS) {
|
|
||||||
await expect(fs.readFile(path.join(packageRoot, sidecar.path), "utf8")).resolves.toBe(
|
|
||||||
sidecar.content,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("keeps packaged postinstall non-fatal when the dist inventory is missing", async () => {
|
it("keeps packaged postinstall non-fatal when the dist inventory is missing", async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user