fix: unblock comfy live plugin loading

This commit is contained in:
Peter Steinberger
2026-04-06 03:01:29 +01:00
parent 9c33b1097c
commit 06b154a6df
13 changed files with 115 additions and 68 deletions

View File

@@ -9,4 +9,3 @@ export { IMESSAGE_LEGACY_OUTBOUND_SEND_DEP_KEYS } from "./src/outbound-send-deps
export * from "./src/probe.js";
export * from "./src/target-parsing-helpers.js";
export * from "./src/targets.js";
export { resolveIMessageRuntimeGroupPolicy } from "./src/monitor/monitor-provider.js";

View File

@@ -5,43 +5,7 @@ export type {
OpenClawPluginApi,
PluginRuntime,
} from "openclaw/plugin-sdk/core";
export type { ChannelGatewayContext } from "openclaw/plugin-sdk/channel-contract";
export { clearAccountEntryFields } from "openclaw/plugin-sdk/core";
export { buildChannelConfigSchema } from "openclaw/plugin-sdk/channel-config-schema";
export type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime";
export type { ChannelStatusIssue } from "openclaw/plugin-sdk/channel-contract";
export {
buildComputedAccountStatusSnapshot,
buildTokenChannelStatusSummary,
} from "openclaw/plugin-sdk/status-helpers";
export type {
CardAction,
LineChannelData,
LineConfig,
ListItem,
LineProbeResult,
ResolvedLineAccount,
} from "./runtime-api.js";
export {
createActionCard,
createImageCard,
createInfoCard,
createListCard,
createReceiptCard,
DEFAULT_ACCOUNT_ID,
formatDocsLink,
LineConfigSchema,
listLineAccountIds,
normalizeAccountId,
processLineMessage,
resolveDefaultLineAccountId,
resolveExactLineGroupConfigKey,
resolveLineAccount,
setSetupChannelEnabled,
splitSetupEntries,
} from "./runtime-api.js";
export type { ResolvedLineAccount } from "./runtime-api.js";
export { linePlugin } from "./src/channel.js";
export { lineSetupPlugin } from "./src/channel.setup.js";
export { registerLineCardCommand } from "./src/card-command.js";
export * from "./runtime-api.js";
export * from "./setup-api.js";

View File

@@ -10,7 +10,7 @@ let lineCardCommandPromise: Promise<RegisteredLineCardCommand> | null = null;
async function loadLineCardCommand(api: OpenClawPluginApi): Promise<RegisteredLineCardCommand> {
lineCardCommandPromise ??= (async () => {
let registered: RegisteredLineCardCommand | null = null;
const { registerLineCardCommand } = await import("./api.js");
const { registerLineCardCommand } = await import("./src/card-command.js");
registerLineCardCommand({
...api,
registerCommand(command: RegisteredLineCardCommand) {

View File

@@ -27,9 +27,6 @@ export {
splitSetupEntries,
} from "openclaw/plugin-sdk/setup";
export { setLineRuntime } from "./src/runtime.js";
// Keep named exports explicit here so the runtime barrel stays self-contained
// and plugin-sdk can re-export this file directly without reaching into
// extension internals.
export {
firstDefined,
isSenderAllowed,

View File

@@ -1,4 +1,5 @@
import type { LineChannelData, OpenClawPluginApi, ReplyPayload } from "../api.js";
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core";
import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime";
import {
createActionCard,
createImageCard,
@@ -7,7 +8,8 @@ import {
createReceiptCard,
type CardAction,
type ListItem,
} from "../api.js";
} from "./flex-templates.js";
import type { LineChannelData } from "./types.js";
const CARD_USAGE = `Usage: /card <type> "title" "body" [options]

View File

@@ -1,4 +1,17 @@
// Private runtime barrel for the bundled Tlon extension.
// Keep this barrel thin and aligned with the local extension surface.
export * from "openclaw/plugin-sdk/tlon";
export type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime";
export type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
export type { RuntimeEnv } from "openclaw/plugin-sdk/runtime";
export { createDedupeCache } from "openclaw/plugin-sdk/core";
export { createLoggerBackedRuntime } from "./src/logger-runtime.js";
export {
fetchWithSsrFGuard,
isBlockedHostnameOrIp,
ssrfPolicyFromAllowPrivateNetwork,
ssrfPolicyFromDangerouslyAllowPrivateNetwork,
type LookupFn,
type SsrFPolicy,
} from "openclaw/plugin-sdk/ssrf-runtime";
export { SsrFBlockedError } from "openclaw/plugin-sdk/browser-security-runtime";

View File

@@ -0,0 +1,37 @@
import { format } from "node:util";
type RuntimeLoggerLike = {
info: (message: string) => void;
error: (message: string) => void;
};
type LoggerBackedRuntime = {
log: (...args: unknown[]) => void;
error: (...args: unknown[]) => void;
writeStdout: (value: string) => void;
writeJson: (value: unknown, space?: number) => void;
exit: (code: number) => never;
};
export function createLoggerBackedRuntime(params: {
logger: RuntimeLoggerLike;
exitError?: (code: number) => Error;
}): LoggerBackedRuntime {
return {
log: (...args) => {
params.logger.info(format(...args));
},
error: (...args) => {
params.logger.error(format(...args));
},
writeStdout: (value) => {
params.logger.info(value);
},
writeJson: (value, space = 2) => {
params.logger.info(JSON.stringify(value, null, space > 0 ? space : undefined));
},
exit: (code: number): never => {
throw params.exitError?.(code) ?? new Error(`exit ${code}`);
},
};
}

View File

@@ -1,9 +1,26 @@
import { mergeAllowlist, summarizeMapping } from "openclaw/plugin-sdk/allow-from";
import { resolveMentionGatingWithBypass } from "openclaw/plugin-sdk/channel-inbound";
import { createChannelPairingController } from "openclaw/plugin-sdk/channel-pairing";
import {
DM_GROUP_ACCESS_REASON,
resolveDmGroupAccessWithLists,
} from "openclaw/plugin-sdk/channel-policy";
import { createChannelReplyPipeline } from "openclaw/plugin-sdk/channel-reply-pipeline";
import { resolveSenderCommandAuthorization } from "openclaw/plugin-sdk/command-auth";
import {
isDangerousNameMatchingEnabled,
resolveDefaultGroupPolicy,
resolveOpenProviderRuntimeGroupPolicy,
type MarkdownTableMode,
type OpenClawConfig,
warnMissingProviderGroupPolicyFallbackOnce,
} from "openclaw/plugin-sdk/config-runtime";
import { KeyedAsyncQueue } from "openclaw/plugin-sdk/core";
import { createDeferred } from "openclaw/plugin-sdk/extension-shared";
import {
evaluateGroupRouteAccessForPolicy,
resolveSenderScopedGroupPolicy,
} from "openclaw/plugin-sdk/group-access";
import {
DEFAULT_GROUP_HISTORY_LIMIT,
type HistoryEntry,
@@ -11,28 +28,12 @@ import {
clearHistoryEntriesIfEnabled,
recordPendingHistoryEntryIfEnabled,
} from "openclaw/plugin-sdk/reply-history";
import type {
MarkdownTableMode,
OpenClawConfig,
OutboundReplyPayload,
RuntimeEnv,
} from "../runtime-api.js";
import {
createChannelPairingController,
createChannelReplyPipeline,
deliverTextOrMediaReply,
evaluateGroupRouteAccessForPolicy,
isDangerousNameMatchingEnabled,
mergeAllowlist,
resolveMentionGatingWithBypass,
resolveOpenProviderRuntimeGroupPolicy,
resolveSendableOutboundReplyParts,
resolveDefaultGroupPolicy,
resolveSenderCommandAuthorization,
resolveSenderScopedGroupPolicy,
summarizeMapping,
warnMissingProviderGroupPolicyFallbackOnce,
} from "../runtime-api.js";
type OutboundReplyPayload,
} from "openclaw/plugin-sdk/reply-payload";
import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime";
import {
buildZalouserGroupCandidates,
findZalouserGroupEntry,

View File

@@ -1,6 +1,6 @@
import fsp from "node:fs/promises";
import path from "node:path";
import { resolvePreferredOpenClawTmpDir } from "../runtime-api.js";
import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/browser-security-runtime";
export async function writeQrDataUrlToTempFile(
qrDataUrl: string,

View File

@@ -1,4 +1,4 @@
import { isDangerousNameMatchingEnabled } from "../runtime-api.js";
import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/config-runtime";
import type { ResolvedZalouserAccount } from "./accounts.js";
export function isZalouserMutableGroupEntry(raw: string): boolean {

View File

@@ -3,8 +3,8 @@ import fs from "node:fs";
import fsp from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { loadOutboundMediaFromUrl } from "openclaw/plugin-sdk/outbound-media";
import { resolveStateDir as resolvePluginStateDir } from "openclaw/plugin-sdk/state-paths";
import { loadOutboundMediaFromUrl } from "../runtime-api.js";
import { normalizeZaloReactionIcon } from "./reaction.js";
import type {
ZaloAuthStatus,

View File

@@ -356,6 +356,32 @@ describe("discoverOpenClawPlugins", () => {
});
});
it("does not treat repo-level live or test files as plugin entrypoints", () => {
const stateDir = makeTempDir();
const bundledDir = path.join(stateDir, "bundled");
mkdirSafe(bundledDir);
writeStandalonePlugin(
path.join(bundledDir, "video-generation-providers.live.test.ts"),
"export default {}",
);
writeStandalonePlugin(
path.join(bundledDir, "music-generation-providers.live.test.ts"),
"export default {}",
);
writeStandalonePlugin(path.join(bundledDir, "real-plugin.ts"), "export default {}");
const { candidates, diagnostics } = discoverOpenClawPlugins({
env: {
...buildDiscoveryEnv(stateDir),
OPENCLAW_BUNDLED_PLUGINS_DIR: bundledDir,
},
});
expectCandidateOrder(candidates, ["real-plugin"]);
expect(diagnostics).toEqual([]);
});
it("loads package extension packs", async () => {
const stateDir = makeTempDir();
const globalExt = path.join(stateDir, "extensions", "pack");

View File

@@ -296,7 +296,15 @@ function isExtensionFile(filePath: string): boolean {
if (!EXTENSION_EXTS.has(ext)) {
return false;
}
return !filePath.endsWith(".d.ts");
if (filePath.endsWith(".d.ts")) {
return false;
}
const baseName = path.basename(filePath).toLowerCase();
return (
!baseName.includes(".test.") &&
!baseName.includes(".live.test.") &&
!baseName.includes(".e2e.test.")
);
}
function shouldIgnoreScannedDirectory(dirName: string): boolean {