perf(plugins): memoize packaged runtime dist mirrors

This commit is contained in:
Peter Steinberger
2026-04-29 13:10:22 +01:00
parent 40f820bda2
commit 234cbf5f46
5 changed files with 190 additions and 23 deletions

View File

@@ -18,6 +18,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- Plugins/runtime-deps: memoize packaged bundled runtime dist-mirror preparation after the first successful pass while keeping source-checkout mirrors refreshable, so constrained Docker/VPS installs avoid repeated root scans before chat turns. Refs #73428, #73421, #73532, and #73477. Thanks @Dimaoggg, @oromeis, @oadiazp, @jmfraga, @bstanbury, @antoniusfelix, and @jkobject.
- Channels/Discord: treat bare numeric outbound targets that match the effective Discord DM allowlist as user DMs while preserving account-specific legacy `dm.allowFrom` precedence over inherited root `allowFrom`. (#74303) Thanks @Squirbie.
- Control UI: make the chat sidebar split divider focusable, keyboard-resizable, ARIA-described, and pointer-event based so sidebar resizing works without a mouse. Thanks @BunsDev.
- Agents/auth: keep OAuth auth profiles inherited from the main agent read-through instead of copying refresh tokens into secondary agents, and refresh Codex app-server tokens against the owning store so multi-agent swarms avoid reused refresh-token failures. Fixes #74055. Thanks @ClarityInvest.

View File

@@ -0,0 +1,52 @@
import fs from "node:fs";
import path from "node:path";
const preparedBundledRuntimeDistMirrors = new Set<string>();
export function clearBundledRuntimeDistMirrorPreparationCache(): void {
preparedBundledRuntimeDistMirrors.clear();
}
export function shouldReusePreparedBundledRuntimeDistMirror(params: {
sourceDistRoot: string;
mirrorDistRoot: string;
}): boolean {
if (isSourceCheckoutDistRoot(params.sourceDistRoot)) {
return false;
}
if (!preparedBundledRuntimeDistMirrors.has(bundledRuntimeDistMirrorCacheKey(params))) {
return false;
}
return (
fs.existsSync(params.mirrorDistRoot) &&
fs.existsSync(path.join(params.mirrorDistRoot, "extensions")) &&
fs.existsSync(path.join(params.mirrorDistRoot, "package.json"))
);
}
export function markBundledRuntimeDistMirrorPrepared(params: {
sourceDistRoot: string;
mirrorDistRoot: string;
}): void {
if (isSourceCheckoutDistRoot(params.sourceDistRoot)) {
return;
}
preparedBundledRuntimeDistMirrors.add(bundledRuntimeDistMirrorCacheKey(params));
}
function bundledRuntimeDistMirrorCacheKey(params: {
sourceDistRoot: string;
mirrorDistRoot: string;
}): string {
return `${path.resolve(params.sourceDistRoot)}\0${path.resolve(params.mirrorDistRoot)}`;
}
function isSourceCheckoutDistRoot(sourceDistRoot: string): boolean {
const packageRoot = path.dirname(sourceDistRoot);
return (
(fs.existsSync(path.join(packageRoot, ".git")) ||
fs.existsSync(path.join(packageRoot, "pnpm-workspace.yaml"))) &&
fs.existsSync(path.join(packageRoot, "src")) &&
fs.existsSync(path.join(packageRoot, "extensions"))
);
}

View File

@@ -198,7 +198,9 @@ describe("prepareBundledPluginRuntimeRoot", () => {
}
const realReadFileSync = fs.readFileSync.bind(fs);
const realReaddirSync = fs.readdirSync.bind(fs);
const readPaths: string[] = [];
const readdirPaths: string[] = [];
vi.spyOn(fs, "readFileSync").mockImplementation(((target, options) => {
const targetPath = target.toString();
if (targetPath === rootChunk || targetPath === externalChunk) {
@@ -206,6 +208,16 @@ describe("prepareBundledPluginRuntimeRoot", () => {
}
return realReadFileSync(target, options as never);
}) as typeof fs.readFileSync);
vi.spyOn(fs, "readdirSync").mockImplementation(((target, options) => {
const targetPath = target.toString();
if (
targetPath === path.join(packageRoot, "dist") &&
new Error().stack?.includes("mirrorBundledRuntimeDistRootEntries")
) {
readdirPaths.push(targetPath);
}
return realReaddirSync(target, options as never);
}) as typeof fs.readdirSync);
for (const pluginId of ["alpha", "beta"]) {
const pluginRoot = path.join(packageRoot, "dist", "extensions", pluginId);
@@ -219,6 +231,75 @@ describe("prepareBundledPluginRuntimeRoot", () => {
expect(readPaths.filter((entry) => entry === rootChunk)).toHaveLength(1);
expect(readPaths.filter((entry) => entry === externalChunk)).toHaveLength(1);
expect(readdirPaths).toHaveLength(1);
});
it("does not memoize source-checkout dist mirrors", () => {
const packageRoot = makeTempRoot();
const stageDir = makeTempRoot();
const env = { ...process.env, OPENCLAW_PLUGIN_STAGE_DIR: stageDir };
fs.mkdirSync(path.join(packageRoot, ".git"), { recursive: true });
fs.mkdirSync(path.join(packageRoot, "src"), { recursive: true });
fs.mkdirSync(path.join(packageRoot, "extensions"), { recursive: true });
const pluginRoot = path.join(packageRoot, "dist", "extensions", "alpha");
fs.mkdirSync(pluginRoot, { recursive: true });
fs.writeFileSync(
path.join(packageRoot, "package.json"),
JSON.stringify({ name: "openclaw", version: "2026.4.27", type: "module" }),
"utf8",
);
fs.writeFileSync(path.join(packageRoot, "dist", "shared-runtime.js"), "export {};\n", "utf8");
fs.writeFileSync(
path.join(pluginRoot, "index.js"),
`import "../../shared-runtime.js"; export default { id: "alpha" };\n`,
"utf8",
);
fs.writeFileSync(
path.join(pluginRoot, "package.json"),
JSON.stringify(
{
name: "@openclaw/alpha",
version: "1.0.0",
type: "module",
dependencies: { "alpha-runtime": "1.0.0" },
openclaw: { extensions: ["./index.js"] },
},
null,
2,
),
"utf8",
);
const installRoot = resolveBundledRuntimeDependencyInstallRoot(pluginRoot, { env });
fs.mkdirSync(path.join(installRoot, "node_modules", "alpha-runtime"), { recursive: true });
fs.writeFileSync(
path.join(installRoot, "node_modules", "alpha-runtime", "package.json"),
JSON.stringify({ name: "alpha-runtime", version: "1.0.0", type: "module" }),
"utf8",
);
const realReaddirSync = fs.readdirSync.bind(fs);
const readdirPaths: string[] = [];
vi.spyOn(fs, "readdirSync").mockImplementation(((target, options) => {
const targetPath = target.toString();
if (
targetPath === path.join(packageRoot, "dist") &&
new Error().stack?.includes("mirrorBundledRuntimeDistRootEntries")
) {
readdirPaths.push(targetPath);
}
return realReaddirSync(target, options as never);
}) as typeof fs.readdirSync);
for (let index = 0; index < 2; index += 1) {
prepareBundledPluginRuntimeRoot({
pluginId: "alpha",
pluginRoot,
modulePath: path.join(pluginRoot, "index.js"),
env,
});
}
expect(readdirPaths).toHaveLength(2);
});
it("does not copy staged runtime mirror dist files onto themselves", () => {

View File

@@ -9,6 +9,10 @@ import {
shouldMaterializeBundledRuntimeMirrorDistFile,
withBundledRuntimeDepsFilesystemLock,
} from "./bundled-runtime-deps.js";
import {
markBundledRuntimeDistMirrorPrepared,
shouldReusePreparedBundledRuntimeDistMirror,
} from "./bundled-runtime-dist-mirror-cache.js";
import {
copyBundledPluginRuntimeRoot,
precomputeBundledRuntimeMirrorMetadata,
@@ -162,10 +166,13 @@ function prepareBundledPluginRuntimeDistMirror(params: {
ensureBundledRuntimeMirrorDirectory(mirrorDistRoot);
fs.mkdirSync(mirrorExtensionsRoot, { recursive: true, mode: 0o755 });
ensureBundledRuntimeDistPackageJson(mirrorDistRoot);
mirrorBundledRuntimeDistRootEntries({
sourceDistRoot,
mirrorDistRoot,
});
if (!shouldReusePreparedBundledRuntimeDistMirror({ sourceDistRoot, mirrorDistRoot })) {
mirrorBundledRuntimeDistRootEntries({
sourceDistRoot,
mirrorDistRoot,
});
markBundledRuntimeDistMirrorPrepared({ sourceDistRoot, mirrorDistRoot });
}
if (sourceDistRootName === "dist-runtime") {
mirrorCanonicalBundledRuntimeDistRoot({
installRoot: params.installRoot,
@@ -242,10 +249,21 @@ function mirrorCanonicalBundledRuntimeDistRoot(params: {
ensureBundledRuntimeMirrorDirectory(targetCanonicalDistRoot);
fs.mkdirSync(path.join(targetCanonicalDistRoot, "extensions"), { recursive: true, mode: 0o755 });
ensureBundledRuntimeDistPackageJson(targetCanonicalDistRoot);
mirrorBundledRuntimeDistRootEntries({
sourceDistRoot: sourceCanonicalDistRoot,
mirrorDistRoot: targetCanonicalDistRoot,
});
if (
!shouldReusePreparedBundledRuntimeDistMirror({
sourceDistRoot: sourceCanonicalDistRoot,
mirrorDistRoot: targetCanonicalDistRoot,
})
) {
mirrorBundledRuntimeDistRootEntries({
sourceDistRoot: sourceCanonicalDistRoot,
mirrorDistRoot: targetCanonicalDistRoot,
});
markBundledRuntimeDistMirrorPrepared({
sourceDistRoot: sourceCanonicalDistRoot,
mirrorDistRoot: targetCanonicalDistRoot,
});
}
ensureOpenClawPluginSdkAlias(targetCanonicalDistRoot);
const pluginId = path.basename(params.pluginRoot);

View File

@@ -43,6 +43,11 @@ import {
withBundledRuntimeDepsFilesystemLock,
type BundledRuntimeDepsInstallParams,
} from "./bundled-runtime-deps.js";
import {
clearBundledRuntimeDistMirrorPreparationCache,
markBundledRuntimeDistMirrorPrepared,
shouldReusePreparedBundledRuntimeDistMirror,
} from "./bundled-runtime-dist-mirror-cache.js";
import {
copyBundledPluginRuntimeRoot,
precomputeBundledRuntimeMirrorMetadata,
@@ -114,8 +119,8 @@ import {
normalizePluginIdScope,
serializePluginIdScope,
} from "./plugin-scope.js";
import { createPluginRegistry, type PluginRecord, type PluginRegistry } from "./registry.js";
import { createEmptyPluginRegistry } from "./registry-empty.js";
import { createPluginRegistry, type PluginRecord, type PluginRegistry } from "./registry.js";
import { resolvePluginCacheInputs } from "./roots.js";
import {
getActivePluginRegistry,
@@ -280,6 +285,7 @@ function createPluginCandidatesFromManifestRegistry(
export function clearPluginLoaderCache(): void {
pluginLoaderCacheState.clear();
clearBundledRuntimeDependencyNodePaths();
clearBundledRuntimeDistMirrorPreparationCache();
bundledRuntimeDependencyJitiAliases.clear();
clearAgentHarnesses();
clearPluginCommands();
@@ -770,10 +776,13 @@ function prepareBundledPluginRuntimeDistMirror(params: {
ensureBundledRuntimeMirrorDirectory(mirrorDistRoot);
fs.mkdirSync(mirrorExtensionsRoot, { recursive: true, mode: 0o755 });
ensureBundledRuntimeDistPackageJson(mirrorDistRoot);
mirrorBundledRuntimeDistRootEntries({
sourceDistRoot,
mirrorDistRoot,
});
if (!shouldReusePreparedBundledRuntimeDistMirror({ sourceDistRoot, mirrorDistRoot })) {
mirrorBundledRuntimeDistRootEntries({
sourceDistRoot,
mirrorDistRoot,
});
markBundledRuntimeDistMirrorPrepared({ sourceDistRoot, mirrorDistRoot });
}
if (sourceDistRootName === "dist-runtime") {
mirrorCanonicalBundledRuntimeDistRoot({
installRoot: params.installRoot,
@@ -850,10 +859,21 @@ function mirrorCanonicalBundledRuntimeDistRoot(params: {
ensureBundledRuntimeMirrorDirectory(targetCanonicalDistRoot);
fs.mkdirSync(path.join(targetCanonicalDistRoot, "extensions"), { recursive: true, mode: 0o755 });
ensureBundledRuntimeDistPackageJson(targetCanonicalDistRoot);
mirrorBundledRuntimeDistRootEntries({
sourceDistRoot: sourceCanonicalDistRoot,
mirrorDistRoot: targetCanonicalDistRoot,
});
if (
!shouldReusePreparedBundledRuntimeDistMirror({
sourceDistRoot: sourceCanonicalDistRoot,
mirrorDistRoot: targetCanonicalDistRoot,
})
) {
mirrorBundledRuntimeDistRootEntries({
sourceDistRoot: sourceCanonicalDistRoot,
mirrorDistRoot: targetCanonicalDistRoot,
});
markBundledRuntimeDistMirrorPrepared({
sourceDistRoot: sourceCanonicalDistRoot,
mirrorDistRoot: targetCanonicalDistRoot,
});
}
ensureOpenClawPluginSdkAlias(targetCanonicalDistRoot);
const pluginId = path.basename(params.pluginRoot);
@@ -2243,12 +2263,7 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
clearPluginInteractiveHandlers();
clearDetachedTaskLifecycleRuntimeRegistration();
clearMemoryPluginState();
activatePluginRegistry(
emptyRegistry,
cacheKey,
runtimeSubagentMode,
options.workspaceDir,
);
activatePluginRegistry(emptyRegistry, cacheKey, runtimeSubagentMode, options.workspaceDir);
}
return emptyRegistry;
}