opencode-telegram-link 1.0.0-rc.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.
Files changed (82) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +464 -0
  3. package/container/broker.Dockerfile +30 -0
  4. package/container/entrypoint.sh +19 -0
  5. package/dist/broker/commands.d.ts +17 -0
  6. package/dist/broker/commands.d.ts.map +1 -0
  7. package/dist/broker/dashboard-html.d.ts +2 -0
  8. package/dist/broker/dashboard-html.d.ts.map +1 -0
  9. package/dist/broker/index.d.ts +3 -0
  10. package/dist/broker/index.d.ts.map +1 -0
  11. package/dist/broker/main.d.ts +3 -0
  12. package/dist/broker/main.d.ts.map +1 -0
  13. package/dist/broker/main.js +21896 -0
  14. package/dist/broker/main.js.map +110 -0
  15. package/dist/broker/registry.d.ts +92 -0
  16. package/dist/broker/registry.d.ts.map +1 -0
  17. package/dist/broker/server.d.ts +133 -0
  18. package/dist/broker/server.d.ts.map +1 -0
  19. package/dist/config.d.ts +76 -0
  20. package/dist/config.d.ts.map +1 -0
  21. package/dist/doctor.d.ts +21 -0
  22. package/dist/doctor.d.ts.map +1 -0
  23. package/dist/i18n/catalogs.d.ts +120 -0
  24. package/dist/i18n/catalogs.d.ts.map +1 -0
  25. package/dist/i18n/index.d.ts +10 -0
  26. package/dist/i18n/index.d.ts.map +1 -0
  27. package/dist/opencode/bridge.d.ts +39 -0
  28. package/dist/opencode/bridge.d.ts.map +1 -0
  29. package/dist/opencode/config-helper.d.ts +20 -0
  30. package/dist/opencode/config-helper.d.ts.map +1 -0
  31. package/dist/opencode/events.d.ts +47 -0
  32. package/dist/opencode/events.d.ts.map +1 -0
  33. package/dist/opencode/index.d.ts +4 -0
  34. package/dist/opencode/index.d.ts.map +1 -0
  35. package/dist/plugin/client.d.ts +57 -0
  36. package/dist/plugin/client.d.ts.map +1 -0
  37. package/dist/plugin/commands.d.ts +4 -0
  38. package/dist/plugin/commands.d.ts.map +1 -0
  39. package/dist/plugin/index.d.ts +2 -0
  40. package/dist/plugin/index.d.ts.map +1 -0
  41. package/dist/plugin.d.ts +11 -0
  42. package/dist/plugin.d.ts.map +1 -0
  43. package/dist/plugin.js +16913 -0
  44. package/dist/plugin.js.map +95 -0
  45. package/dist/protocol/index.d.ts +792 -0
  46. package/dist/protocol/index.d.ts.map +1 -0
  47. package/dist/protocol/index.js +14540 -0
  48. package/dist/protocol/index.js.map +84 -0
  49. package/dist/setup.d.ts +77 -0
  50. package/dist/setup.d.ts.map +1 -0
  51. package/dist/state/database.d.ts +159 -0
  52. package/dist/state/database.d.ts.map +1 -0
  53. package/dist/state/discovery.d.ts +16 -0
  54. package/dist/state/discovery.d.ts.map +1 -0
  55. package/dist/state/identity.d.ts +19 -0
  56. package/dist/state/identity.d.ts.map +1 -0
  57. package/dist/state/index.d.ts +4 -0
  58. package/dist/state/index.d.ts.map +1 -0
  59. package/dist/telegram/api.d.ts +212 -0
  60. package/dist/telegram/api.d.ts.map +1 -0
  61. package/dist/telegram/authorization.d.ts +25 -0
  62. package/dist/telegram/authorization.d.ts.map +1 -0
  63. package/dist/telegram/commands.d.ts +20 -0
  64. package/dist/telegram/commands.d.ts.map +1 -0
  65. package/dist/telegram/index.d.ts +9 -0
  66. package/dist/telegram/index.d.ts.map +1 -0
  67. package/dist/telegram/interaction.d.ts +49 -0
  68. package/dist/telegram/interaction.d.ts.map +1 -0
  69. package/dist/telegram/outbox.d.ts +46 -0
  70. package/dist/telegram/outbox.d.ts.map +1 -0
  71. package/dist/telegram/poller.d.ts +26 -0
  72. package/dist/telegram/poller.d.ts.map +1 -0
  73. package/dist/telegram/render.d.ts +16 -0
  74. package/dist/telegram/render.d.ts.map +1 -0
  75. package/dist/telegram/transcriber.d.ts +20 -0
  76. package/dist/telegram/transcriber.d.ts.map +1 -0
  77. package/dist/uninstall.d.ts +12 -0
  78. package/dist/uninstall.d.ts.map +1 -0
  79. package/dist/version.d.ts +2 -0
  80. package/dist/version.d.ts.map +1 -0
  81. package/docker-compose.yml +19 -0
  82. package/package.json +73 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 OpenCode Telegram Link 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 ADDED
@@ -0,0 +1,464 @@
1
+ # OpenCode Telegram Notifier & OpenCode Commander
2
+
3
+ OpenCode Telegram Notifier is a privacy-first OpenCode plugin and multi-host management gateway for asynchronous notifications, interactive inline buttons, safe remote replies, and proactive remote task dispatching. It is designed for developers who run OpenCode across multiple projects and multiple computers (dev machine, laptop, VPS) while routing every Telegram and Web interaction to the exact originating host, process, and workspace window.
4
+
5
+ > Version: **v1.0.0-rc.1** (OpenCode Commander Web Dashboard, Proactive Remote Dispatch, Multi-Engine Voice STT, Multi-Host Gateway & Node Agent Architecture).
6
+ > Status: Release Candidate 1. Install from a release tarball or source checkout until the first public npm package is published.
7
+
8
+ [繁體中文總覽 (Traditional Chinese)](docs/README.zh-TW.md)
9
+
10
+ ---
11
+
12
+ ## Features & Highlights (v1.0.0-rc.1)
13
+
14
+ - 🖥️ **OpenCode Commander (Web GUI Dashboard)**: Built-in modern Glassmorphism Web Console (`http://<gateway-ip>:42617/dashboard`) providing real-time visibility, live metrics, and centralized cluster management.
15
+ - 🌐 **Cluster Topology & 1-to-1 Window Mapping**: Live cards for all connected computers and OpenCode workspace windows with real-time session indicators and task counters.
16
+ - 🚀 **Proactive Remote Dispatch**: Dispatch new prompts and start new tasks on any connected machine or idle project window directly from the Web Dashboard or Telegram voice/text—no need to switch to VS Code!
17
+ - 🎙️ **Multi-Engine Voice Transcription (Voice STT)**:
18
+ - **Cloudflare Workers AI** (`@cf/openai/whisper-large-v3-turbo` with 10,000 free requests/day).
19
+ - **Groq Whisper** (`whisper-large-v3-turbo` / `whisper-large-v3`).
20
+ - **OpenAI Whisper** (`whisper-1`).
21
+ - **Custom / Self-Hosted Whisper Endpoint**.
22
+ - **Independent Multi-Provider Credentials Retention**: Switch between speech providers seamlessly without losing API tokens.
23
+ - **Live Key Verification & Connection Testing**: In-dashboard one-click authentication and ping testing.
24
+ - 📱 **Mobile & Tablet Responsive Web Design (RWD)**: Touch-friendly navigation tabs, auto-stacking cards, and horizontal scrollable session tables for full smartphone/tablet control.
25
+ - 🛑 **Live Session Cancellation**: One-click remote task cancellation (`[ 🛑 Cancel ]`) from the Web Dashboard or Telegram inline buttons.
26
+ - 🌐 **Multi-Host Hub-and-Spoke Gateway**: Control multiple computers (e.g. Office PC, MacBook, Live VPS) from a single Telegram Bot without message collisions (`409 Conflict`).
27
+ - 🏷️ **Host Tagging**: Notification headers prominently display the origin machine (e.g., `🖥️ [MacBook]` or `☁️ [Live-VPS]`).
28
+ - 🔄 **Cross-Host Reverse Routing**: Tap buttons or reply to any notification—the Central Gateway routes commands back to the exact machine and session.
29
+ - 🔘 **Interactive Inline Buttons**: Single-tap remote permission approvals (`[ ✅ Allow Once ]`, `[ ⚡ Always Allow ]`, `[ ❌ Reject ]`) and question option selections.
30
+ - 📝 **AI Execution Summaries**: Task completion notifications automatically include a concise AI-generated summary of actions taken.
31
+ - ⏰ **Host Local Time**: Timestamps formatted in the server host's local timezone.
32
+ - 🧹 **Interactive Uninstaller**: One-command safe cleanup (`bun run uninstall`) for database, state, tokens, and `opencode.json` configurations.
33
+ - 🌐 **Bilingual Support**: Full Traditional Chinese (`zh-TW`) and English (`en`) notifications and dashboard guidance.
34
+
35
+ ## Architecture
36
+
37
+ ```text
38
+ [ Node Agent 1 (MacBook) ] ──── (WebSocket) ──┐
39
+
40
+ [ Node Agent 2 (Live VPS) ] ─── (WebSocket) ──► [ Central Gateway Broker ] ──► Telegram Bot API
41
+ ▲ (Local or VPS) │
42
+ [ Local OpenCode ] ───────────────────────────┘ ▼
43
+ [ Telegram App (Mobile) ]
44
+ ```
45
+
46
+ - **Gateway Mode (Default)**: Runs as the singleton Telegram Poller. Serves local OpenCode instances and accepts reverse WebSocket connections from remote Node Agents.
47
+ - **Node Agent Mode**: Lightweight mode for second/third machines that connects to the Central Gateway, allowing all machines to share one Telegram Bot seamlessly.
48
+
49
+ ## Security and Privacy
50
+
51
+ - Central Gateway and Node Agents authenticate over WebSocket using secure tokens.
52
+ - Notifications omit transcripts, source code, tool output, local filesystem paths, and secrets by default.
53
+ - Telegram user and private-chat identities are pinned during Gateway setup.
54
+ - Offline, stale, ambiguous, or unauthorized actions fail closed and are never queued.
55
+
56
+ ## Installation & Setup
57
+
58
+ Requirements:
59
+ - Bun `>=1.3.0`.
60
+ - OpenCode with `@opencode-ai/plugin` `>=1.18.0 <2`.
61
+ - A user-owned Telegram bot token from BotFather (only needed on the Gateway machine).
62
+
63
+ ## Quick Start (4-Step Setup)
64
+
65
+ On any machine (development host or remote server) where you want to enable notifications:
66
+
67
+ ```sh
68
+ # 1. Clone the repository
69
+ git clone https://github.com/proamo/opencode_notification.git
70
+ cd opencode_notification
71
+
72
+ # 2. Install dependencies
73
+ bun install
74
+
75
+ # 3. Build the project
76
+ bun run build
77
+
78
+ # 4. Run the interactive setup wizard
79
+ bun run setup
80
+ ```
81
+
82
+ *(Note: Once published to npm, you will also be able to run `bunx opencode-telegram-link setup` directly).*
83
+
84
+ The interactive wizard will:
85
+ - Ask for your preferred language (Traditional Chinese / English).
86
+ - Ask for your preferred deployment mode:
87
+ - **1) Native Mode (Default)**: Broker runs as a lightweight background process, auto-spawned by OpenCode.
88
+ - **2) Docker Container Mode**: The wizard will **automatically build and start the Docker container in the background** via Docker Compose!
89
+ - Prompt and instantly verify your Bot Token with Telegram.
90
+ - Guide you through private chat pairing with a short-lived nonce code.
91
+ - Automatically save the token in a secure private state file (`0600`/`0700`).
92
+ - Automatically detect and update your `opencode.json` configuration file.
93
+ - Send a test welcome notification to your Telegram!
94
+
95
+ ---
96
+
97
+ ## 🖥️ OpenCode Commander (Web Dashboard)
98
+
99
+ Once the Gateway is running, navigate to:
100
+
101
+ ```text
102
+ http://localhost:42617/dashboard
103
+ # Or from another device / smartphone:
104
+ http://<gateway-ip>:42617/dashboard
105
+ ```
106
+
107
+ ### Dashboard Tabs & Capabilities:
108
+ 1. **🖥️ Cluster Topology (Nodes)**:
109
+ - Live overview of all connected machines and OpenCode workspace windows (1-to-1 live mapping).
110
+ - Real-time status: Active sessions, running subagent counts, and idle window indicators.
111
+ - One-click **`🚀 Dispatch`** to start a new prompt on any window.
112
+ 2. **📝 Active Sessions (Sessions)**:
113
+ - Live stream of all ongoing tasks across the entire cluster.
114
+ - One-click **`🛑 Cancel`** to immediately abort runaway tasks.
115
+ 3. **🚀 Proactive Remote Dispatch (Dispatch)**:
116
+ - Select any connected machine / workspace (or auto-detect).
117
+ - Enter your prompt and click **`🚀 Dispatch Task`** to launch tasks remotely.
118
+ 4. **⚙️ System Settings (Settings)**:
119
+ - Configure **Voice STT Engine** (Cloudflare Workers AI, Groq Whisper, OpenAI Whisper, Custom Endpoint).
120
+ - **Independent Multi-Provider Credentials Retention**: Switch between providers without losing your saved API keys.
121
+ - In-dashboard **`⚡ Test & Verify Key`** connection diagnostic box.
122
+ - Dynamic zero-downtime hot reloading of speech engine credentials.
123
+
124
+ ---
125
+
126
+ ## 🎙️ Telegram Voice Input
127
+
128
+ Send Telegram voice messages or audio files directly to the Bot! The Gateway transcribes voice messages using your configured speech engine:
129
+
130
+ 1. **Cloudflare Workers AI (Recommended)**:
131
+ - Model: `@cf/openai/whisper-large-v3-turbo`
132
+ - Free tier: **10,000 requests per day**.
133
+ - Requires: Cloudflare Account ID and API Token.
134
+ 2. **Groq Whisper**:
135
+ - Model: `whisper-large-v3-turbo` / `whisper-large-v3`
136
+ - Ultra-low latency transcription.
137
+ - Requires: Groq API Key (`gsk_...`).
138
+ 3. **OpenAI Whisper**:
139
+ - Model: `whisper-1`
140
+ - Requires: OpenAI API Key (`sk-...`).
141
+
142
+ ---
143
+
144
+ ## Multi-Host & Node Agent Setup (Connecting a 2nd Machine)
145
+
146
+ To share the **same Telegram Bot** across multiple computers (e.g. Machine A as Central Gateway, Machine B as Node Agent):
147
+
148
+ ### Step 1: Set up Machine A (Central Gateway)
149
+ Run `bun run setup` on Machine A, choose `1) Standalone Gateway Mode`, and pair your Telegram Bot.
150
+ Ensure Machine A's Broker WebSocket port (`42617`) is accessible by Machine B (e.g., via LAN, Tailscale VPN, or reverse proxy).
151
+
152
+ ### Step 2: Set up Machine B (Node Agent)
153
+ On Machine B (e.g., your laptop or another server):
154
+ 1. Run `bun run setup`.
155
+ 2. Choose **`2) Node Agent Mode`**.
156
+ 3. Enter your machine label (e.g., `MacBook` or `Live-VPS`).
157
+ 4. Enter Machine A's Gateway WebSocket URL (e.g., `ws://192.168.1.100:42617`, `ws://100.x.x.x:42617` via Tailscale, or `wss://gateway.example.com`).
158
+ 5. Enter Gateway Secret Token (if configured).
159
+
160
+ ### Machine B `opencode.json` Example
161
+ ```json
162
+ {
163
+ "plugin": {
164
+ "opencode-telegram-link": {
165
+ "mode": "local",
166
+ "role": "node",
167
+ "hostLabel": "MacBook",
168
+ "gateway": {
169
+ "url": "ws://gateway-host-ip:42617",
170
+ "secret": "your-secret-token"
171
+ },
172
+ "notifications": {
173
+ "completion": true,
174
+ "error": true,
175
+ "question": true,
176
+ "permission": true
177
+ }
178
+ }
179
+ }
180
+ }
181
+ ```
182
+
183
+ > 💡 **How to get the Gateway Secret Token?**
184
+ > Run the following command on Machine A (Gateway) to view and copy the secret token:
185
+ > `cat ~/.local/state/opencode-telegram-link/broker-secret`
186
+ > (Or on Windows: `type %USERPROFILE%\.local\state\opencode-telegram-link\broker-secret`).
187
+
188
+ Notifications from Machine B will automatically display `🖥️ [MacBook]` in Telegram, and button clicks or replies from Telegram will automatically route back to Machine B!
189
+
190
+ ---
191
+
192
+ ## Non-Interactive & Scripted Setup (CI / Automated Environments)
193
+
194
+ If you prefer scripted setup with environment variables or flags:
195
+
196
+ ```sh
197
+ # Pair with short-lived nonce
198
+ OPENCODE_TELEGRAM_BOT_TOKEN='123456:REPLACE_WITH_BOTFATHER_TOKEN' \
199
+ opencode-telegram-broker setup --pair --locale en
200
+
201
+ # Or specify existing Telegram User and Chat IDs directly
202
+ OPENCODE_TELEGRAM_BOT_TOKEN_FILE=~/.local/state/opencode-telegram-link/telegram-bot-token \
203
+ opencode-telegram-broker setup --user-id 123456789 --chat-id 123456789 --locale en
204
+ ```
205
+
206
+ ## Configuration
207
+
208
+ OpenCode supports both **Global Configuration** and **Project-Specific Configuration**:
209
+
210
+ - **Global Config**: `~/.config/opencode/opencode.json` (applied to all projects).
211
+ - **Project-Specific Config**: `<project-root>/.opencode/opencode.json` or `<project-root>/opencode.json`.
212
+
213
+ > ⚠️ **Important: Project Config Overrides Global Plugins**
214
+ > If your project contains its own `.opencode/opencode.json` or `opencode.json` that defines a `"plugin"` array, OpenCode will use that workspace `"plugin"` list and **will not inherit** plugins from your global configuration.
215
+ >
216
+ > Therefore, if a project has its own `opencode.json`, you **must** also add the notification plugin to that project's configuration.
217
+
218
+ ### How to Configure a Project with its Own `opencode.json`
219
+
220
+ #### Option 1: Manual Edit (Recommended)
221
+ Open your project's `.opencode/opencode.json` (or `opencode.json`) and add the absolute directory path to the `"plugin"` array:
222
+
223
+ ```json
224
+ {
225
+ "$schema": "https://opencode.ai/config.json",
226
+ "plugin": [
227
+ "oc-codex-multi-auth@6.12.1",
228
+ "/home/you/opencode_notification"
229
+ ]
230
+ }
231
+ ```
232
+
233
+ > 💡 **Local Install vs npm Package**: Until published on the official npm registry, specify the absolute directory path to this repository. Once published, you can simply write `"opencode-telegram-link"`. The plugin automatically reads the paired credentials from the secure local state directory.
234
+
235
+ #### Option 2: Automatic Injection via Setup Wizard
236
+ You can run the setup tool directly inside your target project workspace:
237
+
238
+ ```sh
239
+ cd /path/to/your/project
240
+ bun run --cwd /path/to/opencode_notification setup --config-only
241
+ ```
242
+ The wizard will automatically detect the local workspace `opencode.json`, create a `.bak` backup, and inject the plugin entry safely.
243
+
244
+ ### Permission Configuration (Automatic Command Execution)
245
+
246
+ To allow shell and file operations without manual approval prompts, configure permissions in `opencode.json` or in your `.opencode/agent/<agent-name>.md`:
247
+
248
+ ```json
249
+ {
250
+ "permission": {
251
+ "edit": "allow",
252
+ "bash": "allow",
253
+ "webfetch": "allow",
254
+ "task": "allow",
255
+ "external_directory": "allow"
256
+ }
257
+ }
258
+ ```
259
+
260
+ Use exactly one of `telegram.tokenFile` or `telegram.botToken`. `tokenFile` is recommended because the file permission checker rejects group-readable, world-readable, non-regular, and wrong-owner token files on non-Windows platforms. Inline tokens are accepted for constrained environments but are easier to leak through config sharing.
261
+
262
+ ## Broker Commands
263
+
264
+ Start or reuse the native loopback broker:
265
+
266
+ ```sh
267
+ opencode-telegram-broker start
268
+ ```
269
+
270
+ Check readiness and diagnostics:
271
+
272
+ ```sh
273
+ opencode-telegram-broker status
274
+ opencode-telegram-broker doctor
275
+ ```
276
+
277
+ Send a credential and chat connectivity test without creating a routable session action:
278
+
279
+ ```sh
280
+ OPENCODE_TELEGRAM_BOT_TOKEN_FILE=~/.local/state/opencode-telegram-link/telegram-bot-token \
281
+ opencode-telegram-broker test-notification --chat-id 123456789 --locale en
282
+ ```
283
+
284
+ Stop the broker without terminating OpenCode sessions:
285
+
286
+ ```sh
287
+ opencode-telegram-broker stop
288
+ ```
289
+
290
+ Purge operational routing state only after the broker is stopped:
291
+
292
+ ```sh
293
+ opencode-telegram-broker purge-state
294
+ ```
295
+
296
+ Rotate the stored token file after changing the token through BotFather:
297
+
298
+ ```sh
299
+ OPENCODE_TELEGRAM_BOT_TOKEN='123456:NEW_TOKEN' \
300
+ opencode-telegram-broker rotate-credential --token-file ~/.local/state/opencode-telegram-link/telegram-bot-token
301
+ opencode-telegram-broker stop
302
+ opencode-telegram-broker start
303
+ ```
304
+
305
+ ## Sample Notifications
306
+
307
+ ### 1. Task Completed Notification (with AI Summary & Local Time)
308
+
309
+ ```text
310
+ OpenCode Completed
311
+ Project: api-server
312
+ Session: Fix flaky checkout test
313
+ Time: 2026-08-26 09:30:15
314
+
315
+ 📝 Summary:
316
+ Fixed race condition in Stripe webhook handler by wrapping state lookup in a database transaction. Added unit test.
317
+
318
+ Reply to this message to continue the session.
319
+ ```
320
+
321
+ ### 2. Interactive Permission Request (V1.5 Inline Keyboard)
322
+
323
+ ```text
324
+ OpenCode Needs Permission
325
+ Project: api-server
326
+ Session: Fix flaky checkout test
327
+ Time: 2026-08-26 09:32:00
328
+ Action: Execute bash command `npm run test:e2e`
329
+
330
+ [ ✅ Allow Once ] [ ⚡ Always Allow ] [ ❌ Reject ]
331
+ ```
332
+
333
+ ### 3. Interactive Question Notification (V1.5 Option Buttons)
334
+
335
+ ```text
336
+ OpenCode Needs Input
337
+ Project: api-server
338
+ Question: Which migration strategy should be used?
339
+ Time: 2026-08-26 09:35:10
340
+
341
+ [ Blue-Green ] [ Canary ] [ In-Place ]
342
+ ```
343
+
344
+ Notification bodies are intentionally minimal. They omit raw transcripts, source code, tool output, local filesystem paths, and secrets by default.
345
+
346
+ ## Reply & Interaction Behavior
347
+
348
+ - **Interactive Permission Approval**: Tap `[ ✅ Allow Once ]`, `[ ⚡ Always Allow ]`, or `[ ❌ Reject ]` on the Telegram message. The Broker validates a single-use token and remotely unblocks OpenCode in the terminal immediately!
349
+ - **Interactive Question Selection**: Tap an option button on the Telegram question notification, or reply directly with text.
350
+ - **Continue Session**: Reply directly with text to any completed task notification to send a new prompt to that exact OpenCode session (active for 24 hours).
351
+
352
+ Rejected replies receive localized feedback when the route is expired, offline, unauthorized, or rejected by OpenCode. Offline commands are not queued.
353
+
354
+ ## 🤖 Telegram Slash Commands (Mobile Commander)
355
+
356
+ You can manage your multi-host cluster directly inside Telegram using slash commands:
357
+
358
+ | Command | Description | Example |
359
+ | :--- | :--- | :--- |
360
+ | `/help` | Show command menu and interactive guide | `/help` |
361
+ | `/status` | View Central Gateway health, uptime, memory, and version | `/status` |
362
+ | `/nodes` | List all currently connected machines and active projects | `/nodes` |
363
+ | `/sessions` | List active sessions across all connected nodes | `/sessions` |
364
+ | `/run <target> <prompt>` | Dispatch new prompt to a machine, project, or resume session | `/run openclaw check test logs`<br>`/run ses_abc123 continue debugging` |
365
+ | `/cancel <session_id>` | Abort a running session safely (fail-closed disambiguation) | `/cancel ses_abc123` |
366
+
367
+ ## Docker Broker
368
+
369
+ Native mode is recommended. Docker mode runs only the broker in a container; OpenCode and plugins continue to run on the host.
370
+
371
+ ### Quick Start with Docker Compose (Recommended)
372
+
373
+ ```sh
374
+ docker compose up -d --build
375
+ ```
376
+
377
+ To stop:
378
+ ```sh
379
+ docker compose down
380
+ ```
381
+
382
+ ### Manual Container Run
383
+
384
+ ```sh
385
+ bun run build
386
+ docker build -f container/broker.Dockerfile -t opencode-telegram-broker:local .
387
+
388
+ docker run -d --rm \
389
+ --name opencode-telegram-broker \
390
+ -p 127.0.0.1:42617:42617 \
391
+ -v opencode-telegram-state:/state \
392
+ -v "$HOME/.local/state/opencode-telegram-link/telegram-bot-token:/run/secrets/telegram-bot-token:ro" \
393
+ -e OPENCODE_TELEGRAM_BOT_TOKEN_FILE=/run/secrets/telegram-bot-token \
394
+ opencode-telegram-broker:local start
395
+ ```
396
+
397
+ Do not publish the port as `42617:42617`; include the `127.0.0.1` host IP so Docker does not expose the broker on every host interface. Do not run native and Docker brokers at the same time for one state directory and bot token.
398
+
399
+ ## Diagnostics
400
+
401
+ Use `opencode-telegram-broker doctor` first when setup fails or notifications stop. It checks configuration validity, token-file permissions, broker reachability, singleton conflicts, loopback binding, Telegram API connectivity, allowed identities, catalogs, and OpenCode compatibility. Output is sanitized and should not include bot tokens, broker secrets, reply text, source code, or file contents.
402
+
403
+ Common outcomes:
404
+
405
+ - `ready: true`: setup is usable.
406
+ - `warning`: setup can run but has an operational limitation, such as no active plugin registration yet.
407
+ - `failure`: fix the reported remediation before expecting notifications or replies.
408
+ - Telegram `409 Conflict`: the same bot is being polled elsewhere; stop the other consumer or use a different bot.
409
+
410
+ ## Update
411
+
412
+ 1. Stop idle OpenCode sessions or leave them running if you only update a compatible patch release.
413
+ 2. Update the package or rebuild the checkout.
414
+ 3. Restart the broker with `opencode-telegram-broker stop` and `opencode-telegram-broker start`.
415
+ 4. Restart OpenCode processes if doctor reports a protocol or compatibility mismatch.
416
+ 5. Run `opencode-telegram-broker doctor` and `opencode-telegram-broker test-notification --chat-id <id>`.
417
+
418
+ The broker and plugin negotiate protocol major version `1`. Incompatible upgrades fail closed instead of silently downgrading routing or reply behavior.
419
+
420
+ ## Uninstall
421
+
422
+ Run the interactive uninstaller wizard:
423
+
424
+ ```sh
425
+ bun run uninstall
426
+ # Or
427
+ opencode-telegram-broker uninstall
428
+ ```
429
+
430
+ The uninstaller will safely:
431
+ 1. Stop the running broker process.
432
+ 2. Search and remove the plugin configuration from `opencode.json` files (with `.bak` backup).
433
+ 3. Clear SQLite database and message routing state.
434
+ 4. Prompt to remove the private token file and state directory.
435
+
436
+ ## Specifications
437
+
438
+ - [Proposal](openspec/changes/design-telegram-notifier/proposal.md)
439
+ - [Technical design](openspec/changes/design-telegram-notifier/design.md)
440
+ - [Telegram notifications](openspec/changes/design-telegram-notifier/specs/telegram-notifications/spec.md)
441
+ - [Local instance routing](openspec/changes/design-telegram-notifier/specs/local-instance-routing/spec.md)
442
+ - [Telegram session interaction](openspec/changes/design-telegram-notifier/specs/telegram-session-interaction/spec.md)
443
+ - [Setup and diagnostics](openspec/changes/design-telegram-notifier/specs/setup-and-diagnostics/spec.md)
444
+ - [Implementation tasks](openspec/changes/design-telegram-notifier/tasks.md)
445
+ - [Future Architecture & Roadmap (V2/V3)](docs/future-architecture-spec.md)
446
+ - [Compatibility policy](docs/compatibility.md)
447
+ - [Local state management](docs/state-management.md)
448
+ - [Threat model](docs/threat-model.md)
449
+ - [Local broker protocol](docs/protocol.md)
450
+ - [Data retention](docs/data-retention.md)
451
+ - [Contributor guide](docs/contributing.md)
452
+ - [GitNexus release readiness](docs/gitnexus-release-readiness.md)
453
+
454
+ The OpenSpec artifacts are the current source of truth. Requirements use RFC 2119 language and testable scenarios.
455
+
456
+ ## Technology
457
+
458
+ - TypeScript and Bun
459
+ - `@opencode-ai/plugin` and the OpenCode SDK
460
+ - Telegram Bot API with long polling
461
+ - Authenticated loopback WebSocket protocol
462
+ - SQLite for minimal route, delivery, and idempotency state
463
+
464
+ The project uses the MIT License. `opencode-telegram-link` is the current working npm package name and may be changed before the first public release.
@@ -0,0 +1,30 @@
1
+ # syntax=docker/dockerfile:1
2
+
3
+ FROM oven/bun:1.3.14-slim AS runtime
4
+
5
+ WORKDIR /app
6
+
7
+ ENV NODE_ENV=production \
8
+ OPENCODE_TELEGRAM_CONTAINER=1 \
9
+ OPENCODE_TELEGRAM_BROKER_STATE_DIR=/state \
10
+ OPENCODE_TELEGRAM_BROKER_BIND_HOST=0.0.0.0 \
11
+ OPENCODE_TELEGRAM_BROKER_PORT=42617
12
+
13
+ RUN apt-get update \
14
+ && apt-get install -y --no-install-recommends gosu \
15
+ && rm -rf /var/lib/apt/lists/* \
16
+ && groupadd -g 10001 opencode \
17
+ && useradd -u 10001 -g opencode -d /nonexistent -s /usr/sbin/nologin opencode \
18
+ && mkdir -p /state \
19
+ && chown -R opencode:opencode /app /state
20
+
21
+ COPY dist ./dist
22
+ COPY package.json README.md LICENSE ./
23
+ COPY container/entrypoint.sh /app/entrypoint.sh
24
+ RUN chmod +x /app/entrypoint.sh
25
+
26
+ VOLUME ["/state"]
27
+ EXPOSE 42617/tcp
28
+
29
+ ENTRYPOINT ["/app/entrypoint.sh"]
30
+ CMD ["start"]
@@ -0,0 +1,19 @@
1
+ #!/bin/sh
2
+ set -e
3
+
4
+ if [ "$(id -u)" = "0" ]; then
5
+ if [ -d "/state" ]; then
6
+ STATE_UID=$(stat -c '%u' /state 2>/dev/null || stat -f '%u' /state 2>/dev/null || echo "")
7
+ STATE_GID=$(stat -c '%g' /state 2>/dev/null || stat -f '%g' /state 2>/dev/null || echo "")
8
+ if [ "$STATE_UID" != "" ] && [ "$STATE_UID" != "0" ]; then
9
+ usermod -o -u "$STATE_UID" opencode 2>/dev/null || true
10
+ if [ "$STATE_GID" != "" ] && [ "$STATE_GID" != "0" ]; then
11
+ groupmod -o -g "$STATE_GID" opencode 2>/dev/null || true
12
+ fi
13
+ fi
14
+ fi
15
+ chown -R opencode:opencode /app 2>/dev/null || true
16
+ exec gosu opencode bun /app/dist/broker/main.js "$@"
17
+ fi
18
+
19
+ exec bun /app/dist/broker/main.js "$@"
@@ -0,0 +1,17 @@
1
+ import { type BrokerServer, type StartBrokerOptions } from "./server";
2
+ type CommandStreams = {
3
+ stdout: Pick<NodeJS.WriteStream, "write">;
4
+ stderr: Pick<NodeJS.WriteStream, "write">;
5
+ };
6
+ export type BrokerCliOptions = {
7
+ argv?: string[];
8
+ env?: NodeJS.ProcessEnv;
9
+ stdout?: Pick<NodeJS.WriteStream, "write">;
10
+ stderr?: Pick<NodeJS.WriteStream, "write">;
11
+ fetch?: typeof fetch;
12
+ onStarted?: (broker: BrokerServer) => void | Promise<void>;
13
+ };
14
+ export declare function runBrokerCli(options?: BrokerCliOptions): Promise<number | undefined>;
15
+ export declare function runStopCommand(options: StartBrokerOptions, streams: CommandStreams, fetchImplementation?: typeof fetch): Promise<number>;
16
+ export {};
17
+ //# sourceMappingURL=commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/broker/commands.ts"],"names":[],"mappings":"AAMA,OAAO,EAEL,KAAK,YAAY,EAEjB,KAAK,kBAAkB,EAExB,MAAM,UAAU,CAAC;AAElB,KAAK,cAAc,GAAG;IACpB,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC1C,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC3C,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC3C,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5D,CAAC;AAEF,wBAAsB,YAAY,CAAC,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAqC9F;AA2DD,wBAAsB,cAAc,CAClC,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,cAAc,EACvB,mBAAmB,GAAE,OAAO,KAAa,GACxC,OAAO,CAAC,MAAM,CAAC,CAejB"}
@@ -0,0 +1,2 @@
1
+ export declare function renderDashboardHtml(): string;
2
+ //# sourceMappingURL=dashboard-html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard-html.d.ts","sourceRoot":"","sources":["../../src/broker/dashboard-html.ts"],"names":[],"mappings":"AAEA,wBAAgB,mBAAmB,IAAI,MAAM,CAy5B5C"}
@@ -0,0 +1,3 @@
1
+ export { type BrokerConnectionData, type RegisteredRoute, RouteRegistrationError, RouteRegistry, serializeRouteKey, } from "./registry";
2
+ export { BrokerPortConflictError, BrokerServer, probeBroker, type StartBrokerOptions, type StartOrReuseBrokerResult, startBroker, startOrReuseBroker, } from "./server";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/broker/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,sBAAsB,EACtB,aAAa,EACb,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,uBAAuB,EACvB,YAAY,EACZ,WAAW,EACX,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,WAAW,EACX,kBAAkB,GACnB,MAAM,UAAU,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bun
2
+ export declare function runBroker(): Promise<void>;
3
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/broker/main.ts"],"names":[],"mappings":";AAKA,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAa/C"}