virtualcode 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.
package/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # opencode-telegram
2
+
3
+ A [OpenCode](https://opencode.ai) plugin that bridges your terminal sessions with Telegram.
4
+
5
+ Send prompts from your phone via Telegram and receive LLM responses in real time. Also lets the LLM send messages back to you via a `telegram_send` tool.
6
+
7
+ ## Features
8
+
9
+ - **Bidirectional**: Send prompts from Telegram, get responses back
10
+ - **`/link` sessions**: Bind a Telegram chat to an OpenCode session
11
+ - **`telegram_send` tool**: LLM can proactively message you on Telegram
12
+ - **Multi-session**: One chat linked to one session; multiple chats can link to the same session
13
+ - **Persistent links**: Session-chat bindings survive restarts
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install @opencode-ai/plugin-telegram
19
+ ```
20
+
21
+ Then add it to your `.opencode/opencode.json`:
22
+
23
+ ```json
24
+ {
25
+ "plugins": [
26
+ ["@opencode-ai/plugin-telegram", {
27
+ "token": "YOUR_BOT_TOKEN",
28
+ "allowed_users": [YOUR_TELEGRAM_ID]
29
+ }]
30
+ ]
31
+ }
32
+ ```
33
+
34
+ ## Configuration
35
+
36
+ | Option | Type | Default | Description |
37
+ |--------|------|---------|-------------|
38
+ | `token` | `string` | `env.TELEGRAM_BOT_TOKEN` | Telegram bot token |
39
+ | `allowed_users` | `number[]` | `null` (all) | Restrict to specific Telegram user IDs |
40
+ | `notify_on_reconnect` | `boolean` | `false` | Send reconnection notice to linked chats |
41
+
42
+ ## Commands
43
+
44
+ - `/link <sessionId>` — Bind this chat to a session
45
+ - `/unlink` — Remove binding
46
+ - `/status` — Show connection state
47
+ - `/sessions` — List recent sessions
48
+ - `/help` — Show this help
49
+
50
+ ## License
51
+
52
+ MIT
@@ -0,0 +1,7 @@
1
+ import { type Plugin } from "@opencode-ai/plugin";
2
+ declare const _default: {
3
+ id: string;
4
+ server: Plugin;
5
+ };
6
+ export default _default;
7
+ //# 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,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAA;;;;;AA4ajD,wBAGC"}
package/dist/index.js ADDED
@@ -0,0 +1,424 @@
1
+ import { tool } from "@opencode-ai/plugin/tool";
2
+ import { Telegraf } from "telegraf";
3
+ import { readFileSync, writeFileSync, mkdirSync, existsSync, renameSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { homedir } from "node:os";
6
+ const LINK_FILE = join(homedir(), ".config", "opencode", "telegram-links.json");
7
+ const LINK_TMP = LINK_FILE + ".tmp";
8
+ const TOKEN_FILE = join(homedir(), ".config", "opencode", "telegram-token.json");
9
+ const TOKEN_TMP = TOKEN_FILE + ".tmp";
10
+ const CONFIG_DIR = join(homedir(), ".config", "opencode");
11
+ function loadLinks() {
12
+ try {
13
+ if (existsSync(LINK_FILE)) {
14
+ return JSON.parse(readFileSync(LINK_FILE, "utf-8"));
15
+ }
16
+ }
17
+ catch { }
18
+ return {};
19
+ }
20
+ function persistLinks(links) {
21
+ mkdirSync(CONFIG_DIR, { recursive: true });
22
+ writeFileSync(LINK_TMP, JSON.stringify(links, null, 2));
23
+ try {
24
+ renameSync(LINK_TMP, LINK_FILE);
25
+ }
26
+ catch {
27
+ writeFileSync(LINK_FILE, JSON.stringify(links, null, 2));
28
+ }
29
+ }
30
+ function loadSavedToken() {
31
+ try {
32
+ if (existsSync(TOKEN_FILE)) {
33
+ const data = JSON.parse(readFileSync(TOKEN_FILE, "utf-8"));
34
+ if (data?.token)
35
+ return data.token;
36
+ }
37
+ }
38
+ catch { }
39
+ return null;
40
+ }
41
+ function saveToken(token) {
42
+ mkdirSync(CONFIG_DIR, { recursive: true });
43
+ writeFileSync(TOKEN_TMP, JSON.stringify({ token }, null, 2));
44
+ try {
45
+ renameSync(TOKEN_TMP, TOKEN_FILE);
46
+ }
47
+ catch {
48
+ writeFileSync(TOKEN_FILE, JSON.stringify({ token }, null, 2));
49
+ }
50
+ }
51
+ function chunkText(text, maxLen = 4000) {
52
+ if (text.length <= maxLen)
53
+ return [text];
54
+ const chunks = [];
55
+ for (let i = 0; i < text.length; i += maxLen) {
56
+ chunks.push(text.slice(i, i + maxLen));
57
+ }
58
+ return chunks;
59
+ }
60
+ const TelegramPlugin = async ({ client, directory }, options) => {
61
+ console.log("[telegram-plugin] initializing");
62
+ const config = options;
63
+ const allowedSet = config?.allowed_users?.length ? new Set(config.allowed_users) : null;
64
+ const notifyOnReconnect = config?.notify_on_reconnect ?? false;
65
+ let bot = null;
66
+ let botReady = false;
67
+ let botStarting = false;
68
+ const lastForwardedBySession = new Map();
69
+ const pendingTelegram = new Map();
70
+ const links = loadLinks();
71
+ const chatToSession = new Map();
72
+ const sessionToChats = new Map();
73
+ function rebuildMaps() {
74
+ chatToSession.clear();
75
+ sessionToChats.clear();
76
+ for (const [chatId, sessionId] of Object.entries(links)) {
77
+ const cid = Number(chatId);
78
+ chatToSession.set(cid, sessionId);
79
+ let set = sessionToChats.get(sessionId);
80
+ if (!set) {
81
+ set = new Set();
82
+ sessionToChats.set(sessionId, set);
83
+ }
84
+ set.add(cid);
85
+ }
86
+ }
87
+ rebuildMaps();
88
+ function addLink(chatId, sessionId) {
89
+ links[chatId] = sessionId;
90
+ chatToSession.set(chatId, sessionId);
91
+ let set = sessionToChats.get(sessionId);
92
+ if (!set) {
93
+ set = new Set();
94
+ sessionToChats.set(sessionId, set);
95
+ }
96
+ set.add(chatId);
97
+ persistLinks(links);
98
+ }
99
+ function removeLink(chatId) {
100
+ const sessionId = links[chatId];
101
+ if (!sessionId)
102
+ return;
103
+ delete links[chatId];
104
+ chatToSession.delete(chatId);
105
+ const set = sessionToChats.get(sessionId);
106
+ if (set) {
107
+ set.delete(chatId);
108
+ if (set.size === 0)
109
+ sessionToChats.delete(sessionId);
110
+ }
111
+ persistLinks(links);
112
+ }
113
+ async function sendToChats(chats, text) {
114
+ if (!botReady)
115
+ return;
116
+ const chunks = chunkText(text);
117
+ for (const chatId of chats) {
118
+ for (const chunk of chunks) {
119
+ await bot.telegram.sendMessage(chatId, chunk).catch(() => { });
120
+ }
121
+ }
122
+ }
123
+ async function sendToSession(sessionId, text) {
124
+ const chats = sessionToChats.get(sessionId);
125
+ if (!chats)
126
+ return;
127
+ await sendToChats(chats, text);
128
+ }
129
+ async function startBot(token) {
130
+ if (botStarting)
131
+ return;
132
+ botStarting = true;
133
+ botReady = false;
134
+ try {
135
+ bot?.stop();
136
+ bot = new Telegraf(token);
137
+ bot.command("link", async (ctx) => {
138
+ if (allowedSet && !allowedSet.has(ctx.from.id))
139
+ return;
140
+ const sessionId = ctx.payload.trim();
141
+ if (!sessionId) {
142
+ await ctx.reply("Usage: /link <sessionId>");
143
+ return;
144
+ }
145
+ const res = await client.session.get({ path: { id: sessionId } });
146
+ if (res.error) {
147
+ await ctx.reply("Session not found: " + sessionId.slice(0, 12) + "...");
148
+ return;
149
+ }
150
+ addLink(ctx.chat.id, sessionId);
151
+ await ctx.reply("Linked to session: " + sessionId.slice(0, 12) + "...");
152
+ });
153
+ bot.command("unlink", async (ctx) => {
154
+ if (allowedSet && !allowedSet.has(ctx.from.id))
155
+ return;
156
+ if (!links[ctx.chat.id]) {
157
+ await ctx.reply("No link found for this chat.");
158
+ return;
159
+ }
160
+ removeLink(ctx.chat.id);
161
+ await ctx.reply("Unlinked from session.");
162
+ });
163
+ bot.command("status", async (ctx) => {
164
+ if (allowedSet && !allowedSet.has(ctx.from.id))
165
+ return;
166
+ const sessionId = links[ctx.chat.id];
167
+ if (!sessionId) {
168
+ await ctx.reply("Not linked. Use /link <sessionId>");
169
+ return;
170
+ }
171
+ await ctx.reply("Connected\nSession: " + sessionId.slice(0, 12) + "...\nProject: " + (directory || "unknown"));
172
+ });
173
+ bot.command(["ls", "sessions"], async (ctx) => {
174
+ if (allowedSet && !allowedSet.has(ctx.from.id))
175
+ return;
176
+ const res = await client.session.list();
177
+ if (res.error || !res.data) {
178
+ await ctx.reply("Failed to list sessions.");
179
+ return;
180
+ }
181
+ const current = links[ctx.chat.id];
182
+ const lines = res.data.slice(-20).map((s, i, arr) => {
183
+ const num = arr.length - i;
184
+ const marker = s.id === current ? " \u2705" : "";
185
+ const title = s.title || s.id.slice(0, 12);
186
+ return `${num}. ${title}${marker}`;
187
+ });
188
+ await ctx.reply("Sessions:\n" + (lines.length ? lines.join("\n") : "None"));
189
+ });
190
+ bot.command("use", async (ctx) => {
191
+ if (allowedSet && !allowedSet.has(ctx.from.id))
192
+ return;
193
+ const arg = ctx.payload.trim();
194
+ if (!arg) {
195
+ await ctx.reply("Usage: /use <sessionId | number>");
196
+ return;
197
+ }
198
+ const res = await client.session.list();
199
+ if (!res.error && res.data) {
200
+ const num = parseInt(arg);
201
+ if (!isNaN(num) && num > 0 && num <= res.data.length) {
202
+ const s = res.data[res.data.length - num];
203
+ if (!s)
204
+ return;
205
+ addLink(ctx.chat.id, s.id);
206
+ await ctx.reply("Switched to: " + (s.title || s.id.slice(0, 12)));
207
+ return;
208
+ }
209
+ }
210
+ const sessionId = arg;
211
+ const check = await client.session.get({ path: { id: sessionId } });
212
+ if (check.error) {
213
+ await ctx.reply("Session not found: " + sessionId.slice(0, 12) + "...");
214
+ return;
215
+ }
216
+ addLink(ctx.chat.id, sessionId);
217
+ await ctx.reply("Switched to: " + sessionId.slice(0, 12) + "...");
218
+ });
219
+ bot.command("history", async (ctx) => {
220
+ if (allowedSet && !allowedSet.has(ctx.from.id))
221
+ return;
222
+ const sessionId = links[ctx.chat.id];
223
+ if (!sessionId) {
224
+ await ctx.reply("Not linked. Use /link <sessionId>");
225
+ return;
226
+ }
227
+ const limitText = ctx.payload.trim();
228
+ const limit = limitText ? Math.min(parseInt(limitText) || 20, 100) : 20;
229
+ const res = await client.session.messages({ path: { id: sessionId }, query: { directory, limit } });
230
+ if (res.error || !res.data || res.data.length === 0) {
231
+ await ctx.reply("No messages found.");
232
+ return;
233
+ }
234
+ const lines = [];
235
+ for (const msg of res.data) {
236
+ const role = msg.info.role === "user" ? "\uD83D\uDC64 User" : "\uD83E\uDD16 OpenCode";
237
+ const text = msg.parts
238
+ .filter((p) => p.type === "text" && !p.synthetic)
239
+ .map((p) => p.text)
240
+ .join("\n")
241
+ .trim();
242
+ if (!text)
243
+ continue;
244
+ const truncated = text.length > 500 ? text.slice(0, 500) + "..." : text;
245
+ lines.push(role + "\n" + truncated);
246
+ }
247
+ if (lines.length === 0) {
248
+ await ctx.reply("No text messages found.");
249
+ return;
250
+ }
251
+ const text = lines.join("\n\n");
252
+ for (const chunk of chunkText(text)) {
253
+ await ctx.reply(chunk);
254
+ }
255
+ });
256
+ bot.command("help", async (ctx) => {
257
+ if (allowedSet && !allowedSet.has(ctx.from.id))
258
+ return;
259
+ await ctx.reply("/link <sessionId> - Bind this chat to a session\n" +
260
+ "/unlink - Remove binding\n" +
261
+ "/status - Show connection state\n" +
262
+ "/ls - List recent sessions\n" +
263
+ "/use <N|id> - Switch active session\n" +
264
+ "/history [N] - View last N messages\n" +
265
+ "/help - Show this help\n\n" +
266
+ "Any other message will be sent to the linked session.");
267
+ });
268
+ bot.on("text", async (ctx) => {
269
+ if (allowedSet && !allowedSet.has(ctx.from.id))
270
+ return;
271
+ const sessionId = links[ctx.chat.id];
272
+ if (!sessionId) {
273
+ await ctx.reply("Not linked. Use /link <sessionId>");
274
+ return;
275
+ }
276
+ const working = await ctx.reply("\u23F3 Working...");
277
+ pendingTelegram.set(sessionId, ctx.chat.id);
278
+ const res = await client.session.prompt({
279
+ path: { id: sessionId },
280
+ body: {
281
+ parts: [{ type: "text", text: ctx.message.text, metadata: { opencodeTelegram: true } }],
282
+ },
283
+ query: { directory },
284
+ });
285
+ pendingTelegram.delete(sessionId);
286
+ try {
287
+ await ctx.deleteMessage(working.message_id);
288
+ }
289
+ catch { }
290
+ if (res.error) {
291
+ await ctx.reply("Error: " + String(res.error).slice(0, 200));
292
+ }
293
+ });
294
+ if (notifyOnReconnect) {
295
+ for (const chatId of Object.keys(links)) {
296
+ bot.telegram.sendMessage(Number(chatId), "OpenCode Telegram bridge reconnected.").catch(() => { });
297
+ }
298
+ }
299
+ await bot.telegram.getMe();
300
+ botReady = true;
301
+ botStarting = false;
302
+ bot.launch().catch((err) => {
303
+ console.warn("[telegram-plugin] bot polling error:", err);
304
+ botReady = false;
305
+ });
306
+ console.log("[telegram-plugin] bot connected");
307
+ }
308
+ catch (err) {
309
+ botStarting = false;
310
+ botReady = false;
311
+ console.warn("[telegram-plugin] bot failed to start:", err);
312
+ }
313
+ }
314
+ const existingToken = config?.token || process.env.TELEGRAM_BOT_TOKEN || loadSavedToken();
315
+ if (existingToken) {
316
+ console.log("[telegram-plugin] token found, creating bot");
317
+ await startBot(existingToken);
318
+ }
319
+ else {
320
+ console.log("[telegram-plugin] no token found — type /telegram in OpenCode to set up");
321
+ }
322
+ return {
323
+ async event({ event }) {
324
+ if (!botReady)
325
+ return;
326
+ if (event.type === "session.error") {
327
+ const sessionId = event.properties.sessionID;
328
+ if (sessionId) {
329
+ const err = event.properties.error;
330
+ const msg = err && "data" in err ? String(err.data.message) : String(err ?? "Unknown");
331
+ sendToSession(sessionId, "Error: " + msg.slice(0, 500));
332
+ }
333
+ return;
334
+ }
335
+ if (event.type === "session.status" && event.properties.status.type === "idle") {
336
+ const sid = event.properties.sessionID;
337
+ const pending = pendingTelegram.get(sid);
338
+ const chats = pending ? new Set([pending]) : sessionToChats.get(sid);
339
+ if (!chats || chats.size === 0)
340
+ return;
341
+ let msgs;
342
+ try {
343
+ msgs = await client.session.messages({ path: { id: sid }, query: { directory, limit: 5 } });
344
+ }
345
+ catch {
346
+ return;
347
+ }
348
+ if (msgs.error || !msgs.data)
349
+ return;
350
+ const last = [...msgs.data].reverse().find((m) => m.info.role === "assistant");
351
+ if (!last || lastForwardedBySession.get(sid) === last.info.id)
352
+ return;
353
+ lastForwardedBySession.set(sid, last.info.id);
354
+ const text = last.parts
355
+ .filter((p) => p.type === "text" && !p.synthetic)
356
+ .map((p) => p.text)
357
+ .join("\n");
358
+ if (text)
359
+ sendToChats(chats, text);
360
+ }
361
+ },
362
+ "chat.message": async (_input, output) => {
363
+ if (!botReady) {
364
+ const saved = loadSavedToken();
365
+ if (saved) {
366
+ console.log("[telegram-plugin] token found from TUI setup, connecting...");
367
+ await startBot(saved);
368
+ }
369
+ }
370
+ for (const part of output.parts) {
371
+ if (part.type !== "text")
372
+ continue;
373
+ const text = part.text;
374
+ if (text.startsWith("/telegram")) {
375
+ const token = text.slice("/telegram".length).trim();
376
+ if (!token) {
377
+ part.text = botReady
378
+ ? "Telegram bot is already connected. Status: connected."
379
+ : "The user ran /telegram to set up Telegram. Guide them through the setup.";
380
+ return;
381
+ }
382
+ client.tui.showToast({
383
+ body: { title: "Telegram", message: "Connecting...", variant: "info" },
384
+ query: { directory },
385
+ }).catch(() => { });
386
+ saveToken(token);
387
+ await startBot(token);
388
+ if (botReady) {
389
+ client.tui.showToast({
390
+ body: { title: "Telegram", message: "Bot connected!", variant: "success", duration: 3000 },
391
+ query: { directory },
392
+ }).catch(() => { });
393
+ }
394
+ part.text = botReady
395
+ ? "\u2705 Telegram bot connected!"
396
+ : "\u274c Invalid token. Check the token from @BotFather and try again.";
397
+ return;
398
+ }
399
+ }
400
+ },
401
+ tool: {
402
+ telegram_send: tool({
403
+ description: "Send a message to Telegram chat(s) linked to the current session",
404
+ args: {
405
+ text: tool.schema.string().describe("Text to send"),
406
+ sessionId: tool.schema.string().optional().describe("Target session ID (defaults to current)"),
407
+ },
408
+ async execute({ text, sessionId }, ctx) {
409
+ const targetId = sessionId || ctx.sessionID;
410
+ await sendToSession(targetId, text);
411
+ return { output: "Message sent to Telegram" };
412
+ },
413
+ }),
414
+ },
415
+ async dispose() {
416
+ bot?.stop();
417
+ },
418
+ };
419
+ };
420
+ export default {
421
+ id: "virtualcode",
422
+ server: TelegramPlugin,
423
+ };
424
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/tui.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ declare const TuiPlugin: {
2
+ id: string;
3
+ tui(api: any): Promise<void>;
4
+ };
5
+ export default TuiPlugin;
6
+ //# sourceMappingURL=tui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"AAOA,QAAA,MAAM,SAAS;;aAEE,GAAG;CAmCnB,CAAA;AAED,eAAe,SAAS,CAAA"}
package/dist/tui.js ADDED
@@ -0,0 +1,44 @@
1
+ import { writeFileSync, mkdirSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { homedir } from "node:os";
4
+ const CONFIG_DIR = join(homedir(), ".config", "opencode");
5
+ const TOKEN_FILE = join(CONFIG_DIR, "telegram-token.json");
6
+ const TuiPlugin = {
7
+ id: "@opencode-ai/plugin-telegram/tui",
8
+ async tui(api) {
9
+ api.keymap.registerLayer({
10
+ commands: [
11
+ {
12
+ namespace: "palette",
13
+ name: "telegram.setup",
14
+ title: "/telegram",
15
+ category: "Telegram",
16
+ run() {
17
+ api.ui.dialog.replace(() => api.ui.DialogPrompt({
18
+ title: "Telegram Setup",
19
+ placeholder: "Paste your BotFather token here",
20
+ onConfirm(token) {
21
+ if (!token?.trim())
22
+ return;
23
+ mkdirSync(CONFIG_DIR, { recursive: true });
24
+ writeFileSync(TOKEN_FILE, JSON.stringify({ token: token.trim() }, null, 2));
25
+ api.ui.toast({
26
+ title: "Telegram",
27
+ message: "Token saved! Restart OpenCode to connect.",
28
+ variant: "success",
29
+ duration: 4000,
30
+ });
31
+ api.ui.dialog.clear();
32
+ },
33
+ onCancel() {
34
+ api.ui.dialog.clear();
35
+ },
36
+ }));
37
+ },
38
+ },
39
+ ],
40
+ });
41
+ },
42
+ };
43
+ export default TuiPlugin;
44
+ //# sourceMappingURL=tui.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui.js","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAEjC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,UAAU,CAAC,CAAA;AACzD,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,qBAAqB,CAAC,CAAA;AAE1D,MAAM,SAAS,GAAG;IAChB,EAAE,EAAE,kCAAkC;IACtC,KAAK,CAAC,GAAG,CAAC,GAAQ;QAChB,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC;YACvB,QAAQ,EAAE;gBACR;oBACE,SAAS,EAAE,SAAS;oBACpB,IAAI,EAAE,gBAAgB;oBACtB,KAAK,EAAE,WAAW;oBAClB,QAAQ,EAAE,UAAU;oBACpB,GAAG;wBACD,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CACzB,GAAG,CAAC,EAAE,CAAC,YAAY,CAAC;4BAClB,KAAK,EAAE,gBAAgB;4BACvB,WAAW,EAAE,iCAAiC;4BAC9C,SAAS,CAAC,KAAa;gCACrB,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE;oCAAE,OAAM;gCAC1B,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;gCAC1C,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;gCAC3E,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC;oCACX,KAAK,EAAE,UAAU;oCACjB,OAAO,EAAE,2CAA2C;oCACpD,OAAO,EAAE,SAAS;oCAClB,QAAQ,EAAE,IAAI;iCACf,CAAC,CAAA;gCACF,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,CAAA;4BACvB,CAAC;4BACD,QAAQ;gCACN,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,CAAA;4BACvB,CAAC;yBACF,CAAC,CACH,CAAA;oBACH,CAAC;iBACF;aACF;SACF,CAAC,CAAA;IACJ,CAAC;CACF,CAAA;AAED,eAAe,SAAS,CAAA"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "virtualcode",
3
+ "version": "1.0.0",
4
+ "description": "OpenCode plugin that bridges your terminal sessions with Telegram",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ },
14
+ "./tui": {
15
+ "types": "./dist/tui.d.ts",
16
+ "import": "./dist/tui.js"
17
+ }
18
+ },
19
+ "files": [
20
+ "dist"
21
+ ],
22
+ "scripts": {
23
+ "build": "tsc",
24
+ "prepublishOnly": "npm run build",
25
+ "typecheck": "tsc --noEmit"
26
+ },
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "git+https://github.com/anomalyco/opencode-telegram.git"
30
+ },
31
+ "keywords": [
32
+ "opencode",
33
+ "telegram",
34
+ "plugin",
35
+ "ai"
36
+ ],
37
+ "dependencies": {
38
+ "@opencode-ai/plugin": "^1.17.8",
39
+ "telegraf": "^4.16.3",
40
+ "virtualcode-telegram": "^1.0.0"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^22.0.0",
44
+ "typescript": "^5.8.0"
45
+ }
46
+ }