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
package/CHANGELOG.md ADDED
@@ -0,0 +1,20 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0 (2026-03-28)
4
+
5
+ Initial release.
6
+
7
+ ### Features
8
+
9
+ - **Agent Identity Protocol (AIP) v1.0** -- single `IDENTITY.md` file defines agent name, personality, channels, and backend URL with YAML frontmatter
10
+ - **10 channel adapters** -- Telegram, Discord, Slack, SMS, WhatsApp, Email, Voice, Teams, Messenger, Web Widget
11
+ - **Unified gateway** -- normalizes all incoming messages to `GatewayMessage` format and routes to any HTTP agent backend
12
+ - **Per-channel response formatting** -- Markdown for Telegram, embeds for Discord, blocks for Slack, plain text fallback
13
+ - **Interactive setup wizard** -- `agentdial setup` guides through identity creation and channel configuration
14
+ - **Secure credential storage** -- per-channel JSON files in `~/.agentdial/credentials/` with 0600 permissions
15
+ - **Voice support** -- Twilio-based voice calls with speech-to-text and text-to-speech
16
+ - **Rich responses** -- cards with images, action buttons (URL, callback, reply), and metadata
17
+ - **MCP server mode** -- `agentdial mcp-serve` integrates with Claude Code as a tool provider
18
+ - **Channel management CLI** -- add, remove, list, and test channels individually or all at once
19
+ - **Zod-validated schemas** -- all message types, configs, and identity files validated at runtime
20
+ - **Zero lock-in** -- agent backend is any HTTP endpoint that accepts JSON POST requests
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Naman Parikh
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,310 @@
1
+ # agentdial
2
+
3
+ [![npm version](https://img.shields.io/npm/v/agentdial.svg)](https://www.npmjs.com/package/agentdial)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![Platform](https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20WSL-blue.svg)](#supported-channels)
6
+ [![Tests](https://img.shields.io/badge/tests-passing-brightgreen.svg)](#tests)
7
+ [![Downloads](https://img.shields.io/npm/dm/agentdial.svg)](https://www.npmjs.com/package/agentdial)
8
+
9
+ **Dial your AI agent into every platform.**
10
+
11
+ One identity file. Seven channels. Zero boilerplate.
12
+
13
+ ```bash
14
+ npx agentdial setup
15
+ ```
16
+
17
+ ```
18
+ ___ __ ____ _ __
19
+ / _ |___ ____ ___ ____/ / / __ \(_)___ _/ /
20
+ / __ / _ `/ -_) _ \/ __/ / / / / / / _ `/ /
21
+ /_/ |_\_, /\__/_//_/\__/_/ /_/ /_/_/\_,_/_/
22
+ /___/
23
+
24
+ v1.0.0 One identity. Every channel.
25
+
26
+ ┌────────────────────────────────────────┐
27
+ │ Agent Identity │
28
+ ├────────────────────────────────────────┤
29
+ │ Name: Spark │
30
+ │ Tagline: Your AI concierge │
31
+ │ Backend: http://localhost:8080/agent │
32
+ └────────────────────────────────────────┘
33
+
34
+ Channel Status Cost Setup
35
+ ──────────────── ──────── ─────── ─────
36
+ Telegram Bot active Free 2 min
37
+ Discord Bot active Free 3 min
38
+ Slack App ready Free 5 min
39
+ SMS (Twilio) ---- ~$0.01 5 min
40
+ Web Widget active Free 1 min
41
+ ```
42
+
43
+ agentdial gives your AI agent a single identity file (`IDENTITY.md`) and connects it to Telegram, Discord, Slack, SMS, WhatsApp, email, and voice -- through one unified gateway.
44
+
45
+ ## Install
46
+
47
+ ```bash
48
+ npm install -g agentdial
49
+ ```
50
+
51
+ Or run directly:
52
+
53
+ ```bash
54
+ npx agentdial setup
55
+ ```
56
+
57
+ **Requirements:** Node.js >= 18 · **Supports:** macOS, Linux, Windows (WSL)
58
+
59
+ ## Quick Start
60
+
61
+ Three steps. Two minutes.
62
+
63
+ ```bash
64
+ # 1. Create your agent identity + pick channels
65
+ agentdial setup
66
+
67
+ # 2. Add a channel (interactive credential prompts)
68
+ agentdial channels add telegram
69
+
70
+ # 3. Start the gateway
71
+ agentdial serve --agent-url http://localhost:8080/agent
72
+ ```
73
+
74
+ Your agent is now live on Telegram. Add more channels anytime with `agentdial channels add <channel>`.
75
+
76
+ ## Why agentdial?
77
+
78
+ Every AI agent needs to talk to users. Today that means:
79
+
80
+ - **5-15 separate API integrations** (Telegram Bot API, Discord.js, Slack SDK, Twilio, SendGrid...)
81
+ - **Hundreds of lines of boilerplate** per channel (webhook setup, message normalization, response formatting)
82
+ - **No standard identity format** -- every platform represents your agent differently
83
+ - **Credential sprawl** -- API keys scattered across env files, dashboards, and config files
84
+
85
+ agentdial solves this with:
86
+
87
+ - **One identity file** (`IDENTITY.md`) that defines your agent's name, personality, and channel config
88
+ - **One gateway** that normalizes all incoming messages to a single `GatewayMessage` format
89
+ - **One response format** (`GatewayResponse`) that agentdial translates per-channel (Markdown for Telegram, embeds for Discord, blocks for Slack)
90
+ - **Secure credential storage** in `~/.agentdial/credentials/` with 0600 permissions
91
+ - **Zero lock-in** -- your agent backend is a plain HTTP endpoint that receives JSON
92
+
93
+ ## Supported Channels
94
+
95
+ | Channel | Cost | Setup Time | Credentials Needed |
96
+ | ----------------- | -------------- | ---------- | -------------------------- |
97
+ | Telegram Bot | Free | 2 min | Bot token from @BotFather |
98
+ | Discord Bot | Free | 3 min | Bot token + application ID |
99
+ | Slack App | Free | 5 min | Bot token + signing secret |
100
+ | SMS (Twilio) | ~$0.0079/msg | 5 min | Account SID + auth token |
101
+ | WhatsApp (Twilio) | ~$0.005/msg | 10 min | Account SID + auth token |
102
+ | Email (SendGrid) | 60-day trial\* | 3 min | API key + verified sender |
103
+ | Voice (Twilio) | ~$0.013/min | 5 min | Account SID + auth token |
104
+
105
+ Free channels (Telegram, Discord) need zero payment info. Paid channels use Twilio or SendGrid with usage-based pricing. \*SendGrid free tier was removed May 2025; 60-day trial (100 emails/day), then $19.95/mo.
106
+
107
+ ### Coming Soon
108
+
109
+ | Channel | Status |
110
+ | ------------------ | ------- |
111
+ | Microsoft Teams | Planned |
112
+ | Facebook Messenger | Planned |
113
+ | Web Widget | Planned |
114
+
115
+ ## Architecture
116
+
117
+ ```
118
+ Telegram ──┐
119
+ Discord ──┤ ┌──────────────────┐
120
+ Slack ──┤ ┌────────────┐ │ │
121
+ SMS ──┼──>│ agentdial │──>│ Your Agent │
122
+ WhatsApp ──┤ │ Gateway │ │ Backend │
123
+ Email ──┤ │ :3141 │ │ (any HTTP) │
124
+ Voice ──┘ └────────────┘ └──────────────────┘
125
+
126
+ │ Normalizes all messages to:
127
+ │ { id, channel, from, text, timestamp }
128
+
129
+ │ Formats responses per-channel:
130
+ │ Telegram: Markdown + inline keyboards
131
+ │ Discord: Embeds + components
132
+ │ Slack: Blocks + actions
133
+ └ Others: Plain text fallback
134
+ ```
135
+
136
+ The gateway runs on port 3141 by default. Every incoming message from any channel is normalized into a `GatewayMessage`, forwarded to your agent backend as a POST request, and the response is formatted back into the channel's native format.
137
+
138
+ Your agent backend just needs one endpoint that accepts a JSON body and returns `{ text: "..." }`.
139
+
140
+ ## IDENTITY.md Spec
141
+
142
+ agentdial introduces the **Agent Identity Protocol (AIP) v1.0** -- a single markdown file that defines your agent across all platforms.
143
+
144
+ ```yaml
145
+ ---
146
+ name: spark
147
+ tagline: Your AI concierge
148
+ version: "1.0.0"
149
+ agent_url: http://localhost:8080/agent
150
+ channels:
151
+ telegram:
152
+ enabled: true
153
+ handle: "@spark_bot"
154
+ discord:
155
+ enabled: true
156
+ handle: "Spark#1234"
157
+ slack:
158
+ enabled: true
159
+ web:
160
+ enabled: true
161
+ ---
162
+
163
+ # Spark
164
+
165
+ > Your AI concierge
166
+
167
+ ## Personality
168
+
169
+ - Friendly and knowledgeable
170
+ - Concise but thorough
171
+ - Uses casual tone with professional substance
172
+
173
+ ## Capabilities
174
+
175
+ - Restaurant recommendations and reservations
176
+ - Event discovery and booking
177
+ - Local area knowledge
178
+
179
+ ## Boundaries
180
+
181
+ - No financial transactions
182
+ - No medical or legal advice
183
+ - No personal data retention beyond the session
184
+ ```
185
+
186
+ The YAML frontmatter is machine-readable. The markdown body is human-readable context your agent can use as a system prompt. The `channels` block declares which platforms your agent is active on.
187
+
188
+ ## Claude Code Integration
189
+
190
+ agentdial ships as an MCP server for Claude Code. Add it to your project's `.mcp.json`:
191
+
192
+ ```json
193
+ {
194
+ "mcpServers": {
195
+ "agentdial": {
196
+ "command": "npx",
197
+ "args": ["-y", "agentdial", "mcp-serve"]
198
+ }
199
+ }
200
+ }
201
+ ```
202
+
203
+ This gives Claude Code tools to manage channels, test connections, and check agent status without leaving the terminal.
204
+
205
+ Start the MCP server standalone:
206
+
207
+ ```bash
208
+ agentdial mcp-serve
209
+ ```
210
+
211
+ ## Voice
212
+
213
+ Voice channels use Twilio for telephony. Configure with:
214
+
215
+ ```bash
216
+ agentdial voice setup
217
+ ```
218
+
219
+ This prompts for your Twilio Account SID, Auth Token, and phone number. Test with:
220
+
221
+ ```bash
222
+ agentdial voice test --number +15551234567
223
+ ```
224
+
225
+ Voice calls are transcribed to text, sent through the same gateway pipeline as chat messages, and the response is synthesized back to speech via Twilio.
226
+
227
+ ## Configuration
228
+
229
+ All config and credentials are stored locally:
230
+
231
+ ```
232
+ ~/.agentdial/
233
+ ├── config.json # Gateway port, log level, identity file path
234
+ ├── credentials/ # Per-channel credential files (0600 permissions)
235
+ │ ├── telegram.json
236
+ │ ├── discord.json
237
+ │ ├── slack.json
238
+ │ └── twilio.json
239
+ ├── templates/ # Identity file templates
240
+ └── logs/ # Gateway logs
241
+ ```
242
+
243
+ Example `config.json`:
244
+
245
+ ```json
246
+ {
247
+ "identityFile": "IDENTITY.md",
248
+ "gatewayPort": 3141,
249
+ "logLevel": "info"
250
+ }
251
+ ```
252
+
253
+ Credentials are never stored in your project directory or committed to git. The `credentials/` directory is created with 0700 permissions, and individual credential files with 0600.
254
+
255
+ ## All Commands
256
+
257
+ ```
258
+ SETUP
259
+ agentdial setup Interactive wizard (identity + channels)
260
+ agentdial setup --file ./agent.md Use existing identity file
261
+
262
+ CHANNELS
263
+ agentdial channels add <channel> Configure a new channel
264
+ agentdial channels remove <channel> Remove a channel
265
+ agentdial channels list Show all channels and status
266
+ agentdial channels test [channel] Test one or all channels
267
+
268
+ VOICE
269
+ agentdial voice setup Configure Twilio voice
270
+ agentdial voice test -n <phone> Test call to a number
271
+
272
+ GATEWAY
273
+ agentdial serve Start the gateway (port 3141)
274
+ agentdial serve -p 8080 Custom port
275
+ agentdial serve -a http://my-agent Point to agent backend
276
+
277
+ STATUS
278
+ agentdial status Show all channel statuses
279
+ agentdial status --json Machine-readable output
280
+
281
+ TEST
282
+ agentdial test Send test message through gateway
283
+ agentdial test -c telegram -m "hi" Test specific channel
284
+
285
+ MCP
286
+ agentdial mcp-serve Start as MCP server for Claude Code
287
+ ```
288
+
289
+ ## Tests
290
+
291
+ ```bash
292
+ cd tools/agentdial && pnpm test
293
+ ```
294
+
295
+ Tests cover identity parsing/validation, gateway message normalization, response formatting, adapter interface compliance, and Zod schema validation. All tests use mocks -- no real API calls.
296
+
297
+ ## Contributing
298
+
299
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on adding adapters, running tests, and submitting PRs.
300
+
301
+ ## See Also
302
+
303
+ - **[agentgrid](https://github.com/naman10parikh/agentgrid)** -- Spawn grids of AI coding agents in parallel terminal panes
304
+ - **[Energy](https://github.com/naman10parikh/Energy)** -- Self-improving agent platform. agentdial is part of the Energy toolkit
305
+ - **[Model Context Protocol](https://modelcontextprotocol.io)** -- The MCP standard agentdial integrates with
306
+ - **[Google A2A](https://google.github.io/A2A/)** -- Agent-to-Agent protocol for inter-agent communication
307
+
308
+ ## License
309
+
310
+ MIT -- see [LICENSE](LICENSE).
@@ -0,0 +1,24 @@
1
+ import type { ChannelAdapter, ChannelConfig, ChannelStatus, GatewayMessage, GatewayResponse } from "./types.js";
2
+ export declare class DiscordAdapter implements ChannelAdapter {
3
+ readonly name: "discord";
4
+ readonly displayName: string;
5
+ readonly free = true;
6
+ readonly setupTime: string;
7
+ private client;
8
+ private token;
9
+ private messageHandler;
10
+ private connectedAt;
11
+ private lastMessageAt;
12
+ private loadDiscordJs;
13
+ setup(config: ChannelConfig): Promise<void>;
14
+ connect(): Promise<void>;
15
+ disconnect(): Promise<void>;
16
+ send(to: string, response: GatewayResponse): Promise<void>;
17
+ onMessage(handler: (msg: GatewayMessage) => Promise<GatewayResponse>): void;
18
+ test(): Promise<{
19
+ ok: boolean;
20
+ error?: string;
21
+ }>;
22
+ status(): Promise<ChannelStatus>;
23
+ }
24
+ //# sourceMappingURL=discord.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discord.d.ts","sourceRoot":"","sources":["../../src/adapters/discord.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EACb,aAAa,EACb,cAAc,EACd,eAAe,EAChB,MAAM,YAAY,CAAC;AA+BpB,qBAAa,cAAe,YAAW,cAAc;IACnD,QAAQ,CAAC,IAAI,EAAG,SAAS,CAAU;IACnC,QAAQ,CAAC,WAAW,SAAiC;IACrD,QAAQ,CAAC,IAAI,QAAQ;IACrB,QAAQ,CAAC,SAAS,SAA+B;IAEjD,OAAO,CAAC,MAAM,CAA8B;IAC5C,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,cAAc,CAEN;IAChB,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,aAAa,CAAuB;YAE9B,aAAa;IAgBrB,KAAK,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAW3C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA+CxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ3B,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAchE,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;IAehD,MAAM,IAAI,OAAO,CAAC,aAAa,CAAC;CAUvC"}
@@ -0,0 +1,129 @@
1
+ import { getCredential, saveCredential } from "../lib/credentials.js";
2
+ import { CHANNEL_DISPLAY_NAMES, CHANNEL_SETUP_TIMES, } from "../lib/constants.js";
3
+ export class DiscordAdapter {
4
+ name = "discord";
5
+ displayName = CHANNEL_DISPLAY_NAMES.discord;
6
+ free = true;
7
+ setupTime = CHANNEL_SETUP_TIMES.discord;
8
+ client = null;
9
+ token = null;
10
+ messageHandler = null;
11
+ connectedAt = null;
12
+ lastMessageAt = null;
13
+ async loadDiscordJs() {
14
+ try {
15
+ const pkg = "discord.js";
16
+ const mod = (await import(/* webpackIgnore: true */ pkg));
17
+ return mod;
18
+ }
19
+ catch {
20
+ throw new Error("discord.js not installed. Run: npm install discord.js");
21
+ }
22
+ }
23
+ async setup(config) {
24
+ const token = config.credentials?.["bot_token"];
25
+ if (!token)
26
+ throw new Error("Missing credential: bot_token. Create a bot at discord.com/developers/applications.");
27
+ await this.loadDiscordJs();
28
+ this.token = token;
29
+ await saveCredential("discord", "bot_token", token);
30
+ }
31
+ async connect() {
32
+ if (!this.token) {
33
+ const stored = await getCredential("discord", "bot_token");
34
+ if (!stored)
35
+ throw new Error("Not configured. Run setup() first.");
36
+ this.token = stored;
37
+ }
38
+ const { Client, GatewayIntentBits } = await this.loadDiscordJs();
39
+ this.client = new Client({
40
+ intents: [
41
+ GatewayIntentBits.Guilds,
42
+ GatewayIntentBits.GuildMessages,
43
+ GatewayIntentBits.MessageContent,
44
+ ],
45
+ });
46
+ this.client.on("messageCreate", (raw) => {
47
+ const message = raw;
48
+ if (message.author.bot || !this.messageHandler)
49
+ return;
50
+ this.lastMessageAt = Date.now();
51
+ const attachments = [...message.attachments.values()].map((a) => ({
52
+ type: "file",
53
+ url: a.url,
54
+ name: a.name,
55
+ mimeType: a.contentType ?? undefined,
56
+ }));
57
+ const msg = {
58
+ id: message.id,
59
+ channel: "discord",
60
+ from: message.author.username,
61
+ text: message.content,
62
+ timestamp: message.createdTimestamp,
63
+ threadId: message.channelId,
64
+ replyTo: message.reference?.messageId,
65
+ attachments: attachments.length ? attachments : undefined,
66
+ metadata: { guildId: message.guildId, channelId: message.channelId },
67
+ };
68
+ this.messageHandler(msg)
69
+ .then((response) => {
70
+ this.send(message.channelId, response).catch(() => { });
71
+ })
72
+ .catch(() => { });
73
+ });
74
+ await this.client.login(this.token);
75
+ this.connectedAt = Date.now();
76
+ }
77
+ async disconnect() {
78
+ if (this.client) {
79
+ await this.client.destroy();
80
+ this.client = null;
81
+ }
82
+ this.connectedAt = null;
83
+ }
84
+ async send(to, response) {
85
+ if (!this.client)
86
+ throw new Error("Not connected");
87
+ const channel = await this.client.channels.fetch(to);
88
+ let content = response.text;
89
+ if (response.cards?.length) {
90
+ for (const card of response.cards) {
91
+ content += `\n\n**${card.title}**`;
92
+ if (card.description)
93
+ content += `\n${card.description}`;
94
+ }
95
+ }
96
+ if (content.length > 2000)
97
+ content = content.slice(0, 1997) + "...";
98
+ await channel.send({ content });
99
+ }
100
+ onMessage(handler) {
101
+ this.messageHandler = handler;
102
+ }
103
+ async test() {
104
+ try {
105
+ if (!this.client?.isReady())
106
+ return { ok: false, error: "Bot not connected" };
107
+ const tag = this.client.user?.tag ?? "unknown";
108
+ const guilds = this.client.guilds.cache.size;
109
+ return { ok: true, error: undefined };
110
+ }
111
+ catch (err) {
112
+ return {
113
+ ok: false,
114
+ error: err instanceof Error ? err.message : "Unknown error",
115
+ };
116
+ }
117
+ }
118
+ async status() {
119
+ const connected = this.client?.isReady() ?? false;
120
+ return {
121
+ channel: "discord",
122
+ connected,
123
+ latencyMs: connected ? this.client.ws.ping : null,
124
+ lastMessage: this.lastMessageAt,
125
+ error: connected ? null : "Not connected",
126
+ };
127
+ }
128
+ }
129
+ //# sourceMappingURL=discord.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discord.js","sourceRoot":"","sources":["../../src/adapters/discord.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import type { ChannelAdapter, ChannelConfig, ChannelStatus, GatewayMessage, GatewayResponse } from "./types.js";
2
+ interface InboundParsePayload {
3
+ from: string;
4
+ to: string;
5
+ subject: string;
6
+ text: string;
7
+ html?: string;
8
+ attachments?: string;
9
+ "attachment-info"?: string;
10
+ [key: string]: string | undefined;
11
+ }
12
+ export declare class EmailAdapter implements ChannelAdapter {
13
+ readonly name: "email";
14
+ readonly displayName = "Email (SendGrid)";
15
+ readonly free = false;
16
+ readonly cost = "100/day free, then $0.001/msg";
17
+ readonly setupTime = "3 min";
18
+ private apiKey;
19
+ private fromEmail;
20
+ private fromName;
21
+ private messageHandler;
22
+ private connected;
23
+ private lastMessageTs;
24
+ setup(config: ChannelConfig): Promise<void>;
25
+ connect(): Promise<void>;
26
+ disconnect(): Promise<void>;
27
+ send(to: string, response: GatewayResponse): Promise<void>;
28
+ onMessage(handler: (msg: GatewayMessage) => Promise<GatewayResponse>): void;
29
+ /** Call from HTTP webhook handler with parsed SendGrid Inbound Parse POST body. */
30
+ handleWebhook(payload: InboundParsePayload): Promise<GatewayResponse | null>;
31
+ test(): Promise<{
32
+ ok: boolean;
33
+ error?: string;
34
+ }>;
35
+ status(): Promise<ChannelStatus>;
36
+ }
37
+ export {};
38
+ //# sourceMappingURL=email.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email.d.ts","sourceRoot":"","sources":["../../src/adapters/email.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EACb,aAAa,EACb,cAAc,EACd,eAAe,EAChB,MAAM,YAAY,CAAC;AAapB,UAAU,mBAAmB;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACnC;AA+DD,qBAAa,YAAa,YAAW,cAAc;IACjD,QAAQ,CAAC,IAAI,EAAG,OAAO,CAAU;IACjC,QAAQ,CAAC,WAAW,sBAAsB;IAC1C,QAAQ,CAAC,IAAI,SAAS;IACtB,QAAQ,CAAC,IAAI,mCAAmC;IAChD,QAAQ,CAAC,SAAS,WAAW;IAE7B,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,SAAS,CAAM;IACvB,OAAO,CAAC,QAAQ,CAAM;IACtB,OAAO,CAAC,cAAc,CAEN;IAChB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,aAAa,CAAuB;IAEtC,KAAK,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IA0B3C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAMxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IA4BhE,SAAS,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI;IAI3E,mFAAmF;IAC7E,aAAa,CACjB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAwB5B,IAAI,IAAI,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAehD,MAAM,IAAI,OAAO,CAAC,aAAa,CAAC;CAqBvC"}