Diff
1diff --git a/README.md b/README.md
2index 3ed441dd3e42dc7dfc9fda6687d5d3cb7ad1944f..3b3110476531a35ee97517b06d34a60c3e6342dc 100644
3--- a/README.md
4+++ b/README.md
5@@ -1,15 +1,65 @@
6 # opencode-telegram
7
8-To install dependencies:
9+A Telegram bot plugin for [opencode](https://github.com/opencode-ai/opencode) that bridges Telegram chats to opencode. Send prompts and receive streamed responses directly in Telegram.
10
11-```bash
12-bun install
13+## Features
14+
15+- **Streaming responses** — responses are streamed with real-time edit-in-place updates
16+- **Session management** — create, list, and switch between opencode sessions
17+- **Agent switching** — list available agents or switch to a specific one
18+- **Permission handling** — inline keyboard buttons to allow/deny tool execution requests
19+- **Tool output formatting** — tool calls rendered as code blocks with name, target, and truncated output
20+- **Message splitting** — long responses are split respecting Telegram's 4096-char limit and code block boundaries
21+- **Auth** — only allowed Telegram user IDs can interact with the bot
22+
23+### Bot commands
24+
25+| Command | Description |
26+| --------------- | ------------------------------------------------------------- |
27+| `/new` | Create a new opencode session |
28+| `/sessions` | List all sessions with inline keyboard to switch between them |
29+| `/abort` | Abort the current in-flight prompt |
30+| `/agent [name]` | List available agents or switch to a specific one |
31+| _(text)_ | Send as a prompt to the active opencode session |
32+
33+## Installation
34+
35+Add the plugin to your opencode config (`~/.config/opencode/config.json`):
36+
37+```json
38+{
39+ "plugin": ["@theedgeofrage/opencode-telegram@latest"]
40+}
41 ```
42
43-To run:
44+## Configuration
45+
46+Create `~/.config/opencode/telegram.json`:
47
48-```bash
49-bun run
50+```json
51+{
52+ "token": "<telegram-bot-token>",
53+ "allowedUsers": [123456789]
54+}
55 ```
56
57-This project was created using `bun init` in bun v1.3.11. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
58+- `token` — Telegram Bot API token from [@BotFather](https://t.me/BotFather)
59+- `allowedUsers` — array of numeric Telegram user IDs authorized to use the bot
60+
61+## Usage
62+
63+Once installed and configured, ask opencode to connect to Telegram:
64+
65+> Connect telegram
66+
67+This starts the bot and attaches it to the current opencode session. All messages sent to the bot in Telegram will be routed to this session.
68+
69+Alternatively, set the `TELEGRAM_AUTOCONNECT=1` environment variable to start the bot automatically when the plugin loads. Useful when starting opencode as a headless server.
70+
71+## Limitations
72+
73+- Connecting multiple opencode sessions to one bot is not supported
74+- Text-only — no support for photos, files, voice messages, or other media; only text messages are handled
75+- MarkdownV2 rendering — some LLM outputs with complex formatting may render incorrectly in Telegram
76+- Tool output truncation — tool outputs are truncated to 3000 characters
77+- Agent selection not persisted — per-chat agent choice is lost on restart
78diff --git a/src/telegram.ts b/src/telegram.ts
79index 3dd876f7949c868b052b02120a212f7502886f1d..c0653568839d1a2da2a36bb84889d5fa0b9b7aa1 100644
80--- a/src/telegram.ts
81+++ b/src/telegram.ts
82@@ -24,7 +24,6 @@ export const BOT_COMMANDS = [
83 { command: "new", description: "New session" },
84 { command: "sessions", description: "List and switch sessions" },
85 { command: "abort", description: "Abort current session" },
86- { command: "history", description: "Recent messages from current session" },
87 { command: "agent", description: "Switch agent (/agent <name>)" },
88 ];
89
90@@ -169,44 +168,6 @@ export function createBot(token: string, allowedUsers: number[]): Bot {
91 }
92 });
93
94- bot.command("history", async (ctx) => {
95- log.info(`[cmd] /history chat=${ctx.chat.id}`);
96- const sessionId = getSessionId(ctx.chat.id);
97- if (!sessionId) {
98- await ctx.reply("No active session\\. Use /new to create one\\.", {
99- parse_mode: "MarkdownV2",
100- });
101- return;
102- }
103- try {
104- const messages = await getSessionMessages(sessionId);
105- if (messages.length === 0) {
106- await ctx.reply("No messages in this session\\.", {
107- parse_mode: "MarkdownV2",
108- });
109- return;
110- }
111-
112- const lines: string[] = [];
113- for (const msg of messages) {
114- const role = msg.role === "user" ? "You" : "Assistant";
115- const text = formatParts(msg.parts);
116- const preview = text
117- ? text.slice(0, 200) + (text.length > 200 ? escapeMarkdownV2("...") : "")
118- : escapeMarkdownV2("(no text)");
119- lines.push(`*${escapeMarkdownV2(role)}:* ${preview}`);
120- }
121-
122- const chunks = splitMessage(lines.join("\n\n"));
123- for (const chunk of chunks) {
124- await ctx.reply(chunk, { parse_mode: "MarkdownV2" });
125- }
126- } catch (err) {
127- log.error(`[cmd] /history error:`, err);
128- await ctx.reply(`Failed to fetch history: ${String(err)}`);
129- }
130- });
131-
132 // Handle callback queries (session switch, permissions)
133 bot.on("callback_query:data", async (ctx) => {
134 const data = ctx.callbackQuery.data;