mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 09:40:43 +00:00
fix(plugins): avoid plugin sdk alias rewrite races
This commit is contained in:
@@ -39,6 +39,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Gateway/sessions: extend the webchat session-mutation guard to `sessions.compact` and `sessions.compaction.restore`, so `WEBCHAT_UI` clients are rejected from compaction-side session mutations consistently with the existing patch/delete guards. (#70716) Thanks @drobison00.
|
||||
- QA channel/security: reject non-HTTP(S) inbound attachment URLs before media fetch, and log rejected schemes so suspicious or misconfigured payloads are visible during debugging. (#70708) Thanks @vincentkoc.
|
||||
- Plugins/install: link the host OpenClaw package into external plugins that declare `openclaw` as a peer dependency, so peer-only plugin SDK imports resolve after install without bundling a duplicate host package. (#70462) Thanks @anishesg.
|
||||
- Plugins/Windows: refresh the packaged plugin SDK alias in place during bundled runtime dependency repair, so gateway and CLI plugin startup no longer race on `ENOTEMPTY`/`EPERM` after same-guest npm updates.
|
||||
- Teams/security: require shared Bot Framework audience tokens to name the configured Teams app via verified `appid` or `azp`, blocking cross-bot token replay on the global audience. (#70724) Thanks @vincentkoc.
|
||||
- Plugins/startup: resolve bundled plugin Jiti loads relative to the target plugin module instead of the central loader, so Bun global installs no longer hang while discovering bundled image providers. (#70073) Thanks @yidianyiko.
|
||||
- Anthropic/CLI security: derive Claude CLI `bypassPermissions` from OpenClaw's existing YOLO exec policy, preserve explicit raw Claude `--permission-mode` overrides, and strip malformed permission-mode args instead of silently falling back to a bypass. (#70723) Thanks @vincentkoc.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "openclaw",
|
||||
"version": "2026.4.23-beta.2",
|
||||
"version": "2026.4.23-beta.3",
|
||||
"description": "Multi-channel AI gateway with extensible messaging integrations",
|
||||
"keywords": [],
|
||||
"homepage": "https://github.com/openclaw/openclaw#readme",
|
||||
|
||||
@@ -27769,6 +27769,6 @@ export const GENERATED_BASE_CONFIG_SCHEMA: BaseConfigSchemaResponse = {
|
||||
tags: ["advanced", "url-secret"],
|
||||
},
|
||||
},
|
||||
version: "2026.4.23-beta.2",
|
||||
version: "2026.4.23-beta.3",
|
||||
generatedAt: "2026-03-22T21:17:33.302Z",
|
||||
};
|
||||
|
||||
@@ -837,6 +837,24 @@ afterAll(() => {
|
||||
});
|
||||
|
||||
describe("loadOpenClawPlugins", () => {
|
||||
it("refreshes bundled plugin-sdk aliases without deleting the shared alias directory", () => {
|
||||
const distRoot = makeTempDir();
|
||||
const pluginSdkDir = path.join(distRoot, "plugin-sdk");
|
||||
const aliasDir = path.join(distRoot, "extensions", "node_modules", "openclaw", "plugin-sdk");
|
||||
mkdirSafe(pluginSdkDir);
|
||||
mkdirSafe(aliasDir);
|
||||
fs.writeFileSync(path.join(pluginSdkDir, "index.js"), "export const value = 1;\n", "utf8");
|
||||
fs.writeFileSync(path.join(pluginSdkDir, "core.js"), "export const core = 1;\n", "utf8");
|
||||
fs.writeFileSync(path.join(aliasDir, "sentinel.txt"), "keep\n", "utf8");
|
||||
|
||||
__testing.ensureOpenClawPluginSdkAlias(distRoot);
|
||||
fs.writeFileSync(path.join(pluginSdkDir, "core.js"), "export const core = 2;\n", "utf8");
|
||||
__testing.ensureOpenClawPluginSdkAlias(distRoot);
|
||||
|
||||
expect(fs.existsSync(path.join(aliasDir, "sentinel.txt"))).toBe(true);
|
||||
expect(fs.readFileSync(path.join(aliasDir, "core.js"), "utf8")).toContain("core.js");
|
||||
});
|
||||
|
||||
it("disables bundled plugins by default", () => {
|
||||
const bundledDir = makeTempDir();
|
||||
writePlugin({
|
||||
|
||||
@@ -689,7 +689,14 @@ function ensureOpenClawPluginSdkAlias(distRoot: string): void {
|
||||
"./plugin-sdk/*": "./plugin-sdk/*.js",
|
||||
},
|
||||
});
|
||||
fs.rmSync(pluginSdkAliasDir, { recursive: true, force: true });
|
||||
try {
|
||||
if (fs.existsSync(pluginSdkAliasDir) && !fs.lstatSync(pluginSdkAliasDir).isDirectory()) {
|
||||
fs.rmSync(pluginSdkAliasDir, { recursive: true, force: true });
|
||||
}
|
||||
} catch {
|
||||
// Another process may be creating the alias at the same time; mkdir/write
|
||||
// below will either converge or surface the real filesystem error.
|
||||
}
|
||||
fs.mkdirSync(pluginSdkAliasDir, { recursive: true });
|
||||
for (const entry of fs.readdirSync(pluginSdkDir, { withFileTypes: true })) {
|
||||
if (!entry.isFile() || path.extname(entry.name) !== ".js") {
|
||||
@@ -727,6 +734,7 @@ export const __testing = {
|
||||
resolvePluginSdkAliasCandidateOrder,
|
||||
resolvePluginSdkAliasFile,
|
||||
resolvePluginRuntimeModulePath,
|
||||
ensureOpenClawPluginSdkAlias,
|
||||
shouldLoadChannelPluginInSetupRuntime,
|
||||
shouldPreferNativeJiti,
|
||||
toSafeImportPath,
|
||||
|
||||
Reference in New Issue
Block a user