style: run oxfmt

This commit is contained in:
Peter Steinberger
2026-01-17 07:59:53 +00:00
parent 5986175268
commit 7cebe7a506
34 changed files with 127 additions and 148 deletions

View File

@@ -33,9 +33,7 @@ const processSchema = Type.Object({
keys: Type.Optional(
Type.Array(Type.String(), { description: "Key tokens to send for send-keys" }),
),
hex: Type.Optional(
Type.Array(Type.String(), { description: "Hex bytes to send for send-keys" }),
),
hex: Type.Optional(Type.Array(Type.String(), { description: "Hex bytes to send for send-keys" })),
literal: Type.Optional(Type.String({ description: "Literal string for send-keys" })),
text: Type.Optional(Type.String({ description: "Text to paste for paste" })),
bracketed: Type.Optional(Type.Boolean({ description: "Wrap paste in bracketed mode" })),
@@ -121,10 +119,7 @@ export function createProcessTool(
.sort((a, b) => b.startedAt - a.startedAt)
.map((s) => {
const label = s.name ? truncateMiddle(s.name, 80) : truncateMiddle(s.command, 120);
return `${s.sessionId} ${pad(
s.status,
9,
)} ${formatDuration(s.runtimeMs)} :: ${label}`;
return `${s.sessionId} ${pad(s.status, 9)} ${formatDuration(s.runtimeMs)} :: ${label}`;
});
return {
content: [

View File

@@ -1,6 +1,11 @@
import { expect, test } from "vitest";
import { BRACKETED_PASTE_END, BRACKETED_PASTE_START, encodeKeySequence, encodePaste } from "./pty-keys.js";
import {
BRACKETED_PASTE_END,
BRACKETED_PASTE_START,
encodeKeySequence,
encodePaste,
} from "./pty-keys.js";
test("encodeKeySequence maps common keys and modifiers", () => {
const enter = encodeKeySequence({ keys: ["Enter"] });

View File

@@ -150,12 +150,12 @@ export function createSessionsListTool(opts?: {
: undefined;
const deliveryChannel =
typeof deliveryContext?.channel === "string" ? deliveryContext.channel : undefined;
const deliveryTo =
typeof deliveryContext?.to === "string" ? deliveryContext.to : undefined;
const deliveryTo = typeof deliveryContext?.to === "string" ? deliveryContext.to : undefined;
const deliveryAccountId =
typeof deliveryContext?.accountId === "string" ? deliveryContext.accountId : undefined;
const lastChannel =
deliveryChannel ?? (typeof entry.lastChannel === "string" ? entry.lastChannel : undefined);
deliveryChannel ??
(typeof entry.lastChannel === "string" ? entry.lastChannel : undefined);
const lastAccountId =
deliveryAccountId ??
(typeof entry.lastAccountId === "string" ? entry.lastAccountId : undefined);

View File

@@ -297,9 +297,7 @@ export async function runPreparedReply(
abortKey: command.abortKey,
messageId: sessionCtx.MessageSid,
});
const isGroupSession =
sessionEntry?.chatType === "group" ||
sessionEntry?.chatType === "channel";
const isGroupSession = sessionEntry?.chatType === "group" || sessionEntry?.chatType === "channel";
const isMainSession = !isGroupSession && sessionKey === normalizeMainKey(sessionCfg?.mainKey);
prefixedBodyBase = await prependSystemEvents({
cfg,

View File

@@ -1,7 +1,4 @@
import {
applyQueueDropPolicy,
shouldSkipQueueItem,
} from "../../../utils/queue-helpers.js";
import { applyQueueDropPolicy, shouldSkipQueueItem } from "../../../utils/queue-helpers.js";
import { FOLLOWUP_QUEUES, getFollowupQueue } from "./state.js";
import type { FollowupRun, QueueDedupeMode, QueueSettings } from "./types.js";

View File

@@ -193,11 +193,9 @@ export async function initSessionState(params: {
const baseEntry = !isNewSession && freshEntry ? entry : undefined;
// Track the originating channel/to for announce routing (subagent announce-back).
const lastChannelRaw =
(ctx.OriginatingChannel as string | undefined) || baseEntry?.lastChannel;
const lastChannelRaw = (ctx.OriginatingChannel as string | undefined) || baseEntry?.lastChannel;
const lastToRaw = (ctx.OriginatingTo as string | undefined) || ctx.To || baseEntry?.lastTo;
const lastAccountIdRaw =
(ctx.AccountId as string | undefined) || baseEntry?.lastAccountId;
const lastAccountIdRaw = (ctx.AccountId as string | undefined) || baseEntry?.lastAccountId;
const deliveryFields = normalizeSessionDeliveryFields({
deliveryContext: {
channel: lastChannelRaw,

View File

@@ -70,4 +70,3 @@ describe("resolveCommandAuthorizedFromAuthorizers", () => {
).toBe(true);
});
});

View File

@@ -21,4 +21,3 @@ export function resolveCommandAuthorizedFromAuthorizers(params: {
}
return authorizers.some((entry) => entry.configured && entry.allowed);
}

View File

@@ -26,10 +26,7 @@ import {
} from "./config-helpers.js";
import { resolveDiscordGroupRequireMention } from "./group-mentions.js";
import { formatPairingApproveHint } from "./helpers.js";
import {
looksLikeDiscordTargetId,
normalizeDiscordMessagingTarget,
} from "./normalize-target.js";
import { looksLikeDiscordTargetId, normalizeDiscordMessagingTarget } from "./normalize-target.js";
import { discordOnboardingAdapter } from "./onboarding/discord.js";
import { PAIRING_APPROVED_MESSAGE } from "./pairing-message.js";
import {

View File

@@ -18,10 +18,7 @@ import {
} from "./config-helpers.js";
import { formatPairingApproveHint } from "./helpers.js";
import { resolveChannelMediaMaxBytes } from "./media-limits.js";
import {
looksLikeSignalTargetId,
normalizeSignalMessagingTarget,
} from "./normalize-target.js";
import { looksLikeSignalTargetId, normalizeSignalMessagingTarget } from "./normalize-target.js";
import { signalOnboardingAdapter } from "./onboarding/signal.js";
import { PAIRING_APPROVED_MESSAGE } from "./pairing-message.js";
import {

View File

@@ -26,10 +26,7 @@ import {
} from "./config-helpers.js";
import { resolveTelegramGroupRequireMention } from "./group-mentions.js";
import { formatPairingApproveHint } from "./helpers.js";
import {
looksLikeTelegramTargetId,
normalizeTelegramMessagingTarget,
} from "./normalize-target.js";
import { looksLikeTelegramTargetId, normalizeTelegramMessagingTarget } from "./normalize-target.js";
import { telegramOnboardingAdapter } from "./onboarding/telegram.js";
import { PAIRING_APPROVED_MESSAGE } from "./pairing-message.js";
import {

View File

@@ -26,10 +26,7 @@ import { buildChannelConfigSchema } from "./config-schema.js";
import { createWhatsAppLoginTool } from "./agent-tools/whatsapp-login.js";
import { resolveWhatsAppGroupRequireMention } from "./group-mentions.js";
import { formatPairingApproveHint } from "./helpers.js";
import {
looksLikeWhatsAppTargetId,
normalizeWhatsAppMessagingTarget,
} from "./normalize-target.js";
import { looksLikeWhatsAppTargetId, normalizeWhatsAppMessagingTarget } from "./normalize-target.js";
import { whatsappOnboardingAdapter } from "./onboarding/whatsapp.js";
import {
applyAccountNameToChannelSection,

View File

@@ -129,7 +129,9 @@ export function normalizeAnyChannelId(raw?: string | null): ChannelId | null {
if (!registry) return null;
const hit = registry.channels.find((entry) => {
const id = String(entry.plugin.id ?? "").trim().toLowerCase();
const id = String(entry.plugin.id ?? "")
.trim()
.toLowerCase();
if (id && id === key) return true;
return (entry.plugin.meta.aliases ?? []).some((alias) => alias.trim().toLowerCase() === key);
});

View File

@@ -51,7 +51,9 @@ export async function deliverAgentCommandResult(params: {
isInternalMessageChannel(deliveryChannel) || Boolean(deliveryPlugin);
const targetMode =
opts.deliveryTargetMode ?? deliveryPlan.deliveryTargetMode ?? (opts.to ? "explicit" : "implicit");
opts.deliveryTargetMode ??
deliveryPlan.deliveryTargetMode ??
(opts.to ? "explicit" : "implicit");
const resolvedAccountId = deliveryPlan.resolvedAccountId;
const resolved =
deliver && isDeliveryChannelKnown && deliveryChannel

View File

@@ -243,10 +243,7 @@ export function formatMessageCliText(result: MessageActionRunResult): string[] {
const results = result.payload.results ?? [];
const rows = results.map((entry) => ({
Channel: resolveChannelLabel(entry.channel),
Target: shortenText(
formatTargetDisplay({ channel: entry.channel, target: entry.to }),
36,
),
Target: shortenText(formatTargetDisplay({ channel: entry.channel, target: entry.to }), 36),
Status: entry.ok ? "ok" : "error",
Error: entry.ok ? "" : shortenText(entry.error ?? "unknown error", 48),
}));

View File

@@ -251,11 +251,7 @@ export const MediaUnderstandingScopeSchema = z
.object({
channel: z.string().optional(),
chatType: z
.union([
z.literal("direct"),
z.literal("group"),
z.literal("channel"),
])
.union([z.literal("direct"), z.literal("group"), z.literal("channel")])
.optional(),
keyPrefix: z.string().optional(),
})

View File

@@ -39,11 +39,7 @@ export const SessionSchema = z
.object({
channel: z.string().optional(),
chatType: z
.union([
z.literal("direct"),
z.literal("group"),
z.literal("channel"),
])
.union([z.literal("direct"), z.literal("group"), z.literal("channel")])
.optional(),
keyPrefix: z.string().optional(),
})

View File

@@ -319,38 +319,38 @@ export async function preflightDiscordMessage(
surface: "discord",
});
if (!isDirectMessage) {
const ownerAllowList = normalizeDiscordAllowList(params.allowFrom, ["discord:", "user:"]);
const ownerOk = ownerAllowList
? allowListMatches(ownerAllowList, {
if (!isDirectMessage) {
const ownerAllowList = normalizeDiscordAllowList(params.allowFrom, ["discord:", "user:"]);
const ownerOk = ownerAllowList
? allowListMatches(ownerAllowList, {
id: author.id,
name: author.username,
tag: formatDiscordUserTag(author),
})
: false;
const channelUsers = channelConfig?.users ?? guildInfo?.users;
const usersOk =
Array.isArray(channelUsers) && channelUsers.length > 0
? resolveDiscordUserAllowed({
allowList: channelUsers,
userId: author.id,
userName: author.username,
userTag: formatDiscordUserTag(author),
})
: false;
const useAccessGroups = params.cfg.commands?.useAccessGroups !== false;
commandAuthorized = resolveCommandAuthorizedFromAuthorizers({
useAccessGroups,
authorizers: [
{ configured: ownerAllowList != null, allowed: ownerOk },
{ configured: Array.isArray(channelUsers) && channelUsers.length > 0, allowed: usersOk },
],
modeWhenAccessGroupsOff: "configured",
});
const channelUsers = channelConfig?.users ?? guildInfo?.users;
const usersOk =
Array.isArray(channelUsers) && channelUsers.length > 0
? resolveDiscordUserAllowed({
allowList: channelUsers,
userId: author.id,
userName: author.username,
userTag: formatDiscordUserTag(author),
})
: false;
const useAccessGroups = params.cfg.commands?.useAccessGroups !== false;
commandAuthorized = resolveCommandAuthorizedFromAuthorizers({
useAccessGroups,
authorizers: [
{ configured: ownerAllowList != null, allowed: ownerOk },
{ configured: Array.isArray(channelUsers) && channelUsers.length > 0, allowed: usersOk },
],
modeWhenAccessGroupsOff: "configured",
});
if (allowTextCommands && hasControlCommand(baseText, params.cfg) && !commandAuthorized) {
logVerbose(`Blocked discord control command from unauthorized sender ${author.id}`);
return null;
if (allowTextCommands && hasControlCommand(baseText, params.cfg) && !commandAuthorized) {
logVerbose(`Blocked discord control command from unauthorized sender ${author.id}`);
return null;
}
}

View File

@@ -230,19 +230,19 @@ describe("gateway server agent", () => {
await server.close();
});
test("agent uses webchat for internal runs when last provider is webchat", async () => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-"));
testState.sessionStorePath = path.join(dir, "sessions.json");
await writeSessionStore({
entries: {
main: {
sessionId: "sess-main-webchat-internal",
updatedAt: Date.now(),
lastChannel: "webchat",
lastTo: "+1555",
},
test("agent uses webchat for internal runs when last provider is webchat", async () => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-"));
testState.sessionStorePath = path.join(dir, "sessions.json");
await writeSessionStore({
entries: {
main: {
sessionId: "sess-main-webchat-internal",
updatedAt: Date.now(),
lastChannel: "webchat",
lastTo: "+1555",
},
});
},
});
const { server, ws } = await startServerWithClient();
await connectOk(ws);

View File

@@ -97,9 +97,8 @@ describe("hooks install (e2e)", () => {
expect(installResult.ok).toBe(true);
if (!installResult.ok) return;
const { clearInternalHooks, createInternalHookEvent, triggerInternalHook } = await import(
"./internal-hooks.js"
);
const { clearInternalHooks, createInternalHookEvent, triggerInternalHook } =
await import("./internal-hooks.js");
const { loadInternalHooks } = await import("./loader.js");
clearInternalHooks();

View File

@@ -62,7 +62,7 @@ describe("installHooksFromArchive", () => {
"---",
"name: zip-hook",
"description: Zip hook",
"metadata: {\"clawdbot\":{\"events\":[\"command:new\"]}}",
'metadata: {"clawdbot":{"events":["command:new"]}}',
"---",
"",
"# Zip Hook",
@@ -82,9 +82,7 @@ describe("installHooksFromArchive", () => {
expect(result.hookPackId).toBe("zip-hooks");
expect(result.hooks).toContain("zip-hook");
expect(result.targetDir).toBe(path.join(stateDir, "hooks", "zip-hooks"));
expect(
fs.existsSync(path.join(result.targetDir, "hooks", "zip-hook", "HOOK.md")),
).toBe(true);
expect(fs.existsSync(path.join(result.targetDir, "hooks", "zip-hook", "HOOK.md"))).toBe(true);
});
it("installs hook packs from tar archives", async () => {
@@ -109,7 +107,7 @@ describe("installHooksFromArchive", () => {
"---",
"name: tar-hook",
"description: Tar hook",
"metadata: {\"clawdbot\":{\"events\":[\"command:new\"]}}",
'metadata: {"clawdbot":{"events":["command:new"]}}',
"---",
"",
"# Tar Hook",
@@ -148,7 +146,7 @@ describe("installHooksFromPath", () => {
"---",
"name: my-hook",
"description: My hook",
"metadata: {\"clawdbot\":{\"events\":[\"command:new\"]}}",
'metadata: {"clawdbot":{"events":["command:new"]}}',
"---",
"",
"# My Hook",

View File

@@ -134,7 +134,9 @@ async function installHookPackageFromDir(params: {
};
}
const hooksDir = params.hooksDir ? resolveUserPath(params.hooksDir) : path.join(CONFIG_DIR, "hooks");
const hooksDir = params.hooksDir
? resolveUserPath(params.hooksDir)
: path.join(CONFIG_DIR, "hooks");
await fs.mkdir(hooksDir, { recursive: true });
const targetDir = resolveHookInstallDir(hookPackId, hooksDir);
@@ -232,7 +234,9 @@ async function installHookFromDir(params: {
};
}
const hooksDir = params.hooksDir ? resolveUserPath(params.hooksDir) : path.join(CONFIG_DIR, "hooks");
const hooksDir = params.hooksDir
? resolveUserPath(params.hooksDir)
: path.join(CONFIG_DIR, "hooks");
await fs.mkdir(hooksDir, { recursive: true });
const targetDir = resolveHookInstallDir(hookName, hooksDir);

View File

@@ -79,9 +79,7 @@ export async function loadInternalHooks(
// Register for all events listed in metadata
const events = entry.clawdbot?.events ?? [];
if (events.length === 0) {
console.warn(
`Hook warning: Hook '${entry.hook.name}' has no events defined in metadata`,
);
console.warn(`Hook warning: Hook '${entry.hook.name}' has no events defined in metadata`);
continue;
}
@@ -126,9 +124,7 @@ export async function loadInternalHooks(
const handler = mod[exportName];
if (typeof handler !== "function") {
console.error(
`Hook error: Handler '${exportName}' from ${modulePath} is not a function`,
);
console.error(`Hook error: Handler '${exportName}' from ${modulePath} is not a function`);
continue;
}

View File

@@ -48,7 +48,11 @@ function resolvePackageHooks(manifest: HookPackageManifest): string[] {
return raw.map((entry) => (typeof entry === "string" ? entry.trim() : "")).filter(Boolean);
}
function loadHookFromDir(params: { hookDir: string; source: string; nameHint?: string }): Hook | null {
function loadHookFromDir(params: {
hookDir: string;
source: string;
nameHint?: string;
}): Hook | null {
const hookMdPath = path.join(params.hookDir, "HOOK.md");
if (!fs.existsSync(hookMdPath)) return null;

View File

@@ -61,10 +61,7 @@ export async function withTimeout<T>(
}
}
async function extractZip(params: {
archivePath: string;
destDir: string;
}): Promise<void> {
async function extractZip(params: { archivePath: string; destDir: string }): Promise<void> {
const buffer = await fs.readFile(params.archivePath);
const zip = await JSZip.loadAsync(buffer);
const entries = Object.values(zip.files);

View File

@@ -9,7 +9,11 @@ import {
normalizeMessageChannel,
type GatewayMessageChannel,
} from "../../utils/message-channel.js";
import { resolveOutboundTarget, resolveSessionDeliveryTarget, type SessionDeliveryTarget } from "./targets.js";
import {
resolveOutboundTarget,
resolveSessionDeliveryTarget,
type SessionDeliveryTarget,
} from "./targets.js";
import type { ClawdbotConfig } from "../../config/config.js";
import type { OutboundTargetResolution } from "./targets.js";

View File

@@ -121,9 +121,7 @@ describe("applyMediaUnderstanding", () => {
expect(result.appliedAudio).toBe(true);
expect(ctx.Transcript).toBe("transcribed text");
expect(ctx.Body).toBe(
"[Audio]\nUser text:\n/capture status\nTranscript:\ntranscribed text",
);
expect(ctx.Body).toBe("[Audio]\nUser text:\n/capture status\nTranscript:\ntranscribed text");
expect(ctx.CommandBody).toBe("/capture status");
expect(ctx.RawBody).toBe("/capture status");
expect(ctx.BodyForCommands).toBe("/capture status");

View File

@@ -78,10 +78,7 @@ export async function applyMediaUnderstanding(params: {
}
if (decisions.length > 0) {
ctx.MediaUnderstandingDecisions = [
...(ctx.MediaUnderstandingDecisions ?? []),
...decisions,
];
ctx.MediaUnderstandingDecisions = [...(ctx.MediaUnderstandingDecisions ?? []), ...decisions];
}
if (outputs.length > 0) {

View File

@@ -1,10 +1,7 @@
import { describe, expect, it } from "vitest";
import type { ClawdbotConfig } from "../config/config.js";
import {
resolveEntriesWithActiveFallback,
resolveModelEntries,
} from "./resolve.js";
import { resolveEntriesWithActiveFallback, resolveModelEntries } from "./resolve.js";
const providerRegistry = new Map([
["openai", { capabilities: ["image"] }],

View File

@@ -100,7 +100,9 @@ function buildModelDecision(params: {
function formatDecisionSummary(decision: MediaUnderstandingDecision): string {
const total = decision.attachments.length;
const success = decision.attachments.filter((entry) => entry.chosen?.outcome === "success").length;
const success = decision.attachments.filter(
(entry) => entry.chosen?.outcome === "success",
).length;
const chosen = decision.attachments.find((entry) => entry.chosen)?.chosen;
const provider = chosen?.provider?.trim();
const model = chosen?.model?.trim();
@@ -355,7 +357,10 @@ async function runAttachmentEntries(params: {
cache: MediaAttachmentCache;
entries: MediaUnderstandingModelConfig[];
config?: MediaUnderstandingConfig;
}): Promise<{ output: MediaUnderstandingOutput | null; attempts: MediaUnderstandingModelDecision[] }> {
}): Promise<{
output: MediaUnderstandingOutput | null;
attempts: MediaUnderstandingModelDecision[];
}> {
const { entries, capability } = params;
const attempts: MediaUnderstandingModelDecision[] = [];
for (const entry of entries) {

View File

@@ -474,10 +474,8 @@ async function collectChannelSecurityFindings(params: {
if (plugin.id === "discord") {
const discordCfg =
(account as { config?: Record<string, unknown> } | null)?.config ?? ({} as Record<
string,
unknown
>);
(account as { config?: Record<string, unknown> } | null)?.config ??
({} as Record<string, unknown>);
const nativeEnabled = resolveNativeCommandsEnabled({
providerId: "discord",
providerSetting: coerceNativeSetting(
@@ -516,15 +514,20 @@ async function collectChannelSecurityFindings(params: {
normalizeAllowFromList([...dmAllowFrom, ...storeAllowFrom]).length > 0;
const useAccessGroups = params.cfg.commands?.useAccessGroups !== false;
if (!useAccessGroups && groupPolicy !== "disabled" && guildsConfigured && !hasAnyUserAllowlist) {
if (
!useAccessGroups &&
groupPolicy !== "disabled" &&
guildsConfigured &&
!hasAnyUserAllowlist
) {
findings.push({
checkId: "channels.discord.commands.native.unrestricted",
severity: "critical",
title: "Discord slash commands are unrestricted",
detail:
'commands.useAccessGroups=false disables sender allowlists for Discord slash commands unless a per-guild/channel users allowlist is configured; with no users allowlist, any user in allowed guild channels can invoke /… commands.',
"commands.useAccessGroups=false disables sender allowlists for Discord slash commands unless a per-guild/channel users allowlist is configured; with no users allowlist, any user in allowed guild channels can invoke /… commands.",
remediation:
'Set commands.useAccessGroups=true (recommended), or configure channels.discord.guilds.<id>.users (or channels.discord.guilds.<id>.channels.<channel>.users).',
"Set commands.useAccessGroups=true (recommended), or configure channels.discord.guilds.<id>.users (or channels.discord.guilds.<id>.channels.<channel>.users).",
});
} else if (
useAccessGroups &&
@@ -540,7 +543,7 @@ async function collectChannelSecurityFindings(params: {
detail:
"Discord slash commands are enabled, but neither an owner allowFrom list nor any per-guild/channel users allowlist is configured; /… commands will be rejected for everyone.",
remediation:
'Add your user id to channels.discord.dm.allowFrom (or approve yourself via pairing), or configure channels.discord.guilds.<id>.users.',
"Add your user id to channels.discord.dm.allowFrom (or approve yourself via pairing), or configure channels.discord.guilds.<id>.users.",
});
}
}
@@ -567,7 +570,7 @@ async function collectChannelSecurityFindings(params: {
const slashCommandEnabled =
nativeEnabled ||
nativeSkillsEnabled ||
((slackCfg.slashCommand as { enabled?: unknown } | undefined)?.enabled === true);
(slackCfg.slashCommand as { enabled?: unknown } | undefined)?.enabled === true;
if (slashCommandEnabled) {
const useAccessGroups = params.cfg.commands?.useAccessGroups !== false;
if (!useAccessGroups) {
@@ -580,7 +583,8 @@ async function collectChannelSecurityFindings(params: {
remediation: "Set commands.useAccessGroups=true (recommended).",
});
} else {
const dmAllowFromRaw = (account as { dm?: { allowFrom?: unknown } } | null)?.dm?.allowFrom;
const dmAllowFromRaw = (account as { dm?: { allowFrom?: unknown } } | null)?.dm
?.allowFrom;
const dmAllowFrom = Array.isArray(dmAllowFromRaw) ? dmAllowFromRaw : [];
const storeAllowFrom = await readChannelAllowFromStore("slack").catch(() => []);
const ownerAllowFromConfigured =

View File

@@ -110,8 +110,8 @@ export const registerTelegramNativeCommands = ({
if (allCommands.length > 0) {
bot.api.setMyCommands(allCommands).catch((err) => {
runtime.error?.(danger(`telegram setMyCommands failed: ${String(err)}`));
});
runtime.error?.(danger(`telegram setMyCommands failed: ${String(err)}`));
});
if (typeof (bot as unknown as { command?: unknown }).command !== "function") {
logVerbose("telegram: bot.command unavailable; skipping native handlers");

View File

@@ -19,7 +19,7 @@ export function normalizeDeliveryContext(context?: DeliveryContext): DeliveryCon
if (!context) return undefined;
const channel =
typeof context.channel === "string"
? normalizeMessageChannel(context.channel) ?? context.channel.trim()
? (normalizeMessageChannel(context.channel) ?? context.channel.trim())
: undefined;
const to = typeof context.to === "string" ? context.to.trim() : undefined;
const accountId = normalizeAccountId(context.accountId);
@@ -31,9 +31,7 @@ export function normalizeDeliveryContext(context?: DeliveryContext): DeliveryCon
};
}
export function normalizeSessionDeliveryFields(
source?: DeliveryContextSessionSource,
): {
export function normalizeSessionDeliveryFields(source?: DeliveryContextSessionSource): {
deliveryContext?: DeliveryContext;
lastChannel?: string;
lastTo?: string;

View File

@@ -78,9 +78,15 @@ async function resolveWhatsAppCommandAuthorized(params: {
}
const storeAllowFrom = await readChannelAllowFromStore("whatsapp").catch(() => []);
const combinedAllowFrom = Array.from(new Set([...(configuredAllowFrom ?? []), ...storeAllowFrom]));
const combinedAllowFrom = Array.from(
new Set([...(configuredAllowFrom ?? []), ...storeAllowFrom]),
);
const allowFrom =
combinedAllowFrom.length > 0 ? combinedAllowFrom : params.msg.selfE164 ? [params.msg.selfE164] : [];
combinedAllowFrom.length > 0
? combinedAllowFrom
: params.msg.selfE164
? [params.msg.selfE164]
: [];
if (allowFrom.some((v) => String(v).trim() === "*")) return true;
return normalizeAllowFromE164(allowFrom).includes(senderE164);
}