v2: add Chat SDK channel adapters and skills for 11 platforms

Thin wrapper adapters + SKILL.md for Slack, Telegram, GitHub, Linear,
Google Chat, Teams, WhatsApp Cloud API, Resend, Matrix, Webex, iMessage.
All follow the same pattern as discord-v2.ts: readEnvFile → create*Adapter
→ createChatSdkBridge → registerChannelAdapter.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
gavrielc
2026-04-09 11:26:33 +03:00
parent 8a06b01646
commit 12af451069
24 changed files with 1338 additions and 4 deletions

20
src/channels/gchat-v2.ts Normal file
View File

@@ -0,0 +1,20 @@
/**
* Google Chat channel adapter (v2) — uses Chat SDK bridge.
* Self-registers on import.
*/
import { createGoogleChatAdapter } from '@chat-adapter/gchat';
import { readEnvFile } from '../env.js';
import { createChatSdkBridge } from './chat-sdk-bridge.js';
import { registerChannelAdapter } from './channel-registry.js';
registerChannelAdapter('gchat', {
factory: () => {
const env = readEnvFile(['GCHAT_CREDENTIALS']);
if (!env.GCHAT_CREDENTIALS) return null;
const gchatAdapter = createGoogleChatAdapter({
credentials: JSON.parse(env.GCHAT_CREDENTIALS),
});
return createChatSdkBridge({ adapter: gchatAdapter, concurrency: 'concurrent' });
},
});

22
src/channels/github-v2.ts Normal file
View File

@@ -0,0 +1,22 @@
/**
* GitHub channel adapter (v2) — uses Chat SDK bridge.
* PR comment threads as conversations.
* Self-registers on import.
*/
import { createGitHubAdapter } from '@chat-adapter/github';
import { readEnvFile } from '../env.js';
import { createChatSdkBridge } from './chat-sdk-bridge.js';
import { registerChannelAdapter } from './channel-registry.js';
registerChannelAdapter('github', {
factory: () => {
const env = readEnvFile(['GITHUB_TOKEN', 'GITHUB_WEBHOOK_SECRET']);
if (!env.GITHUB_TOKEN) return null;
const githubAdapter = createGitHubAdapter({
token: env.GITHUB_TOKEN,
webhookSecret: env.GITHUB_WEBHOOK_SECRET,
});
return createChatSdkBridge({ adapter: githubAdapter, concurrency: 'queue' });
},
});

View File

@@ -0,0 +1,25 @@
/**
* iMessage channel adapter (v2) — uses Chat SDK bridge.
* Supports local mode (macOS Full Disk Access) and remote mode (Photon API).
* Self-registers on import.
*/
import { createiMessageAdapter } from 'chat-adapter-imessage';
import { readEnvFile } from '../env.js';
import { createChatSdkBridge } from './chat-sdk-bridge.js';
import { registerChannelAdapter } from './channel-registry.js';
registerChannelAdapter('imessage', {
factory: () => {
const env = readEnvFile(['IMESSAGE_ENABLED', 'IMESSAGE_LOCAL', 'IMESSAGE_SERVER_URL', 'IMESSAGE_API_KEY']);
const isLocal = env.IMESSAGE_LOCAL !== 'false';
if (isLocal && !env.IMESSAGE_ENABLED) return null;
if (!isLocal && !env.IMESSAGE_SERVER_URL) return null;
const imessageAdapter = createiMessageAdapter({
local: isLocal,
serverUrl: env.IMESSAGE_SERVER_URL,
apiKey: env.IMESSAGE_API_KEY,
});
return createChatSdkBridge({ adapter: imessageAdapter, concurrency: 'concurrent' });
},
});

View File

@@ -1,12 +1,42 @@
// Channel self-registration barrel file.
// Each import triggers the channel module's registerChannel() call.
// Each import triggers the channel module's registerChannelAdapter() call.
// discord
// gmail
// import './discord-v2.js';
// slack
// import './slack-v2.js';
// telegram
// import './telegram-v2.js';
// whatsapp
// github
// import './github-v2.js';
// linear
// import './linear-v2.js';
// google chat
// import './gchat-v2.js';
// microsoft teams
// import './teams-v2.js';
// whatsapp cloud api
// import './whatsapp-cloud-v2.js';
// resend (email)
// import './resend-v2.js';
// matrix
// import './matrix-v2.js';
// webex
// import './webex-v2.js';
// imessage
// import './imessage-v2.js';
// gmail (native, no Chat SDK)
// whatsapp baileys (native, no Chat SDK)

22
src/channels/linear-v2.ts Normal file
View File

@@ -0,0 +1,22 @@
/**
* Linear channel adapter (v2) — uses Chat SDK bridge.
* Issue comment threads as conversations.
* Self-registers on import.
*/
import { createLinearAdapter } from '@chat-adapter/linear';
import { readEnvFile } from '../env.js';
import { createChatSdkBridge } from './chat-sdk-bridge.js';
import { registerChannelAdapter } from './channel-registry.js';
registerChannelAdapter('linear', {
factory: () => {
const env = readEnvFile(['LINEAR_API_KEY', 'LINEAR_WEBHOOK_SECRET']);
if (!env.LINEAR_API_KEY) return null;
const linearAdapter = createLinearAdapter({
apiKey: env.LINEAR_API_KEY,
webhookSecret: env.LINEAR_WEBHOOK_SECRET,
});
return createChatSdkBridge({ adapter: linearAdapter, concurrency: 'queue' });
},
});

23
src/channels/matrix-v2.ts Normal file
View File

@@ -0,0 +1,23 @@
/**
* Matrix channel adapter (v2) — uses Chat SDK bridge.
* Self-registers on import.
*/
import { createMatrixAdapter } from '@beeper/chat-adapter-matrix';
import { readEnvFile } from '../env.js';
import { createChatSdkBridge } from './chat-sdk-bridge.js';
import { registerChannelAdapter } from './channel-registry.js';
registerChannelAdapter('matrix', {
factory: () => {
const env = readEnvFile(['MATRIX_BASE_URL', 'MATRIX_ACCESS_TOKEN', 'MATRIX_USER_ID', 'MATRIX_BOT_USERNAME']);
if (!env.MATRIX_BASE_URL) return null;
// Matrix adapter reads from process.env directly
process.env.MATRIX_BASE_URL = env.MATRIX_BASE_URL;
if (env.MATRIX_ACCESS_TOKEN) process.env.MATRIX_ACCESS_TOKEN = env.MATRIX_ACCESS_TOKEN;
if (env.MATRIX_USER_ID) process.env.MATRIX_USER_ID = env.MATRIX_USER_ID;
if (env.MATRIX_BOT_USERNAME) process.env.MATRIX_BOT_USERNAME = env.MATRIX_BOT_USERNAME;
const matrixAdapter = createMatrixAdapter();
return createChatSdkBridge({ adapter: matrixAdapter, concurrency: 'concurrent' });
},
});

23
src/channels/resend-v2.ts Normal file
View File

@@ -0,0 +1,23 @@
/**
* Resend (email) channel adapter (v2) — uses Chat SDK bridge.
* Self-registers on import.
*/
import { createResendAdapter } from '@resend/chat-sdk-adapter';
import { readEnvFile } from '../env.js';
import { createChatSdkBridge } from './chat-sdk-bridge.js';
import { registerChannelAdapter } from './channel-registry.js';
registerChannelAdapter('resend', {
factory: () => {
const env = readEnvFile(['RESEND_API_KEY', 'RESEND_FROM_ADDRESS', 'RESEND_FROM_NAME', 'RESEND_WEBHOOK_SECRET']);
if (!env.RESEND_API_KEY) return null;
const resendAdapter = createResendAdapter({
apiKey: env.RESEND_API_KEY,
fromAddress: env.RESEND_FROM_ADDRESS,
fromName: env.RESEND_FROM_NAME,
webhookSecret: env.RESEND_WEBHOOK_SECRET,
});
return createChatSdkBridge({ adapter: resendAdapter, concurrency: 'queue' });
},
});

21
src/channels/slack-v2.ts Normal file
View File

@@ -0,0 +1,21 @@
/**
* Slack channel adapter (v2) — uses Chat SDK bridge.
* Self-registers on import.
*/
import { createSlackAdapter } from '@chat-adapter/slack';
import { readEnvFile } from '../env.js';
import { createChatSdkBridge } from './chat-sdk-bridge.js';
import { registerChannelAdapter } from './channel-registry.js';
registerChannelAdapter('slack', {
factory: () => {
const env = readEnvFile(['SLACK_BOT_TOKEN', 'SLACK_SIGNING_SECRET']);
if (!env.SLACK_BOT_TOKEN) return null;
const slackAdapter = createSlackAdapter({
botToken: env.SLACK_BOT_TOKEN,
signingSecret: env.SLACK_SIGNING_SECRET,
});
return createChatSdkBridge({ adapter: slackAdapter, concurrency: 'concurrent' });
},
});

21
src/channels/teams-v2.ts Normal file
View File

@@ -0,0 +1,21 @@
/**
* Microsoft Teams channel adapter (v2) — uses Chat SDK bridge.
* Self-registers on import.
*/
import { createTeamsAdapter } from '@chat-adapter/teams';
import { readEnvFile } from '../env.js';
import { createChatSdkBridge } from './chat-sdk-bridge.js';
import { registerChannelAdapter } from './channel-registry.js';
registerChannelAdapter('teams', {
factory: () => {
const env = readEnvFile(['TEAMS_APP_ID', 'TEAMS_APP_PASSWORD']);
if (!env.TEAMS_APP_ID) return null;
const teamsAdapter = createTeamsAdapter({
appId: env.TEAMS_APP_ID,
appPassword: env.TEAMS_APP_PASSWORD,
});
return createChatSdkBridge({ adapter: teamsAdapter, concurrency: 'concurrent' });
},
});

View File

@@ -0,0 +1,21 @@
/**
* Telegram channel adapter (v2) — uses Chat SDK bridge.
* Self-registers on import.
*/
import { createTelegramAdapter } from '@chat-adapter/telegram';
import { readEnvFile } from '../env.js';
import { createChatSdkBridge } from './chat-sdk-bridge.js';
import { registerChannelAdapter } from './channel-registry.js';
registerChannelAdapter('telegram', {
factory: () => {
const env = readEnvFile(['TELEGRAM_BOT_TOKEN']);
if (!env.TELEGRAM_BOT_TOKEN) return null;
const telegramAdapter = createTelegramAdapter({
botToken: env.TELEGRAM_BOT_TOKEN,
mode: 'polling',
});
return createChatSdkBridge({ adapter: telegramAdapter, concurrency: 'concurrent' });
},
});

21
src/channels/webex-v2.ts Normal file
View File

@@ -0,0 +1,21 @@
/**
* Webex channel adapter (v2) — uses Chat SDK bridge.
* Self-registers on import.
*/
import { createWebexAdapter } from '@bitbasti/chat-adapter-webex';
import { readEnvFile } from '../env.js';
import { createChatSdkBridge } from './chat-sdk-bridge.js';
import { registerChannelAdapter } from './channel-registry.js';
registerChannelAdapter('webex', {
factory: () => {
const env = readEnvFile(['WEBEX_BOT_TOKEN', 'WEBEX_WEBHOOK_SECRET']);
if (!env.WEBEX_BOT_TOKEN) return null;
const webexAdapter = createWebexAdapter({
botToken: env.WEBEX_BOT_TOKEN,
webhookSecret: env.WEBEX_WEBHOOK_SECRET,
});
return createChatSdkBridge({ adapter: webexAdapter, concurrency: 'concurrent' });
},
});

View File

@@ -0,0 +1,24 @@
/**
* WhatsApp Cloud API channel adapter (v2) — uses Chat SDK bridge.
* Uses the official Meta WhatsApp Business Cloud API (not Baileys).
* Self-registers on import.
*/
import { createWhatsAppAdapter } from '@chat-adapter/whatsapp';
import { readEnvFile } from '../env.js';
import { createChatSdkBridge } from './chat-sdk-bridge.js';
import { registerChannelAdapter } from './channel-registry.js';
registerChannelAdapter('whatsapp-cloud', {
factory: () => {
const env = readEnvFile(['WHATSAPP_ACCESS_TOKEN', 'WHATSAPP_PHONE_NUMBER_ID', 'WHATSAPP_APP_SECRET', 'WHATSAPP_VERIFY_TOKEN']);
if (!env.WHATSAPP_ACCESS_TOKEN) return null;
const whatsappAdapter = createWhatsAppAdapter({
accessToken: env.WHATSAPP_ACCESS_TOKEN,
phoneNumberId: env.WHATSAPP_PHONE_NUMBER_ID,
appSecret: env.WHATSAPP_APP_SECRET,
verifyToken: env.WHATSAPP_VERIFY_TOKEN,
});
return createChatSdkBridge({ adapter: whatsappAdapter, concurrency: 'concurrent' });
},
});