opencode-telegram-bridge 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 (48) hide show
  1. package/.env.example +9 -0
  2. package/README.md +62 -0
  3. package/bin/opencode-telegram-bridge.js +2 -0
  4. package/dist/bot.d.ts +7 -0
  5. package/dist/bot.d.ts.map +1 -0
  6. package/dist/bot.js +337 -0
  7. package/dist/bot.js.map +1 -0
  8. package/dist/config.d.ts +14 -0
  9. package/dist/config.d.ts.map +1 -0
  10. package/dist/config.js +49 -0
  11. package/dist/config.js.map +1 -0
  12. package/dist/index.d.ts +2 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +15 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/opencode.d.ts +38 -0
  17. package/dist/opencode.d.ts.map +1 -0
  18. package/dist/opencode.js +142 -0
  19. package/dist/opencode.js.map +1 -0
  20. package/dist/projects.d.ts +14 -0
  21. package/dist/projects.d.ts.map +1 -0
  22. package/dist/projects.js +74 -0
  23. package/dist/projects.js.map +1 -0
  24. package/dist/prompt-guard.d.ts +7 -0
  25. package/dist/prompt-guard.d.ts.map +1 -0
  26. package/dist/prompt-guard.js +47 -0
  27. package/dist/prompt-guard.js.map +1 -0
  28. package/dist/state.d.ts +10 -0
  29. package/dist/state.d.ts.map +1 -0
  30. package/dist/state.js +56 -0
  31. package/dist/state.js.map +1 -0
  32. package/dist/storage.d.ts +8 -0
  33. package/dist/storage.d.ts.map +1 -0
  34. package/dist/storage.js +16 -0
  35. package/dist/storage.js.map +1 -0
  36. package/dist/telegram.d.ts +3 -0
  37. package/dist/telegram.d.ts.map +1 -0
  38. package/dist/telegram.js +12 -0
  39. package/dist/telegram.js.map +1 -0
  40. package/docs/configuration.md +17 -0
  41. package/docs/index.md +8 -0
  42. package/docs/installation.md +42 -0
  43. package/docs/release.md +56 -0
  44. package/docs/systemd.md +42 -0
  45. package/docs/usage.md +20 -0
  46. package/package.json +52 -0
  47. package/systemd/opencode-telegram-bridge.env.example +7 -0
  48. package/systemd/opencode-telegram-bridge.service +14 -0
package/.env.example ADDED
@@ -0,0 +1,9 @@
1
+ TELEGRAM_BOT_TOKEN=your-telegram-bot-token
2
+ TELEGRAM_ALLOWED_USER_ID=your-telegram-user-id
3
+ TELEGRAM_HANDLER_TIMEOUT_MS=630000
4
+
5
+ # OpenCode server config
6
+ OPENCODE_SERVER_URL=http://127.0.0.1:4096
7
+ OPENCODE_SERVER_USERNAME=opencode
8
+ OPENCODE_SERVER_PASSWORD=
9
+ OPENCODE_PROMPT_TIMEOUT_MS=600000
package/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # OpenCode Telegram Bridge
2
+
3
+ Run a Telegram bot that forwards messages to an OpenCode backend and returns responses.
4
+
5
+ ## Requirements
6
+ - Node.js 18+
7
+ - OpenCode CLI installed and available on PATH
8
+ - OpenCode server running (`opencode serve`)
9
+
10
+ ## Quickstart
11
+ 1. Install dependencies:
12
+
13
+ ```bash
14
+ npm install
15
+ ```
16
+
17
+ 2. Create `.env` from the example:
18
+
19
+ ```bash
20
+ cp .env.example .env
21
+ ```
22
+
23
+ 3. Start OpenCode server in another terminal:
24
+
25
+ ```bash
26
+ opencode serve
27
+ ```
28
+
29
+ 4. Run the bot:
30
+
31
+ ```bash
32
+ npm run dev
33
+ ```
34
+
35
+ ## Install via npm
36
+ ```bash
37
+ npm install -g opencode-telegram-bridge
38
+ ```
39
+
40
+ Run:
41
+ ```bash
42
+ opencode-telegram-bridge
43
+ ```
44
+
45
+ You still need OpenCode running separately:
46
+ ```bash
47
+ opencode serve
48
+ ```
49
+
50
+ ## Docs
51
+ - `docs/index.md`
52
+ - `docs/installation.md`
53
+ - `docs/configuration.md`
54
+ - `docs/usage.md`
55
+ - `docs/systemd.md`
56
+ - `docs/release.md`
57
+
58
+ ## Releases
59
+ This project uses Changesets. See `docs/release.md`.
60
+
61
+ ## Notes
62
+ - Project aliases and chat project selection are stored in `~/.opencode-telegram-bridge/projects.db`.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import "../dist/index.js"
package/dist/bot.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import { Telegraf } from "telegraf";
2
+ import type { BotConfig } from "./config.js";
3
+ import type { OpencodeBridge } from "./opencode.js";
4
+ import { type ProjectStore } from "./projects.js";
5
+ import type { ChatProjectStore } from "./state.js";
6
+ export declare const startBot: (config: BotConfig, opencode: OpencodeBridge, projects: ProjectStore, chatProjects: ChatProjectStore) => Telegraf<import("telegraf").Context<import("@telegraf/types").Update>>;
7
+ //# sourceMappingURL=bot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bot.d.ts","sourceRoot":"","sources":["../src/bot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,QAAQ,EAAE,MAAM,UAAU,CAAA;AAE3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAmB,MAAM,eAAe,CAAA;AAEpE,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,eAAe,CAAA;AACrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AA8BlD,eAAO,MAAM,QAAQ,GACnB,QAAQ,SAAS,EACjB,UAAU,cAAc,EACxB,UAAU,YAAY,EACtB,cAAc,gBAAgB,2EAia/B,CAAA"}
package/dist/bot.js ADDED
@@ -0,0 +1,337 @@
1
+ import { Markup, Telegraf } from "telegraf";
2
+ import { createPromptGuard } from "./prompt-guard.js";
3
+ import { HOME_PROJECT_ALIAS } from "./projects.js";
4
+ import { splitTelegramMessage } from "./telegram.js";
5
+ const isAuthorized = (user, allowedUserId) => user?.id === allowedUserId;
6
+ const formatUserLabel = (user) => {
7
+ if (!user) {
8
+ return "unknown";
9
+ }
10
+ if (user.username) {
11
+ return `${user.username} (${user.id ?? "unknown"})`;
12
+ }
13
+ return String(user.id ?? "unknown");
14
+ };
15
+ export const startBot = (config, opencode, projects, chatProjects) => {
16
+ const bot = new Telegraf(config.botToken, {
17
+ handlerTimeout: config.handlerTimeoutMs,
18
+ });
19
+ /*
20
+ * Telegraf wraps each update handler in a timeout. When that timeout fires,
21
+ * it logs an error but does not cancel the async handler. To avoid dangling
22
+ * prompts and a stuck in-flight lock, we enforce our own per-chat timeout
23
+ * and abort the OpenCode request when it exceeds the limit.
24
+ */
25
+ const promptGuard = createPromptGuard(config.promptTimeoutMs);
26
+ const pendingPermissions = new Map();
27
+ const sendReply = async (chatId, replyToMessageId, text) => {
28
+ try {
29
+ const chunks = splitTelegramMessage(text);
30
+ for (const [index, chunk] of chunks.entries()) {
31
+ const replyParameters = index === 0 && replyToMessageId
32
+ ? { reply_parameters: { message_id: replyToMessageId } }
33
+ : undefined;
34
+ await bot.telegram.sendMessage(chatId, chunk, replyParameters);
35
+ }
36
+ }
37
+ catch (error) {
38
+ console.error("Failed to send Telegram reply", error);
39
+ }
40
+ };
41
+ const buildPermissionSummary = (request) => {
42
+ const lines = ["OpenCode permission request", `Permission: ${request.permission}`];
43
+ if (request.patterns.length > 0) {
44
+ lines.push(`Patterns: ${request.patterns.join(", ")}`);
45
+ }
46
+ if (request.always.length > 0) {
47
+ lines.push(`Always scopes: ${request.always.join(", ")}`);
48
+ }
49
+ return lines.join("\n");
50
+ };
51
+ const buildPermissionKeyboard = (requestId, includeAlways) => {
52
+ const buttons = [
53
+ Markup.button.callback("Approve once", `perm:${requestId}:once`),
54
+ Markup.button.callback("Reject", `perm:${requestId}:reject`),
55
+ ];
56
+ if (includeAlways) {
57
+ buttons.splice(1, 0, Markup.button.callback("Approve always", `perm:${requestId}:always`));
58
+ }
59
+ return Markup.inlineKeyboard([buttons]);
60
+ };
61
+ opencode.startPermissionEventStream({
62
+ onPermissionAsked: async ({ request, directory }) => {
63
+ const owner = opencode.getSessionOwner(request.sessionID);
64
+ if (!owner) {
65
+ console.warn("Permission request for unknown session", {
66
+ sessionId: request.sessionID,
67
+ requestId: request.id,
68
+ });
69
+ return;
70
+ }
71
+ const summary = buildPermissionSummary(request);
72
+ try {
73
+ const replyMarkup = buildPermissionKeyboard(request.id, request.always.length > 0);
74
+ const message = await bot.telegram.sendMessage(owner.chatId, summary, {
75
+ reply_markup: replyMarkup.reply_markup,
76
+ });
77
+ pendingPermissions.set(request.id, {
78
+ chatId: owner.chatId,
79
+ messageId: message.message_id,
80
+ directory,
81
+ summary,
82
+ });
83
+ }
84
+ catch (error) {
85
+ console.error("Failed to send permission request", error);
86
+ }
87
+ },
88
+ onError: (error) => {
89
+ console.error("OpenCode event stream error", error);
90
+ },
91
+ });
92
+ const getChatProjectAlias = (chatId) => chatProjects.getActiveAlias(chatId) ?? HOME_PROJECT_ALIAS;
93
+ const setChatProjectAlias = (chatId, alias) => {
94
+ chatProjects.setActiveAlias(chatId, alias);
95
+ };
96
+ const formatProjectList = (activeAlias) => {
97
+ const entries = projects.listProjects();
98
+ if (entries.length === 0) {
99
+ return "No projects configured.";
100
+ }
101
+ const lines = entries.map((entry) => {
102
+ const prefix = entry.alias === activeAlias ? "*" : " ";
103
+ return `${prefix} ${entry.alias}: ${entry.path}`;
104
+ });
105
+ return ["Projects (active marked with *):", ...lines].join("\n");
106
+ };
107
+ const isCommandMessage = (ctx) => ctx.message?.entities?.some((entity) => entity.type === "bot_command" && entity.offset === 0) ?? false;
108
+ bot.start(async (ctx) => {
109
+ if (!isAuthorized(ctx.from, config.allowedUserId)) {
110
+ await ctx.reply("Not authorized.");
111
+ return;
112
+ }
113
+ await ctx.reply("Bot is online. Send me a message and I'll log it here.");
114
+ });
115
+ bot.command("project", async (ctx) => {
116
+ if (!isAuthorized(ctx.from, config.allowedUserId)) {
117
+ await ctx.reply("Not authorized.");
118
+ return;
119
+ }
120
+ const chatId = ctx.chat?.id;
121
+ if (!chatId) {
122
+ console.warn("Missing chat id for incoming project command");
123
+ await ctx.reply("Missing chat context.");
124
+ return;
125
+ }
126
+ const messageText = ctx.message?.text ?? "";
127
+ const parts = messageText.trim().split(/\s+/);
128
+ parts.shift();
129
+ const subcommand = parts[0] ?? "list";
130
+ const args = parts.slice(1);
131
+ try {
132
+ switch (subcommand) {
133
+ case "list": {
134
+ await ctx.reply(formatProjectList(getChatProjectAlias(chatId)));
135
+ return;
136
+ }
137
+ case "current": {
138
+ const activeAlias = getChatProjectAlias(chatId);
139
+ const project = projects.getProject(activeAlias);
140
+ if (!project) {
141
+ throw new Error(`Project alias '${activeAlias}' not found`);
142
+ }
143
+ await ctx.reply(`${project.alias}: ${project.path}`);
144
+ return;
145
+ }
146
+ case "add": {
147
+ const alias = args[0];
148
+ const projectPath = args.slice(1).join(" ");
149
+ if (!alias) {
150
+ await ctx.reply("Usage: /project add <alias> <path>");
151
+ return;
152
+ }
153
+ const project = projects.addProject(alias, projectPath);
154
+ await ctx.reply(`Added ${project.alias}: ${project.path}`);
155
+ return;
156
+ }
157
+ case "remove": {
158
+ const alias = args[0];
159
+ if (!alias) {
160
+ await ctx.reply("Usage: /project remove <alias>");
161
+ return;
162
+ }
163
+ projects.removeProject(alias);
164
+ if (getChatProjectAlias(chatId) === alias) {
165
+ setChatProjectAlias(chatId, HOME_PROJECT_ALIAS);
166
+ }
167
+ await ctx.reply(`Removed ${alias}`);
168
+ return;
169
+ }
170
+ case "set": {
171
+ const alias = args[0];
172
+ if (!alias) {
173
+ await ctx.reply("Usage: /project set <alias>");
174
+ return;
175
+ }
176
+ const project = projects.getProject(alias);
177
+ if (!project) {
178
+ throw new Error(`Project alias '${alias}' not found`);
179
+ }
180
+ setChatProjectAlias(chatId, project.alias);
181
+ await ctx.reply(`Active project: ${project.alias}`);
182
+ return;
183
+ }
184
+ default: {
185
+ await ctx.reply("Usage: /project <list|current|add|remove|set> ...");
186
+ }
187
+ }
188
+ }
189
+ catch (error) {
190
+ console.error("Failed to handle /project command", error);
191
+ const message = error instanceof Error
192
+ ? error.message
193
+ : "Project command failed. Check server logs.";
194
+ await ctx.reply(message);
195
+ }
196
+ });
197
+ bot.command("reset", async (ctx) => {
198
+ if (!isAuthorized(ctx.from, config.allowedUserId)) {
199
+ await ctx.reply("Not authorized.");
200
+ return;
201
+ }
202
+ const chatId = ctx.chat?.id;
203
+ if (!chatId) {
204
+ console.warn("Missing chat id for incoming reset command");
205
+ await ctx.reply("Missing chat context.");
206
+ return;
207
+ }
208
+ const activeAlias = getChatProjectAlias(chatId);
209
+ const project = projects.getProject(activeAlias);
210
+ if (!project) {
211
+ console.error("Missing project for chat", { chatId, activeAlias });
212
+ await ctx.reply("Missing project configuration.");
213
+ return;
214
+ }
215
+ const didReset = opencode.resetSession(chatId, project.path);
216
+ if (didReset) {
217
+ await ctx.reply(`Session reset for ${project.alias}.`);
218
+ return;
219
+ }
220
+ await ctx.reply(`No active session to reset for ${project.alias}.`);
221
+ });
222
+ bot.on("callback_query", async (ctx) => {
223
+ const callbackQuery = ctx.callbackQuery;
224
+ if (!callbackQuery || !("data" in callbackQuery)) {
225
+ return;
226
+ }
227
+ const data = callbackQuery.data;
228
+ if (!data.startsWith("perm:")) {
229
+ return;
230
+ }
231
+ if (!isAuthorized(ctx.from, config.allowedUserId)) {
232
+ await ctx.answerCbQuery("Not authorized.");
233
+ return;
234
+ }
235
+ const [, requestId, reply] = data.split(":");
236
+ if (!requestId || !reply) {
237
+ await ctx.answerCbQuery("Invalid permission response.");
238
+ return;
239
+ }
240
+ const permissionReply = reply;
241
+ if (!["once", "always", "reject"].includes(permissionReply)) {
242
+ await ctx.answerCbQuery("Invalid permission response.");
243
+ return;
244
+ }
245
+ const pending = pendingPermissions.get(requestId);
246
+ if (!pending) {
247
+ await ctx.answerCbQuery("Permission request not found.");
248
+ return;
249
+ }
250
+ try {
251
+ await opencode.replyToPermission(requestId, permissionReply, pending.directory);
252
+ pendingPermissions.delete(requestId);
253
+ const decisionLabel = permissionReply === "reject"
254
+ ? "Rejected"
255
+ : permissionReply === "always"
256
+ ? "Approved (always)"
257
+ : "Approved (once)";
258
+ await bot.telegram.editMessageText(pending.chatId, pending.messageId, undefined, `${pending.summary}\nDecision: ${decisionLabel}`);
259
+ await ctx.answerCbQuery("Response sent.");
260
+ }
261
+ catch (error) {
262
+ console.error("Failed to reply to permission", error);
263
+ await ctx.answerCbQuery("Failed to send response.");
264
+ }
265
+ });
266
+ bot.on("text", (ctx) => {
267
+ if (!isAuthorized(ctx.from, config.allowedUserId)) {
268
+ void ctx.reply("Not authorized.");
269
+ return;
270
+ }
271
+ if (isCommandMessage(ctx)) {
272
+ return;
273
+ }
274
+ const text = ctx.message.text;
275
+ const userLabel = formatUserLabel(ctx.from);
276
+ const chatId = ctx.chat?.id;
277
+ const replyToMessageId = ctx.message.message_id;
278
+ if (!chatId) {
279
+ console.warn("Missing chat id for incoming message", { userLabel });
280
+ void ctx.reply("Missing chat context.");
281
+ return;
282
+ }
283
+ const activeAlias = getChatProjectAlias(chatId);
284
+ const project = projects.getProject(activeAlias);
285
+ if (!project) {
286
+ console.error("Missing project for chat", { chatId, activeAlias });
287
+ void ctx.reply("Missing project configuration.");
288
+ return;
289
+ }
290
+ console.log(`[telegram] ${userLabel}: ${text}`);
291
+ /*
292
+ * If we cannot start a prompt, we reply to the new message and ignore it.
293
+ * When a prompt times out, the guard clears the in-flight state so new
294
+ * messages can be accepted even if the original handler is still running.
295
+ */
296
+ /*
297
+ * timedOut becomes true only if our prompt timeout fires. Telegraf's
298
+ * handler timeout does not stop background work, so we guard against
299
+ * late replies by checking this flag before responding.
300
+ */
301
+ let timedOut = false;
302
+ const abortController = promptGuard.tryStart(chatId, () => {
303
+ timedOut = true;
304
+ void sendReply(chatId, replyToMessageId, "OpenCode request timed out. You can send a new message.");
305
+ });
306
+ if (!abortController) {
307
+ void sendReply(chatId, replyToMessageId, "Your previous message has not been replied to yet. This message will be ignored.");
308
+ return;
309
+ }
310
+ void (async () => {
311
+ try {
312
+ const reply = await opencode.promptFromChat(chatId, text, project.path, { signal: abortController.signal });
313
+ if (!timedOut) {
314
+ await sendReply(chatId, replyToMessageId, reply);
315
+ }
316
+ }
317
+ catch (error) {
318
+ console.error("Failed to send prompt to OpenCode", error);
319
+ if (!timedOut) {
320
+ await sendReply(chatId, replyToMessageId, "OpenCode error. Check server logs.");
321
+ }
322
+ }
323
+ finally {
324
+ promptGuard.finish(chatId);
325
+ }
326
+ })();
327
+ });
328
+ bot.catch((error, ctx) => {
329
+ console.error("Telegram bot error", {
330
+ error,
331
+ updateId: ctx.update.update_id,
332
+ });
333
+ });
334
+ bot.launch();
335
+ return bot;
336
+ };
337
+ //# sourceMappingURL=bot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bot.js","sourceRoot":"","sources":["../src/bot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAI3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,kBAAkB,EAAqB,MAAM,eAAe,CAAA;AAErE,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AAcpD,MAAM,YAAY,GAAG,CAAC,IAA8B,EAAE,aAAqB,EAAE,EAAE,CAC7E,IAAI,EAAE,EAAE,KAAK,aAAa,CAAA;AAE5B,MAAM,eAAe,GAAG,CAAC,IAA8B,EAAE,EAAE;IACzD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,OAAO,GAAG,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,EAAE,IAAI,SAAS,GAAG,CAAA;IACrD,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,SAAS,CAAC,CAAA;AACrC,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,MAAiB,EACjB,QAAwB,EACxB,QAAsB,EACtB,YAA8B,EAC9B,EAAE;IACF,MAAM,GAAG,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE;QACxC,cAAc,EAAE,MAAM,CAAC,gBAAgB;KACxC,CAAC,CAAA;IACF;;;;;OAKG;IACH,MAAM,WAAW,GAAG,iBAAiB,CAAC,MAAM,CAAC,eAAe,CAAC,CAAA;IAC7D,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAA6B,CAAA;IAE/D,MAAM,SAAS,GAAG,KAAK,EACrB,MAAc,EACd,gBAAoC,EACpC,IAAY,EACZ,EAAE;QACF,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAA;YACzC,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;gBAC9C,MAAM,eAAe,GACnB,KAAK,KAAK,CAAC,IAAI,gBAAgB;oBAC7B,CAAC,CAAC,EAAE,gBAAgB,EAAE,EAAE,UAAU,EAAE,gBAAgB,EAAE,EAAE;oBACxD,CAAC,CAAC,SAAS,CAAA;gBACf,MAAM,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,eAAe,CAAC,CAAA;YAChE,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,KAAK,CAAC,CAAA;QACvD,CAAC;IACH,CAAC,CAAA;IAED,MAAM,sBAAsB,GAAG,CAAC,OAI/B,EAAE,EAAE;QACH,MAAM,KAAK,GAAG,CAAC,6BAA6B,EAAE,eAAe,OAAO,CAAC,UAAU,EAAE,CAAC,CAAA;QAClF,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChC,KAAK,CAAC,IAAI,CAAC,aAAa,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACxD,CAAC;QACD,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC,kBAAkB,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAC3D,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACzB,CAAC,CAAA;IAED,MAAM,uBAAuB,GAAG,CAC9B,SAAiB,EACjB,aAAsB,EACtB,EAAE;QACF,MAAM,OAAO,GAAG;YACd,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,EAAE,QAAQ,SAAS,OAAO,CAAC;YAChE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,SAAS,SAAS,CAAC;SAC7D,CAAA;QACD,IAAI,aAAa,EAAE,CAAC;YAClB,OAAO,CAAC,MAAM,CACZ,CAAC,EACD,CAAC,EACD,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,EAAE,QAAQ,SAAS,SAAS,CAAC,CACrE,CAAA;QACH,CAAC;QAED,OAAO,MAAM,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,CAAA;IACzC,CAAC,CAAA;IAED,QAAQ,CAAC,0BAA0B,CAAC;QAClC,iBAAiB,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE;YAClD,MAAM,KAAK,GAAG,QAAQ,CAAC,eAAe,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;YACzD,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO,CAAC,IAAI,CAAC,wCAAwC,EAAE;oBACrD,SAAS,EAAE,OAAO,CAAC,SAAS;oBAC5B,SAAS,EAAE,OAAO,CAAC,EAAE;iBACtB,CAAC,CAAA;gBACF,OAAM;YACR,CAAC;YAED,MAAM,OAAO,GAAG,sBAAsB,CAAC,OAAO,CAAC,CAAA;YAC/C,IAAI,CAAC;gBACH,MAAM,WAAW,GAAG,uBAAuB,CACzC,OAAO,CAAC,EAAE,EACV,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAC1B,CAAA;gBACD,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;oBACpE,YAAY,EAAE,WAAW,CAAC,YAAY;iBACvC,CAAC,CAAA;gBACF,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE;oBACjC,MAAM,EAAE,KAAK,CAAC,MAAM;oBACpB,SAAS,EAAE,OAAO,CAAC,UAAU;oBAC7B,SAAS;oBACT,OAAO;iBACR,CAAC,CAAA;YACJ,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,KAAK,CAAC,CAAA;YAC3D,CAAC;QACH,CAAC;QACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YACjB,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAA;QACrD,CAAC;KACF,CAAC,CAAA;IAEF,MAAM,mBAAmB,GAAG,CAAC,MAAc,EAAE,EAAE,CAC7C,YAAY,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,kBAAkB,CAAA;IAE3D,MAAM,mBAAmB,GAAG,CAAC,MAAc,EAAE,KAAa,EAAE,EAAE;QAC5D,YAAY,CAAC,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;IAC5C,CAAC,CAAA;IAED,MAAM,iBAAiB,GAAG,CAAC,WAAmB,EAAE,EAAE;QAChD,MAAM,OAAO,GAAG,QAAQ,CAAC,YAAY,EAAE,CAAA;QACvC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,yBAAyB,CAAA;QAClC,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YAClC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,KAAK,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAA;YACtD,OAAO,GAAG,MAAM,IAAI,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,IAAI,EAAE,CAAA;QAClD,CAAC,CAAC,CAAA;QAEF,OAAO,CAAC,kCAAkC,EAAE,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAClE,CAAC,CAAA;IAED,MAAM,gBAAgB,GAAG,CAAC,GAAyE,EAAE,EAAE,CACrG,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,CACzB,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,aAAa,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,CACjE,IAAI,KAAK,CAAA;IAEZ,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACtB,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;YAClD,MAAM,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAA;YAClC,OAAM;QACR,CAAC;QAED,MAAM,GAAG,CAAC,KAAK,CAAC,wDAAwD,CAAC,CAAA;IAC3E,CAAC,CAAC,CAAA;IAEF,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACnC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;YAClD,MAAM,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAA;YAClC,OAAM;QACR,CAAC;QAED,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,EAAE,CAAA;QAC3B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAA;YAC5D,MAAM,GAAG,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;YACxC,OAAM;QACR,CAAC;QAED,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,EAAE,IAAI,IAAI,EAAE,CAAA;QAC3C,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QAC7C,KAAK,CAAC,KAAK,EAAE,CAAA;QAEb,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,MAAM,CAAA;QACrC,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QAE3B,IAAI,CAAC;YACH,QAAQ,UAAU,EAAE,CAAC;gBACnB,KAAK,MAAM,CAAC,CAAC,CAAC;oBACZ,MAAM,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;oBAC/D,OAAM;gBACR,CAAC;gBACD,KAAK,SAAS,CAAC,CAAC,CAAC;oBACf,MAAM,WAAW,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAA;oBAC/C,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC,WAAW,CAAC,CAAA;oBAChD,IAAI,CAAC,OAAO,EAAE,CAAC;wBACb,MAAM,IAAI,KAAK,CAAC,kBAAkB,WAAW,aAAa,CAAC,CAAA;oBAC7D,CAAC;oBAED,MAAM,GAAG,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,KAAK,KAAK,OAAO,CAAC,IAAI,EAAE,CAAC,CAAA;oBACpD,OAAM;gBACR,CAAC;gBACD,KAAK,KAAK,CAAC,CAAC,CAAC;oBACX,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;oBACrB,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;oBAC3C,IAAI,CAAC,KAAK,EAAE,CAAC;wBACX,MAAM,GAAG,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAA;wBACrD,OAAM;oBACR,CAAC;oBAED,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC,KAAK,EAAE,WAAW,CAAC,CAAA;oBACvD,MAAM,GAAG,CAAC,KAAK,CAAC,SAAS,OAAO,CAAC,KAAK,KAAK,OAAO,CAAC,IAAI,EAAE,CAAC,CAAA;oBAC1D,OAAM;gBACR,CAAC;gBACD,KAAK,QAAQ,CAAC,CAAC,CAAC;oBACd,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;oBACrB,IAAI,CAAC,KAAK,EAAE,CAAC;wBACX,MAAM,GAAG,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAA;wBACjD,OAAM;oBACR,CAAC;oBAED,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;oBAC7B,IAAI,mBAAmB,CAAC,MAAM,CAAC,KAAK,KAAK,EAAE,CAAC;wBAC1C,mBAAmB,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAA;oBACjD,CAAC;oBACD,MAAM,GAAG,CAAC,KAAK,CAAC,WAAW,KAAK,EAAE,CAAC,CAAA;oBACnC,OAAM;gBACR,CAAC;gBACD,KAAK,KAAK,CAAC,CAAC,CAAC;oBACX,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;oBACrB,IAAI,CAAC,KAAK,EAAE,CAAC;wBACX,MAAM,GAAG,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAA;wBAC9C,OAAM;oBACR,CAAC;oBAED,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;oBAC1C,IAAI,CAAC,OAAO,EAAE,CAAC;wBACb,MAAM,IAAI,KAAK,CAAC,kBAAkB,KAAK,aAAa,CAAC,CAAA;oBACvD,CAAC;oBAED,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,CAAA;oBAC1C,MAAM,GAAG,CAAC,KAAK,CAAC,mBAAmB,OAAO,CAAC,KAAK,EAAE,CAAC,CAAA;oBACnD,OAAM;gBACR,CAAC;gBACD,OAAO,CAAC,CAAC,CAAC;oBACR,MAAM,GAAG,CAAC,KAAK,CACb,mDAAmD,CACpD,CAAA;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,KAAK,CAAC,CAAA;YACzD,MAAM,OAAO,GACX,KAAK,YAAY,KAAK;gBACpB,CAAC,CAAC,KAAK,CAAC,OAAO;gBACf,CAAC,CAAC,4CAA4C,CAAA;YAClD,MAAM,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QAC1B,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACjC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;YAClD,MAAM,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAA;YAClC,OAAM;QACR,CAAC;QAED,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,EAAE,CAAA;QAC3B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAA;YAC1D,MAAM,GAAG,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;YACxC,OAAM;QACR,CAAC;QAED,MAAM,WAAW,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAA;QAC/C,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC,WAAW,CAAC,CAAA;QAChD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAA;YAClE,MAAM,GAAG,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAA;YACjD,OAAM;QACR,CAAC;QAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;QAC5D,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,GAAG,CAAC,KAAK,CAAC,qBAAqB,OAAO,CAAC,KAAK,GAAG,CAAC,CAAA;YACtD,OAAM;QACR,CAAC;QAED,MAAM,GAAG,CAAC,KAAK,CAAC,kCAAkC,OAAO,CAAC,KAAK,GAAG,CAAC,CAAA;IACrE,CAAC,CAAC,CAAA;IAEF,GAAG,CAAC,EAAE,CAAC,gBAAgB,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACrC,MAAM,aAAa,GAAG,GAAG,CAAC,aAAa,CAAA;QACvC,IAAI,CAAC,aAAa,IAAI,CAAC,CAAC,MAAM,IAAI,aAAa,CAAC,EAAE,CAAC;YACjD,OAAM;QACR,CAAC;QAED,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,CAAA;QAC/B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC9B,OAAM;QACR,CAAC;QAED,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;YAClD,MAAM,GAAG,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAA;YAC1C,OAAM;QACR,CAAC;QAED,MAAM,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAC5C,IAAI,CAAC,SAAS,IAAI,CAAC,KAAK,EAAE,CAAC;YACzB,MAAM,GAAG,CAAC,aAAa,CAAC,8BAA8B,CAAC,CAAA;YACvD,OAAM;QACR,CAAC;QAED,MAAM,eAAe,GAAG,KAAwB,CAAA;QAChD,IAAI,CAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAuB,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;YACnF,MAAM,GAAG,CAAC,aAAa,CAAC,8BAA8B,CAAC,CAAA;YACvD,OAAM;QACR,CAAC;QAED,MAAM,OAAO,GAAG,kBAAkB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QACjD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,GAAG,CAAC,aAAa,CAAC,+BAA+B,CAAC,CAAA;YACxD,OAAM;QACR,CAAC;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,CAAC,iBAAiB,CAC9B,SAAS,EACT,eAAe,EACf,OAAO,CAAC,SAAS,CAClB,CAAA;YACD,kBAAkB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;YACpC,MAAM,aAAa,GACjB,eAAe,KAAK,QAAQ;gBAC1B,CAAC,CAAC,UAAU;gBACZ,CAAC,CAAC,eAAe,KAAK,QAAQ;oBAC9B,CAAC,CAAC,mBAAmB;oBACrB,CAAC,CAAC,iBAAiB,CAAA;YACvB,MAAM,GAAG,CAAC,QAAQ,CAAC,eAAe,CAChC,OAAO,CAAC,MAAM,EACd,OAAO,CAAC,SAAS,EACjB,SAAS,EACT,GAAG,OAAO,CAAC,OAAO,eAAe,aAAa,EAAE,CACjD,CAAA;YACD,MAAM,GAAG,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAA;QAC3C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,KAAK,CAAC,CAAA;YACrD,MAAM,GAAG,CAAC,aAAa,CAAC,0BAA0B,CAAC,CAAA;QACrD,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE;QACrB,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;YAClD,KAAK,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAA;YACjC,OAAM;QACR,CAAC;QAED,IAAI,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,OAAM;QACR,CAAC;QAED,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAA;QAC7B,MAAM,SAAS,GAAG,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QAC3C,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,EAAE,CAAA;QAC3B,MAAM,gBAAgB,GAAG,GAAG,CAAC,OAAO,CAAC,UAAU,CAAA;QAE/C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,CAAC,sCAAsC,EAAE,EAAE,SAAS,EAAE,CAAC,CAAA;YACnE,KAAK,GAAG,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;YACvC,OAAM;QACR,CAAC;QAED,MAAM,WAAW,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAA;QAC/C,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC,WAAW,CAAC,CAAA;QAChD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAA;YAClE,KAAK,GAAG,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAA;YAChD,OAAM;QACR,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,cAAc,SAAS,KAAK,IAAI,EAAE,CAAC,CAAA;QAE/C;;;;WAIG;QACH;;;;WAIG;QACH,IAAI,QAAQ,GAAG,KAAK,CAAA;QACpB,MAAM,eAAe,GAAG,WAAW,CAAC,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE;YACxD,QAAQ,GAAG,IAAI,CAAA;YACf,KAAK,SAAS,CACZ,MAAM,EACN,gBAAgB,EAChB,yDAAyD,CAC1D,CAAA;QACH,CAAC,CAAC,CAAA;QAEF,IAAI,CAAC,eAAe,EAAE,CAAC;YACrB,KAAK,SAAS,CACZ,MAAM,EACN,gBAAgB,EAChB,kFAAkF,CACnF,CAAA;YACD,OAAM;QACR,CAAC;QAED,KAAK,CAAC,KAAK,IAAI,EAAE;YACf,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,cAAc,CACzC,MAAM,EACN,IAAI,EACJ,OAAO,CAAC,IAAI,EACZ,EAAE,MAAM,EAAE,eAAe,CAAC,MAAM,EAAE,CACnC,CAAA;gBACD,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACd,MAAM,SAAS,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,CAAC,CAAA;gBAClD,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,KAAK,CAAC,CAAA;gBACzD,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACd,MAAM,SAAS,CACb,MAAM,EACN,gBAAgB,EAChB,oCAAoC,CACrC,CAAA;gBACH,CAAC;YACH,CAAC;oBAAS,CAAC;gBACT,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YAC5B,CAAC;QACH,CAAC,CAAC,EAAE,CAAA;IACN,CAAC,CAAC,CAAA;IAEF,GAAG,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACvB,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE;YAClC,KAAK;YACL,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS;SAC/B,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,GAAG,CAAC,MAAM,EAAE,CAAA;IACZ,OAAO,GAAG,CAAA;AACZ,CAAC,CAAA"}
@@ -0,0 +1,14 @@
1
+ export type BotConfig = {
2
+ botToken: string;
3
+ allowedUserId: number;
4
+ opencode: OpencodeConfig;
5
+ handlerTimeoutMs: number;
6
+ promptTimeoutMs: number;
7
+ };
8
+ export type OpencodeConfig = {
9
+ serverUrl: string;
10
+ serverUsername: string;
11
+ serverPassword?: string;
12
+ };
13
+ export declare const loadConfig: () => BotConfig;
14
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;IACrB,QAAQ,EAAE,cAAc,CAAA;IACxB,gBAAgB,EAAE,MAAM,CAAA;IACxB,eAAe,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,MAAM,CAAA;IACtB,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,CAAA;AA+BD,eAAO,MAAM,UAAU,QAAO,SAwC7B,CAAA"}
package/dist/config.js ADDED
@@ -0,0 +1,49 @@
1
+ const parseAllowedUserId = (rawValue) => {
2
+ if (!rawValue) {
3
+ throw new Error("Missing TELEGRAM_ALLOWED_USER_ID");
4
+ }
5
+ const parsedValue = Number(rawValue);
6
+ if (!Number.isInteger(parsedValue)) {
7
+ throw new Error("TELEGRAM_ALLOWED_USER_ID must be an integer");
8
+ }
9
+ return parsedValue;
10
+ };
11
+ const parseDurationMs = (rawValue, label) => {
12
+ if (!rawValue) {
13
+ return undefined;
14
+ }
15
+ const parsedValue = Number(rawValue);
16
+ if (!Number.isFinite(parsedValue) || parsedValue < 0) {
17
+ throw new Error(`${label} must be a non-negative number`);
18
+ }
19
+ return parsedValue;
20
+ };
21
+ export const loadConfig = () => {
22
+ const botToken = process.env.TELEGRAM_BOT_TOKEN;
23
+ if (!botToken) {
24
+ throw new Error("Missing TELEGRAM_BOT_TOKEN");
25
+ }
26
+ const allowedUserId = parseAllowedUserId(process.env.TELEGRAM_ALLOWED_USER_ID);
27
+ const serverUrl = process.env.OPENCODE_SERVER_URL;
28
+ if (!serverUrl) {
29
+ throw new Error("Missing OPENCODE_SERVER_URL");
30
+ }
31
+ const opencode = {
32
+ serverUrl,
33
+ serverUsername: process.env.OPENCODE_SERVER_USERNAME ?? "opencode",
34
+ };
35
+ const serverPassword = process.env.OPENCODE_SERVER_PASSWORD;
36
+ if (serverPassword) {
37
+ opencode.serverPassword = serverPassword;
38
+ }
39
+ const promptTimeoutMs = parseDurationMs(process.env.OPENCODE_PROMPT_TIMEOUT_MS, "OPENCODE_PROMPT_TIMEOUT_MS") ?? 10 * 60 * 1000;
40
+ const handlerTimeoutMs = parseDurationMs(process.env.TELEGRAM_HANDLER_TIMEOUT_MS, "TELEGRAM_HANDLER_TIMEOUT_MS") ?? promptTimeoutMs + 30_000;
41
+ return {
42
+ botToken,
43
+ allowedUserId,
44
+ opencode,
45
+ handlerTimeoutMs,
46
+ promptTimeoutMs,
47
+ };
48
+ };
49
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAcA,MAAM,kBAAkB,GAAG,CAAC,QAA4B,EAAU,EAAE;IAClE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAA;IACrD,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAA;IACpC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAA;IAChE,CAAC;IAED,OAAO,WAAW,CAAA;AACpB,CAAC,CAAA;AAED,MAAM,eAAe,GAAG,CACtB,QAA4B,EAC5B,KAAa,EACO,EAAE;IACtB,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAA;IACpC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;QACrD,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,gCAAgC,CAAC,CAAA;IAC3D,CAAC;IAED,OAAO,WAAW,CAAA;AACpB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,GAAc,EAAE;IACxC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAA;IAC/C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAA;IAC/C,CAAC;IAED,MAAM,aAAa,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAA;IAC9E,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAA;IACjD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAA;IAChD,CAAC;IAED,MAAM,QAAQ,GAAmB;QAC/B,SAAS;QACT,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,UAAU;KACnE,CAAA;IAED,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAA;IAC3D,IAAI,cAAc,EAAE,CAAC;QACnB,QAAQ,CAAC,cAAc,GAAG,cAAc,CAAA;IAC1C,CAAC;IAED,MAAM,eAAe,GACnB,eAAe,CACb,OAAO,CAAC,GAAG,CAAC,0BAA0B,EACtC,4BAA4B,CAC7B,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;IACrB,MAAM,gBAAgB,GACpB,eAAe,CACb,OAAO,CAAC,GAAG,CAAC,2BAA2B,EACvC,6BAA6B,CAC9B,IAAI,eAAe,GAAG,MAAM,CAAA;IAE/B,OAAO;QACL,QAAQ;QACR,aAAa;QACb,QAAQ;QACR,gBAAgB;QAChB,eAAe;KAChB,CAAA;AACH,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ import "dotenv/config";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ import "dotenv/config";
2
+ import { loadConfig } from "./config.js";
3
+ import { startBot } from "./bot.js";
4
+ import { createOpencodeBridge } from "./opencode.js";
5
+ import { createProjectStore } from "./projects.js";
6
+ import { createChatProjectStore, createPersistentSessionStore } from "./state.js";
7
+ const config = loadConfig();
8
+ const sessionStore = createPersistentSessionStore();
9
+ const opencode = createOpencodeBridge(config.opencode, { sessionStore });
10
+ const projects = createProjectStore();
11
+ const chatProjects = createChatProjectStore();
12
+ const bot = startBot(config, opencode, projects, chatProjects);
13
+ process.once("SIGINT", () => bot.stop("SIGINT"));
14
+ process.once("SIGTERM", () => bot.stop("SIGTERM"));
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAA;AAEtB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AACnC,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAClD,OAAO,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,MAAM,YAAY,CAAA;AAEjF,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;AAC3B,MAAM,YAAY,GAAG,4BAA4B,EAAE,CAAA;AACnD,MAAM,QAAQ,GAAG,oBAAoB,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,YAAY,EAAE,CAAC,CAAA;AACxE,MAAM,QAAQ,GAAG,kBAAkB,EAAE,CAAA;AACrC,MAAM,YAAY,GAAG,sBAAsB,EAAE,CAAA;AAC7C,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAA;AAE9D,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAA;AAChD,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAA"}
@@ -0,0 +1,38 @@
1
+ import type { PermissionRequest } from "@opencode-ai/sdk/v2";
2
+ import type { OpencodeConfig } from "./config.js";
3
+ export type OpencodeBridge = {
4
+ promptFromChat: (chatId: number, text: string, projectDir: string, options?: PromptOptions) => Promise<string>;
5
+ resetSession: (chatId: number, projectDir: string) => boolean;
6
+ getSessionOwner: (sessionId: string) => SessionOwner | null;
7
+ replyToPermission: (requestId: string, reply: PermissionReply, directory?: string) => Promise<boolean>;
8
+ startPermissionEventStream: (handlers: PermissionEventHandlers) => {
9
+ stop: () => void;
10
+ };
11
+ };
12
+ export type SessionStore = {
13
+ getSessionId: (chatId: number, projectDir: string) => string | undefined;
14
+ setSessionId: (chatId: number, projectDir: string, sessionId: string) => void;
15
+ clearSession: (chatId: number, projectDir: string) => boolean;
16
+ getSessionOwner: (sessionId: string) => SessionOwner | null;
17
+ };
18
+ export type OpencodeBridgeOptions = {
19
+ sessionStore?: SessionStore;
20
+ };
21
+ export type PromptOptions = {
22
+ signal?: AbortSignal;
23
+ };
24
+ export type PermissionReply = "once" | "always" | "reject";
25
+ export type SessionOwner = {
26
+ chatId: number;
27
+ projectDir: string;
28
+ };
29
+ export type PermissionEventHandlers = {
30
+ onPermissionAsked: (event: {
31
+ request: PermissionRequest;
32
+ directory: string;
33
+ }) => void | Promise<void>;
34
+ onError?: (error: unknown) => void;
35
+ };
36
+ export declare const createSessionStore: () => SessionStore;
37
+ export declare const createOpencodeBridge: (config: OpencodeConfig, options?: OpencodeBridgeOptions) => OpencodeBridge;
38
+ //# sourceMappingURL=opencode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode.d.ts","sourceRoot":"","sources":["../src/opencode.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAqB,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAE/E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAEjD,MAAM,MAAM,cAAc,GAAG;IAC3B,cAAc,EAAE,CACd,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,aAAa,KACpB,OAAO,CAAC,MAAM,CAAC,CAAA;IACpB,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAA;IAC7D,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,YAAY,GAAG,IAAI,CAAA;IAC3D,iBAAiB,EAAE,CACjB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,eAAe,EACtB,SAAS,CAAC,EAAE,MAAM,KACf,OAAO,CAAC,OAAO,CAAC,CAAA;IACrB,0BAA0B,EAAE,CAAC,QAAQ,EAAE,uBAAuB,KAAK;QACjE,IAAI,EAAE,MAAM,IAAI,CAAA;KACjB,CAAA;CACF,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAA;IACxE,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IAC7E,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAA;IAC7D,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,YAAY,GAAG,IAAI,CAAA;CAC5D,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,YAAY,CAAC,EAAE,YAAY,CAAA;CAC5B,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAA;AAE1D,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,iBAAiB,EAAE,CAAC,KAAK,EAAE;QACzB,OAAO,EAAE,iBAAiB,CAAA;QAC1B,SAAS,EAAE,MAAM,CAAA;KAClB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CACnC,CAAA;AA8BD,eAAO,MAAM,kBAAkB,QAAO,YA4BrC,CAAA;AAED,eAAO,MAAM,oBAAoB,GAC/B,QAAQ,cAAc,EACtB,UAAS,qBAA0B,KAClC,cAyHF,CAAA"}