mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 09:20:43 +00:00
fix: preserve bundled facade fallback semantics
This commit is contained in:
@@ -19,6 +19,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
### Fixes
|
||||
|
||||
- Plugin SDK: fall back from partial bundled plugin directory overrides to package source public surfaces while preserving `OPENCLAW_DISABLE_BUNDLED_PLUGINS` as a hard disable. (#72817) Thanks @serkonyc.
|
||||
- Agents/ACPX: stop forwarding Codex ACP timeout config controls that Codex rejects while preserving OpenClaw's run-timeout watchdog for ACP subagents. Fixes #73052. Thanks @pfrederiksen and @richa65.
|
||||
- Memory/Ollama: add `memorySearch.remote.nonBatchConcurrency` for inline embedding indexing, default Ollama non-batch indexing to one request at a time, and keep batch concurrency separate from non-batch concurrency so local embedding backfills avoid timeout storms on smaller hosts. Carries forward #57733. Thanks @itilys.
|
||||
- Docs/tools: clarify that `tools.profile: "messaging"` is intentionally narrow and that `tools.profile: "full"` is the unrestricted baseline for broader command/control access. Carries forward #39954. Thanks @posigit.
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
|
||||
const { createTempDirSync } = createPluginSdkTestHarness();
|
||||
const originalBundledPluginsDir = process.env.OPENCLAW_BUNDLED_PLUGINS_DIR;
|
||||
const originalDisableBundledPlugins = process.env.OPENCLAW_DISABLE_BUNDLED_PLUGINS;
|
||||
const FACADE_LOADER_GLOBAL = "__openclawTestLoadBundledPluginPublicSurfaceModuleSync";
|
||||
type FacadeLoaderJitiFactory = NonNullable<Parameters<typeof setFacadeLoaderJitiFactoryForTest>[0]>;
|
||||
|
||||
@@ -86,6 +87,11 @@ afterEach(() => {
|
||||
} else {
|
||||
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = originalBundledPluginsDir;
|
||||
}
|
||||
if (originalDisableBundledPlugins === undefined) {
|
||||
delete process.env.OPENCLAW_DISABLE_BUNDLED_PLUGINS;
|
||||
} else {
|
||||
process.env.OPENCLAW_DISABLE_BUNDLED_PLUGINS = originalDisableBundledPlugins;
|
||||
}
|
||||
});
|
||||
|
||||
describe("plugin-sdk facade loader", () => {
|
||||
@@ -108,6 +114,31 @@ describe("plugin-sdk facade loader", () => {
|
||||
expect(fromB.marker).toBe("override-b");
|
||||
});
|
||||
|
||||
it("falls back to package source surfaces when an override dir lacks a bundled plugin", () => {
|
||||
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = createTempDirSync("openclaw-facade-loader-empty-");
|
||||
|
||||
const loaded = loadBundledPluginPublicSurfaceModuleSync<{
|
||||
closeTrackedBrowserTabsForSessions: unknown;
|
||||
}>({
|
||||
dirName: "browser",
|
||||
artifactBasename: "browser-maintenance.js",
|
||||
});
|
||||
|
||||
expect(loaded.closeTrackedBrowserTabsForSessions).toEqual(expect.any(Function));
|
||||
});
|
||||
|
||||
it("keeps bundled facade loads disabled when bundled plugins are disabled", () => {
|
||||
process.env.OPENCLAW_DISABLE_BUNDLED_PLUGINS = "1";
|
||||
delete process.env.OPENCLAW_BUNDLED_PLUGINS_DIR;
|
||||
|
||||
expect(() =>
|
||||
loadBundledPluginPublicSurfaceModuleSync({
|
||||
dirName: "browser",
|
||||
artifactBasename: "browser-maintenance.js",
|
||||
}),
|
||||
).toThrow("Unable to resolve bundled plugin public surface browser/browser-maintenance.js");
|
||||
});
|
||||
|
||||
it("shares loaded facade ids with facade-runtime", () => {
|
||||
const dir = createBundledPluginDir("openclaw-facade-loader-ids-", "identity-check");
|
||||
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = dir;
|
||||
|
||||
@@ -59,7 +59,11 @@ function createFacadeResolutionKey(params: {
|
||||
env?: NodeJS.ProcessEnv;
|
||||
}): string {
|
||||
const bundledPluginsDir = resolveBundledPluginsDir(params.env ?? process.env);
|
||||
return createFacadeResolutionKeyShared({ ...params, bundledPluginsDir });
|
||||
return createFacadeResolutionKeyShared({
|
||||
...params,
|
||||
bundledPluginsDir,
|
||||
...(params.env ? { env: params.env } : {}),
|
||||
});
|
||||
}
|
||||
|
||||
function resolveFacadeModuleLocationUncached(params: {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { areBundledPluginsDisabled } from "../plugins/bundled-dir.js";
|
||||
import {
|
||||
PUBLIC_SURFACE_SOURCE_EXTENSIONS,
|
||||
normalizeBundledPluginArtifactSubpath,
|
||||
@@ -22,10 +23,12 @@ export function createFacadeResolutionKey(params: {
|
||||
dirName: string;
|
||||
artifactBasename: string;
|
||||
bundledPluginsDir?: string | null;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
}): string {
|
||||
const disabledKey = areBundledPluginsDisabled(params.env ?? process.env) ? "disabled" : "enabled";
|
||||
return `${params.dirName}::${params.artifactBasename}::${
|
||||
params.bundledPluginsDir ? path.resolve(params.bundledPluginsDir) : "<default>"
|
||||
}`;
|
||||
}::${disabledKey}`;
|
||||
}
|
||||
|
||||
export function resolveCachedFacadeModuleLocation<TLocation>(params: {
|
||||
@@ -64,6 +67,8 @@ export function resolveBundledFacadeModuleLocation(params: {
|
||||
bundledPluginsDir?: string | null;
|
||||
}): FacadeModuleLocationLike | null {
|
||||
const preferSource = !params.currentModulePath.includes(`${path.sep}dist${path.sep}`);
|
||||
const env = params.env ?? process.env;
|
||||
const packageSourceRoot = path.resolve(params.packageRoot, "extensions");
|
||||
const publicSurfaceParams = {
|
||||
rootDir: params.packageRoot,
|
||||
env: params.env,
|
||||
@@ -75,8 +80,16 @@ export function resolveBundledFacadeModuleLocation(params: {
|
||||
? (resolveBundledPluginSourcePublicSurfacePath({
|
||||
dirName: params.dirName,
|
||||
artifactBasename: params.artifactBasename,
|
||||
sourceRoot: params.bundledPluginsDir ?? path.resolve(params.packageRoot, "extensions"),
|
||||
}) ?? resolveBundledPluginPublicSurfacePath(publicSurfaceParams))
|
||||
sourceRoot: params.bundledPluginsDir ?? packageSourceRoot,
|
||||
}) ??
|
||||
(params.bundledPluginsDir && !areBundledPluginsDisabled(env)
|
||||
? resolveBundledPluginSourcePublicSurfacePath({
|
||||
dirName: params.dirName,
|
||||
artifactBasename: params.artifactBasename,
|
||||
sourceRoot: packageSourceRoot,
|
||||
})
|
||||
: null) ??
|
||||
resolveBundledPluginPublicSurfacePath(publicSurfaceParams))
|
||||
: resolveBundledPluginPublicSurfacePath(publicSurfaceParams);
|
||||
return modulePath
|
||||
? {
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
|
||||
const { createTempDirSync } = createPluginSdkTestHarness();
|
||||
const originalBundledPluginsDir = process.env.OPENCLAW_BUNDLED_PLUGINS_DIR;
|
||||
const originalDisableBundledPlugins = process.env.OPENCLAW_DISABLE_BUNDLED_PLUGINS;
|
||||
const originalStateDir = process.env.OPENCLAW_STATE_DIR;
|
||||
|
||||
function createBundledPluginDir(prefix: string, marker: string): string {
|
||||
@@ -48,6 +49,11 @@ afterEach(() => {
|
||||
} else {
|
||||
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = originalBundledPluginsDir;
|
||||
}
|
||||
if (originalDisableBundledPlugins === undefined) {
|
||||
delete process.env.OPENCLAW_DISABLE_BUNDLED_PLUGINS;
|
||||
} else {
|
||||
process.env.OPENCLAW_DISABLE_BUNDLED_PLUGINS = originalDisableBundledPlugins;
|
||||
}
|
||||
if (originalStateDir === undefined) {
|
||||
delete process.env.OPENCLAW_STATE_DIR;
|
||||
} else {
|
||||
@@ -81,6 +87,32 @@ describe("plugin-sdk facade runtime", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("falls back to package source surfaces when an override dir is partial", () => {
|
||||
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = createTempDirSync("openclaw-facade-runtime-empty-");
|
||||
|
||||
expect(
|
||||
__testing.resolveFacadeModuleLocation({
|
||||
dirName: "browser",
|
||||
artifactBasename: "browser-maintenance.js",
|
||||
}),
|
||||
).toEqual({
|
||||
modulePath: path.resolve("extensions/browser/browser-maintenance.ts"),
|
||||
boundaryRoot: path.resolve("."),
|
||||
});
|
||||
});
|
||||
|
||||
it("does not fall back to package source surfaces when bundled plugins are disabled", () => {
|
||||
process.env.OPENCLAW_DISABLE_BUNDLED_PLUGINS = "1";
|
||||
delete process.env.OPENCLAW_BUNDLED_PLUGINS_DIR;
|
||||
|
||||
expect(
|
||||
__testing.resolveFacadeModuleLocation({
|
||||
dirName: "browser",
|
||||
artifactBasename: "browser-maintenance.js",
|
||||
}),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
it("returns the same object identity on repeated calls (sentinel consistency)", () => {
|
||||
const dir = createBundledPluginDir("openclaw-facade-identity-", "identity-check");
|
||||
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = dir;
|
||||
|
||||
@@ -59,7 +59,11 @@ function createFacadeResolutionKey(params: {
|
||||
env?: NodeJS.ProcessEnv;
|
||||
}): string {
|
||||
const bundledPluginsDir = resolveBundledPluginsDir(params.env ?? process.env);
|
||||
return createFacadeResolutionKeyShared({ ...params, bundledPluginsDir });
|
||||
return createFacadeResolutionKeyShared({
|
||||
...params,
|
||||
bundledPluginsDir,
|
||||
...(params.env ? { env: params.env } : {}),
|
||||
});
|
||||
}
|
||||
|
||||
function resolveRegistryPluginModuleLocation(params: {
|
||||
|
||||
@@ -8,7 +8,7 @@ import { resolveUserPath } from "../utils.js";
|
||||
|
||||
const DISABLED_BUNDLED_PLUGINS_DIR = path.join(os.tmpdir(), "openclaw-empty-bundled-plugins");
|
||||
|
||||
function bundledPluginsDisabled(env: NodeJS.ProcessEnv): boolean {
|
||||
export function areBundledPluginsDisabled(env: NodeJS.ProcessEnv = process.env): boolean {
|
||||
const raw = normalizeOptionalLowercaseString(env.OPENCLAW_DISABLE_BUNDLED_PLUGINS);
|
||||
return raw === "1" || raw === "true";
|
||||
}
|
||||
@@ -109,7 +109,7 @@ function resolveBundledDirFromPackageRoot(
|
||||
}
|
||||
|
||||
export function resolveBundledPluginsDir(env: NodeJS.ProcessEnv = process.env): string | undefined {
|
||||
if (bundledPluginsDisabled(env)) {
|
||||
if (areBundledPluginsDisabled(env)) {
|
||||
return resolveDisabledBundledPluginsDir();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user