mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:10:44 +00:00
fix(status): resolve packaged channel setup loader
This commit is contained in:
@@ -30,6 +30,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
### Fixes
|
||||
|
||||
- CLI/status: resolve read-only channel setup runtime fallback from the packaged OpenClaw dist root, so `status --all`, `status --deep`, channel, and doctor paths do not crash when an external channel plugin needs setup metadata. Fixes #74693. Thanks @giangthb.
|
||||
- CLI/update: scope packaged Node compile caches by OpenClaw version and install metadata, so global installs no longer reuse stale compiled chunks after package updates. Thanks @pashpashpash.
|
||||
- Plugin SDK/testing: lazy-load TypeScript from the plugin test-contract runtime and add release checks for critical SDK contract entrypoint imports and bundle size, so published packages fail preflight before shipping ESM-incompatible or oversized contract helpers. Thanks @vincentkoc.
|
||||
- Channels/Microsoft Teams: treat configured `19:...@thread.tacv2` and legacy `19:...@thread.skype` team/channel IDs as already resolved during startup, avoiding false `channels unresolved` warnings while preserving Graph name lookup for display-name entries. Fixes #74683. Thanks @dseravalli.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath, pathToFileURL } from "node:url";
|
||||
import { afterAll, afterEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
cleanupPluginLoaderFixturesForTest,
|
||||
@@ -8,7 +9,10 @@ import {
|
||||
resetPluginLoaderTestStateForTest,
|
||||
useNoBundledPlugins,
|
||||
} from "../../plugins/loader.test-fixtures.js";
|
||||
import { listReadOnlyChannelPluginsForConfig } from "./read-only.js";
|
||||
import {
|
||||
listPluginLoaderModuleCandidateUrls,
|
||||
listReadOnlyChannelPluginsForConfig,
|
||||
} from "./read-only.js";
|
||||
|
||||
vi.mock("../../plugins/bundled-dir.js", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("../../plugins/bundled-dir.js")>();
|
||||
@@ -423,6 +427,20 @@ afterAll(() => {
|
||||
});
|
||||
|
||||
describe("listReadOnlyChannelPluginsForConfig", () => {
|
||||
it("keeps built plugin loader candidates inside the installed package dist root", () => {
|
||||
const packageRoot = path.join(makeTempDir(), "node_modules", "openclaw");
|
||||
const importerPath = path.join(packageRoot, "dist", "read-only-B4EkEtUx.js");
|
||||
const candidates = listPluginLoaderModuleCandidateUrls(pathToFileURL(importerPath).href).map(
|
||||
(candidate) => fileURLToPath(candidate),
|
||||
);
|
||||
|
||||
expect(candidates).toEqual([
|
||||
path.join(packageRoot, "dist", "plugins", "loader.js"),
|
||||
path.join(packageRoot, "dist", "plugins", "build-smoke-entry.js"),
|
||||
]);
|
||||
expect(candidates).not.toContain(path.join(packageRoot, "..", "plugins", "loader.js"));
|
||||
});
|
||||
|
||||
it("does not load setup-only channel plugin runtime by default", () => {
|
||||
const { pluginDir, fullMarker, setupMarker } = writeExternalSetupChannelPlugin();
|
||||
const plugins = listReadOnlyChannelPluginsForConfig(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { fileURLToPath } from "node:url";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath, pathToFileURL } from "node:url";
|
||||
import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../../agents/agent-scope.js";
|
||||
import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
||||
import { isBlockedObjectKey } from "../../infra/prototype-keys.js";
|
||||
@@ -25,9 +26,13 @@ import {
|
||||
import { listChannelPlugins } from "./registry.js";
|
||||
import type { ChannelPlugin } from "./types.plugin.js";
|
||||
|
||||
const LOADER_MODULE_CANDIDATES = [
|
||||
new URL("../../plugins/loader.js", import.meta.url),
|
||||
new URL("../../plugins/loader.ts", import.meta.url),
|
||||
const SOURCE_PLUGIN_LOADER_MODULE_CANDIDATES = [
|
||||
"../../plugins/loader.js",
|
||||
"../../plugins/loader.ts",
|
||||
] as const;
|
||||
const BUILT_PLUGIN_LOADER_MODULE_CANDIDATES = [
|
||||
"plugins/loader.js",
|
||||
"plugins/build-smoke-entry.js",
|
||||
] as const;
|
||||
const jitiLoaders: PluginJitiLoaderCache = new Map();
|
||||
|
||||
@@ -53,11 +58,39 @@ type PluginLoaderModule = {
|
||||
|
||||
let pluginLoaderModule: PluginLoaderModule | undefined;
|
||||
|
||||
function listBuiltPluginLoaderModuleCandidateUrls(importerUrl: string): URL[] {
|
||||
let importerPath: string;
|
||||
try {
|
||||
importerPath = fileURLToPath(importerUrl);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
const distMarker = `${path.sep}dist${path.sep}`;
|
||||
const distMarkerIndex = importerPath.lastIndexOf(distMarker);
|
||||
if (distMarkerIndex < 0) {
|
||||
return [];
|
||||
}
|
||||
// Bundled read-only chunks live under dist/ with hashed names. Source-relative
|
||||
// ../../plugins candidates would escape the installed openclaw package there.
|
||||
const distRoot = importerPath.slice(0, distMarkerIndex + distMarker.length - 1);
|
||||
return BUILT_PLUGIN_LOADER_MODULE_CANDIDATES.map((candidate) =>
|
||||
pathToFileURL(path.join(distRoot, candidate)),
|
||||
);
|
||||
}
|
||||
|
||||
export function listPluginLoaderModuleCandidateUrls(importerUrl = import.meta.url): URL[] {
|
||||
const builtCandidates = listBuiltPluginLoaderModuleCandidateUrls(importerUrl);
|
||||
if (builtCandidates.length > 0) {
|
||||
return builtCandidates;
|
||||
}
|
||||
return SOURCE_PLUGIN_LOADER_MODULE_CANDIDATES.map((candidate) => new URL(candidate, importerUrl));
|
||||
}
|
||||
|
||||
function loadPluginLoaderModule(): PluginLoaderModule {
|
||||
if (pluginLoaderModule) {
|
||||
return pluginLoaderModule;
|
||||
}
|
||||
for (const candidate of LOADER_MODULE_CANDIDATES) {
|
||||
for (const candidate of listPluginLoaderModuleCandidateUrls()) {
|
||||
const modulePath = fileURLToPath(candidate);
|
||||
try {
|
||||
const jiti = getCachedPluginJitiLoader({
|
||||
|
||||
@@ -226,6 +226,7 @@ function buildCoreDistEntries(): Record<string, string> {
|
||||
"plugins/provider-discovery.runtime": "src/plugins/provider-discovery.runtime.ts",
|
||||
"plugins/provider-runtime.runtime": "src/plugins/provider-runtime.runtime.ts",
|
||||
"plugins/public-surface-runtime": "src/plugins/public-surface-runtime.ts",
|
||||
"plugins/loader": "src/plugins/loader.ts",
|
||||
"plugins/sdk-alias": "src/plugins/sdk-alias.ts",
|
||||
"facade-activation-check.runtime": "src/plugin-sdk/facade-activation-check.runtime.ts",
|
||||
extensionAPI: "src/extensionAPI.ts",
|
||||
|
||||
Reference in New Issue
Block a user