agentdial 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/LICENSE +21 -0
  3. package/README.md +310 -0
  4. package/dist/adapters/discord.d.ts +24 -0
  5. package/dist/adapters/discord.d.ts.map +1 -0
  6. package/dist/adapters/discord.js +129 -0
  7. package/dist/adapters/discord.js.map +1 -0
  8. package/dist/adapters/email.d.ts +38 -0
  9. package/dist/adapters/email.d.ts.map +1 -0
  10. package/dist/adapters/email.js +187 -0
  11. package/dist/adapters/email.js.map +1 -0
  12. package/dist/adapters/index.d.ts +12 -0
  13. package/dist/adapters/index.d.ts.map +1 -0
  14. package/dist/adapters/index.js +36 -0
  15. package/dist/adapters/index.js.map +1 -0
  16. package/dist/adapters/slack.d.ts +27 -0
  17. package/dist/adapters/slack.d.ts.map +1 -0
  18. package/dist/adapters/slack.js +173 -0
  19. package/dist/adapters/slack.js.map +1 -0
  20. package/dist/adapters/telegram.d.ts +28 -0
  21. package/dist/adapters/telegram.d.ts.map +1 -0
  22. package/dist/adapters/telegram.js +155 -0
  23. package/dist/adapters/telegram.js.map +1 -0
  24. package/dist/adapters/twilio-sms.d.ts +36 -0
  25. package/dist/adapters/twilio-sms.d.ts.map +1 -0
  26. package/dist/adapters/twilio-sms.js +187 -0
  27. package/dist/adapters/twilio-sms.js.map +1 -0
  28. package/dist/adapters/twilio-whatsapp.d.ts +37 -0
  29. package/dist/adapters/twilio-whatsapp.d.ts.map +1 -0
  30. package/dist/adapters/twilio-whatsapp.js +188 -0
  31. package/dist/adapters/twilio-whatsapp.js.map +1 -0
  32. package/dist/adapters/types.d.ts +349 -0
  33. package/dist/adapters/types.d.ts.map +1 -0
  34. package/dist/adapters/types.js +82 -0
  35. package/dist/adapters/types.js.map +1 -0
  36. package/dist/adapters/voice.d.ts +54 -0
  37. package/dist/adapters/voice.d.ts.map +1 -0
  38. package/dist/adapters/voice.js +250 -0
  39. package/dist/adapters/voice.js.map +1 -0
  40. package/dist/commands/channels.d.ts +5 -0
  41. package/dist/commands/channels.d.ts.map +1 -0
  42. package/dist/commands/channels.js +188 -0
  43. package/dist/commands/channels.js.map +1 -0
  44. package/dist/commands/mcp-serve.d.ts +14 -0
  45. package/dist/commands/mcp-serve.d.ts.map +1 -0
  46. package/dist/commands/mcp-serve.js +479 -0
  47. package/dist/commands/mcp-serve.js.map +1 -0
  48. package/dist/commands/serve.d.ts +6 -0
  49. package/dist/commands/serve.d.ts.map +1 -0
  50. package/dist/commands/serve.js +128 -0
  51. package/dist/commands/serve.js.map +1 -0
  52. package/dist/commands/setup.d.ts +4 -0
  53. package/dist/commands/setup.d.ts.map +1 -0
  54. package/dist/commands/setup.js +174 -0
  55. package/dist/commands/setup.js.map +1 -0
  56. package/dist/commands/status.d.ts +4 -0
  57. package/dist/commands/status.d.ts.map +1 -0
  58. package/dist/commands/status.js +86 -0
  59. package/dist/commands/status.js.map +1 -0
  60. package/dist/commands/test.d.ts +5 -0
  61. package/dist/commands/test.d.ts.map +1 -0
  62. package/dist/commands/test.js +48 -0
  63. package/dist/commands/test.js.map +1 -0
  64. package/dist/commands/voice.d.ts +6 -0
  65. package/dist/commands/voice.d.ts.map +1 -0
  66. package/dist/commands/voice.js +192 -0
  67. package/dist/commands/voice.js.map +1 -0
  68. package/dist/index.d.ts +3 -0
  69. package/dist/index.d.ts.map +1 -0
  70. package/dist/index.js +119 -0
  71. package/dist/index.js.map +1 -0
  72. package/dist/lib/config.d.ts +7 -0
  73. package/dist/lib/config.d.ts.map +1 -0
  74. package/dist/lib/config.js +36 -0
  75. package/dist/lib/config.js.map +1 -0
  76. package/dist/lib/constants.d.ts +13 -0
  77. package/dist/lib/constants.d.ts.map +1 -0
  78. package/dist/lib/constants.js +52 -0
  79. package/dist/lib/constants.js.map +1 -0
  80. package/dist/lib/credentials.d.ts +7 -0
  81. package/dist/lib/credentials.d.ts.map +1 -0
  82. package/dist/lib/credentials.js +61 -0
  83. package/dist/lib/credentials.js.map +1 -0
  84. package/dist/lib/gateway.d.ts +27 -0
  85. package/dist/lib/gateway.d.ts.map +1 -0
  86. package/dist/lib/gateway.js +103 -0
  87. package/dist/lib/gateway.js.map +1 -0
  88. package/dist/lib/identity.d.ts +5 -0
  89. package/dist/lib/identity.d.ts.map +1 -0
  90. package/dist/lib/identity.js +36 -0
  91. package/dist/lib/identity.js.map +1 -0
  92. package/dist/lib/ui.d.ts +12 -0
  93. package/dist/lib/ui.d.ts.map +1 -0
  94. package/dist/lib/ui.js +91 -0
  95. package/dist/lib/ui.js.map +1 -0
  96. package/package.json +95 -0
  97. package/templates/IDENTITY.md +59 -0
@@ -0,0 +1,187 @@
1
+ import { getCredential } from "../lib/credentials.js";
2
+ const SENDGRID_API = "https://api.sendgrid.com/v3";
3
+ async function sendgridFetch(apiKey, path, options = {}) {
4
+ const res = await fetch(`${SENDGRID_API}${path}`, {
5
+ ...options,
6
+ headers: {
7
+ Authorization: `Bearer ${apiKey}`,
8
+ "Content-Type": "application/json",
9
+ ...options.headers,
10
+ },
11
+ });
12
+ return res;
13
+ }
14
+ function extractEmail(raw) {
15
+ // Handle "Name <email@example.com>" format
16
+ const match = raw.match(/<([^>]+)>/);
17
+ return match ? match[1] : raw.trim();
18
+ }
19
+ function responseToHtml(response) {
20
+ let html = `<p>${escapeHtml(response.text).replace(/\n/g, "<br>")}</p>`;
21
+ if (response.cards?.length) {
22
+ for (const card of response.cards) {
23
+ html += `<div style="border:1px solid #333;border-radius:8px;padding:16px;margin:12px 0;">`;
24
+ if (card.imageUrl) {
25
+ html += `<img src="${escapeHtml(card.imageUrl)}" style="max-width:100%;border-radius:4px;" />`;
26
+ }
27
+ html += `<h3 style="margin:8px 0 4px;">${escapeHtml(card.title)}</h3>`;
28
+ if (card.description) {
29
+ html += `<p style="color:#666;">${escapeHtml(card.description)}</p>`;
30
+ }
31
+ if (card.actions?.length) {
32
+ for (const action of card.actions) {
33
+ if (action.type === "url") {
34
+ html += `<a href="${escapeHtml(action.value)}" style="display:inline-block;padding:8px 16px;background:#6b21a8;color:white;border-radius:4px;text-decoration:none;margin:4px 4px 4px 0;">${escapeHtml(action.label)}</a>`;
35
+ }
36
+ }
37
+ }
38
+ html += `</div>`;
39
+ }
40
+ }
41
+ if (response.actions?.length) {
42
+ html += `<div style="margin-top:12px;">`;
43
+ for (const action of response.actions) {
44
+ if (action.type === "url") {
45
+ html += `<a href="${escapeHtml(action.value)}" style="display:inline-block;padding:8px 16px;background:#6b21a8;color:white;border-radius:4px;text-decoration:none;margin:4px;">${escapeHtml(action.label)}</a>`;
46
+ }
47
+ }
48
+ html += `</div>`;
49
+ }
50
+ return html;
51
+ }
52
+ export class EmailAdapter {
53
+ name = "email";
54
+ displayName = "Email (SendGrid)";
55
+ free = false;
56
+ cost = "100/day free, then $0.001/msg";
57
+ setupTime = "3 min";
58
+ apiKey = "";
59
+ fromEmail = "";
60
+ fromName = "";
61
+ messageHandler = null;
62
+ connected = false;
63
+ lastMessageTs = null;
64
+ async setup(config) {
65
+ this.apiKey =
66
+ config.credentials?.apiKey ??
67
+ (await getCredential("email", "apiKey")) ??
68
+ "";
69
+ this.fromEmail =
70
+ config.credentials?.fromEmail ??
71
+ (await getCredential("email", "fromEmail")) ??
72
+ "";
73
+ this.fromName =
74
+ config.credentials?.fromName ??
75
+ (await getCredential("email", "fromName")) ??
76
+ "Agent";
77
+ if (!this.apiKey || !this.fromEmail) {
78
+ throw new Error("Email adapter requires apiKey and fromEmail");
79
+ }
80
+ // Validate API key
81
+ const res = await sendgridFetch(this.apiKey, "/user/profile");
82
+ if (!res.ok) {
83
+ const text = await res.text();
84
+ throw new Error(`SendGrid API key invalid: ${text}`);
85
+ }
86
+ }
87
+ async connect() {
88
+ // API-based, no persistent connection needed.
89
+ // Inbound email uses SendGrid Inbound Parse webhook — configured in SG dashboard.
90
+ this.connected = true;
91
+ }
92
+ async disconnect() {
93
+ this.connected = false;
94
+ }
95
+ async send(to, response) {
96
+ const subject = response.metadata?.subject ?? "New message";
97
+ const body = {
98
+ personalizations: [{ to: [{ email: to }] }],
99
+ from: { email: this.fromEmail, name: this.fromName },
100
+ subject,
101
+ content: [
102
+ { type: "text/plain", value: response.text },
103
+ { type: "text/html", value: responseToHtml(response) },
104
+ ],
105
+ };
106
+ const res = await sendgridFetch(this.apiKey, "/mail/send", {
107
+ method: "POST",
108
+ body: JSON.stringify(body),
109
+ });
110
+ // SendGrid returns 202 on success, no body
111
+ if (!res.ok) {
112
+ const errBody = (await res.json());
113
+ const errMsg = errBody.errors?.map((e) => e.message).join(", ") ?? "Send failed";
114
+ throw new Error(`SendGrid send failed: ${errMsg}`);
115
+ }
116
+ }
117
+ onMessage(handler) {
118
+ this.messageHandler = handler;
119
+ }
120
+ /** Call from HTTP webhook handler with parsed SendGrid Inbound Parse POST body. */
121
+ async handleWebhook(payload) {
122
+ this.lastMessageTs = Date.now();
123
+ const fromEmail = extractEmail(payload.from);
124
+ const text = payload.text ?? "";
125
+ const subject = payload.subject ?? "";
126
+ const msg = {
127
+ id: `email-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
128
+ channel: "email",
129
+ from: fromEmail,
130
+ text: text || subject,
131
+ timestamp: Date.now(),
132
+ metadata: {
133
+ subject,
134
+ to: payload.to,
135
+ html: payload.html ?? undefined,
136
+ },
137
+ };
138
+ if (!this.messageHandler)
139
+ return null;
140
+ return this.messageHandler(msg);
141
+ }
142
+ async test() {
143
+ try {
144
+ const res = await sendgridFetch(this.apiKey, "/user/profile");
145
+ if (!res.ok) {
146
+ return { ok: false, error: `API returned ${res.status}` };
147
+ }
148
+ return { ok: true };
149
+ }
150
+ catch (err) {
151
+ return {
152
+ ok: false,
153
+ error: err instanceof Error ? err.message : "Unknown error",
154
+ };
155
+ }
156
+ }
157
+ async status() {
158
+ const start = Date.now();
159
+ try {
160
+ const res = await sendgridFetch(this.apiKey, "/user/profile");
161
+ return {
162
+ channel: "email",
163
+ connected: this.connected && res.ok,
164
+ latencyMs: Date.now() - start,
165
+ lastMessage: this.lastMessageTs,
166
+ error: res.ok ? null : `API returned ${res.status}`,
167
+ };
168
+ }
169
+ catch (err) {
170
+ return {
171
+ channel: "email",
172
+ connected: false,
173
+ latencyMs: Date.now() - start,
174
+ lastMessage: this.lastMessageTs,
175
+ error: err instanceof Error ? err.message : "Unknown error",
176
+ };
177
+ }
178
+ }
179
+ }
180
+ function escapeHtml(text) {
181
+ return text
182
+ .replace(/&/g, "&amp;")
183
+ .replace(/</g, "&lt;")
184
+ .replace(/>/g, "&gt;")
185
+ .replace(/"/g, "&quot;");
186
+ }
187
+ //# sourceMappingURL=email.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email.js","sourceRoot":"","sources":["../../src/adapters/email.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { ChannelAdapter, ChannelType } from "./types.js";
2
+ export declare function getAdapter(channel: ChannelType): ChannelAdapter;
3
+ export declare function getAllAdapters(): ChannelAdapter[];
4
+ export declare function hasAdapter(channel: ChannelType): boolean;
5
+ export { TelegramAdapter } from "./telegram.js";
6
+ export { DiscordAdapter } from "./discord.js";
7
+ export { SlackAdapter } from "./slack.js";
8
+ export { TwilioSmsAdapter } from "./twilio-sms.js";
9
+ export { TwilioWhatsAppAdapter } from "./twilio-whatsapp.js";
10
+ export { EmailAdapter } from "./email.js";
11
+ export { VoiceAdapter } from "./voice.js";
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAmB9D,wBAAgB,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc,CAI/D;AAED,wBAAgB,cAAc,IAAI,cAAc,EAAE,CAEjD;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAExD;AAED,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,36 @@
1
+ import { TelegramAdapter } from "./telegram.js";
2
+ import { DiscordAdapter } from "./discord.js";
3
+ import { SlackAdapter } from "./slack.js";
4
+ import { TwilioSmsAdapter } from "./twilio-sms.js";
5
+ import { TwilioWhatsAppAdapter } from "./twilio-whatsapp.js";
6
+ import { EmailAdapter } from "./email.js";
7
+ import { VoiceAdapter } from "./voice.js";
8
+ const adapters = new Map([
9
+ ["telegram", new TelegramAdapter()],
10
+ ["discord", new DiscordAdapter()],
11
+ ["slack", new SlackAdapter()],
12
+ ["sms", new TwilioSmsAdapter()],
13
+ ["whatsapp", new TwilioWhatsAppAdapter()],
14
+ ["email", new EmailAdapter()],
15
+ ["voice", new VoiceAdapter()],
16
+ ]);
17
+ export function getAdapter(channel) {
18
+ const adapter = adapters.get(channel);
19
+ if (!adapter)
20
+ throw new Error(`No adapter for channel: ${channel}`);
21
+ return adapter;
22
+ }
23
+ export function getAllAdapters() {
24
+ return [...adapters.values()];
25
+ }
26
+ export function hasAdapter(channel) {
27
+ return adapters.has(channel);
28
+ }
29
+ export { TelegramAdapter } from "./telegram.js";
30
+ export { DiscordAdapter } from "./discord.js";
31
+ export { SlackAdapter } from "./slack.js";
32
+ export { TwilioSmsAdapter } from "./twilio-sms.js";
33
+ export { TwilioWhatsAppAdapter } from "./twilio-whatsapp.js";
34
+ export { EmailAdapter } from "./email.js";
35
+ export { VoiceAdapter } from "./voice.js";
36
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,QAAQ,GAAG,IAAI,GAAG,CAA8B;IACpD,CAAC,UAAU,EAAE,IAAI,eAAe,EAAE,CAAC;IACnC,CAAC,SAAS,EAAE,IAAI,cAAc,EAAE,CAAC;IACjC,CAAC,OAAO,EAAE,IAAI,YAAY,EAAE,CAAC;IAC7B,CAAC,KAAK,EAAE,IAAI,gBAAgB,EAAE,CAAC;IAC/B,CAAC,UAAU,EAAE,IAAI,qBAAqB,EAAE,CAAC;IACzC,CAAC,OAAO,EAAE,IAAI,YAAY,EAAE,CAAC;IAC7B,CAAC,OAAO,EAAE,IAAI,YAAY,EAAE,CAAC;CAC9B,CAAC,CAAC;AAEH,MAAM,UAAU,UAAU,CAAC,OAAoB;IAC7C,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACtC,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,OAAO,EAAE,CAAC,CAAC;IACpE,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,OAAoB;IAC7C,OAAO,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAC/B,CAAC;AAED,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,27 @@
1
+ import type { ChannelAdapter, ChannelConfig, ChannelStatus, GatewayMessage, GatewayResponse } from "./types.js";
2
+ export declare class SlackAdapter implements ChannelAdapter {
3
+ readonly name: "slack";
4
+ readonly displayName: string;
5
+ readonly free = false;
6
+ readonly cost = "Free (Slack workspace required)";
7
+ readonly setupTime: string;
8
+ private socketClient;
9
+ private webClient;
10
+ private botToken;
11
+ private appToken;
12
+ private messageHandler;
13
+ private connectedAt;
14
+ private lastMessageAt;
15
+ private loadSdk;
16
+ setup(config: ChannelConfig): Promise<void>;
17
+ connect(): Promise<void>;
18
+ disconnect(): Promise<void>;
19
+ send(to: string, response: GatewayResponse): Promise<void>;
20
+ onMessage(handler: (msg: GatewayMessage) => Promise<GatewayResponse>): void;
21
+ test(): Promise<{
22
+ ok: boolean;
23
+ error?: string;
24
+ }>;
25
+ status(): Promise<ChannelStatus>;
26
+ }
27
+ //# sourceMappingURL=slack.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slack.d.ts","sourceRoot":"","sources":["../../src/adapters/slack.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EACb,aAAa,EACb,cAAc,EACd,eAAe,EAGhB,MAAM,YAAY,CAAC;AA4EpB,qBAAa,YAAa,YAAW,cAAc;IACjD,QAAQ,CAAC,IAAI,EAAG,OAAO,CAAU;IACjC,QAAQ,CAAC,WAAW,SAA+B;IACnD,QAAQ,CAAC,IAAI,SAAS;IACtB,QAAQ,CAAC,IAAI,qCAAqC;IAClD,QAAQ,CAAC,SAAS,SAA6B;IAE/C,OAAO,CAAC,YAAY,CAAyB;IAC7C,OAAO,CAAC,SAAS,CAAwB;IACzC,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,cAAc,CAEN;IAChB,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,aAAa,CAAuB;YAE9B,OAAO;IAuBf,KAAK,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB3C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAmDxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAS3B,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAShE,SAAS,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI;IAIrE,IAAI,IAAI,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAmBhD,MAAM,IAAI,OAAO,CAAC,aAAa,CAAC;CASvC"}
@@ -0,0 +1,173 @@
1
+ import { getCredential, saveCredential } from "../lib/credentials.js";
2
+ import { CHANNEL_DISPLAY_NAMES, CHANNEL_SETUP_TIMES, } from "../lib/constants.js";
3
+ function buildBlocks(cards, actions) {
4
+ const blocks = [];
5
+ if (cards?.length) {
6
+ for (const c of cards) {
7
+ blocks.push({
8
+ type: "header",
9
+ text: { type: "plain_text", text: c.title },
10
+ });
11
+ if (c.description)
12
+ blocks.push({
13
+ type: "section",
14
+ text: { type: "mrkdwn", text: c.description },
15
+ });
16
+ if (c.imageUrl)
17
+ blocks.push({
18
+ type: "image",
19
+ image_url: c.imageUrl,
20
+ alt_text: c.title,
21
+ });
22
+ }
23
+ }
24
+ if (actions?.length) {
25
+ blocks.push({
26
+ type: "actions",
27
+ elements: actions.map((a) => ({
28
+ type: "button",
29
+ text: { type: "plain_text", text: a.label },
30
+ ...(a.type === "url" ? { url: a.value } : { value: a.value }),
31
+ })),
32
+ });
33
+ }
34
+ return blocks.length ? blocks : undefined;
35
+ }
36
+ export class SlackAdapter {
37
+ name = "slack";
38
+ displayName = CHANNEL_DISPLAY_NAMES.slack;
39
+ free = false;
40
+ cost = "Free (Slack workspace required)";
41
+ setupTime = CHANNEL_SETUP_TIMES.slack;
42
+ socketClient = null;
43
+ webClient = null;
44
+ botToken = null;
45
+ appToken = null;
46
+ messageHandler = null;
47
+ connectedAt = null;
48
+ lastMessageAt = null;
49
+ async loadSdk() {
50
+ try {
51
+ const sp = "@slack/socket-mode";
52
+ const wp = "@slack/web-api";
53
+ const [s, w] = await Promise.all([
54
+ import(/* webpackIgnore: true */ sp),
55
+ import(/* webpackIgnore: true */ wp),
56
+ ]);
57
+ return { SM: s.SocketModeClient, WC: w.WebClient };
58
+ }
59
+ catch {
60
+ throw new Error("Slack SDK not installed. Run: npm install @slack/socket-mode @slack/web-api");
61
+ }
62
+ }
63
+ async setup(config) {
64
+ const botToken = config.credentials?.["bot_token"];
65
+ const appToken = config.credentials?.["app_token"];
66
+ if (!botToken)
67
+ throw new Error("Missing credential: bot_token (xoxb-...). Create a Slack app at api.slack.com/apps.");
68
+ if (!appToken)
69
+ throw new Error("Missing credential: app_token (xapp-...). Enable Socket Mode in your Slack app.");
70
+ await this.loadSdk();
71
+ this.botToken = botToken;
72
+ this.appToken = appToken;
73
+ await saveCredential("slack", "bot_token", botToken);
74
+ await saveCredential("slack", "app_token", appToken);
75
+ }
76
+ async connect() {
77
+ if (!this.botToken || !this.appToken) {
78
+ this.botToken = (await getCredential("slack", "bot_token")) ?? null;
79
+ this.appToken = (await getCredential("slack", "app_token")) ?? null;
80
+ if (!this.botToken || !this.appToken)
81
+ throw new Error("Not configured. Run setup() first.");
82
+ }
83
+ const { SM, WC } = await this.loadSdk();
84
+ this.webClient = new WC(this.botToken);
85
+ this.socketClient = new SM({ appToken: this.appToken });
86
+ await this.webClient.auth.test();
87
+ this.socketClient.on("message", (raw) => {
88
+ const { event: evt, ack } = raw;
89
+ ack?.({}).catch(() => { });
90
+ if (!evt ||
91
+ evt.type !== "message" ||
92
+ evt.bot_id ||
93
+ !evt.text ||
94
+ !this.messageHandler)
95
+ return;
96
+ this.lastMessageAt = Date.now();
97
+ const attachments = evt.files?.map((f) => ({
98
+ type: "file",
99
+ url: f.url_private,
100
+ name: f.name,
101
+ mimeType: f.mimetype,
102
+ }));
103
+ const msg = {
104
+ id: evt.ts ?? String(Date.now()),
105
+ channel: "slack",
106
+ from: evt.user ?? "unknown",
107
+ text: evt.text,
108
+ timestamp: evt.ts ? parseFloat(evt.ts) * 1000 : Date.now(),
109
+ threadId: evt.thread_ts,
110
+ attachments: attachments?.length ? attachments : undefined,
111
+ metadata: { channelId: evt.channel },
112
+ };
113
+ this.messageHandler(msg)
114
+ .then((res) => {
115
+ if (evt.channel)
116
+ this.send(evt.channel, res).catch(() => { });
117
+ })
118
+ .catch(() => { });
119
+ });
120
+ await this.socketClient.start();
121
+ this.connectedAt = Date.now();
122
+ }
123
+ async disconnect() {
124
+ if (this.socketClient) {
125
+ await this.socketClient.disconnect();
126
+ this.socketClient = null;
127
+ }
128
+ this.webClient = null;
129
+ this.connectedAt = null;
130
+ }
131
+ async send(to, response) {
132
+ if (!this.webClient)
133
+ throw new Error("Not connected");
134
+ await this.webClient.chat.postMessage({
135
+ channel: to,
136
+ text: response.text,
137
+ blocks: buildBlocks(response.cards, response.actions),
138
+ });
139
+ }
140
+ onMessage(handler) {
141
+ this.messageHandler = handler;
142
+ }
143
+ async test() {
144
+ try {
145
+ if (!this.webClient) {
146
+ const botToken = await getCredential("slack", "bot_token");
147
+ if (!botToken)
148
+ return { ok: false, error: "No bot token configured" };
149
+ const { WC } = await this.loadSdk();
150
+ const res = await new WC(botToken).auth.test();
151
+ return { ok: res.ok, error: res.ok ? undefined : "Auth test failed" };
152
+ }
153
+ const res = await this.webClient.auth.test();
154
+ return { ok: res.ok, error: res.ok ? undefined : "Auth test failed" };
155
+ }
156
+ catch (err) {
157
+ return {
158
+ ok: false,
159
+ error: err instanceof Error ? err.message : "Unknown error",
160
+ };
161
+ }
162
+ }
163
+ async status() {
164
+ return {
165
+ channel: "slack",
166
+ connected: this.socketClient?.connected ?? false,
167
+ latencyMs: this.connectedAt ? Date.now() - this.connectedAt : null,
168
+ lastMessage: this.lastMessageAt,
169
+ error: this.socketClient?.connected ? null : "Not connected",
170
+ };
171
+ }
172
+ }
173
+ //# sourceMappingURL=slack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slack.js","sourceRoot":"","sources":["../../src/adapters/slack.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { ChannelAdapter, ChannelConfig, ChannelStatus, GatewayMessage, GatewayResponse } from "./types.js";
2
+ export declare class TelegramAdapter implements ChannelAdapter {
3
+ readonly name: "telegram";
4
+ readonly displayName: string;
5
+ readonly free = true;
6
+ readonly setupTime: string;
7
+ private token;
8
+ private botInfo;
9
+ private polling;
10
+ private pollAbort;
11
+ private lastUpdateId;
12
+ private messageHandler;
13
+ private connectedAt;
14
+ private lastMessageAt;
15
+ private api;
16
+ setup(config: ChannelConfig): Promise<void>;
17
+ connect(): Promise<void>;
18
+ private pollLoop;
19
+ disconnect(): Promise<void>;
20
+ send(to: string, response: GatewayResponse): Promise<void>;
21
+ onMessage(handler: (msg: GatewayMessage) => Promise<GatewayResponse>): void;
22
+ test(): Promise<{
23
+ ok: boolean;
24
+ error?: string;
25
+ }>;
26
+ status(): Promise<ChannelStatus>;
27
+ }
28
+ //# sourceMappingURL=telegram.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telegram.d.ts","sourceRoot":"","sources":["../../src/adapters/telegram.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EACb,aAAa,EACb,cAAc,EACd,eAAe,EAChB,MAAM,YAAY,CAAC;AAsBpB,qBAAa,eAAgB,YAAW,cAAc;IACpD,QAAQ,CAAC,IAAI,EAAG,UAAU,CAAU;IACpC,QAAQ,CAAC,WAAW,SAAkC;IACtD,QAAQ,CAAC,IAAI,QAAQ;IACrB,QAAQ,CAAC,SAAS,SAAgC;IAElD,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,cAAc,CAEN;IAChB,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,aAAa,CAAuB;YAE9B,GAAG;IAqBX,KAAK,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAW3C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YAahB,QAAQ;IAsChB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAO3B,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAyBhE,SAAS,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI;IAIrE,IAAI,IAAI,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAiBhD,MAAM,IAAI,OAAO,CAAC,aAAa,CAAC;CAUvC"}
@@ -0,0 +1,155 @@
1
+ import { getCredential, saveCredential } from "../lib/credentials.js";
2
+ import { CHANNEL_DISPLAY_NAMES, CHANNEL_SETUP_TIMES, } from "../lib/constants.js";
3
+ const TELEGRAM_API = "https://api.telegram.org/bot";
4
+ export class TelegramAdapter {
5
+ name = "telegram";
6
+ displayName = CHANNEL_DISPLAY_NAMES.telegram;
7
+ free = true;
8
+ setupTime = CHANNEL_SETUP_TIMES.telegram;
9
+ token = null;
10
+ botInfo = null;
11
+ polling = false;
12
+ pollAbort = null;
13
+ lastUpdateId = 0;
14
+ messageHandler = null;
15
+ connectedAt = null;
16
+ lastMessageAt = null;
17
+ async api(method, body) {
18
+ if (!this.token)
19
+ throw new Error("Telegram bot token not configured");
20
+ const url = `${TELEGRAM_API}${this.token}/${method}`;
21
+ const res = await fetch(url, {
22
+ method: body ? "POST" : "GET",
23
+ headers: body ? { "Content-Type": "application/json" } : undefined,
24
+ body: body ? JSON.stringify(body) : undefined,
25
+ });
26
+ const json = (await res.json());
27
+ if (!json.ok)
28
+ throw new Error(`Telegram API error: ${json.description ?? "unknown"}`);
29
+ return json.result;
30
+ }
31
+ async setup(config) {
32
+ const token = config.credentials?.["bot_token"];
33
+ if (!token)
34
+ throw new Error("Missing credential: bot_token. Get one from @BotFather on Telegram.");
35
+ this.token = token;
36
+ this.botInfo = await this.api("getMe");
37
+ await saveCredential("telegram", "bot_token", token);
38
+ }
39
+ async connect() {
40
+ if (!this.token) {
41
+ const stored = await getCredential("telegram", "bot_token");
42
+ if (!stored)
43
+ throw new Error("Not configured. Run setup() first.");
44
+ this.token = stored;
45
+ }
46
+ if (!this.botInfo)
47
+ this.botInfo = await this.api("getMe");
48
+ this.polling = true;
49
+ this.connectedAt = Date.now();
50
+ this.pollAbort = new AbortController();
51
+ this.pollLoop();
52
+ }
53
+ async pollLoop() {
54
+ while (this.polling) {
55
+ try {
56
+ const updates = await this.api("getUpdates", {
57
+ offset: this.lastUpdateId + 1,
58
+ timeout: 30,
59
+ });
60
+ for (const update of updates) {
61
+ this.lastUpdateId = update.update_id;
62
+ if (update.message?.text && this.messageHandler) {
63
+ this.lastMessageAt = Date.now();
64
+ const msg = {
65
+ id: String(update.message.message_id),
66
+ channel: "telegram",
67
+ from: update.message.from?.username ??
68
+ String(update.message.from?.id ?? "unknown"),
69
+ text: update.message.text,
70
+ timestamp: update.message.date * 1000,
71
+ metadata: {
72
+ chatId: update.message.chat.id,
73
+ chatType: update.message.chat.type,
74
+ },
75
+ };
76
+ try {
77
+ const response = await this.messageHandler(msg);
78
+ await this.send(String(update.message.chat.id), response);
79
+ }
80
+ catch {
81
+ /* handler errors don't crash polling */
82
+ }
83
+ }
84
+ }
85
+ }
86
+ catch {
87
+ if (this.polling)
88
+ await new Promise((r) => setTimeout(r, 5000));
89
+ }
90
+ }
91
+ }
92
+ async disconnect() {
93
+ this.polling = false;
94
+ this.pollAbort?.abort();
95
+ this.pollAbort = null;
96
+ this.connectedAt = null;
97
+ }
98
+ async send(to, response) {
99
+ let text = response.text;
100
+ if (response.cards?.length) {
101
+ for (const card of response.cards) {
102
+ text += `\n\n*${card.title}*`;
103
+ if (card.description)
104
+ text += `\n${card.description}`;
105
+ }
106
+ }
107
+ const body = {
108
+ chat_id: to,
109
+ text,
110
+ parse_mode: "Markdown",
111
+ };
112
+ if (response.actions?.length) {
113
+ body["reply_markup"] = {
114
+ inline_keyboard: response.actions.map((a) => [
115
+ a.type === "url"
116
+ ? { text: a.label, url: a.value }
117
+ : { text: a.label, callback_data: a.value },
118
+ ]),
119
+ };
120
+ }
121
+ await this.api("sendMessage", body);
122
+ }
123
+ onMessage(handler) {
124
+ this.messageHandler = handler;
125
+ }
126
+ async test() {
127
+ try {
128
+ if (!this.token) {
129
+ const stored = await getCredential("telegram", "bot_token");
130
+ if (!stored)
131
+ return { ok: false, error: "No bot token configured" };
132
+ this.token = stored;
133
+ }
134
+ const me = await this.api("getMe");
135
+ return { ok: true, error: undefined };
136
+ }
137
+ catch (err) {
138
+ return {
139
+ ok: false,
140
+ error: err instanceof Error ? err.message : "Unknown error",
141
+ };
142
+ }
143
+ }
144
+ async status() {
145
+ const result = await this.test();
146
+ return {
147
+ channel: "telegram",
148
+ connected: this.polling && result.ok,
149
+ latencyMs: this.connectedAt ? Date.now() - this.connectedAt : null,
150
+ lastMessage: this.lastMessageAt,
151
+ error: result.error ?? null,
152
+ };
153
+ }
154
+ }
155
+ //# sourceMappingURL=telegram.js.map