virtualcode 1.9.2 → 2.0.1

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/CHANGELOG.md ADDED
@@ -0,0 +1,106 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [2.0.0] - 2026-06-19
9
+
10
+ ### Added
11
+ - `/start` command with welcome message and quick setup guide
12
+ - Token format validation (`^\d+:[\w-]+$`) before connecting
13
+ - Auto-reconnect with exponential backoff (5s -> 10s -> 20s -> 30s cap)
14
+ - LRU-bounded session tracking (max 100 entries)
15
+ - Pending message timeout (30s) to prevent memory leaks
16
+ - Non-text message handler (replies "Only text messages are supported.")
17
+ - Prefix ambiguity detection ("Multiple sessions match. Use the full ID.")
18
+ - Graceful shutdown in `dispose()` (clears all timers, maps, and state)
19
+
20
+ ### Changed
21
+ - Removed all emoji characters from user-facing messages
22
+ - `findSessionById` now returns typed result (`found | ambiguous | not_found`)
23
+ - `lastForwardedBySession` uses LRU eviction instead of unbounded growth
24
+ - `pendingTelegram` entries auto-expire after 30s
25
+ - Error messages are shorter and more consistent
26
+
27
+ ### Fixed
28
+ - Bot never auto-reconnected after 403/block errors
29
+ - `lastForwardedBySession` grew unbounded with every new session
30
+ - `pendingTelegram` leaked entries when `prompt()` hung
31
+ - Prefix matching silently failed when multiple sessions matched
32
+ - `dispose()` didn't clean up timers or pending state
33
+
34
+ ## [1.9.2] - 2026-06-19
35
+
36
+ ### Changed
37
+ - All error messages prefixed with error indicators
38
+ - `sanitizeUI()` strips stack traces and truncates to 200 chars
39
+ - `fmtId()` truncates session IDs to 12 chars
40
+
41
+ ### Fixed
42
+ - `userError()` now extracts only the first line of error messages
43
+ - All `ctx.reply()` error paths go through `sanitizeUI()`
44
+
45
+ ## [1.9.1] - 2026-06-19
46
+
47
+ ### Added
48
+ - Prefix matching for session IDs in `/link` and `/use`
49
+ - `/ls` now shows full session IDs for easy copy-paste
50
+
51
+ ### Fixed
52
+ - `/link` used `client.session.get()` which failed for valid IDs from other directories
53
+ - Now uses `client.session.list()` + `findSessionById()` for reliable matching
54
+
55
+ ## [1.9.0] - 2026-06-19
56
+
57
+ ### Added
58
+ - `handlePluginError()` maps known errors to friendly messages
59
+ - `debugLog()` for structured debug output (enable with `DEBUG_TELEGRAM=1`)
60
+ - All bot command handlers wrapped in try/catch
61
+
62
+ ### Fixed
63
+ - Raw error objects could overflow the TUI with stack traces
64
+ - `String(err)` on SDK errors produced 500+ line dumps
65
+ - Event handler errors not sanitized
66
+
67
+ ## [1.8.1] - 2026-06-19
68
+
69
+ ### Changed
70
+ - `/ls` output shows both session title and ID
71
+
72
+ ## [1.8.0] - 2026-06-19
73
+
74
+ ### Added
75
+ - `slashName: "telegram"` on TUI palette command
76
+ - `/telegram` now appears in chat slash suggestions
77
+ - `desc` field on palette command for meaningful descriptions
78
+
79
+ ### Fixed
80
+ - Removed all 6 `console.log` startup statements
81
+ - All `bot.stop()` calls wrapped in try/catch
82
+ - All `client.session.*` SDK calls wrapped in try/catch
83
+ - Added `bot.catch()` for global Telegraf error handling
84
+
85
+ ## [1.7.0] - 2026-06-18
86
+
87
+ ### Added
88
+ - TUI plugin with `/telegram` slash command for token setup
89
+ - Dialog prompt for pasting bot token
90
+ - Toast notification on successful token save
91
+
92
+ ### Fixed
93
+ - Cleared stale OpenCode cache for plugin updates
94
+
95
+ ## [1.0.0] - 2026-06-13
96
+
97
+ ### Added
98
+ - Initial release
99
+ - Bidirectional Telegram <-> OpenCode bridge
100
+ - Session linking via `/link`
101
+ - `/ls`, `/use`, `/history`, `/help` commands
102
+ - `telegram_send` tool for LLM-initiated messages
103
+ - Persistent links across restarts
104
+ - Multi-session support
105
+ - `allowed_users` access control
106
+ - `notify_on_reconnect` option
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 virtualcode contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,51 +1,255 @@
1
- # opencode-telegram
1
+ # virtualcode
2
2
 
3
- A [OpenCode](https://opencode.ai) plugin that bridges your terminal sessions with Telegram.
3
+ ```
4
+ __ ___ _
5
+ \ \ / (_)_ __ ___ ___ _ __ ___ | |_
6
+ \ \ / /| | '_ \ / _ \/ _ \| '_ \ / _ \ | __|
7
+ \ V / | | | | | __/ (_) | | | | (_) || |_
8
+ \_/ |_|_| |_|\___|\___/|_| |_|\___/ \__|
9
+
10
+ Talk to your terminal from your phone.
11
+ ```
4
12
 
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.
13
+ An [OpenCode](https://opencode.ai) plugin that bridges your terminal sessions with Telegram.
14
+ Send prompts from your phone, receive LLM responses in real time. The LLM can also message
15
+ you back via a built-in tool.
6
16
 
7
- ## Features
17
+ ```
18
+ ┌─────────────────────────────────────────────────────────────────┐
19
+ │ │
20
+ │ YOUR PHONE YOUR TERMINAL │
21
+ │ ┌───────────────────┐ ┌───────────────────┐ │
22
+ │ │ Telegram │ │ $ opencode │ │
23
+ │ │ │ │ │ │
24
+ │ │ > fix the bug │ ─────────────>│ [AI] analyzing... │ │
25
+ │ │ │ │ │ │
26
+ │ │ [AI] Fixed. The │ <─────────────│ [AI] Fixed. The │ │
27
+ │ │ issue was in... │ │ issue was in... │ │
28
+ │ │ │ │ │ │
29
+ │ └───────────────────┘ └───────────────────┘ │
30
+ │ │
31
+ └─────────────────────────────────────────────────────────────────┘
32
+ ```
8
33
 
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
34
+ ---
14
35
 
15
36
  ## Installation
16
37
 
17
38
  ```bash
18
- npm install @opencode-ai/plugin-telegram
39
+ npm install -g virtualcode
40
+ ```
41
+
42
+ Then add the plugin to your OpenCode config:
43
+
44
+ ```json
45
+ {
46
+ "plugin": ["virtualcode"]
47
+ }
19
48
  ```
20
49
 
21
- Then add it to your `.opencode/opencode.json`:
50
+ And to your TUI config (`~/.config/opencode/tui.json`):
22
51
 
23
52
  ```json
24
53
  {
25
- "plugins": [
26
- ["@opencode-ai/plugin-telegram", {
54
+ "plugin": ["virtualcode"]
55
+ }
56
+ ```
57
+
58
+ ---
59
+
60
+ ## Setup
61
+
62
+ ### 1. Create a Telegram Bot
63
+
64
+ ```
65
+ 1. Open Telegram and search for @BotFather
66
+ 2. Send /newbot
67
+ 3. Choose a name and username for your bot
68
+ 4. Copy the token (format: 123456789:ABCdefGHIjklMNOpqrsTUVwxyz)
69
+ ```
70
+
71
+ ### 2. Connect the Bot
72
+
73
+ In your OpenCode terminal, type `/telegram` and paste your bot token.
74
+
75
+ Or configure it directly in `opencode.jsonc`:
76
+
77
+ ```json
78
+ {
79
+ "plugin": [
80
+ ["virtualcode", {
27
81
  "token": "YOUR_BOT_TOKEN",
28
- "allowed_users": [YOUR_TELEGRAM_ID]
82
+ "allowed_users": [YOUR_TELEGRAM_USER_ID]
29
83
  }]
30
84
  ]
31
85
  }
32
86
  ```
33
87
 
88
+ ### 3. Link a Session
89
+
90
+ In your Telegram chat with the bot:
91
+
92
+ ```
93
+ /ls -- list your OpenCode sessions
94
+ /link <ID> -- bind this chat to a session
95
+ ```
96
+
97
+ Now any message you send goes to that session. Responses come back automatically.
98
+
99
+ ---
100
+
101
+ ## Commands
102
+
103
+ ### Telegram Bot Commands
104
+
105
+ | Command | Description |
106
+ |---------|-------------|
107
+ | `/start` | Welcome message and quick setup guide |
108
+ | `/link <ID>` | Bind this chat to an OpenCode session |
109
+ | `/unlink` | Remove the session binding |
110
+ | `/status` | Show connection state and linked session |
111
+ | `/ls` | List recent sessions (number, title, ID) |
112
+ | `/use <N\|ID>` | Switch to a session by number or ID |
113
+ | `/history [N]` | View last N messages in the linked session |
114
+ | `/help` | Show command reference |
115
+
116
+ Any other message is forwarded to the linked session as a prompt.
117
+
118
+ ### OpenCode Terminal Commands
119
+
120
+ | Command | Description |
121
+ |---------|-------------|
122
+ | `/telegram` | Open token setup dialog |
123
+ | `/telegram <token>` | Connect with a bot token |
124
+ | `/telegram status` | Show bot connection state |
125
+ | `/telegram disconnect` | Stop bot and remove saved token |
126
+
127
+ ---
128
+
34
129
  ## Configuration
35
130
 
36
131
  | Option | Type | Default | Description |
37
132
  |--------|------|---------|-------------|
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 |
133
+ | `token` | `string` | `env.TELEGRAM_BOT_TOKEN` | Telegram bot token from @BotFather |
134
+ | `allowed_users` | `number[]` | `null` (all) | Restrict access to specific Telegram user IDs |
135
+ | `notify_on_reconnect` | `boolean` | `false` | Send a message to linked chats when the bot reconnects |
41
136
 
42
- ## Commands
137
+ ### Environment Variables
138
+
139
+ | Variable | Description |
140
+ |----------|-------------|
141
+ | `TELEGRAM_BOT_TOKEN` | Bot token (alternative to config) |
142
+ | `DEBUG_TELEGRAM` | Set to `1` to enable verbose debug logging |
143
+
144
+ ---
145
+
146
+ ## How It Works
147
+
148
+ ```
149
+ ┌──────────────────────────────────────────────────────────────────────┐
150
+ │ │
151
+ │ Telegram Bot OpenCode Plugin │
152
+ │ ┌──────────────┐ ┌──────────────────────────────┐ │
153
+ │ │ │ send prompt │ │ │
154
+ │ │ User sends │ ─────────────> │ session.prompt() │ │
155
+ │ │ a message │ │ │ │
156
+ │ │ │ │ │ │
157
+ │ │ │ response │ session.status -> idle │ │
158
+ │ │ User sees │ <───────────── │ -> fetch last message │ │
159
+ │ │ AI reply │ │ -> sendMessage() │ │
160
+ │ │ │ │ │ │
161
+ │ └──────────────┘ └──────────────────────────────┘ │
162
+ │ │
163
+ │ Persistence: │
164
+ │ ~/.config/opencode/telegram-token.json (bot token) │
165
+ │ ~/.config/opencode/telegram-links.json (chat <-> session map) │
166
+ │ │
167
+ └──────────────────────────────────────────────────────────────────────┘
168
+ ```
169
+
170
+ ---
171
+
172
+ ## Troubleshooting
173
+
174
+ **Bot doesn't respond to messages**
175
+
176
+ ```
177
+ 1. Check /status -- is the chat linked to a session?
178
+ 2. If not linked, use /ls then /link <ID>
179
+ 3. If linked, check OpenCode logs for errors
180
+ ```
181
+
182
+ **"Invalid token" error**
183
+
184
+ ```
185
+ 1. Make sure you copied the full token from @BotFather
186
+ 2. Token format: 123456789:ABCdefGHIjklMNOpqrsTUVwxyz
187
+ 3. Try /telegram disconnect then reconnect with the correct token
188
+ ```
189
+
190
+ **"Another bot instance running" error**
191
+
192
+ ```
193
+ Only one bot can use a token at a time. Check if:
194
+ - Another OpenCode instance is running
195
+ - Another app is using the same bot token
196
+ - A previous instance didn't shut down cleanly (wait 30s)
197
+ ```
198
+
199
+ **Messages not coming back from OpenCode**
200
+
201
+ ```
202
+ 1. Check that the session is still active in OpenCode
203
+ 2. The bot auto-reconnects after failures (5s -> 10s -> 20s -> 30s)
204
+ 3. Set DEBUG_TELEGRAM=1 to see detailed logs
205
+ ```
206
+
207
+ **Session ID not found**
208
+
209
+ ```
210
+ 1. Use /ls to list sessions
211
+ 2. Copy the full ID (starts with "ses_")
212
+ 3. You can also use the number: /use 1
213
+ 4. Prefix matching works: /link ses_123 (if unique)
214
+ ```
215
+
216
+ ---
217
+
218
+ ## Architecture
219
+
220
+ ```
221
+ virtualcode
222
+ ├── src/
223
+ │ ├── index.ts Server plugin (bot logic, session bridge, event handling)
224
+ │ └── tui.ts TUI plugin (slash command, token dialog)
225
+ ├── install.js Postinstall script (auto-configures opencode.jsonc + tui.json)
226
+ ├── package.json npm: virtualcode
227
+ └── dist/ Compiled output
228
+ ```
229
+
230
+ **Key design decisions:**
231
+
232
+ - Atomic file writes (write to .tmp, then rename) prevent corruption
233
+ - All errors are sanitized before reaching the UI (no stack traces)
234
+ - Exponential backoff auto-reconnect (5s -> 10s -> 20s -> 30s cap)
235
+ - LRU-bounded session tracking (max 100 entries)
236
+ - Pending message timeout (30s) prevents memory leaks
237
+ - Prefix matching for session IDs with ambiguity detection
238
+
239
+ ---
240
+
241
+ ## Contributing
242
+
243
+ Issues and PRs welcome.
244
+
245
+ ```bash
246
+ git clone https://github.com/anomalyco/opencode-telegram.git
247
+ cd opencode-telegram
248
+ npm install
249
+ npm run build
250
+ ```
43
251
 
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
252
+ ---
49
253
 
50
254
  ## License
51
255
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAA;;;;;AAmkBjD,wBAGC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAA;;;;;AA+yBjD,wBAGC"}