fix(plugins): resolve bundled channel doctor metadata from package root

This commit is contained in:
Peter Steinberger
2026-04-25 22:12:28 +01:00
parent 20223e02d9
commit 7d343b0b10
3 changed files with 57 additions and 12 deletions

View File

@@ -63,6 +63,10 @@ Docs: https://docs.openclaw.ai
- Windows/native: keep CLI startup and bundled provider plugin loading off
Windows ESM raw-path failure paths, fixing native onboarding/install smoke on
Node 24. Thanks @steipete.
- Plugins/doctor: read bundled channel doctor capabilities through the same
packaged plugin directory resolver used by plugin loading, so published
installs keep Matrix DM allowlist repairs on `channels.matrix.dm.*` instead
of writing invalid top-level `dmPolicy` keys. Fixes #71757.
- Providers/Google: transcode Gemini TTS PCM to Opus for voice-note targets so
WhatsApp and other native voice-note replies can play as voice messages.
- Plugins/runtime deps: reuse existing external bundled-plugin stage roots when

View File

@@ -0,0 +1,51 @@
import path from "node:path";
import { afterEach, describe, expect, it, vi } from "vitest";
import { cleanupTempDirs, makeTempRepoRoot, writeJsonFile } from "../../test/helpers/temp-repo.js";
vi.mock("./bundled-dir.js", () => ({
resolveBundledPluginsDir: vi.fn(),
}));
import { resolveBundledPluginsDir } from "./bundled-dir.js";
import { findBundledPackageChannelMetadata } from "./bundled-package-channel-metadata.js";
const tempDirs: string[] = [];
afterEach(() => {
cleanupTempDirs(tempDirs);
vi.restoreAllMocks();
vi.mocked(resolveBundledPluginsDir).mockReset();
});
describe("bundled package channel metadata", () => {
it("reads doctor capabilities from the resolved bundled plugin dir", () => {
const root = makeTempRepoRoot(tempDirs, "bpcm-");
const extensionsRoot = path.join(root, "dist", "extensions");
writeJsonFile(path.join(extensionsRoot, "matrix", "package.json"), {
name: "@openclaw/matrix",
openclaw: {
channel: {
id: "matrix",
label: "Matrix",
docsPath: "/channels/matrix",
doctorCapabilities: {
dmAllowFromMode: "nestedOnly",
groupModel: "sender",
groupAllowFromFallbackToAllowFrom: false,
warnOnEmptyGroupSenderAllowlist: true,
},
},
},
});
vi.mocked(resolveBundledPluginsDir).mockReturnValue(extensionsRoot);
const matrix = findBundledPackageChannelMetadata("matrix");
expect(matrix?.doctorCapabilities).toEqual({
dmAllowFromMode: "nestedOnly",
groupModel: "sender",
groupAllowFromFallbackToAllowFrom: false,
warnOnEmptyGroupSenderAllowlist: true,
});
});
});

View File

@@ -1,19 +1,12 @@
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { resolveBundledPluginScanDir } from "./bundled-plugin-scan.js";
import { resolveBundledPluginsDir } from "./bundled-dir.js";
import {
getPackageManifestMetadata,
type PackageManifest,
type PluginPackageChannel,
} from "./manifest.js";
const PACKAGE_ROOT = fileURLToPath(new URL("../..", import.meta.url));
const CURRENT_MODULE_PATH = fileURLToPath(import.meta.url);
const RUNNING_FROM_BUILT_ARTIFACT =
CURRENT_MODULE_PATH.includes(`${path.sep}dist${path.sep}`) ||
CURRENT_MODULE_PATH.includes(`${path.sep}dist-runtime${path.sep}`);
let bundledPackageChannelMetadataCache: readonly PluginPackageChannel[] | undefined;
function readPackageManifest(pluginDir: string): PackageManifest | undefined {
@@ -32,10 +25,7 @@ export function listBundledPackageChannelMetadata(): readonly PluginPackageChann
if (bundledPackageChannelMetadataCache) {
return bundledPackageChannelMetadataCache;
}
const scanDir = resolveBundledPluginScanDir({
packageRoot: PACKAGE_ROOT,
runningFromBuiltArtifact: RUNNING_FROM_BUILT_ARTIFACT,
});
const scanDir = resolveBundledPluginsDir();
if (!scanDir || !fs.existsSync(scanDir)) {
bundledPackageChannelMetadataCache = [];
return bundledPackageChannelMetadataCache;