mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-28 10:22:32 +00:00
fix(ci): restore plugin runtime boundaries
This commit is contained in:
@@ -1 +1,56 @@
|
||||
export * from "openclaw/plugin-sdk/bluebubbles";
|
||||
export { resolveAckReaction } from "../../../src/agents/identity.js";
|
||||
export {
|
||||
createActionGate,
|
||||
jsonResult,
|
||||
readNumberParam,
|
||||
readReactionParams,
|
||||
readStringParam,
|
||||
} from "../../../src/agents/tools/common.js";
|
||||
export type { HistoryEntry } from "../../../src/auto-reply/reply/history.js";
|
||||
export {
|
||||
evictOldHistoryKeys,
|
||||
recordPendingHistoryEntryIfEnabled,
|
||||
} from "../../../src/auto-reply/reply/history.js";
|
||||
export { resolveControlCommandGate } from "../../../src/channels/command-gating.js";
|
||||
export { logAckFailure, logInboundDrop, logTypingFailure } from "../../../src/channels/logging.js";
|
||||
export {
|
||||
BLUEBUBBLES_ACTION_NAMES,
|
||||
BLUEBUBBLES_ACTIONS,
|
||||
} from "../../../src/channels/plugins/bluebubbles-actions.js";
|
||||
export { resolveChannelMediaMaxBytes } from "../../../src/channels/plugins/media-limits.js";
|
||||
export { PAIRING_APPROVED_MESSAGE } from "../../../src/channels/plugins/pairing-message.js";
|
||||
export { collectBlueBubblesStatusIssues } from "../../../src/channels/plugins/status-issues/bluebubbles.js";
|
||||
export type {
|
||||
BaseProbeResult,
|
||||
ChannelAccountSnapshot,
|
||||
ChannelMessageActionAdapter,
|
||||
ChannelMessageActionName,
|
||||
} from "../../../src/channels/plugins/types.js";
|
||||
export type { ChannelPlugin } from "../../../src/channels/plugins/types.plugin.js";
|
||||
export type { OpenClawConfig } from "../../../src/config/config.js";
|
||||
export { parseFiniteNumber } from "../../../src/infra/parse-finite-number.js";
|
||||
export type { PluginRuntime } from "../../../src/plugins/runtime/types.js";
|
||||
export { DEFAULT_ACCOUNT_ID } from "../../../src/routing/session-key.js";
|
||||
export {
|
||||
DM_GROUP_ACCESS_REASON,
|
||||
readStoreAllowFromForDmPolicy,
|
||||
resolveDmGroupAccessWithLists,
|
||||
} from "../../../src/security/dm-policy-shared.js";
|
||||
export { readBooleanParam } from "../../../src/plugin-sdk/boolean-param.js";
|
||||
export { mapAllowFromEntries } from "../../../src/plugin-sdk/channel-config-helpers.js";
|
||||
export { createChannelPairingController } from "../../../src/plugin-sdk/channel-pairing.js";
|
||||
export { createChannelReplyPipeline } from "../../../src/plugin-sdk/channel-reply-pipeline.js";
|
||||
export { resolveRequestUrl } from "../../../src/plugin-sdk/request-url.js";
|
||||
export { buildProbeChannelStatusSummary } from "../../../src/plugin-sdk/status-helpers.js";
|
||||
export { stripMarkdown } from "../../../src/plugin-sdk/text-runtime.js";
|
||||
export { extractToolSend } from "../../../src/plugin-sdk/tool-send.js";
|
||||
export {
|
||||
WEBHOOK_RATE_LIMIT_DEFAULTS,
|
||||
createFixedWindowRateLimiter,
|
||||
createWebhookInFlightLimiter,
|
||||
readWebhookBodyOrReject,
|
||||
registerWebhookTargetWithPluginRoute,
|
||||
resolveRequestClientIp,
|
||||
resolveWebhookTargetWithAuthOrRejectSync,
|
||||
withResolvedWebhookRequestPipeline,
|
||||
} from "../../../src/plugin-sdk/webhook-ingress.js";
|
||||
|
||||
@@ -46,7 +46,7 @@ import {
|
||||
normalizeDiscordOutboundTarget,
|
||||
} from "./normalize.js";
|
||||
import { resolveDiscordOutboundSessionRoute } from "./outbound-session-route.js";
|
||||
import { probeDiscord, type DiscordProbe } from "./probe.js";
|
||||
import type { DiscordProbe } from "./probe.js";
|
||||
import { resolveDiscordUserAllowlist } from "./resolve-users.js";
|
||||
import {
|
||||
buildTokenChannelStatusSummary,
|
||||
@@ -74,12 +74,18 @@ type DiscordSendFn = ReturnType<
|
||||
let discordProviderRuntimePromise:
|
||||
| Promise<typeof import("./monitor/provider.runtime.js")>
|
||||
| undefined;
|
||||
let discordProbeRuntimePromise: Promise<typeof import("./probe.runtime.js")> | undefined;
|
||||
|
||||
async function loadDiscordProviderRuntime() {
|
||||
discordProviderRuntimePromise ??= import("./monitor/provider.runtime.js");
|
||||
return await discordProviderRuntimePromise;
|
||||
}
|
||||
|
||||
async function loadDiscordProbeRuntime() {
|
||||
discordProbeRuntimePromise ??= import("./probe.runtime.js");
|
||||
return await discordProbeRuntimePromise;
|
||||
}
|
||||
|
||||
const meta = getChatChannelMeta("discord");
|
||||
const REQUIRED_DISCORD_PERMISSIONS = ["ViewChannel", "SendMessages"] as const;
|
||||
|
||||
@@ -364,7 +370,7 @@ export const discordPlugin: ChannelPlugin<ResolvedDiscordAccount, DiscordProbe>
|
||||
buildChannelSummary: ({ snapshot }) =>
|
||||
buildTokenChannelStatusSummary(snapshot, { includeMode: false }),
|
||||
probeAccount: async ({ account, timeoutMs }) =>
|
||||
probeDiscord(account.token, timeoutMs, {
|
||||
(await loadDiscordProbeRuntime()).probeDiscord(account.token, timeoutMs, {
|
||||
includeApplication: true,
|
||||
}),
|
||||
formatCapabilitiesProbe: ({ probe }) => {
|
||||
@@ -510,7 +516,9 @@ export const discordPlugin: ChannelPlugin<ResolvedDiscordAccount, DiscordProbe>
|
||||
const token = account.token.trim();
|
||||
let discordBotLabel = "";
|
||||
try {
|
||||
const probe = await probeDiscord(token, 2500, {
|
||||
const probe = await (
|
||||
await loadDiscordProbeRuntime()
|
||||
).probeDiscord(token, 2500, {
|
||||
includeApplication: true,
|
||||
});
|
||||
const username = probe.ok ? probe.bot?.username?.trim() : null;
|
||||
|
||||
1
extensions/discord/src/probe.runtime.ts
Normal file
1
extensions/discord/src/probe.runtime.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./probe.js";
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
getRequiredHookHandler,
|
||||
registerHookHandlersForTest,
|
||||
} from "../../../test/helpers/extensions/subagent-hooks.js";
|
||||
import { registerDiscordSubagentHooks } from "./subagent-hooks.js";
|
||||
|
||||
type ThreadBindingRecord = {
|
||||
accountId: string;
|
||||
@@ -39,6 +38,8 @@ const hookMocks = vi.hoisted(() => ({
|
||||
unbindThreadBindingsBySessionKey: vi.fn(() => []),
|
||||
}));
|
||||
|
||||
let registerDiscordSubagentHooks: typeof import("./subagent-hooks.js").registerDiscordSubagentHooks;
|
||||
|
||||
vi.mock("./accounts.js", () => ({
|
||||
resolveDiscordAccount: hookMocks.resolveDiscordAccount,
|
||||
}));
|
||||
@@ -165,7 +166,9 @@ async function expectSubagentSpawningError(params?: {
|
||||
}
|
||||
|
||||
describe("discord subagent hook handlers", () => {
|
||||
beforeEach(() => {
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
({ registerDiscordSubagentHooks } = await import("./subagent-hooks.js"));
|
||||
hookMocks.resolveDiscordAccount.mockClear();
|
||||
hookMocks.resolveDiscordAccount.mockImplementation((params?: { accountId?: string }) => ({
|
||||
accountId: params?.accountId?.trim() || "default",
|
||||
|
||||
@@ -4,17 +4,13 @@ const runFfprobeMock = vi.hoisted(() => vi.fn<(...args: unknown[]) => Promise<st
|
||||
const runFfmpegMock = vi.hoisted(() => vi.fn<(...args: unknown[]) => Promise<void>>());
|
||||
|
||||
vi.mock("openclaw/plugin-sdk/infra-runtime", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("openclaw/plugin-sdk/infra-runtime")>();
|
||||
return {
|
||||
...actual,
|
||||
resolvePreferredOpenClawTmpDir: () => "/tmp",
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("openclaw/plugin-sdk/media-runtime", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("openclaw/plugin-sdk/media-runtime")>();
|
||||
return {
|
||||
...actual,
|
||||
runFfprobe: runFfprobeMock,
|
||||
runFfmpeg: runFfmpegMock,
|
||||
parseFfprobeCodecAndSampleRate: (stdout: string) => {
|
||||
|
||||
@@ -55,7 +55,12 @@ vi.mock("./channel.runtime.js", () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
import { feishuPlugin } from "./channel.js";
|
||||
vi.mock("../../../src/channels/plugins/bundled.js", () => ({
|
||||
bundledChannelPlugins: [],
|
||||
bundledChannelSetupPlugins: [],
|
||||
}));
|
||||
|
||||
let feishuPlugin: typeof import("./channel.js").feishuPlugin;
|
||||
|
||||
function getDescribedActions(cfg: OpenClawConfig): string[] {
|
||||
return [...(feishuPlugin.actions?.describeMessageTool?.({ cfg })?.actions ?? [])];
|
||||
@@ -97,6 +102,11 @@ async function expectLegacyFeishuCardPayloadRejected(cfg: OpenClawConfig, card:
|
||||
}
|
||||
|
||||
describe("feishuPlugin.status.probeAccount", () => {
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
({ feishuPlugin } = await import("./channel.js"));
|
||||
});
|
||||
|
||||
it("uses current account credentials for multi-account config", async () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
|
||||
@@ -94,6 +94,11 @@ vi.mock("./subagent-hooks.js", () => ({
|
||||
registerFeishuSubagentHooks: registerFeishuSubagentHooksMock,
|
||||
}));
|
||||
|
||||
vi.mock("../../../src/channels/plugins/bundled.js", () => ({
|
||||
bundledChannelPlugins: [],
|
||||
bundledChannelSetupPlugins: [],
|
||||
}));
|
||||
|
||||
const baseAccount: ResolvedFeishuAccount = {
|
||||
accountId: "main",
|
||||
selectionSource: "explicit",
|
||||
|
||||
@@ -42,12 +42,15 @@ vi.mock("./runtime.js", () => ({
|
||||
}),
|
||||
}));
|
||||
|
||||
import {
|
||||
downloadImageFeishu,
|
||||
downloadMessageResourceFeishu,
|
||||
sanitizeFileNameForUpload,
|
||||
sendMediaFeishu,
|
||||
} from "./media.js";
|
||||
vi.mock("../../../src/channels/plugins/bundled.js", () => ({
|
||||
bundledChannelPlugins: [],
|
||||
bundledChannelSetupPlugins: [],
|
||||
}));
|
||||
|
||||
let downloadImageFeishu: typeof import("./media.js").downloadImageFeishu;
|
||||
let downloadMessageResourceFeishu: typeof import("./media.js").downloadMessageResourceFeishu;
|
||||
let sanitizeFileNameForUpload: typeof import("./media.js").sanitizeFileNameForUpload;
|
||||
let sendMediaFeishu: typeof import("./media.js").sendMediaFeishu;
|
||||
|
||||
function expectPathIsolatedToTmpRoot(pathValue: string, key: string): void {
|
||||
expect(pathValue).not.toContain(key);
|
||||
@@ -79,7 +82,14 @@ function mockResolvedFeishuAccount() {
|
||||
}
|
||||
|
||||
describe("sendMediaFeishu msg_type routing", () => {
|
||||
beforeEach(() => {
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
({
|
||||
downloadImageFeishu,
|
||||
downloadMessageResourceFeishu,
|
||||
sanitizeFileNameForUpload,
|
||||
sendMediaFeishu,
|
||||
} = await import("./media.js"));
|
||||
vi.clearAllMocks();
|
||||
mockResolvedFeishuAccount();
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { ClawdbotConfig } from "../runtime-api.js";
|
||||
import { resolveFeishuSendTarget } from "./send-target.js";
|
||||
|
||||
const resolveFeishuAccountMock = vi.hoisted(() => vi.fn());
|
||||
const createFeishuClientMock = vi.hoisted(() => vi.fn());
|
||||
@@ -14,11 +13,15 @@ vi.mock("./client.js", () => ({
|
||||
createFeishuClient: createFeishuClientMock,
|
||||
}));
|
||||
|
||||
let resolveFeishuSendTarget: typeof import("./send-target.js").resolveFeishuSendTarget;
|
||||
|
||||
describe("resolveFeishuSendTarget", () => {
|
||||
const cfg = {} as ClawdbotConfig;
|
||||
const client = { id: "client" };
|
||||
|
||||
beforeEach(() => {
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
({ resolveFeishuSendTarget } = await import("./send-target.js"));
|
||||
resolveFeishuAccountMock.mockReset().mockReturnValue({
|
||||
accountId: "default",
|
||||
enabled: true,
|
||||
|
||||
@@ -9,6 +9,7 @@ vi.mock("./send-target.js", () => ({
|
||||
}));
|
||||
|
||||
vi.mock("./runtime.js", () => ({
|
||||
setFeishuRuntime: vi.fn(),
|
||||
getFeishuRuntime: () => ({
|
||||
channel: {
|
||||
text: {
|
||||
@@ -19,7 +20,13 @@ vi.mock("./runtime.js", () => ({
|
||||
}),
|
||||
}));
|
||||
|
||||
import { sendCardFeishu, sendMessageFeishu } from "./send.js";
|
||||
vi.mock("../../../src/channels/plugins/bundled.js", () => ({
|
||||
bundledChannelPlugins: [],
|
||||
bundledChannelSetupPlugins: [],
|
||||
}));
|
||||
|
||||
let sendCardFeishu: typeof import("./send.js").sendCardFeishu;
|
||||
let sendMessageFeishu: typeof import("./send.js").sendMessageFeishu;
|
||||
|
||||
describe("Feishu reply fallback for withdrawn/deleted targets", () => {
|
||||
const replyMock = vi.fn();
|
||||
@@ -35,7 +42,9 @@ describe("Feishu reply fallback for withdrawn/deleted targets", () => {
|
||||
expect(result.messageId).toBe(expectedMessageId);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
({ sendCardFeishu, sendMessageFeishu } = await import("./send.js"));
|
||||
vi.clearAllMocks();
|
||||
resolveFeishuSendTargetMock.mockReturnValue({
|
||||
client: {
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { ClawdbotConfig } from "../runtime-api.js";
|
||||
import {
|
||||
buildStructuredCard,
|
||||
editMessageFeishu,
|
||||
getMessageFeishu,
|
||||
listFeishuThreadMessages,
|
||||
resolveFeishuCardTemplate,
|
||||
} from "./send.js";
|
||||
|
||||
const {
|
||||
mockClientGet,
|
||||
@@ -42,8 +35,22 @@ vi.mock("./runtime.js", () => ({
|
||||
}),
|
||||
}));
|
||||
|
||||
let buildStructuredCard: typeof import("./send.js").buildStructuredCard;
|
||||
let editMessageFeishu: typeof import("./send.js").editMessageFeishu;
|
||||
let getMessageFeishu: typeof import("./send.js").getMessageFeishu;
|
||||
let listFeishuThreadMessages: typeof import("./send.js").listFeishuThreadMessages;
|
||||
let resolveFeishuCardTemplate: typeof import("./send.js").resolveFeishuCardTemplate;
|
||||
|
||||
describe("getMessageFeishu", () => {
|
||||
beforeEach(() => {
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
({
|
||||
buildStructuredCard,
|
||||
editMessageFeishu,
|
||||
getMessageFeishu,
|
||||
listFeishuThreadMessages,
|
||||
resolveFeishuCardTemplate,
|
||||
} = await import("./send.js"));
|
||||
vi.clearAllMocks();
|
||||
mockResolveFeishuAccount.mockReturnValue({
|
||||
accountId: "default",
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import { beforeEach, describe, expect, test, vi } from "vitest";
|
||||
import type { OpenClawPluginApi } from "../runtime-api.js";
|
||||
import { registerFeishuBitableTools } from "./bitable.js";
|
||||
import { registerFeishuDriveTools } from "./drive.js";
|
||||
import { registerFeishuPermTools } from "./perm.js";
|
||||
import { createToolFactoryHarness } from "./tool-factory-test-harness.js";
|
||||
import { registerFeishuWikiTools } from "./wiki.js";
|
||||
|
||||
const createFeishuClientMock = vi.fn((account: { appId?: string } | undefined) => ({
|
||||
__appId: account?.appId,
|
||||
@@ -14,6 +10,11 @@ vi.mock("./client.js", () => ({
|
||||
createFeishuClient: (account: { appId?: string } | undefined) => createFeishuClientMock(account),
|
||||
}));
|
||||
|
||||
let registerFeishuBitableTools: typeof import("./bitable.js").registerFeishuBitableTools;
|
||||
let registerFeishuDriveTools: typeof import("./drive.js").registerFeishuDriveTools;
|
||||
let registerFeishuPermTools: typeof import("./perm.js").registerFeishuPermTools;
|
||||
let registerFeishuWikiTools: typeof import("./wiki.js").registerFeishuWikiTools;
|
||||
|
||||
function createConfig(params: {
|
||||
toolsA?: {
|
||||
wiki?: boolean;
|
||||
@@ -50,7 +51,16 @@ function createConfig(params: {
|
||||
}
|
||||
|
||||
describe("feishu tool account routing", () => {
|
||||
beforeEach(() => {
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
({ registerFeishuBitableTools, registerFeishuDriveTools, registerFeishuPermTools } =
|
||||
await import("./bitable.js").then(async ({ registerFeishuBitableTools }) => ({
|
||||
registerFeishuBitableTools,
|
||||
...(await import("./drive.js")),
|
||||
...(await import("./perm.js")),
|
||||
...(await import("./wiki.js")),
|
||||
})));
|
||||
({ registerFeishuWikiTools } = await import("./wiki.js"));
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
|
||||
@@ -25,6 +25,11 @@ vi.mock("./token.js", () => ({
|
||||
resolveMSTeamsCredentials,
|
||||
}));
|
||||
|
||||
vi.mock("../../../src/channels/plugins/bundled.js", () => ({
|
||||
bundledChannelPlugins: [],
|
||||
bundledChannelSetupPlugins: [],
|
||||
}));
|
||||
|
||||
describe("msteams setup surface", () => {
|
||||
beforeEach(() => {
|
||||
resolveMSTeamsUserAllowlist.mockReset();
|
||||
|
||||
@@ -8,4 +8,4 @@ export * from "./src/probe.js";
|
||||
export * from "./src/reaction-level.js";
|
||||
export * from "./src/send-reactions.js";
|
||||
export * from "./src/send.js";
|
||||
export { normalizeSignalAccountInput } from "./src/setup-surface.js";
|
||||
export { normalizeSignalAccountInput } from "./src/setup-core.js";
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
resolveMergedAccountConfig,
|
||||
type OpenClawConfig,
|
||||
} from "openclaw/plugin-sdk/account-resolution";
|
||||
import type { SignalAccountConfig } from "./runtime-api.js";
|
||||
import type { SignalAccountConfig } from "openclaw/plugin-sdk/signal";
|
||||
|
||||
export type ResolvedSignalAccount = {
|
||||
accountId: string;
|
||||
|
||||
@@ -13,6 +13,7 @@ import { createComputedAccountStatusAdapter } from "openclaw/plugin-sdk/status-h
|
||||
import { resolveSignalAccount, type ResolvedSignalAccount } from "./accounts.js";
|
||||
import { markdownToSignalTextChunks } from "./format.js";
|
||||
import { signalMessageActions } from "./message-actions.js";
|
||||
import { looksLikeSignalTargetId, normalizeSignalMessagingTarget } from "./normalize.js";
|
||||
import { resolveSignalOutboundTarget } from "./outbound-session.js";
|
||||
import type { SignalProbe } from "./probe.js";
|
||||
import {
|
||||
@@ -20,9 +21,7 @@ import {
|
||||
collectStatusIssuesFromLastError,
|
||||
createDefaultChannelRuntimeState,
|
||||
DEFAULT_ACCOUNT_ID,
|
||||
looksLikeSignalTargetId,
|
||||
normalizeE164,
|
||||
normalizeSignalMessagingTarget,
|
||||
PAIRING_APPROVED_MESSAGE,
|
||||
resolveChannelMediaMaxBytes,
|
||||
type ChannelPlugin,
|
||||
|
||||
@@ -47,7 +47,7 @@ import {
|
||||
resolveSignalSender,
|
||||
type SignalSender,
|
||||
} from "../identity.js";
|
||||
import { normalizeSignalMessagingTarget } from "../runtime-api.js";
|
||||
import { normalizeSignalMessagingTarget } from "../normalize.js";
|
||||
import { sendMessageSignal, sendReadReceiptSignal, sendTypingSignal } from "../send.js";
|
||||
import { handleSignalDirectMessageAccess, resolveSignalAccessState } from "./access-policy.js";
|
||||
import type {
|
||||
|
||||
67
extensions/signal/src/normalize.ts
Normal file
67
extensions/signal/src/normalize.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
export function normalizeSignalMessagingTarget(raw: string): string | undefined {
|
||||
const trimmed = raw.trim();
|
||||
if (!trimmed) {
|
||||
return undefined;
|
||||
}
|
||||
let normalized = trimmed;
|
||||
if (normalized.toLowerCase().startsWith("signal:")) {
|
||||
normalized = normalized.slice("signal:".length).trim();
|
||||
}
|
||||
if (!normalized) {
|
||||
return undefined;
|
||||
}
|
||||
const lower = normalized.toLowerCase();
|
||||
if (lower.startsWith("group:")) {
|
||||
const id = normalized.slice("group:".length).trim();
|
||||
return id ? `group:${id}` : undefined;
|
||||
}
|
||||
if (lower.startsWith("username:")) {
|
||||
const id = normalized.slice("username:".length).trim();
|
||||
return id ? `username:${id}`.toLowerCase() : undefined;
|
||||
}
|
||||
if (lower.startsWith("u:")) {
|
||||
const id = normalized.slice("u:".length).trim();
|
||||
return id ? `username:${id}`.toLowerCase() : undefined;
|
||||
}
|
||||
if (lower.startsWith("uuid:")) {
|
||||
const id = normalized.slice("uuid:".length).trim();
|
||||
return id ? id.toLowerCase() : undefined;
|
||||
}
|
||||
return normalized.toLowerCase();
|
||||
}
|
||||
|
||||
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
||||
const UUID_COMPACT_PATTERN = /^[0-9a-f]{32}$/i;
|
||||
|
||||
export function looksLikeSignalTargetId(raw: string, normalized?: string): boolean {
|
||||
const candidates = [raw, normalized ?? ""].map((value) => value.trim()).filter(Boolean);
|
||||
|
||||
for (const candidate of candidates) {
|
||||
if (/^(signal:)?(group:|username:|u:)/i.test(candidate)) {
|
||||
return true;
|
||||
}
|
||||
if (/^(signal:)?uuid:/i.test(candidate)) {
|
||||
const stripped = candidate
|
||||
.replace(/^signal:/i, "")
|
||||
.replace(/^uuid:/i, "")
|
||||
.trim();
|
||||
if (!stripped) {
|
||||
continue;
|
||||
}
|
||||
if (UUID_PATTERN.test(stripped) || UUID_COMPACT_PATTERN.test(stripped)) {
|
||||
return true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const withoutSignalPrefix = candidate.replace(/^signal:/i, "").trim();
|
||||
if (UUID_PATTERN.test(withoutSignalPrefix) || UUID_COMPACT_PATTERN.test(withoutSignalPrefix)) {
|
||||
return true;
|
||||
}
|
||||
if (/^\+?\d{3,}$/.test(withoutSignalPrefix)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -4,7 +4,12 @@ import {
|
||||
createScopedChannelConfigAdapter,
|
||||
} from "openclaw/plugin-sdk/channel-config-helpers";
|
||||
import { createRestrictSendersChannelSecurity } from "openclaw/plugin-sdk/channel-policy";
|
||||
import { createChannelPluginBase } from "openclaw/plugin-sdk/core";
|
||||
import {
|
||||
createChannelPluginBase,
|
||||
getChatChannelMeta,
|
||||
type ChannelPlugin,
|
||||
} from "openclaw/plugin-sdk/core";
|
||||
import { normalizeE164 } from "openclaw/plugin-sdk/setup";
|
||||
import {
|
||||
listSignalAccountIds,
|
||||
resolveDefaultSignalAccountId,
|
||||
@@ -12,7 +17,6 @@ import {
|
||||
type ResolvedSignalAccount,
|
||||
} from "./accounts.js";
|
||||
import { SignalChannelConfigSchema } from "./config-schema.js";
|
||||
import { getChatChannelMeta, normalizeE164, type ChannelPlugin } from "./runtime-api.js";
|
||||
import { createSignalSetupWizardProxy } from "./setup-core.js";
|
||||
|
||||
export const SIGNAL_CHANNEL = "signal" as const;
|
||||
@@ -27,9 +31,9 @@ export const signalSetupWizard = createSignalSetupWizardProxy(
|
||||
|
||||
export const signalConfigAdapter = createScopedChannelConfigAdapter<ResolvedSignalAccount>({
|
||||
sectionKey: SIGNAL_CHANNEL,
|
||||
listAccountIds: listSignalAccountIds,
|
||||
resolveAccount: adaptScopedAccountAccessor(resolveSignalAccount),
|
||||
defaultAccountId: resolveDefaultSignalAccountId,
|
||||
listAccountIds: (cfg) => listSignalAccountIds(cfg),
|
||||
resolveAccount: adaptScopedAccountAccessor((params) => resolveSignalAccount(params)),
|
||||
defaultAccountId: (cfg) => resolveDefaultSignalAccountId(cfg),
|
||||
clearBaseFields: ["account", "httpUrl", "httpHost", "httpPort", "cliPath", "name"],
|
||||
resolveAllowFrom: (account: ResolvedSignalAccount) => account.config.allowFrom,
|
||||
formatAllowFrom: (allowFrom) =>
|
||||
|
||||
@@ -20,13 +20,19 @@ export { normalizeE164, pathExists, resolveUserPath } from "../utils.js";
|
||||
export {
|
||||
resolveDiscordAccount,
|
||||
type ResolvedDiscordAccount,
|
||||
} from "../../extensions/discord/api.js";
|
||||
export { resolveSlackAccount, type ResolvedSlackAccount } from "../../extensions/slack/api.js";
|
||||
} from "../../extensions/discord/src/accounts.js";
|
||||
export {
|
||||
resolveSlackAccount,
|
||||
type ResolvedSlackAccount,
|
||||
} from "../../extensions/slack/src/accounts.js";
|
||||
export {
|
||||
resolveTelegramAccount,
|
||||
type ResolvedTelegramAccount,
|
||||
} from "../../extensions/telegram/api.js";
|
||||
export { resolveSignalAccount, type ResolvedSignalAccount } from "../../extensions/signal/api.js";
|
||||
} from "../../extensions/telegram/src/accounts.js";
|
||||
export {
|
||||
resolveSignalAccount,
|
||||
type ResolvedSignalAccount,
|
||||
} from "../../extensions/signal/src/accounts.js";
|
||||
|
||||
/** Resolve an account by id, then fall back to the default account when the primary lacks credentials. */
|
||||
export function resolveAccountWithDefaultFallback<TAccount>(params: {
|
||||
|
||||
@@ -28,7 +28,7 @@ export { buildChannelConfigSchema } from "../channels/plugins/config-schema.js";
|
||||
export {
|
||||
resolveBlueBubblesGroupRequireMention,
|
||||
resolveBlueBubblesGroupToolPolicy,
|
||||
} from "../../extensions/bluebubbles/runtime-api.js";
|
||||
} from "../../extensions/bluebubbles/src/group-policy.js";
|
||||
export { formatPairingApproveHint } from "../channels/plugins/helpers.js";
|
||||
export { resolveChannelMediaMaxBytes } from "../channels/plugins/media-limits.js";
|
||||
export {
|
||||
|
||||
@@ -48,5 +48,5 @@ export { mapAllowlistResolutionInputs } from "./allow-from.js";
|
||||
export {
|
||||
resolveBlueBubblesGroupRequireMention,
|
||||
resolveBlueBubblesGroupToolPolicy,
|
||||
} from "../../extensions/bluebubbles/runtime-api.js";
|
||||
} from "../../extensions/bluebubbles/src/group-policy.js";
|
||||
export { collectBlueBubblesStatusIssues } from "../channels/plugins/status-issues/bluebubbles.js";
|
||||
|
||||
@@ -31,14 +31,14 @@ export {
|
||||
normalizeAccountId,
|
||||
resolveDefaultLineAccountId,
|
||||
resolveLineAccount,
|
||||
} from "../../extensions/line/api.js";
|
||||
export { LineConfigSchema } from "../../extensions/line/api.js";
|
||||
} from "../../extensions/line/runtime-api.js";
|
||||
export { LineConfigSchema } from "../../extensions/line/runtime-api.js";
|
||||
export type {
|
||||
LineChannelData,
|
||||
LineConfig,
|
||||
ResolvedLineAccount,
|
||||
} from "../../extensions/line/api.js";
|
||||
export type { LineProbeResult } from "../../extensions/line/api.js";
|
||||
} from "../../extensions/line/runtime-api.js";
|
||||
export type { LineProbeResult } from "../../extensions/line/runtime-api.js";
|
||||
export {
|
||||
createActionCard,
|
||||
createAgendaCard,
|
||||
@@ -52,5 +52,5 @@ export {
|
||||
createReceiptCard,
|
||||
type CardAction,
|
||||
type ListItem,
|
||||
} from "../../extensions/line/api.js";
|
||||
export { processLineMessage } from "../../extensions/line/api.js";
|
||||
} from "../../extensions/line/runtime-api.js";
|
||||
export { processLineMessage } from "../../extensions/line/runtime-api.js";
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
export type { ChannelMessageActionAdapter } from "../channels/plugins/types.js";
|
||||
export type { OpenClawConfig } from "../config/config.js";
|
||||
export type { SignalAccountConfig } from "../config/types.js";
|
||||
export type { ResolvedSignalAccount } from "../../extensions/signal/api.js";
|
||||
export type { ResolvedSignalAccount } from "../../extensions/signal/src/accounts.js";
|
||||
export type {
|
||||
ChannelMessageActionContext,
|
||||
ChannelPlugin,
|
||||
@@ -54,10 +54,13 @@ export {
|
||||
listEnabledSignalAccounts,
|
||||
listSignalAccountIds,
|
||||
resolveDefaultSignalAccountId,
|
||||
} from "../../extensions/signal/api.js";
|
||||
export { monitorSignalProvider } from "../../extensions/signal/api.js";
|
||||
export { probeSignal } from "../../extensions/signal/api.js";
|
||||
export { resolveSignalReactionLevel } from "../../extensions/signal/api.js";
|
||||
export { removeReactionSignal, sendReactionSignal } from "../../extensions/signal/api.js";
|
||||
export { sendMessageSignal } from "../../extensions/signal/api.js";
|
||||
export { signalMessageActions } from "../../extensions/signal/api.js";
|
||||
} from "../../extensions/signal/src/accounts.js";
|
||||
export { monitorSignalProvider } from "../../extensions/signal/src/monitor.js";
|
||||
export { probeSignal } from "../../extensions/signal/src/probe.js";
|
||||
export { resolveSignalReactionLevel } from "../../extensions/signal/src/reaction-level.js";
|
||||
export {
|
||||
removeReactionSignal,
|
||||
sendReactionSignal,
|
||||
} from "../../extensions/signal/src/send-reactions.js";
|
||||
export { sendMessageSignal } from "../../extensions/signal/src/send.js";
|
||||
export { signalMessageActions } from "../../extensions/signal/src/message-actions.js";
|
||||
|
||||
Reference in New Issue
Block a user