From cdc00614cc9aca69261a05b89b627a9b5b0fb216 Mon Sep 17 00:00:00 2001 From: Dallin Romney Date: Mon, 4 May 2026 14:59:20 +0800 Subject: [PATCH] fix(plugins): warn on source-only installed packages instead of blocking config --- CHANGELOG.md | 1 + src/plugins/discovery.test.ts | 8 ++++---- src/plugins/package-entry-resolution.ts | 3 +-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fac779a9f31..7e4cca2b144 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,7 @@ Docs: https://docs.openclaw.ai - Discord: clear stale startup probe bot/application status when the async bot probe throws, not just when it returns a degraded probe result. Thanks @vincentkoc. - Web search: scope explicit bundled `web_search` provider runtime loading through manifest ownership, so selecting DuckDuckGo/Gemini/etc. does not import unrelated bundled providers or log their optional dependency failures. Thanks @vincentkoc. +- Plugins/discovery: demote the source-only TypeScript runtime check on already-installed `origin: "global"` plugin packages from a config-blocking error to a warning and let the runtime fall through to the TypeScript source via jiti, so a single broken installed package no longer blocks `plugins install` for unrelated plugins; install-time rejection of newly-installed source-only packages is unchanged. Thanks @romneyda. - Release/beta smoke: resolve the dispatched Telegram beta E2E run from `gh run list` when `gh workflow run` returns no run URL, so the maintainer helper does not fail immediately after dispatch. Thanks @vincentkoc. - Media/images: keep HEIC/HEIF attachments fail-closed when optional Sharp conversion is unavailable instead of sending originals that still need conversion. Thanks @vincentkoc. - Google Meet: fork the caller's current agent transcript into agent-mode meeting consultant sessions, so Meet replies inherit the context from the tool call that joined the meeting. diff --git a/src/plugins/discovery.test.ts b/src/plugins/discovery.test.ts index d4546ae65cd..a5f8a483c34 100644 --- a/src/plugins/discovery.test.ts +++ b/src/plugins/discovery.test.ts @@ -333,7 +333,7 @@ async function expectRejectedPackageExtensionEntry(params: { if (params.expectedDiagnostic === "runtime") { expect( result.diagnostics.some( - (entry) => entry.level === "error" && entry.message.includes("compiled runtime output"), + (entry) => entry.level === "warn" && entry.message.includes("compiled runtime output"), ), ).toBe(true); return; @@ -748,7 +748,7 @@ describe("discoverOpenClawPlugins", () => { expectCandidateIds(candidates, { includes: ["pack/one", "pack/two"] }); }); - it("rejects source-only TypeScript entries for installed package plugins", async () => { + it("warns but still loads source-only TypeScript entries for installed package plugins", async () => { const stateDir = makeTempDir(); const pluginDir = path.join(stateDir, "extensions", "source-only-pack"); mkdirSafe(path.join(pluginDir, "src")); @@ -762,11 +762,11 @@ describe("discoverOpenClawPlugins", () => { const result = await discoverWithStateDir(stateDir, {}); - expectCandidatePresence(result, { absent: ["source-only-pack"] }); + expectCandidateIds(result.candidates, { includes: ["source-only-pack"] }); expect( result.diagnostics.some( (entry) => - entry.level === "error" && + entry.level === "warn" && entry.message.includes("requires compiled runtime output") && entry.message.includes("./dist/index.js"), ), diff --git a/src/plugins/package-entry-resolution.ts b/src/plugins/package-entry-resolution.ts index e6571d5b8c2..f117562abd6 100644 --- a/src/plugins/package-entry-resolution.ts +++ b/src/plugins/package-entry-resolution.ts @@ -495,7 +495,7 @@ function resolvePackageRuntimeEntrySource(params: { isTypeScriptPackageEntry(safeEntry.relativePath) ) { params.diagnostics.push({ - level: "error", + level: "warn", message: missingCompiledRuntimeEntryMessage({ label: "installed plugin package", entry: safeEntry.relativePath, @@ -503,7 +503,6 @@ function resolvePackageRuntimeEntrySource(params: { }), source: params.sourceLabel, }); - return null; } }