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 +106 -0
- package/LICENSE +21 -0
- package/README.md +227 -23
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +485 -154
- package/dist/index.js.map +1 -1
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +103 -34
- package/dist/tui.js.map +1 -1
- package/install.js +69 -6
- package/package.json +14 -3
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
|
-
#
|
|
1
|
+
# virtualcode
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
```
|
|
4
|
+
__ ___ _
|
|
5
|
+
\ \ / (_)_ __ ___ ___ _ __ ___ | |_
|
|
6
|
+
\ \ / /| | '_ \ / _ \/ _ \| '_ \ / _ \ | __|
|
|
7
|
+
\ V / | | | | | __/ (_) | | | | (_) || |_
|
|
8
|
+
\_/ |_|_| |_|\___|\___/|_| |_|\___/ \__|
|
|
9
|
+
|
|
10
|
+
Talk to your terminal from your phone.
|
|
11
|
+
```
|
|
4
12
|
|
|
5
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
50
|
+
And to your TUI config (`~/.config/opencode/tui.json`):
|
|
22
51
|
|
|
23
52
|
```json
|
|
24
53
|
{
|
|
25
|
-
"
|
|
26
|
-
|
|
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": [
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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;;;;;
|
|
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"}
|