feat: complete DM pairing codes with channel adapters, gateway handlers, and TUI command (Tier 4 feature 4)

This commit is contained in:
William Valentin
2026-02-09 18:28:10 -08:00
parent 9d4d440ecf
commit 1e29da4da2
11 changed files with 270 additions and 7 deletions
+29 -1
View File
@@ -16,6 +16,7 @@ import type {
ChannelStatus,
} from '../types.js';
import { splitMessage } from '../utils.js';
import type { PairingManager } from '../pairing.js';
/** Configuration for the Slack channel adapter. */
export interface SlackAdapterConfig {
@@ -26,6 +27,8 @@ export interface SlackAdapterConfig {
allowedChannelIds?: string[];
/** Require bot mention to respond (default: false). */
requireMention?: boolean;
/** Optional pairing manager for DM pairing codes. */
pairingManager?: PairingManager;
}
/** Minimal shape of a Slack message event from Bolt. */
@@ -275,7 +278,32 @@ export class SlackAdapter implements ChannelAdapter {
this.config.allowedChannelIds.length > 0 &&
!this.config.allowedChannelIds.includes(channelId)
) {
return;
// Pairing fallback — check if the Slack user is approved or sending a valid code
const pm = this.config.pairingManager;
const userId = message.user;
if (pm?.enabled && userId) {
if (pm.isApproved('slack', userId)) {
// Approved — fall through to normal message handling
} else {
const text = (message.text ?? '').trim();
if (text && pm.validateCode('slack', userId, text)) {
// Code validated — send confirmation via Slack
if (this.app) {
const threadTs = message.thread_ts ?? message.ts ?? '';
try {
await this.app.client.chat.postMessage({
channel: channelId,
text: 'Pairing successful! You can now chat with Flynn.',
thread_ts: threadTs || undefined,
});
} catch { /* ignore send errors */ }
}
}
return;
}
} else {
return;
}
}
// Mention requirement