pi-courier 0.1.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 (86) hide show
  1. package/README.md +363 -0
  2. package/README.zh-CN.md +362 -0
  3. package/deploy/pi-msg-bridge.service +26 -0
  4. package/deploy/pi-msg-bridge.user.service +37 -0
  5. package/dist/auth/challenge-auth.d.ts +76 -0
  6. package/dist/auth/challenge-auth.d.ts.map +1 -0
  7. package/dist/auth/challenge-auth.js +337 -0
  8. package/dist/auth/challenge-auth.js.map +1 -0
  9. package/dist/cli.d.ts +3 -0
  10. package/dist/cli.d.ts.map +1 -0
  11. package/dist/cli.js +265 -0
  12. package/dist/cli.js.map +1 -0
  13. package/dist/config.d.ts +10 -0
  14. package/dist/config.d.ts.map +1 -0
  15. package/dist/config.js +49 -0
  16. package/dist/config.js.map +1 -0
  17. package/dist/formatting.d.ts +22 -0
  18. package/dist/formatting.d.ts.map +1 -0
  19. package/dist/formatting.js +74 -0
  20. package/dist/formatting.js.map +1 -0
  21. package/dist/lock.d.ts +3 -0
  22. package/dist/lock.d.ts.map +1 -0
  23. package/dist/lock.js +75 -0
  24. package/dist/lock.js.map +1 -0
  25. package/dist/rpc/command-map.d.ts +19 -0
  26. package/dist/rpc/command-map.d.ts.map +1 -0
  27. package/dist/rpc/command-map.js +191 -0
  28. package/dist/rpc/command-map.js.map +1 -0
  29. package/dist/rpc/message-router.d.ts +30 -0
  30. package/dist/rpc/message-router.d.ts.map +1 -0
  31. package/dist/rpc/message-router.js +110 -0
  32. package/dist/rpc/message-router.js.map +1 -0
  33. package/dist/rpc/pi-rpc.d.ts +79 -0
  34. package/dist/rpc/pi-rpc.d.ts.map +1 -0
  35. package/dist/rpc/pi-rpc.js +199 -0
  36. package/dist/rpc/pi-rpc.js.map +1 -0
  37. package/dist/setup.d.ts +10 -0
  38. package/dist/setup.d.ts.map +1 -0
  39. package/dist/setup.js +159 -0
  40. package/dist/setup.js.map +1 -0
  41. package/dist/standalone.d.ts +13 -0
  42. package/dist/standalone.d.ts.map +1 -0
  43. package/dist/standalone.js +184 -0
  44. package/dist/standalone.js.map +1 -0
  45. package/dist/transports/discord.d.ts +33 -0
  46. package/dist/transports/discord.d.ts.map +1 -0
  47. package/dist/transports/discord.js +216 -0
  48. package/dist/transports/discord.js.map +1 -0
  49. package/dist/transports/interface.d.ts +42 -0
  50. package/dist/transports/interface.d.ts.map +1 -0
  51. package/dist/transports/interface.js +2 -0
  52. package/dist/transports/interface.js.map +1 -0
  53. package/dist/transports/manager.d.ts +54 -0
  54. package/dist/transports/manager.d.ts.map +1 -0
  55. package/dist/transports/manager.js +98 -0
  56. package/dist/transports/manager.js.map +1 -0
  57. package/dist/transports/matrix-utils.d.ts +31 -0
  58. package/dist/transports/matrix-utils.d.ts.map +1 -0
  59. package/dist/transports/matrix-utils.js +99 -0
  60. package/dist/transports/matrix-utils.js.map +1 -0
  61. package/dist/transports/matrix-utils.test.d.ts +2 -0
  62. package/dist/transports/matrix-utils.test.d.ts.map +1 -0
  63. package/dist/transports/matrix-utils.test.js +246 -0
  64. package/dist/transports/matrix-utils.test.js.map +1 -0
  65. package/dist/transports/matrix.d.ts +34 -0
  66. package/dist/transports/matrix.d.ts.map +1 -0
  67. package/dist/transports/matrix.js +240 -0
  68. package/dist/transports/matrix.js.map +1 -0
  69. package/dist/transports/slack.d.ts +31 -0
  70. package/dist/transports/slack.d.ts.map +1 -0
  71. package/dist/transports/slack.js +203 -0
  72. package/dist/transports/slack.js.map +1 -0
  73. package/dist/transports/telegram.d.ts +38 -0
  74. package/dist/transports/telegram.d.ts.map +1 -0
  75. package/dist/transports/telegram.js +167 -0
  76. package/dist/transports/telegram.js.map +1 -0
  77. package/dist/transports/whatsapp.d.ts +31 -0
  78. package/dist/transports/whatsapp.d.ts.map +1 -0
  79. package/dist/transports/whatsapp.js +235 -0
  80. package/dist/transports/whatsapp.js.map +1 -0
  81. package/dist/types.d.ts +69 -0
  82. package/dist/types.d.ts.map +1 -0
  83. package/dist/types.js +2 -0
  84. package/dist/types.js.map +1 -0
  85. package/extensions/index.ts +42 -0
  86. package/package.json +71 -0
@@ -0,0 +1,240 @@
1
+ import { AutojoinRoomsMixin, LogService, MatrixClient, RichConsoleLogger, RustSdkCryptoStorageProvider, SimpleFsStorageProvider, } from "matrix-bot-sdk";
2
+ import * as os from "os";
3
+ import * as path from "path";
4
+ import { extractUsername, formatForMatrix, shouldSkipEvent, stripBotMention, wasBotMentioned, } from "./matrix-utils.js";
5
+ /**
6
+ * Matrix transport provider using matrix-bot-sdk
7
+ * Works with any Matrix homeserver — Element X, Element Web, FluffyChat, etc.
8
+ */
9
+ export class MatrixProvider {
10
+ config;
11
+ auth;
12
+ type = "matrix";
13
+ client;
14
+ _isConnected = false;
15
+ messageHandler;
16
+ errorHandler;
17
+ botUserId;
18
+ joinedRooms = new Set();
19
+ roomMemberCount = new Map();
20
+ connectedAt = 0;
21
+ constructor(config, auth) {
22
+ this.config = config;
23
+ this.auth = auth;
24
+ }
25
+ get isConnected() {
26
+ return this._isConnected;
27
+ }
28
+ // Formatting delegated to matrix-utils.ts (pure, testable)
29
+ async connect() {
30
+ if (this._isConnected)
31
+ return;
32
+ const { homeserverUrl, accessToken } = this.config;
33
+ if (!homeserverUrl || !accessToken) {
34
+ throw new Error("Matrix homeserver URL and access token required");
35
+ }
36
+ const storagePath = path.join(os.homedir(), ".pi", "msg-bridge-matrix-store.json");
37
+ const storage = new SimpleFsStorageProvider(storagePath);
38
+ // Set up E2EE crypto storage if encryption is enabled.
39
+ // Uses @matrix-org/matrix-sdk-crypto-nodejs (native Rust, SQLite on disk).
40
+ // Crypto state persists across restarts — same device, same keys.
41
+ // The device must be verified once from another Matrix client (Element, etc).
42
+ let cryptoProvider;
43
+ if (this.config.encryption !== false) {
44
+ try {
45
+ const cryptoStorePath = path.join(os.homedir(), ".pi", "msg-bridge-matrix-crypto");
46
+ cryptoProvider = new RustSdkCryptoStorageProvider(cryptoStorePath, 0 /* RustSdkCryptoStoreType.Sqlite */);
47
+ console.log("[Matrix] E2EE crypto storage enabled (Rust/SQLite)");
48
+ }
49
+ catch (err) {
50
+ console.warn("[Matrix] E2EE crypto not available, continuing without encryption:", err.message);
51
+ }
52
+ }
53
+ this.client = new MatrixClient(homeserverUrl, accessToken, storage, cryptoProvider);
54
+ // Auto-join rooms the bot is invited to
55
+ AutojoinRoomsMixin.setupOnClient(this.client);
56
+ // Cache bot user ID (never changes)
57
+ this.botUserId = await this.client.getUserId();
58
+ // Track room membership and member counts
59
+ this.client.on("room.join", (roomId) => {
60
+ this.joinedRooms.add(roomId);
61
+ // Refresh member count asynchronously
62
+ this.client?.getJoinedRoomMembers(roomId)
63
+ .then(members => this.roomMemberCount.set(roomId, members.length))
64
+ .catch(() => { });
65
+ });
66
+ this.client.on("room.leave", (roomId) => {
67
+ this.joinedRooms.delete(roomId);
68
+ this.roomMemberCount.delete(roomId);
69
+ });
70
+ // Handle incoming messages
71
+ this.client.on("room.message", async (roomId, event) => {
72
+ try {
73
+ await this.handleMessage(roomId, event);
74
+ }
75
+ catch (err) {
76
+ if (this.errorHandler) {
77
+ this.errorHandler(err);
78
+ }
79
+ }
80
+ });
81
+ try {
82
+ // During initial sync the SDK replays historical events and tries to
83
+ // decrypt them. For E2EE rooms this produces two known error patterns:
84
+ // 1. "Decryption error" — old messages we don't have keys for
85
+ // 2. "M_NOT_FOUND" — stale sync token references a purged event
86
+ // Our connectedAt filter skips these events anyway, so the errors are
87
+ // noise. A filtering logger suppresses only these specific patterns.
88
+ const defaultLogger = new RichConsoleLogger();
89
+ const syncFilterLogger = {
90
+ info: (mod, ...args) => defaultLogger.info(mod, ...args),
91
+ warn: (mod, ...args) => defaultLogger.warn(mod, ...args),
92
+ debug: (mod, ...args) => defaultLogger.debug(mod, ...args),
93
+ trace: (mod, ...args) => defaultLogger.trace(mod, ...args),
94
+ error: (mod, ...args) => {
95
+ const msg = args.map(a => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
96
+ if (mod === "MatrixClientLite" && msg.includes("Decryption error"))
97
+ return;
98
+ if (mod === "MatrixHttpClient" && msg.includes("M_NOT_FOUND"))
99
+ return;
100
+ defaultLogger.error(mod, ...args);
101
+ },
102
+ };
103
+ LogService.setLogger(syncFilterLogger);
104
+ await this.client.start();
105
+ // Restore default logging — real errors after sync should not be filtered
106
+ LogService.setLogger(defaultLogger);
107
+ }
108
+ catch (error) {
109
+ // Clean up dangling state so connect() can be retried
110
+ this.client = undefined;
111
+ this.botUserId = undefined;
112
+ this.joinedRooms.clear();
113
+ this.roomMemberCount.clear();
114
+ console.error("[Matrix] Failed to connect:", error);
115
+ throw error;
116
+ }
117
+ // Seed joined rooms and member count caches
118
+ const rooms = await this.client.getJoinedRooms();
119
+ this.joinedRooms = new Set(rooms);
120
+ await Promise.all(rooms.map(async (roomId) => {
121
+ try {
122
+ const members = await this.client.getJoinedRoomMembers(roomId);
123
+ this.roomMemberCount.set(roomId, members.length);
124
+ }
125
+ catch {
126
+ // Will be fetched on first message if needed
127
+ }
128
+ }));
129
+ this.connectedAt = Date.now();
130
+ this._isConnected = true;
131
+ const cryptoStatus = cryptoProvider ? "E2EE enabled" : "E2EE disabled";
132
+ console.log(`✅ Matrix connected as ${this.botUserId} (${rooms.length} rooms, ${cryptoStatus})`);
133
+ }
134
+ async disconnect() {
135
+ if (!this._isConnected || !this.client)
136
+ return;
137
+ this.client.stop();
138
+ this._isConnected = false;
139
+ this.client = undefined;
140
+ this.botUserId = undefined;
141
+ this.joinedRooms.clear();
142
+ this.roomMemberCount.clear();
143
+ this.connectedAt = 0;
144
+ console.log("[Matrix] Disconnected");
145
+ }
146
+ async sendMessage(chatId, text) {
147
+ if (!this.client) {
148
+ throw new Error("Matrix client not connected");
149
+ }
150
+ if (!text?.trim())
151
+ return;
152
+ const { body, formattedBody } = formatForMatrix(text);
153
+ await this.client.sendMessage(chatId, {
154
+ msgtype: "m.text",
155
+ body,
156
+ ...(formattedBody && {
157
+ format: "org.matrix.custom.html",
158
+ formatted_body: formattedBody,
159
+ }),
160
+ });
161
+ }
162
+ async sendTyping(chatId) {
163
+ if (!this.client)
164
+ return;
165
+ try {
166
+ await this.client.setTyping(chatId, true, 10000);
167
+ }
168
+ catch {
169
+ // Ignore typing indicator errors
170
+ }
171
+ }
172
+ onMessage(handler) {
173
+ this.messageHandler = handler;
174
+ }
175
+ onError(handler) {
176
+ this.errorHandler = handler;
177
+ }
178
+ async handleMessage(roomId, event) {
179
+ if (!this.client || !this.botUserId)
180
+ return;
181
+ // Pure filter — delegates to testable utility
182
+ const skipReason = shouldSkipEvent(event, this.botUserId, this.connectedAt, this.joinedRooms, roomId);
183
+ if (skipReason)
184
+ return;
185
+ const chatId = roomId;
186
+ const userId = event.sender; // e.g. @user:matrix.org
187
+ const username = extractUsername(userId);
188
+ const messageText = event.content.body;
189
+ const messageId = event.event_id;
190
+ // Determine if group chat from cached member count (no API call per message)
191
+ let memberCount = this.roomMemberCount.get(roomId);
192
+ if (memberCount === undefined) {
193
+ // Cache miss — fetch once and cache
194
+ try {
195
+ const members = await this.client.getJoinedRoomMembers(roomId);
196
+ memberCount = members.length;
197
+ this.roomMemberCount.set(roomId, memberCount);
198
+ }
199
+ catch {
200
+ memberCount = 2; // Default to DM if we can't check
201
+ }
202
+ }
203
+ const isGroupChat = memberCount > 2;
204
+ // Check if bot was mentioned (pure utility)
205
+ const wasMentioned = isGroupChat ? wasBotMentioned(messageText, this.botUserId) : false;
206
+ // Check authorization
207
+ const sendMessageToUser = async (cId, text) => {
208
+ await this.sendMessage(cId, text);
209
+ };
210
+ const isAuthorized = await this.auth.checkAuthorization(userId, chatId, username, isGroupChat, wasMentioned, sendMessageToUser, this.type);
211
+ // Handle challenge codes and commands in DMs
212
+ if (!isGroupChat && (messageText.startsWith("/") || messageText.match(/^\d{6}$/))) {
213
+ const handled = await this.auth.handleAdminCommand(messageText, chatId, userId, async (text) => await this.sendMessage(chatId, text), this.type);
214
+ if (handled)
215
+ return;
216
+ }
217
+ if (!isAuthorized)
218
+ return;
219
+ // Strip bot mention from message (pure utility)
220
+ const cleanContent = wasMentioned && this.botUserId
221
+ ? stripBotMention(messageText, this.botUserId)
222
+ : messageText;
223
+ // Forward to message handler
224
+ if (this.messageHandler && cleanContent) {
225
+ const externalMessage = {
226
+ chatId,
227
+ transport: this.type,
228
+ content: cleanContent,
229
+ username,
230
+ userId,
231
+ timestamp: new Date(event.origin_server_ts || Date.now()),
232
+ messageId,
233
+ isGroupChat,
234
+ wasMentioned,
235
+ };
236
+ this.messageHandler(externalMessage);
237
+ }
238
+ }
239
+ }
240
+ //# sourceMappingURL=matrix.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"matrix.js","sourceRoot":"","sources":["../../src/transports/matrix.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import type { ChallengeAuth } from "../auth/challenge-auth.js";
2
+ import type { ExternalMessage } from "../types.js";
3
+ import type { ITransportProvider } from "./interface.js";
4
+ /**
5
+ * Slack transport provider using @slack/bolt
6
+ */
7
+ export declare class SlackProvider implements ITransportProvider {
8
+ private config;
9
+ private auth;
10
+ readonly type = "slack";
11
+ private app;
12
+ private _isConnected;
13
+ private botUserId;
14
+ private messageHandler?;
15
+ private errorHandler?;
16
+ private lastProcessedMessageId;
17
+ private userCache;
18
+ private channelCache;
19
+ constructor(config: {
20
+ botToken: string;
21
+ appToken: string;
22
+ }, auth: ChallengeAuth);
23
+ get isConnected(): boolean;
24
+ connect(): Promise<void>;
25
+ disconnect(): Promise<void>;
26
+ sendMessage(chatId: string, text: string): Promise<void>;
27
+ sendTyping(_chatId: string): Promise<void>;
28
+ onMessage(handler: (message: ExternalMessage) => void): void;
29
+ onError(handler: (error: Error) => void): void;
30
+ }
31
+ //# sourceMappingURL=slack.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slack.d.ts","sourceRoot":"","sources":["../../src/transports/slack.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAUzD;;GAEG;AACH,qBAAa,aAAc,YAAW,kBAAkB;IAepD,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,IAAI;IAfd,QAAQ,CAAC,IAAI,WAAW;IACxB,OAAO,CAAC,GAAG,CAAoB;IAC/B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,cAAc,CAAC,CAAqC;IAC5D,OAAO,CAAC,YAAY,CAAC,CAAyB;IAC9C,OAAO,CAAC,sBAAsB,CAAM;IAGpC,OAAO,CAAC,SAAS,CAAkC;IAEnD,OAAO,CAAC,YAAY,CAA4D;gBAGtE,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAC9C,IAAI,EAAE,aAAa;IAG7B,IAAI,WAAW,IAAI,OAAO,CAEzB;IAEK,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAkKxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAe3B,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBxD,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMhD,SAAS,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,GAAG,IAAI;IAI5D,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI;CAG/C"}
@@ -0,0 +1,203 @@
1
+ async function loadSlackBolt() {
2
+ const slack = await import("@slack/bolt");
3
+ return slack;
4
+ }
5
+ /**
6
+ * Slack transport provider using @slack/bolt
7
+ */
8
+ export class SlackProvider {
9
+ config;
10
+ auth;
11
+ type = "slack";
12
+ app = null;
13
+ _isConnected = false;
14
+ botUserId = "";
15
+ messageHandler;
16
+ errorHandler;
17
+ lastProcessedMessageId = "";
18
+ // Cache user info to avoid repeated API calls
19
+ userCache = new Map();
20
+ // Cache channel info to detect DMs vs channels
21
+ channelCache = new Map();
22
+ constructor(config, auth) {
23
+ this.config = config;
24
+ this.auth = auth;
25
+ }
26
+ get isConnected() {
27
+ return this._isConnected;
28
+ }
29
+ async connect() {
30
+ if (this._isConnected)
31
+ return;
32
+ const { botToken, appToken } = this.config;
33
+ if (!botToken || !appToken) {
34
+ throw new Error("Slack requires both botToken (xoxb-...) and appToken (xapp-...)");
35
+ }
36
+ const slack = await loadSlackBolt();
37
+ this.app = new slack.App({
38
+ token: botToken,
39
+ appToken: appToken,
40
+ socketMode: true,
41
+ logLevel: slack.LogLevel.WARN,
42
+ });
43
+ // Get bot's own user ID for mention detection
44
+ try {
45
+ const authResult = await this.app.client.auth.test();
46
+ this.botUserId = authResult.user_id || "";
47
+ console.log(`[Slack] Bot user ID: ${this.botUserId}`);
48
+ }
49
+ catch (e) {
50
+ console.warn("[Slack] Could not get bot info:", e);
51
+ }
52
+ // Listen for all messages
53
+ this.app.message(async ({ message, client }) => {
54
+ // Skip bot messages, message edits, deletes, etc.
55
+ if (message.subtype) {
56
+ return;
57
+ }
58
+ // TypeScript type guard for regular messages
59
+ if (!("user" in message) || !("text" in message) || !message.text) {
60
+ return;
61
+ }
62
+ const userId = message.user;
63
+ const channelId = message.channel;
64
+ const text = message.text;
65
+ const ts = message.ts;
66
+ // Filter out duplicate messages
67
+ if (ts === this.lastProcessedMessageId) {
68
+ return;
69
+ }
70
+ this.lastProcessedMessageId = ts;
71
+ // Get username from cache or fetch
72
+ let username = this.userCache.get(userId) || userId;
73
+ if (!this.userCache.has(userId)) {
74
+ try {
75
+ const userInfo = await client.users.info({ user: userId });
76
+ const fetchedName = userInfo.user?.real_name || userInfo.user?.name;
77
+ if (fetchedName) {
78
+ username = fetchedName;
79
+ this.userCache.set(userId, username);
80
+ }
81
+ }
82
+ catch {
83
+ username = userId;
84
+ }
85
+ }
86
+ // Get channel info from cache or fetch (to detect DM vs channel)
87
+ let channelInfo = this.channelCache.get(channelId);
88
+ if (!channelInfo) {
89
+ try {
90
+ const convInfo = await client.conversations.info({ channel: channelId });
91
+ const conv = convInfo.channel;
92
+ // is_im = direct message, is_mpim = multi-party DM
93
+ const isDM = conv?.is_im === true || conv?.is_mpim === true;
94
+ const name = conv?.name || (isDM ? "DM" : channelId);
95
+ channelInfo = { isDM, name };
96
+ this.channelCache.set(channelId, channelInfo);
97
+ }
98
+ catch {
99
+ // Default to assuming it's a DM if we can't fetch info
100
+ channelInfo = { isDM: true };
101
+ this.channelCache.set(channelId, channelInfo);
102
+ }
103
+ }
104
+ // Detect bot mention: <@BOT_USER_ID>
105
+ const wasMentioned = this.botUserId
106
+ ? text.includes(`<@${this.botUserId}>`)
107
+ : false;
108
+ const isGroupChat = !channelInfo.isDM;
109
+ // Check authorization
110
+ const sendMessageToUser = async (cId, text) => {
111
+ if (this.app) {
112
+ await this.app.client.chat.postMessage({
113
+ channel: cId,
114
+ text: text,
115
+ });
116
+ }
117
+ };
118
+ const isAuthorized = await this.auth.checkAuthorization(userId, channelId, username, isGroupChat, wasMentioned, sendMessageToUser, this.type);
119
+ // Handle admin commands and challenge codes in DM
120
+ if (!isGroupChat && (text.startsWith("/") || text.match(/^\d{6}$/))) {
121
+ const handled = await this.auth.handleAdminCommand(text, channelId, userId, async (text) => await this.sendMessage(channelId, text), this.type);
122
+ if (handled) {
123
+ return;
124
+ }
125
+ }
126
+ if (!isAuthorized) {
127
+ return; // Auth handler already sent challenge/error messages
128
+ }
129
+ // Forward to message handler
130
+ if (this.messageHandler) {
131
+ const externalMessage = {
132
+ chatId: channelId,
133
+ transport: this.type,
134
+ content: text.trim(),
135
+ username: username,
136
+ userId: userId,
137
+ timestamp: new Date(parseFloat(ts) * 1000),
138
+ messageId: ts,
139
+ isGroupChat,
140
+ wasMentioned,
141
+ };
142
+ this.messageHandler(externalMessage);
143
+ }
144
+ });
145
+ // Handle errors
146
+ this.app.error(async (error) => {
147
+ console.error("[Slack] Error:", error);
148
+ if (this.errorHandler) {
149
+ this.errorHandler(new Error(String(error)));
150
+ }
151
+ });
152
+ try {
153
+ await this.app.start();
154
+ this._isConnected = true;
155
+ }
156
+ catch (error) {
157
+ throw new Error(`Slack connection failed: ${error.message}`);
158
+ }
159
+ }
160
+ async disconnect() {
161
+ if (this.app) {
162
+ try {
163
+ await this.app.stop();
164
+ }
165
+ catch {
166
+ // Ignore stop errors
167
+ }
168
+ this.app = null;
169
+ }
170
+ this._isConnected = false;
171
+ this.userCache.clear();
172
+ this.channelCache.clear();
173
+ console.log("[Slack] Disconnected");
174
+ }
175
+ async sendMessage(chatId, text) {
176
+ if (!this.app) {
177
+ throw new Error("Slack not connected");
178
+ }
179
+ if (!text?.trim())
180
+ return;
181
+ try {
182
+ await this.app.client.chat.postMessage({
183
+ channel: chatId,
184
+ text: text,
185
+ });
186
+ }
187
+ catch (error) {
188
+ throw new Error(`Slack send failed: ${error.message}`);
189
+ }
190
+ }
191
+ async sendTyping(_chatId) {
192
+ // Slack doesn't support typing indicators for bots
193
+ // We could potentially add a reaction or use a "thinking" message
194
+ // but for now we'll just skip it
195
+ }
196
+ onMessage(handler) {
197
+ this.messageHandler = handler;
198
+ }
199
+ onError(handler) {
200
+ this.errorHandler = handler;
201
+ }
202
+ }
203
+ //# sourceMappingURL=slack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slack.js","sourceRoot":"","sources":["../../src/transports/slack.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import type { ChallengeAuth } from "../auth/challenge-auth.js";
2
+ import type { ExternalMessage } from "../types.js";
3
+ import type { ITransportProvider } from "./interface.js";
4
+ /**
5
+ * Telegram transport provider using node-telegram-bot-api
6
+ */
7
+ export declare class TelegramProvider implements ITransportProvider {
8
+ private token;
9
+ private auth;
10
+ readonly type = "telegram";
11
+ private bot?;
12
+ private _isConnected;
13
+ private messageHandler?;
14
+ private errorHandler?;
15
+ private lastProcessedMessageId;
16
+ constructor(token: string, auth: ChallengeAuth);
17
+ get isConnected(): boolean;
18
+ /**
19
+ * Convert standard markdown to Telegram MarkdownV1 format.
20
+ *
21
+ * Telegram MarkdownV1 syntax: *bold*, _italic_, `code`, ```pre```, [text](url).
22
+ * Per docs, only `_ * [ \`` need backslash-escaping when literal — otherwise
23
+ * a stray `_` (e.g. in a snake_case tool name like `hud_canvas`) is parsed
24
+ * as an opening italic marker with no close, returning HTTP 400.
25
+ *
26
+ * Strategy: lift valid markdown patterns into NUL-sentinel placeholders,
27
+ * escape the remaining specials, then restore the placeholders.
28
+ */
29
+ private formatForTelegram;
30
+ connect(): Promise<void>;
31
+ disconnect(): Promise<void>;
32
+ sendMessage(chatId: string, text: string): Promise<void>;
33
+ sendTyping(chatId: string): Promise<void>;
34
+ onMessage(handler: (message: ExternalMessage) => void): void;
35
+ onError(handler: (error: Error) => void): void;
36
+ private handleMessage;
37
+ }
38
+ //# sourceMappingURL=telegram.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telegram.d.ts","sourceRoot":"","sources":["../../src/transports/telegram.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEzD;;GAEG;AACH,qBAAa,gBAAiB,YAAW,kBAAkB;IASvD,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,IAAI;IATd,QAAQ,CAAC,IAAI,cAAc;IAC3B,OAAO,CAAC,GAAG,CAAC,CAAc;IAC1B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,cAAc,CAAC,CAAqC;IAC5D,OAAO,CAAC,YAAY,CAAC,CAAyB;IAC9C,OAAO,CAAC,sBAAsB,CAAK;gBAGzB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,aAAa;IAG7B,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED;;;;;;;;;;OAUG;IACH,OAAO,CAAC,iBAAiB;IAiBnB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAgCxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ3B,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASxD,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK/C,SAAS,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,GAAG,IAAI;IAI5D,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI;YAIhC,aAAa;CA4F5B"}