Skip to content

Commit 990f931

Browse files
committed
fix(upgrade): unlink stale plugin runtime symlinks
1 parent c33e578 commit 990f931

3 files changed

Lines changed: 13 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ Docs: https://docs.openclaw.ai
3838
- Agents/network: allow trusted web-search providers and configured model-provider hosts to work behind Surge/Clash/sing-box fake-IP DNS by accepting RFC 2544 and IPv6 ULA synthetic answers only for the request's scoped hostname, without broad private-network access. Refs #76530 and #76549. Thanks @zqchris.
3939
- Providers: honor env-proxy settings for guarded provider model fetches when no explicit dispatcher policy is configured, preserving explicit transport overrides. Fixes #70453. (#72480) Thanks @mjamiv.
4040
- Feishu: accept and honor `channels.feishu.blockStreaming` at the top level and per account, while keeping the legacy default off so Feishu cards no longer reject documented config or silently drop block replies. Fixes #75555. Thanks @vincentkoc.
41-
- Gateway/update: avoid `launchctl kickstart -k` immediately after fresh macOS update bootstraps, and remove dangling global plugin-runtime symlinks during packaged postinstall and `doctor --fix` so upgrades no longer SIGTERM the newly booted Gateway or leave bundled plugin imports pointed at pruned `plugin-runtime-deps` trees. Completes #76261 and fixes #76466. (#76929)
41+
- Gateway/update: avoid `launchctl kickstart -k` immediately after fresh macOS update bootstraps, and unlink dangling global plugin-runtime symlinks during packaged postinstall and `doctor --fix` so upgrades no longer SIGTERM the newly booted Gateway or leave bundled plugin imports pointed at pruned `plugin-runtime-deps` trees. Completes #76261 and fixes #76466. (#76929)
4242
- Google Chat: normalize custom Google auth transport headers before google-auth/gaxios interceptors run, restoring webhook token verification when certificate retrieval expects Fetch `Headers`. Fixes #76742. Thanks @donbowman.
4343
- Doctor/plugins: reset stale `plugins.slots.memory` and `plugins.slots.contextEngine` references during `doctor --fix`, so cleanup of missing plugin config does not leave unrecoverable slot owners behind. Fixes #76550 and #76551. Thanks @vincentkoc.
4444
- Docs/WhatsApp: merge the duplicate top-level `web` objects in the gateway channel config example so copy-pasted WhatsApp config keeps both `web.whatsapp` and reconnect settings. Fixes #76619. Thanks @WadydX.

scripts/postinstall-bundled-plugins.mjs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,14 +445,15 @@ function collectLegacyPluginRuntimeDepsSymlinkPaths(roots, params = {}) {
445445
export function pruneLegacyPluginRuntimeDepsState(params = {}) {
446446
const pathExists = params.existsSync ?? existsSync;
447447
const removePath = params.rmSync ?? rmSync;
448+
const unlinkPath = params.unlinkSync ?? unlinkSync;
448449
const log = params.log ?? console;
449450
const removed = [];
450451
const removedSymlinks = [];
451452
const roots = collectLegacyPluginRuntimeDepsStateRoots(params);
452453

453454
for (const linkPath of collectLegacyPluginRuntimeDepsSymlinkPaths(roots, params)) {
454455
try {
455-
removePath(linkPath, { force: true });
456+
unlinkPath(linkPath);
456457
removedSymlinks.push(linkPath);
457458
} catch (error) {
458459
log.warn?.(
@@ -889,7 +890,10 @@ export function runBundledPluginPostinstall(params = {}) {
889890
env,
890891
packageRoot,
891892
existsSync: pathExists,
893+
lstatSync: params.lstatSync,
894+
readlinkSync: params.readlinkSync,
892895
rmSync: params.rmSync,
896+
unlinkSync: params.unlinkSync,
893897
log,
894898
homedir: params.homedir,
895899
});

src/commands/doctor/shared/plugin-runtime-symlinks.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ interface FsLike {
1212
readlink(file: string): Promise<string>;
1313
stat(file: string): Promise<unknown>;
1414
rm(file: string, options: { force: true }): Promise<void>;
15+
unlink?(file: string): Promise<void>;
1516
}
1617

1718
interface DirentLike {
@@ -41,6 +42,7 @@ const DEFAULT_FS: FsLike = {
4142
readlink: (file) => fs.readlink(file),
4243
stat: (file) => fs.stat(file),
4344
rm: (file, options) => fs.rm(file, options),
45+
unlink: (file) => fs.unlink(file),
4446
};
4547

4648
export async function collectStalePluginRuntimeSymlinks(
@@ -126,7 +128,11 @@ export async function removeStalePluginRuntimeSymlinks(
126128
const warnings: string[] = [];
127129
for (const item of await collectStalePluginRuntimeSymlinks(packageRoot, options)) {
128130
try {
129-
await fsApi.rm(item.path, { force: true });
131+
if (fsApi.unlink) {
132+
await fsApi.unlink(item.path);
133+
} else {
134+
await fsApi.rm(item.path, { force: true });
135+
}
130136
changes.push(`Removed stale plugin-runtime symlink: ${item.path}`);
131137
} catch (error) {
132138
warnings.push(`Failed to remove stale plugin-runtime symlink ${item.path}: ${String(error)}`);

0 commit comments

Comments
 (0)