tomo-ai 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 (90) hide show
  1. package/README.md +198 -0
  2. package/defaults/AGENT.md +27 -0
  3. package/defaults/IDENTITY.md +27 -0
  4. package/defaults/SOUL.md +34 -0
  5. package/defaults/skills/cron/SKILL.md +68 -0
  6. package/dist/agent.d.ts +25 -0
  7. package/dist/agent.d.ts.map +1 -0
  8. package/dist/agent.js +334 -0
  9. package/dist/agent.js.map +1 -0
  10. package/dist/channels/index.d.ts +3 -0
  11. package/dist/channels/index.d.ts.map +1 -0
  12. package/dist/channels/index.js +2 -0
  13. package/dist/channels/index.js.map +1 -0
  14. package/dist/channels/telegram.d.ts +22 -0
  15. package/dist/channels/telegram.d.ts.map +1 -0
  16. package/dist/channels/telegram.js +189 -0
  17. package/dist/channels/telegram.js.map +1 -0
  18. package/dist/channels/types.d.ts +53 -0
  19. package/dist/channels/types.d.ts.map +1 -0
  20. package/dist/channels/types.js +2 -0
  21. package/dist/channels/types.js.map +1 -0
  22. package/dist/cli/cron.d.ts +3 -0
  23. package/dist/cli/cron.d.ts.map +1 -0
  24. package/dist/cli/cron.js +87 -0
  25. package/dist/cli/cron.js.map +1 -0
  26. package/dist/cli/daemon.d.ts +6 -0
  27. package/dist/cli/daemon.d.ts.map +1 -0
  28. package/dist/cli/daemon.js +100 -0
  29. package/dist/cli/daemon.js.map +1 -0
  30. package/dist/cli/init.d.ts +3 -0
  31. package/dist/cli/init.d.ts.map +1 -0
  32. package/dist/cli/init.js +246 -0
  33. package/dist/cli/init.js.map +1 -0
  34. package/dist/cli/sessions.d.ts +3 -0
  35. package/dist/cli/sessions.d.ts.map +1 -0
  36. package/dist/cli/sessions.js +81 -0
  37. package/dist/cli/sessions.js.map +1 -0
  38. package/dist/cli/start.d.ts +3 -0
  39. package/dist/cli/start.d.ts.map +1 -0
  40. package/dist/cli/start.js +86 -0
  41. package/dist/cli/start.js.map +1 -0
  42. package/dist/cli.d.ts +3 -0
  43. package/dist/cli.d.ts.map +1 -0
  44. package/dist/cli.js +21 -0
  45. package/dist/cli.js.map +1 -0
  46. package/dist/config.d.ts +12 -0
  47. package/dist/config.d.ts.map +1 -0
  48. package/dist/config.js +37 -0
  49. package/dist/config.js.map +1 -0
  50. package/dist/cron/scheduler.d.ts +12 -0
  51. package/dist/cron/scheduler.d.ts.map +1 -0
  52. package/dist/cron/scheduler.js +48 -0
  53. package/dist/cron/scheduler.js.map +1 -0
  54. package/dist/cron/store.d.ts +24 -0
  55. package/dist/cron/store.d.ts.map +1 -0
  56. package/dist/cron/store.js +143 -0
  57. package/dist/cron/store.js.map +1 -0
  58. package/dist/cron/types.d.ts +35 -0
  59. package/dist/cron/types.d.ts.map +1 -0
  60. package/dist/cron/types.js +2 -0
  61. package/dist/cron/types.js.map +1 -0
  62. package/dist/index.d.ts +2 -0
  63. package/dist/index.d.ts.map +1 -0
  64. package/dist/index.js +14 -0
  65. package/dist/index.js.map +1 -0
  66. package/dist/logger.d.ts +3 -0
  67. package/dist/logger.d.ts.map +1 -0
  68. package/dist/logger.js +26 -0
  69. package/dist/logger.js.map +1 -0
  70. package/dist/sessions/index.d.ts +3 -0
  71. package/dist/sessions/index.d.ts.map +1 -0
  72. package/dist/sessions/index.js +2 -0
  73. package/dist/sessions/index.js.map +1 -0
  74. package/dist/sessions/store.d.ts +36 -0
  75. package/dist/sessions/store.d.ts.map +1 -0
  76. package/dist/sessions/store.js +216 -0
  77. package/dist/sessions/store.js.map +1 -0
  78. package/dist/sessions/types.d.ts +32 -0
  79. package/dist/sessions/types.d.ts.map +1 -0
  80. package/dist/sessions/types.js +2 -0
  81. package/dist/sessions/types.js.map +1 -0
  82. package/dist/skills/sync.d.ts +12 -0
  83. package/dist/skills/sync.d.ts.map +1 -0
  84. package/dist/skills/sync.js +71 -0
  85. package/dist/skills/sync.js.map +1 -0
  86. package/dist/workspace/index.d.ts +2 -0
  87. package/dist/workspace/index.d.ts.map +1 -0
  88. package/dist/workspace/index.js +99 -0
  89. package/dist/workspace/index.js.map +1 -0
  90. package/package.json +49 -0
package/dist/agent.js ADDED
@@ -0,0 +1,334 @@
1
+ import { query } from "@anthropic-ai/claude-agent-sdk";
2
+ import { config } from "./config.js";
3
+ import { buildSystemPrompt } from "./workspace/index.js";
4
+ import { SessionStore } from "./sessions/index.js";
5
+ import { log } from "./logger.js";
6
+ const QUERY_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
7
+ const GROUP_PARTICIPANT_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
8
+ const SILENT_TOKEN = "NO_REPLY";
9
+ function isSilentReply(text) {
10
+ return /^\s*NO_REPLY\s*$/i.test(text);
11
+ }
12
+ function sdkOptions(resumeSessionId) {
13
+ return {
14
+ model: config.model,
15
+ cwd: config.workspaceDir,
16
+ systemPrompt: buildSystemPrompt(),
17
+ permissionMode: "bypassPermissions",
18
+ allowDangerouslySkipPermissions: true,
19
+ allowedTools: [
20
+ "Read",
21
+ "Write",
22
+ "Edit",
23
+ "Bash",
24
+ "Glob",
25
+ "Grep",
26
+ "WebSearch",
27
+ "WebFetch",
28
+ "Agent",
29
+ "NotebookEdit",
30
+ "TodoWrite",
31
+ "Skill",
32
+ ],
33
+ settingSources: ["project"],
34
+ maxTurns: 30,
35
+ ...(resumeSessionId ? { resume: resumeSessionId } : {}),
36
+ };
37
+ }
38
+ export class Agent {
39
+ channels = [];
40
+ sessions;
41
+ /** Tracks known participants per group session */
42
+ groupParticipants = new Map();
43
+ lastPromptHash = "";
44
+ constructor() {
45
+ this.sessions = new SessionStore(config.sessionsDir, config.historyLimit);
46
+ }
47
+ addChannel(channel) {
48
+ channel.onMessage((msg) => this.handleMessage(channel, msg));
49
+ channel.onCommand((cmd, chatId, senderName) => this.handleCommand(channel, cmd, chatId, senderName));
50
+ this.channels.push(channel);
51
+ }
52
+ async handleCommand(channel, command, chatId, senderName) {
53
+ if (command === "new") {
54
+ const key = this.sessionKey(channel, chatId);
55
+ this.sessions.clearSdkSessionId(key);
56
+ log.info({ channel: channel.name, chatId, sender: senderName }, "New session started via /new");
57
+ await channel.send({ chatId, text: "New session started." });
58
+ }
59
+ }
60
+ sessionKey(channel, chatId) {
61
+ return `${channel.name}:${chatId}`;
62
+ }
63
+ checkPromptChanged() {
64
+ const currentHash = this.hashString(buildSystemPrompt());
65
+ if (this.lastPromptHash && currentHash !== this.lastPromptHash) {
66
+ log.info("System prompt changed, new sessions will use updated prompt");
67
+ this.lastPromptHash = currentHash;
68
+ return true;
69
+ }
70
+ this.lastPromptHash = currentHash;
71
+ return false;
72
+ }
73
+ hashString(s) {
74
+ let hash = 0;
75
+ for (let i = 0; i < s.length; i++) {
76
+ hash = ((hash << 5) - hash + s.charCodeAt(i)) | 0;
77
+ }
78
+ return String(hash);
79
+ }
80
+ async handleMessage(channel, message) {
81
+ const hasImages = message.images && message.images.length > 0;
82
+ const isGroup = message.isGroup ?? false;
83
+ const isMentioned = message.isMentioned ?? false;
84
+ log.info({ channel: channel.name, sender: message.senderName, group: isGroup || undefined, mentioned: isMentioned || undefined, images: hasImages ? message.images.length : undefined }, message.text);
85
+ const key = this.sessionKey(channel, message.chatId);
86
+ // In groups, prefix with sender name so the agent knows who's talking
87
+ const textForAgent = isGroup ? `${message.senderName}: ${message.text}` : message.text;
88
+ // Track group participants and inject context when needed
89
+ if (isGroup) {
90
+ await this.updateGroupContext(key, message.senderName, message.chatTitle);
91
+ }
92
+ this.sessions.append(key, {
93
+ role: "user",
94
+ content: textForAgent,
95
+ channel: channel.name,
96
+ senderName: message.senderName,
97
+ timestamp: message.timestamp,
98
+ });
99
+ // In groups, only respond when mentioned or replied to
100
+ if (isGroup && !isMentioned) {
101
+ log.debug("Group message ignored (not mentioned)");
102
+ return;
103
+ }
104
+ const stopTyping = channel.startTyping(message.chatId);
105
+ try {
106
+ const stampedText = this.injectTimestamp(textForAgent);
107
+ const response = await this.run(key, stampedText, message.images);
108
+ stopTyping();
109
+ this.sessions.append(key, {
110
+ role: "assistant",
111
+ content: response,
112
+ channel: channel.name,
113
+ timestamp: Date.now(),
114
+ });
115
+ log.info({ channel: channel.name }, "Tomo: %s", response);
116
+ if (isSilentReply(response)) {
117
+ log.info("Silent reply (no message sent)");
118
+ return;
119
+ }
120
+ await channel.send({
121
+ chatId: message.chatId,
122
+ text: response,
123
+ replyTo: message.id,
124
+ });
125
+ }
126
+ catch (err) {
127
+ stopTyping();
128
+ log.error({ err }, "Error handling message");
129
+ await channel.send({
130
+ chatId: message.chatId,
131
+ text: "Sorry, something went wrong. Please try again.",
132
+ replyTo: message.id,
133
+ });
134
+ }
135
+ }
136
+ async run(sessionKey, userMessage, images, isRetry = false) {
137
+ this.checkPromptChanged();
138
+ const resumeId = this.sessions.getSdkSessionId(sessionKey);
139
+ const opts = sdkOptions(resumeId ?? undefined);
140
+ const parts = [];
141
+ // For images, prepend image description request
142
+ // V1 query() only takes string prompt, not content blocks
143
+ // TODO: support multimodal via raw API if needed
144
+ const prompt = images && images.length > 0
145
+ ? `[User sent an image${userMessage !== "[Sent an image]" ? ` with caption: ${userMessage}` : ""}]`
146
+ : userMessage;
147
+ log.debug({ sessionKey, resume: !!resumeId }, "Running query");
148
+ try {
149
+ for await (const event of query({ prompt, options: opts })) {
150
+ if (event.type === "assistant" && event.message?.content) {
151
+ for (const block of event.message.content) {
152
+ if ("text" in block) {
153
+ parts.push(block.text);
154
+ }
155
+ else if ("type" in block && block.type === "tool_use") {
156
+ const tool = block;
157
+ const summary = this.summarizeToolInput(tool.name, tool.input);
158
+ log.info({ tool: tool.name }, summary);
159
+ }
160
+ }
161
+ }
162
+ if (event.type === "system" && event.subtype === "compact_boundary") {
163
+ const compact = event;
164
+ log.info({ pre: compact.compact_metadata?.pre_tokens, post: compact.compact_metadata?.post_tokens }, "Context compacted");
165
+ }
166
+ if (event.type === "tool_use_summary") {
167
+ log.debug(event.summary);
168
+ }
169
+ if (event.type === "result") {
170
+ const result = event;
171
+ // Capture session ID for future resume
172
+ if (result.session_id) {
173
+ if (!this.sessions.getSdkSessionId(sessionKey)) {
174
+ this.sessions.setSdkSessionId(sessionKey, result.session_id);
175
+ log.info({ sessionId: result.session_id, key: sessionKey }, "Session ID captured");
176
+ }
177
+ else {
178
+ this.sessions.touchSession(sessionKey);
179
+ }
180
+ }
181
+ const u = result.usage;
182
+ const input = u?.input_tokens ?? 0;
183
+ const output = u?.output_tokens ?? 0;
184
+ const cacheRead = u?.cache_read_input_tokens ?? 0;
185
+ const cacheCreated = u?.cache_creation_input_tokens ?? 0;
186
+ const model = result.modelUsage ? Object.values(result.modelUsage)[0] : undefined;
187
+ const contextWindow = model?.contextWindow ?? 0;
188
+ const used = (model?.inputTokens ?? 0) + (model?.outputTokens ?? 0);
189
+ const remaining = contextWindow - used;
190
+ const usage_pct = contextWindow > 0 ? Math.round((used / contextWindow) * 100) : 0;
191
+ if (contextWindow > 0 && used >= contextWindow * 0.8) {
192
+ log.warn({ used, contextWindow, pct: `${usage_pct}%` }, "Context nearing compaction threshold");
193
+ }
194
+ log.info({
195
+ turns: result.num_turns,
196
+ duration: `${result.duration_ms}ms`,
197
+ cost: `$${result.total_cost_usd?.toFixed(4)}`,
198
+ tokens: `in:${input} out:${output}`,
199
+ cache: `read:${cacheRead} created:${cacheCreated}`,
200
+ context: `${used}/${contextWindow} (${remaining} remaining, ${usage_pct}%)`,
201
+ }, "Run completed (%s)", result.subtype);
202
+ }
203
+ }
204
+ return parts.join("\n").trim() || "I'm not sure how to respond to that.";
205
+ }
206
+ catch (err) {
207
+ const errMsg = err instanceof Error ? err.message : "";
208
+ const isSessionError = errMsg.includes("No conversation found") || errMsg.includes("session");
209
+ const isMaxTurns = errMsg.includes("maximum number of turns");
210
+ if (isMaxTurns) {
211
+ // Max turns is not a session error — return whatever we have so far
212
+ log.warn("Hit max turns, returning partial response");
213
+ return parts.join("\n").trim() || "I ran out of steps trying to complete that. Can you try a simpler request?";
214
+ }
215
+ if (!isRetry && resumeId && isSessionError) {
216
+ log.warn({ err }, "Session error, resetting and retrying");
217
+ this.sessions.clearSdkSessionId(sessionKey);
218
+ return this.run(sessionKey, userMessage, images, true);
219
+ }
220
+ throw err;
221
+ }
222
+ }
223
+ async updateGroupContext(key, senderName, chatTitle) {
224
+ let participants = this.groupParticipants.get(key);
225
+ const isNew = !participants;
226
+ if (!participants) {
227
+ participants = new Set();
228
+ this.groupParticipants.set(key, participants);
229
+ }
230
+ const wasKnown = participants.has(senderName);
231
+ participants.add(senderName);
232
+ // Send context message on first group message or when a new participant appears
233
+ if (isNew || !wasKnown) {
234
+ const names = [...participants].join(", ");
235
+ const title = chatTitle ? `"${chatTitle}"` : "a group chat";
236
+ const contextMsg = `System: You are in ${title}. Participants so far: ${names}. Messages are prefixed with sender names.`;
237
+ // Inject as a query so it becomes part of the session history
238
+ const resumeId = this.sessions.getSdkSessionId(key);
239
+ const opts = sdkOptions(resumeId ?? undefined);
240
+ for await (const event of query({ prompt: contextMsg, options: { ...opts, maxTurns: 3 } })) {
241
+ if (event.type === "result") {
242
+ const result = event;
243
+ if (result.session_id && !this.sessions.getSdkSessionId(key)) {
244
+ this.sessions.setSdkSessionId(key, result.session_id);
245
+ }
246
+ }
247
+ }
248
+ log.info({ group: chatTitle, participants: names }, "Group context updated");
249
+ }
250
+ }
251
+ injectTimestamp(text) {
252
+ const now = new Date();
253
+ const weekday = now.toLocaleDateString("en-US", { weekday: "short" });
254
+ const mm = String(now.getMonth() + 1).padStart(2, "0");
255
+ const dd = String(now.getDate()).padStart(2, "0");
256
+ const date = `${mm}/${dd}`;
257
+ const time = now.toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit", hour12: false });
258
+ const tz = now.toLocaleTimeString("en-US", { timeZoneName: "short" }).split(" ").pop();
259
+ return `[${weekday} ${date} ${time} ${tz}] ${text}`;
260
+ }
261
+ summarizeToolInput(name, input) {
262
+ if (!input)
263
+ return name;
264
+ switch (name) {
265
+ case "Read": return `Read ${input.file_path}`;
266
+ case "Write": return `Write ${input.file_path}`;
267
+ case "Edit": return `Edit ${input.file_path}`;
268
+ case "Bash": return `Bash: ${String(input.command).slice(0, 80)}`;
269
+ case "Glob": return `Glob ${input.pattern}`;
270
+ case "Grep": return `Grep "${input.pattern}"`;
271
+ case "WebSearch": return `WebSearch: ${input.query}`;
272
+ case "WebFetch": return `WebFetch: ${input.url}`;
273
+ default: return `${name}: ${JSON.stringify(input).slice(0, 100)}`;
274
+ }
275
+ }
276
+ /** Handle a cron-triggered message */
277
+ async handleCronMessage(message, channelName, chatId) {
278
+ const channel = channelName
279
+ ? this.channels.find((ch) => ch.name === channelName)
280
+ : this.channels[0];
281
+ if (!channel) {
282
+ log.warn({ channelName }, "Cron: no channel found for delivery");
283
+ return;
284
+ }
285
+ const targetChatId = chatId ?? this.findLastChatId(channel.name);
286
+ if (!targetChatId) {
287
+ log.warn({ channel: channel.name }, "Cron: no chatId available for delivery");
288
+ return;
289
+ }
290
+ const key = this.sessionKey(channel, targetChatId);
291
+ const stampedMessage = this.injectTimestamp(message);
292
+ log.info({ channel: channel.name, sender: "cron" }, message);
293
+ const stopTyping = channel.startTyping(targetChatId);
294
+ try {
295
+ const response = await this.run(key, stampedMessage);
296
+ stopTyping();
297
+ log.info({ channel: channel.name }, "Tomo: %s", response);
298
+ if (isSilentReply(response)) {
299
+ log.info("Cron completed silently (no reply sent)");
300
+ return;
301
+ }
302
+ this.sessions.append(key, {
303
+ role: "assistant",
304
+ content: response,
305
+ channel: channel.name,
306
+ timestamp: Date.now(),
307
+ });
308
+ await channel.send({ chatId: targetChatId, text: response });
309
+ }
310
+ catch (err) {
311
+ stopTyping();
312
+ log.error({ err }, "Cron message handling failed");
313
+ }
314
+ }
315
+ findLastChatId(channelName) {
316
+ // Check SDK session keys for any chat on this channel
317
+ for (const [key] of this.sessions.listSdkSessionIds()) {
318
+ if (key.startsWith(`${channelName}:`)) {
319
+ return key.slice(channelName.length + 1);
320
+ }
321
+ }
322
+ return undefined;
323
+ }
324
+ async start() {
325
+ log.info({ channels: this.channels.length }, "Starting Tomo");
326
+ await Promise.all(this.channels.map((ch) => ch.start()));
327
+ log.info("Tomo is running");
328
+ }
329
+ async stop() {
330
+ log.info("Shutting down");
331
+ await Promise.all(this.channels.map((ch) => ch.stop()));
332
+ }
333
+ }
334
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export type { Channel, ImageAttachment, IncomingMessage, OutgoingMessage, MessageHandler, } from "./types.js";
2
+ export { TelegramChannel } from "./telegram.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/channels/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,OAAO,EACP,eAAe,EACf,eAAe,EACf,eAAe,EACf,cAAc,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { TelegramChannel } from "./telegram.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/channels/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { Channel, OutgoingMessage, MessageHandler, CommandHandler } from "./types.js";
2
+ export declare class TelegramChannel implements Channel {
3
+ readonly name = "telegram";
4
+ private bot;
5
+ private handlers;
6
+ private commandHandlers;
7
+ private botUsername;
8
+ constructor(token: string);
9
+ private getSenderName;
10
+ private checkMentioned;
11
+ /** Strip @botname from the message text */
12
+ private cleanMention;
13
+ private downloadPhoto;
14
+ private dispatch;
15
+ onMessage(handler: MessageHandler): void;
16
+ onCommand(handler: CommandHandler): void;
17
+ startTyping(chatId: string): () => void;
18
+ send(message: OutgoingMessage): Promise<void>;
19
+ start(): Promise<void>;
20
+ stop(): Promise<void>;
21
+ }
22
+ //# sourceMappingURL=telegram.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telegram.d.ts","sourceRoot":"","sources":["../../src/channels/telegram.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAmB,eAAe,EAAE,cAAc,EAAE,cAAc,EAAmB,MAAM,YAAY,CAAC;AAG7H,qBAAa,eAAgB,YAAW,OAAO;IAC7C,QAAQ,CAAC,IAAI,cAAc;IAC3B,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,QAAQ,CAAwB;IACxC,OAAO,CAAC,eAAe,CAAwB;IAC/C,OAAO,CAAC,WAAW,CAAqB;gBAE5B,KAAK,EAAE,MAAM;IAyDzB,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,cAAc;IAuBtB,2CAA2C;IAC3C,OAAO,CAAC,YAAY;YAKN,aAAa;YAoBb,QAAQ;IAMtB,SAAS,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAIxC,SAAS,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAIxC,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,IAAI;IAsCjC,IAAI,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB7C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IActB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAI5B"}
@@ -0,0 +1,189 @@
1
+ import { Bot } from "grammy";
2
+ import { log } from "../logger.js";
3
+ export class TelegramChannel {
4
+ name = "telegram";
5
+ bot;
6
+ handlers = [];
7
+ commandHandlers = [];
8
+ botUsername;
9
+ constructor(token) {
10
+ this.bot = new Bot(token);
11
+ this.bot.catch((err) => {
12
+ log.error({ err: err.error }, "Telegram bot error");
13
+ });
14
+ // Slash commands
15
+ this.bot.command("new", async (ctx) => {
16
+ const chatId = String(ctx.chat.id);
17
+ const senderName = this.getSenderName(ctx);
18
+ for (const handler of this.commandHandlers) {
19
+ await handler("new", chatId, senderName);
20
+ }
21
+ });
22
+ // Text messages (skip bot commands)
23
+ this.bot.on("message:text", async (ctx) => {
24
+ if (ctx.message.text.startsWith("/"))
25
+ return;
26
+ const isGroup = ctx.chat.type === "group" || ctx.chat.type === "supergroup";
27
+ const isMentioned = this.checkMentioned(ctx);
28
+ await this.dispatch({
29
+ id: String(ctx.message.message_id),
30
+ chatId: String(ctx.chat.id),
31
+ senderName: this.getSenderName(ctx),
32
+ text: this.cleanMention(ctx.message.text),
33
+ timestamp: ctx.message.date * 1000,
34
+ isGroup,
35
+ isMentioned,
36
+ chatTitle: isGroup ? ("title" in ctx.chat ? ctx.chat.title : undefined) : undefined,
37
+ });
38
+ });
39
+ // Photo messages
40
+ this.bot.on("message:photo", async (ctx) => {
41
+ const isGroup = ctx.chat.type === "group" || ctx.chat.type === "supergroup";
42
+ const isMentioned = this.checkMentioned(ctx);
43
+ const photos = ctx.message.photo;
44
+ const largest = photos[photos.length - 1];
45
+ const image = await this.downloadPhoto(largest.file_id);
46
+ await this.dispatch({
47
+ id: String(ctx.message.message_id),
48
+ chatId: String(ctx.chat.id),
49
+ senderName: this.getSenderName(ctx),
50
+ text: this.cleanMention(ctx.message.caption ?? "[Sent an image]"),
51
+ images: image ? [image] : undefined,
52
+ timestamp: ctx.message.date * 1000,
53
+ isGroup,
54
+ isMentioned,
55
+ chatTitle: isGroup ? ("title" in ctx.chat ? ctx.chat.title : undefined) : undefined,
56
+ });
57
+ });
58
+ }
59
+ getSenderName(ctx) {
60
+ const from = ctx.from;
61
+ return from.first_name + (from.last_name ? ` ${from.last_name}` : "");
62
+ }
63
+ checkMentioned(ctx) {
64
+ if (!this.botUsername)
65
+ return false;
66
+ const msg = ctx.message;
67
+ // Replied to the bot
68
+ if (msg.reply_to_message?.from?.id === this.bot.botInfo.id)
69
+ return true;
70
+ // @mentioned in text
71
+ const text = ("text" in msg ? msg.text : msg.caption) ?? "";
72
+ if (text.toLowerCase().includes(`@${this.botUsername.toLowerCase()}`))
73
+ return true;
74
+ // Mentioned via entities
75
+ const entities = ("entities" in msg ? msg.entities : msg.caption_entities) ?? [];
76
+ for (const e of entities) {
77
+ if (e.type === "mention") {
78
+ const mention = text.slice(e.offset, e.offset + e.length);
79
+ if (mention.toLowerCase() === `@${this.botUsername.toLowerCase()}`)
80
+ return true;
81
+ }
82
+ }
83
+ return false;
84
+ }
85
+ /** Strip @botname from the message text */
86
+ cleanMention(text) {
87
+ if (!this.botUsername)
88
+ return text;
89
+ return text.replace(new RegExp(`@${this.botUsername}`, "gi"), "").trim();
90
+ }
91
+ async downloadPhoto(fileId) {
92
+ try {
93
+ const file = await this.bot.api.getFile(fileId);
94
+ if (!file.file_path)
95
+ return undefined;
96
+ const url = `https://api.telegram.org/file/bot${this.bot.token}/${file.file_path}`;
97
+ const res = await fetch(url);
98
+ if (!res.ok)
99
+ return undefined;
100
+ const buffer = Buffer.from(await res.arrayBuffer());
101
+ const ext = file.file_path.split(".").pop()?.toLowerCase();
102
+ const mediaType = ext === "png" ? "image/png" : "image/jpeg";
103
+ return { data: buffer.toString("base64"), mediaType };
104
+ }
105
+ catch (err) {
106
+ log.error({ err }, "Failed to download photo");
107
+ return undefined;
108
+ }
109
+ }
110
+ async dispatch(msg) {
111
+ for (const handler of this.handlers) {
112
+ await handler(msg);
113
+ }
114
+ }
115
+ onMessage(handler) {
116
+ this.handlers.push(handler);
117
+ }
118
+ onCommand(handler) {
119
+ this.commandHandlers.push(handler);
120
+ }
121
+ startTyping(chatId) {
122
+ let sealed = false;
123
+ let consecutiveErrors = 0;
124
+ let interval = null;
125
+ const MAX_ERRORS = 10;
126
+ const INTERVAL_MS = 6000;
127
+ const TTL_MS = 2 * 60 * 1000;
128
+ const send = async () => {
129
+ if (sealed)
130
+ return;
131
+ if (consecutiveErrors >= MAX_ERRORS) {
132
+ log.warn({ chatId }, "Typing suspended after %d consecutive errors", MAX_ERRORS);
133
+ cleanup();
134
+ return;
135
+ }
136
+ try {
137
+ await this.bot.api.sendChatAction(chatId, "typing");
138
+ consecutiveErrors = 0;
139
+ }
140
+ catch {
141
+ consecutiveErrors++;
142
+ }
143
+ };
144
+ const cleanup = () => {
145
+ if (sealed)
146
+ return;
147
+ sealed = true;
148
+ if (interval)
149
+ clearInterval(interval);
150
+ if (ttlTimeout)
151
+ clearTimeout(ttlTimeout);
152
+ };
153
+ send();
154
+ interval = setInterval(send, INTERVAL_MS);
155
+ const ttlTimeout = setTimeout(cleanup, TTL_MS);
156
+ return cleanup;
157
+ }
158
+ async send(message) {
159
+ const replyParams = message.replyTo
160
+ ? { reply_parameters: { message_id: Number(message.replyTo) } }
161
+ : {};
162
+ try {
163
+ await this.bot.api.sendMessage(message.chatId, message.text, {
164
+ ...replyParams,
165
+ parse_mode: "Markdown",
166
+ });
167
+ }
168
+ catch {
169
+ // Fallback to plain text if Markdown parsing fails
170
+ await this.bot.api.sendMessage(message.chatId, message.text, replyParams);
171
+ }
172
+ }
173
+ async start() {
174
+ log.info("Telegram bot starting");
175
+ await this.bot.init();
176
+ this.botUsername = this.bot.botInfo.username;
177
+ log.info({ username: this.botUsername }, "Bot identity loaded");
178
+ // Register commands with Telegram so they show in the menu
179
+ await this.bot.api.setMyCommands([
180
+ { command: "new", description: "Start a new conversation" },
181
+ ]);
182
+ this.bot.start();
183
+ }
184
+ async stop() {
185
+ log.info("Telegram bot stopping");
186
+ await this.bot.stop();
187
+ }
188
+ }
189
+ //# sourceMappingURL=telegram.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telegram.js","sourceRoot":"","sources":["../../src/channels/telegram.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ export interface ImageAttachment {
2
+ /** Base64-encoded image data */
3
+ data: string;
4
+ /** MIME type (e.g. "image/jpeg", "image/png") */
5
+ mediaType: string;
6
+ }
7
+ export interface IncomingMessage {
8
+ /** Unique message ID from the source channel */
9
+ id: string;
10
+ /** Channel-specific chat/conversation ID */
11
+ chatId: string;
12
+ /** Display name of the sender */
13
+ senderName: string;
14
+ /** Message text content */
15
+ text: string;
16
+ /** Optional image attachments */
17
+ images?: ImageAttachment[];
18
+ /** Unix timestamp in milliseconds */
19
+ timestamp: number;
20
+ /** Whether this message is from a group chat */
21
+ isGroup?: boolean;
22
+ /** Whether the bot was mentioned or replied to */
23
+ isMentioned?: boolean;
24
+ /** Group chat title */
25
+ chatTitle?: string;
26
+ }
27
+ export interface OutgoingMessage {
28
+ /** Chat/conversation to send to */
29
+ chatId: string;
30
+ /** Message text content */
31
+ text: string;
32
+ /** Optional: message ID to reply to */
33
+ replyTo?: string;
34
+ }
35
+ export type MessageHandler = (message: IncomingMessage) => Promise<void>;
36
+ export type CommandHandler = (command: string, chatId: string, senderName: string) => Promise<void>;
37
+ export interface Channel {
38
+ /** Channel identifier (e.g. "telegram", "imessage") */
39
+ readonly name: string;
40
+ /** Register a handler for incoming messages */
41
+ onMessage(handler: MessageHandler): void;
42
+ /** Register a handler for slash commands */
43
+ onCommand(handler: CommandHandler): void;
44
+ /** Send a message through this channel */
45
+ send(message: OutgoingMessage): Promise<void>;
46
+ /** Show typing indicator. Returns a stop function. */
47
+ startTyping(chatId: string): () => void;
48
+ /** Start listening for messages */
49
+ start(): Promise<void>;
50
+ /** Gracefully shut down the channel */
51
+ stop(): Promise<void>;
52
+ }
53
+ //# sourceMappingURL=types.d.ts.map