diff --git a/scripts/postinstall-bundled-plugins.mjs b/scripts/postinstall-bundled-plugins.mjs index be084e6d039..2edb66a13c5 100644 --- a/scripts/postinstall-bundled-plugins.mjs +++ b/scripts/postinstall-bundled-plugins.mjs @@ -705,10 +705,22 @@ export async function runPluginRegistryPostinstallMigration(params = {}) { export function isSourceCheckoutRoot(params) { const pathExists = params.existsSync ?? existsSync; + const readFile = params.readFileSync ?? readFileSync; const hasPostinstallInventory = pathExists(join(params.packageRoot, DIST_INVENTORY_PATH)); + let hasDeclaredMirroredPackageRuntimeDeps = false; + try { + const packageJson = JSON.parse(readFile(join(params.packageRoot, "package.json"), "utf8")); + const mirrored = packageJson?.openclaw?.bundle?.mirroredRootRuntimeDependencies; + hasDeclaredMirroredPackageRuntimeDeps = Array.isArray(mirrored) && mirrored.length > 0; + } catch { + hasDeclaredMirroredPackageRuntimeDeps = false; + } + const hasPackagedRuntimeDepsLayout = + hasPostinstallInventory || hasDeclaredMirroredPackageRuntimeDeps; return ( (pathExists(join(params.packageRoot, ".git")) || - (pathExists(join(params.packageRoot, "pnpm-workspace.yaml")) && !hasPostinstallInventory)) && + (pathExists(join(params.packageRoot, "pnpm-workspace.yaml")) && + !hasPackagedRuntimeDepsLayout)) && pathExists(join(params.packageRoot, "src")) && pathExists(join(params.packageRoot, "extensions")) ); diff --git a/test/scripts/postinstall-bundled-plugins.test.ts b/test/scripts/postinstall-bundled-plugins.test.ts index 7f374e3c6a1..8748a9ddfba 100644 --- a/test/scripts/postinstall-bundled-plugins.test.ts +++ b/test/scripts/postinstall-bundled-plugins.test.ts @@ -140,6 +140,7 @@ describe("bundled plugin postinstall", () => { it("does not classify published packages with source files as source checkouts", () => { const packageRoot = "/pkg"; const existingPaths = new Set([ + path.join(packageRoot, "package.json"), path.join(packageRoot, "pnpm-workspace.yaml"), path.join(packageRoot, "src"), path.join(packageRoot, "extensions"), @@ -150,6 +151,14 @@ describe("bundled plugin postinstall", () => { isSourceCheckoutRoot({ packageRoot, existsSync: (value: string) => existingPaths.has(value), + readFileSync: () => + JSON.stringify({ + openclaw: { + bundle: { + mirroredRootRuntimeDependencies: ["json5"], + }, + }, + }), }), ).toBe(false); });