chore(lint): reduce warning debt across core adapters and model clients

This commit is contained in:
William Valentin
2026-02-15 23:03:42 -08:00
parent 92da407e22
commit 49b752e8b0
17 changed files with 239 additions and 117 deletions
+13 -10
View File
@@ -85,7 +85,7 @@ export class DiscordAdapter implements ChannelAdapter {
async connect(): Promise<void> {
this._status = 'connecting';
this.client = new Client({
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
@@ -93,23 +93,24 @@ export class DiscordAdapter implements ChannelAdapter {
GatewayIntentBits.DirectMessages,
],
});
this.client = client;
// ── Ready handler — resolve connect() when the bot is online ──
const readyPromise = new Promise<void>((resolve) => {
this.client!.on(Events.ClientReady, () => {
console.log(`Discord bot ready as ${this.client!.user?.tag}`);
client.on(Events.ClientReady, () => {
console.log(`Discord bot ready as ${client.user?.tag}`);
this._status = 'connected';
resolve();
});
});
// ── Message handler — route inbound messages ──
this.client.on(Events.MessageCreate, (message: DiscordMessage) => {
client.on(Events.MessageCreate, (message: DiscordMessage) => {
void this.handleMessage(message);
});
// Log in and wait for the ready event
await this.client.login(this.config.botToken);
await client.login(this.config.botToken);
await readyPromise;
}
@@ -162,8 +163,11 @@ export class DiscordAdapter implements ChannelAdapter {
name: attachment.filename ?? 'attachment',
});
}
if (!attachment.url) {
throw new Error('Attachment must include data or url');
}
// URL-based attachment
return new AttachmentBuilder(attachment.url!, {
return new AttachmentBuilder(attachment.url, {
name: attachment.filename ?? 'attachment',
});
}
@@ -180,9 +184,8 @@ export class DiscordAdapter implements ChannelAdapter {
// ── Guild/channel filtering ──
if (!isDM) {
// Check allowed guild IDs
if (
!isAllowedByAllowlist(message.guild!.id, this.config.allowedGuildIds)
) {
const guildId = message.guild?.id;
if (!guildId || !isAllowedByAllowlist(guildId, this.config.allowedGuildIds)) {
return;
}
@@ -223,7 +226,7 @@ export class DiscordAdapter implements ChannelAdapter {
// Send typing indicator (lasts 10 seconds, no need for interval)
try {
if ('sendTyping' in message.channel) {
(message.channel as any).sendTyping();
await (message.channel as { sendTyping: () => Promise<unknown> }).sendTyping();
}
} catch { /* ignore typing errors */ }
+21 -10
View File
@@ -57,6 +57,10 @@ interface WhatsAppMessage {
type?: string;
/** Download the media attached to this message. */
downloadMedia?: () => Promise<{ mimetype: string; data: string; filename?: string } | null>;
/** Chat handle for typing indicator. */
getChat?: () => Promise<{ sendStateTyping: () => Promise<void> }>;
/** Mentioned user IDs in message metadata. */
mentionedIds?: string[];
}
/**
@@ -110,34 +114,41 @@ export class WhatsAppAdapter implements ChannelAdapter {
args: puppeteerArgs,
},
});
const client = this.client;
if (!client) {
throw new Error('WhatsApp client initialization failed');
}
// Promise that resolves on 'ready' or rejects on 'auth_failure'
const readyPromise = new Promise<void>((resolve, reject) => {
this.client!.on('ready', () => {
client.on('ready', () => {
console.log('WhatsApp bot connected');
this._status = 'connected';
// Capture bot's own JID for mention detection
this.botId = (this.client as any)?.info?.wid?._serialized;
const clientInfo = client as InstanceType<typeof Client> & {
info?: { wid?: { _serialized?: string } };
};
this.botId = clientInfo.info?.wid?._serialized;
resolve();
});
this.client!.on('auth_failure', (msg: string) => {
client.on('auth_failure', (msg: string) => {
this._status = 'error';
reject(new Error(`WhatsApp auth failure: ${msg}`));
});
this.client!.on('qr', (qr: string) => {
client.on('qr', (qr: string) => {
console.log('WhatsApp QR code received. Scan with your phone:');
console.log(qr);
});
});
// Register message event handler
this.client.on('message', (message: unknown) => {
client.on('message', (message: unknown) => {
this.handleMessage(message as WhatsAppMessage);
});
await this.client.initialize();
await client.initialize();
await readyPromise;
} catch (error) {
this._status = 'error';
@@ -234,7 +245,7 @@ export class WhatsAppAdapter implements ChannelAdapter {
requireMention: this.config.requireMention,
defaultRequireMention: true,
mentionsBot: message.body?.includes(`@${this.botId.replace(/@c\.us$/, '')}`) ||
(message as unknown as { mentionedIds?: string[] }).mentionedIds?.some((id) => id === this.botId) === true,
message.mentionedIds?.some((id) => id === this.botId) === true,
})) {
// WhatsApp mentions use @phone_number format in body
// Also check for mentions in the message mentionedIds
@@ -269,8 +280,8 @@ export class WhatsAppAdapter implements ChannelAdapter {
// Send typing indicator
try {
const chat = await (message as any).getChat();
await chat.sendStateTyping();
const chat = await message.getChat?.();
await chat?.sendStateTyping();
} catch { /* ignore typing errors */ }
// Strip bot mention from message body for group messages
@@ -286,7 +297,7 @@ export class WhatsAppAdapter implements ChannelAdapter {
const attachments: Attachment[] = [];
if (message.hasMedia) {
try {
const media = await (message as any).downloadMedia();
const media = await message.downloadMedia?.();
if (media && typeof media.mimetype === 'string') {
const mimeType = media.mimetype;
const isAudio = mimeType.startsWith('audio/');