fix(doctor): drop stale bundled install records

This commit is contained in:
Vincent Koc
2026-05-04 02:22:40 -07:00
parent 061af13bf3
commit 6b7f9eafed
3 changed files with 48 additions and 5 deletions

View File

@@ -66,6 +66,7 @@ Docs: https://docs.openclaw.ai
- fix: harden backend message action gateway routing [AI]. (#76374) Thanks @pgondhi987.
- Gate QQBot streaming command auth [AI]. (#76375) Thanks @pgondhi987.
- Plugins/release: make the published npm runtime verifier reject blank `openclaw.runtimeExtensions` entries instead of treating them as absent and passing via inferred outputs. Thanks @vincentkoc.
- Doctor/plugins: remove stale managed install records for bundled plugins even when the bundled plugin is not explicitly configured, so doctor cleanup cannot leave orphaned install metadata behind. Thanks @vincentkoc.
- Web fetch: scope provider fallback cache entries by the selected fetch provider so config reloads cannot reuse another provider's cached fallback payload. Thanks @vincentkoc.
- Web search: honor late-bound `tools.web.search.enabled: false` during tool execution so config reloads cannot leave an already-created `web_search` tool runnable. Thanks @vincentkoc.
- Plugins/packages: reject inferred built runtime entries that exist but fail package-boundary checks instead of falling back to TypeScript source for installed packages. Thanks @vincentkoc.

View File

@@ -743,6 +743,52 @@ describe("repairMissingConfiguredPluginInstalls", () => {
});
});
it("removes stale bundled install records even when the plugin is not configured", async () => {
const records = {
"google-meet": {
source: "npm",
spec: "@openclaw/google-meet",
resolvedName: "@openclaw/google-meet",
installPath: "/missing/google-meet",
},
};
mocks.loadInstalledPluginIndexInstallRecords.mockResolvedValue(records);
mocks.loadPluginMetadataSnapshot.mockReturnValue({
plugins: [],
diagnostics: [],
});
mocks.loadInstalledPluginIndex.mockReturnValue({
plugins: [
{
pluginId: "google-meet",
origin: "bundled",
packageName: "@openclaw/google-meet",
},
],
diagnostics: [],
installRecords: {},
});
const { repairMissingConfiguredPluginInstalls } =
await import("./missing-configured-plugin-install.js");
const result = await repairMissingConfiguredPluginInstalls({
cfg: {},
env: {},
});
expect(mocks.installPluginFromNpmSpec).not.toHaveBeenCalled();
expect(mocks.writePersistedInstalledPluginIndexInstallRecords).toHaveBeenCalledWith(
{},
{
env: {},
},
);
expect(result).toEqual({
changes: ['Removed stale managed install record for bundled plugin "google-meet".'],
warnings: [],
});
});
it.each([
[
"npm",

View File

@@ -646,11 +646,7 @@ async function repairMissingPluginInstalls(params: {
for (const [pluginId, record] of Object.entries(records)) {
const bundled = bundledPluginsById.get(pluginId);
if (
!bundled ||
!params.pluginIds.has(pluginId) ||
!recordMatchesBundledPackage(record, bundled)
) {
if (!bundled || !recordMatchesBundledPackage(record, bundled)) {
continue;
}
if (nextRecords === records) {