From ff6e072fdda84a853dc874feaa3edc0252b261cd Mon Sep 17 00:00:00 2001 From: HenryYannis <247510158+HenryYannis@users.noreply.github.com> Date: Fri, 30 Oct 2026 09:39:29 +0000 Subject: [PATCH 1/2] =?UTF-8?q?docs:=20=E4=B8=89=E8=AF=AD=20README=20+=20C?= =?UTF-8?q?I?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - README.md (简体中文, default), README.zh-Hant.md (繁體中文), README.en.md (English) - Fix facts against code: model list source order, 3800-char split, delivery tracker, permission buttons, npm not published - CI: actions v7, run on all pull_requests + workflow_dispatch, Node 20/22/24 --- .github/workflows/ci.yml | 10 +-- README.en.md | 131 ++++++++++++++++++++++++++++++++ README.md | 156 ++++++++++++++++++++++----------------- README.zh-Hant.md | 131 ++++++++++++++++++++++++++++++++ 4 files changed, 357 insertions(+), 71 deletions(-) create mode 100644 README.en.md create mode 100644 README.zh-Hant.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e643476..cf48cbc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,7 +4,7 @@ on: push: branches: [main] pull_request: - branches: [main] + workflow_dispatch: permissions: contents: read @@ -20,14 +20,14 @@ jobs: strategy: fail-fast: false matrix: - # package engines: node >=20; cover LTS current + previous - node: [20, 22] + # package engines: node >=20 + node: [20, 22, 24] steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v7 with: node-version: ${{ matrix.node }} cache: npm diff --git a/README.en.md b/README.en.md new file mode 100644 index 0000000..fff83cc --- /dev/null +++ b/README.en.md @@ -0,0 +1,131 @@ +[简体中文](README.md) | [繁體中文](README.zh-Hant.md) | [English](README.en.md) + +# opencode-telegram-remote + +用 Telegram 在手机上遥控 OpenCode,电脑端的回复实时推送到手机。 +A Telegram remote control for [OpenCode](https://opencode.ai) V2: chat with your sessions from your phone and get desktop replies pushed back in real time. + +[![CI](https://github.com/HenryYannis/opencode-telegram-remote/actions/workflows/ci.yml/badge.svg)](https://github.com/HenryYannis/opencode-telegram-remote/actions/workflows/ci.yml) +[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) + +## Features + +- **Native OpenCode V2 plugin.** Built with `Plugin.define` from `@opencode/plugin` (plugin id `telegram`). It runs inside the OpenCode server and starts and stops with it; there is no separate bridge process to keep alive. +- **Chat from your phone.** Plain text is sent as a prompt to the session your chat is bound to. The bot shows "typing…" while OpenCode works, then sends the reply back. +- **Desktop replies pushed to your phone.** The plugin listens to OpenCode's `session.text.ended` events, so replies produced in the desktop window are sent to every chat bound to that session. A delivery tracker makes sure the same reply is not sent twice. +- **`/current`** attaches your chat to the session you last viewed on the desktop, so you can switch between computer and phone in the same conversation. +- **Switch models** with `/model` (tap a button) or `/model `. +- **Switch or create sessions** with `/sessions` and `/new`; stop a running task with `/abort`. +- **Permission prompts on your phone.** When OpenCode asks for permission in a bound session, you get the request with **Allow once / Always / Reject** buttons. +- **Allow-list.** Only the Telegram user IDs you list can use the bot; everyone else gets "Unauthorized". + +## Requirements + +- OpenCode V2 (the plugin is built against `@opencode/plugin` 2.2). +- Node.js 20 or newer (`engines.node` in `package.json`). +- A Telegram bot token from [@BotFather](https://t.me/BotFather) and your numeric Telegram user ID. + +## Install + +The package is not published to npm yet. Install it from GitHub with the OpenCode CLI: + +```sh +opencode plugin add github:HenryYannis/opencode-telegram-remote +``` + +Or clone it and load it as a local plugin directory: + +```sh +git clone https://github.com/HenryYannis/opencode-telegram-remote.git +cd opencode-telegram-remote +npm install +``` + +Then add the absolute path of the cloned folder to `~/.config/opencode/opencode.json(c)`: + +```jsonc +{ + "plugins": ["/absolute/path/to/opencode-telegram-remote"] +} +``` + +## Configuration + +Create `~/.config/opencode/telegram.json`: + +```json +{ + "token": "YOUR_BOT_TOKEN", + "allowedUsers": [123456789] +} +``` + +| Key | Required | Description | +| :--- | :--- | :--- | +| `token` | yes | Bot token from [@BotFather](https://t.me/BotFather) (`/newbot`). | +| `allowedUsers` | yes, non-empty | Numeric Telegram user IDs allowed to use the bot. Get yours from [@userinfobot](https://t.me/userinfobot). | + +- No chat ID is needed: the bot answers any chat where the sender is on the allow-list. A private chat with your bot is the simplest setup. +- If the file is missing, `token` is empty, or `allowedUsers` is empty, the plugin does not start the bot (OpenCode keeps running normally). +- ⚠️ Anyone on the allow-list can run prompts on your machine through OpenCode. Only add your own ID, and keep `telegram.json` private. +- On Windows the path is `%USERPROFILE%\.config\opencode\telegram.json`. + +Optional environment variable: + +| Variable | Effect | +| :--- | :--- | +| `TELEGRAM_PLUGIN_DEBUG` | When set, writes a debug log to `~/.config/opencode/telegram-plugin.log`. | + +## Commands + +| Command | Action | +| :--- | :--- | +| *(plain text)* | Send a prompt to the bound session | +| `/current` | Attach to the session you last viewed on the desktop | +| `/model` | List models as buttons; `/model ` switches to the first model whose ID contains the keyword | +| `/sessions` | List the 10 most recent sessions, with buttons to switch | +| `/new` | Create a new session and bind to it | +| `/abort` | Stop the task running in the bound session | +| `/status` | Show the working directory, bound session and last viewed session | +| `/start` | Show help | + +**Which session does plain text go to?** The session your chat is bound to. If there is none yet, the plugin uses the session you last viewed on the desktop, then the most recently updated session, and otherwise creates a new "Telegram remote session". + +**Where does the model list come from?** From OpenCode's model list (`ctx.model.list()`). If that returns nothing, it falls back to the model keys under `providers..models` in `~/.config/opencode/opencode.json`. + +## How desktop → phone sync works + +``` +A reply finishes in the desktop window + ↓ OpenCode emits session.text.ended (sessionID, assistantMessageID, ordinal, text) +The plugin finds the chats bound to that session + ↓ splits long text into chunks of up to 3800 characters +bot.api.sendMessage → your phone +``` + +Replies can arrive two ways: the event stream, and a fallback that reads the session after `session.wait()` when you sent the prompt from Telegram. Both paths share one delivery tracker (keyed by message ID and text segment), so each reply is delivered once. + +## Limits + +- Text only; photos and voice messages are not supported yet. +- One bot per machine. OpenCode loads the plugin once per location; a lock file (`~/.config/opencode/telegram-plugin.lock`) makes sure only one instance polls Telegram. +- Chat-to-session bindings live in memory and are cleared when OpenCode restarts. Send `/current` or `/sessions` to bind again. + +## FAQ + +**The bot does not answer.** +Check that `telegram.json` is valid JSON with a `token` and a non-empty `allowedUsers`, and that your ID is in the list. Set `TELEGRAM_PLUGIN_DEBUG=1`, restart OpenCode, and read `~/.config/opencode/telegram-plugin.log`. + +**How do I turn the plugin off without uninstalling it?** +Add `"-telegram"` to `plugins` in `opencode.json(c)`, or remove `telegram.json`. + +## Development + +```sh +npm ci +npm run ci # syntax check, unit tests, package validation, smoke import, pack dry-run +``` + +## License + +MIT © Henry Yannis diff --git a/README.md b/README.md index ae8542f..c893853 100644 --- a/README.md +++ b/README.md @@ -1,107 +1,131 @@ -# ⚡️ opencode-telegram-remote +[简体中文](README.md) | [繁體中文](README.zh-Hant.md) | [English](README.en.md) -**A Telegram remote control for [OpenCode](https://opencode.ai) — chat with any window from your phone, and get desktop replies pushed back in real time.** +# opencode-telegram-remote -> 把手机变成 OpenCode 的遥控器:无缝接管电脑窗口、双向实时同步、手机上切换模型和会话。 +用 Telegram 在手机上遥控 OpenCode,电脑端的回复实时推送到手机。 +A Telegram remote control for [OpenCode](https://opencode.ai) V2: chat with your sessions from your phone and get desktop replies pushed back in real time. -[中文说明见下方](#-中文说明) +[![CI](https://github.com/HenryYannis/opencode-telegram-remote/actions/workflows/ci.yml/badge.svg)](https://github.com/HenryYannis/opencode-telegram-remote/actions/workflows/ci.yml) +[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) ---- +## 功能 -## Why this plugin? +- **原生 OpenCode V2 插件**:基于 `@opencode/plugin` 的 `Plugin.define` 编写(插件 id 为 `telegram`),运行在 OpenCode 服务进程内,随 OpenCode 启停,不需要额外的常驻桥接进程。 +- **手机发消息**:普通文本会作为提示词发送到当前聊天绑定的会话。OpenCode 处理期间机器人显示“正在输入…”,完成后把回复发回手机。 +- **电脑端回复推送到手机**:插件监听 OpenCode 的 `session.text.ended` 事件,电脑窗口里产生的回复会发送到所有绑定该会话的聊天;内置去重,同一条回复不会发两次。 +- **`/current`**:把手机接入你在电脑上最近查看的会话,电脑和手机可以在同一个对话里交替使用。 +- **切换模型**:`/model` 点按钮切换,或用 `/model <关键词>`。 +- **切换或新建会话**:`/sessions`、`/new`;用 `/abort` 中止正在运行的任务。 +- **在手机上处理权限请求**:已绑定会话里 OpenCode 请求权限时,会收到带 **Allow once / Always / Reject** 按钮的消息。 +- **白名单**:只有你列出的 Telegram 用户 ID 能使用机器人,其他人会收到 "Unauthorized"。 -Other Telegram integrations for OpenCode are either **standalone bridge processes** or **plugins built for the V1 API that no longer load on OpenCode V2**. This plugin is a **native OpenCode V2 plugin** (`Plugin.define` + plugin context APIs) and adds the one thing nobody else has: **true bidirectional sync between the desktop window and your phone.** +## 环境要求 -| Capability | This plugin | Typical bridge | -| :--- | :--- | :--- | -| Install as an OpenCode plugin (no extra process) | ✅ | ❌ separate Node process | -| Chat from phone → executed in OpenCode | ✅ | ✅ | -| **Desktop replies auto-pushed to phone** | ✅ real-time via event stream | mostly ❌ | -| `/current` — attach phone to the desktop's *current* window | ✅ | ❌ | -| Switch AI models from phone (`/model` + buttons) | ✅ | varies | -| Switch / create sessions from phone | ✅ | varies | -| Lifecycle bound to OpenCode itself | ✅ | ❌ | +- OpenCode V2(插件基于 `@opencode/plugin` 2.2 开发)。 +- Node.js 20 及以上(见 `package.json` 的 `engines.node`)。 +- 从 [@BotFather](https://t.me/BotFather) 获取的机器人 token,以及你的 Telegram 数字用户 ID。 -## Install +## 安装 -Requires **OpenCode V2** (2.2+). In `~/.config/opencode/opencode.json(c)`: +本包暂未发布到 npm。可以用 OpenCode CLI 直接从 GitHub 安装: -```jsonc -{ - "plugins": ["opencode-telegram-remote"] -} +```sh +opencode plugin add github:HenryYannis/opencode-telegram-remote ``` -or install from Git: +或者克隆到本地,作为本地插件目录加载: ```sh -opencode plugin add github:/opencode-telegram-remote +git clone https://github.com/HenryYannis/opencode-telegram-remote.git +cd opencode-telegram-remote +npm install ``` -## Configure +然后在 `~/.config/opencode/opencode.json(c)` 里加入克隆目录的绝对路径: + +```jsonc +{ + "plugins": ["/absolute/path/to/opencode-telegram-remote"] +} +``` -Create `~/.config/opencode/telegram.json`: +## 配置 + +创建 `~/.config/opencode/telegram.json`: ```json { - "token": "", - "allowedUsers": [] + "token": "YOUR_BOT_TOKEN", + "allowedUsers": [123456789] } ``` -- Get the token from [@BotFather](https://t.me/BotFather) (`/newbot`). -- Get your user ID from [@userinfobot](https://t.me/userinfobot). -- ⚠️ **Keep `allowedUsers` filled** — anyone not in the list is rejected. You are handing out shell-level access to your machine. +| 字段 | 是否必填 | 说明 | +| :--- | :--- | :--- | +| `token` | 必填 | 在 [@BotFather](https://t.me/BotFather) 用 `/newbot` 创建机器人后得到的 token。 | +| `allowedUsers` | 必填,不能为空 | 允许使用机器人的 Telegram 数字用户 ID 列表。可通过 [@userinfobot](https://t.me/userinfobot) 查看自己的 ID。 | + +- 不需要填 chat ID:只要发送者在白名单里,机器人就会响应。最简单的用法是和你的机器人私聊。 +- 如果文件不存在、`token` 为空或 `allowedUsers` 为空,插件不会启动机器人,OpenCode 照常运行。 +- ⚠️ 白名单里的人可以通过 OpenCode 在你的电脑上执行任务。只填你自己的 ID,并妥善保管 `telegram.json`。 +- Windows 下路径为 `%USERPROFILE%\.config\opencode\telegram.json`。 -## Commands +可选环境变量: -| Command | Action | +| 变量 | 作用 | | :--- | :--- | -| *(plain text)* | Send a prompt to the bound session | -| `/current` | Attach to the desktop's current active window | -| `/model` | List models (tappable buttons); `/model ` fuzzy-switch | -| `/sessions` | List recent sessions, switch with inline buttons | -| `/new` | Create a new session | -| `/abort` | Interrupt the running task | -| `/status` | Show bound session & working directory | -| `/start` | Help | +| `TELEGRAM_PLUGIN_DEBUG` | 设置后会把调试日志写入 `~/.config/opencode/telegram-plugin.log`。 | -## How the desktop→phone sync works +## 命令 + +| 命令 | 作用 | +| :--- | :--- | +| *(普通文本)* | 发送提示词到已绑定的会话 | +| `/current` | 接入你在电脑上最近查看的会话 | +| `/model` | 以按钮列出模型;`/model <关键词>` 切换到第一个 ID 包含该关键词的模型 | +| `/sessions` | 列出最近 10 个会话,点按钮切换 | +| `/new` | 新建会话并绑定 | +| `/abort` | 中止已绑定会话中正在运行的任务 | +| `/status` | 显示工作目录、已绑定会话和最近查看的会话 | +| `/start` | 显示帮助 | -The plugin subscribes to OpenCode's server event stream via `ctx.event.subscribe`: +**普通文本发到哪个会话?** 发到当前聊天绑定的会话。如果还没有绑定,依次使用:你在电脑上最近查看的会话 → 最近更新的会话 → 新建一个 "Telegram remote session"。 + +**模型列表从哪来?** 来自 OpenCode 的模型列表(`ctx.model.list()`)。如果为空,再读取 `~/.config/opencode/opencode.json` 中 `providers..models` 下的模型名。 + +## 电脑 → 手机同步原理 ``` -Desktop reply finished - ↓ OpenCode broadcasts -session.text.ended (sessionID + assistantMessageID) - ↓ plugin looks up chats bound to that session -fetches the final message text → splits to ≤4096 chars - ↓ -bot.api.sendMessage → your phone +电脑窗口中一条回复结束 + ↓ OpenCode 发出 session.text.ended(sessionID、assistantMessageID、ordinal、text) +插件找到绑定该会话的聊天 + ↓ 长文本按最多 3800 个字符分段 +bot.api.sendMessage → 你的手机 ``` -A dedupe registry (`sentMessageIds`) guarantees the same assistant message is never delivered twice across the two delivery paths (event push + fallback fetch after `wait()`). +回复有两条送达路径:事件流;以及从 Telegram 发起提示时,在 `session.wait()` 之后读取会话的兜底路径。两条路径共用一个投递记录(按消息 ID 和文本段去重),所以每条回复只发一次。 -## Notes & limits +## 限制 -- Text only (no photos/voice yet — PRs welcome). -- One bot per machine (singleton lock); multi-location OpenCode loads are de-duplicated automatically. -- The plugin follows your `opencode.json` providers for `/model`; if parsing config fails it falls back to `ctx.model.list()`. +- 目前只支持文本,暂不支持图片和语音。 +- 每台电脑只运行一个机器人。OpenCode 会为每个 location 加载一次插件,插件用锁文件(`~/.config/opencode/telegram-plugin.lock`)保证只有一个实例在轮询 Telegram。 +- 聊天与会话的绑定保存在内存中,OpenCode 重启后会清空,发送 `/current` 或 `/sessions` 重新绑定即可。 -## License +## 常见问题 -MIT © 2026 HenryYannis +**机器人没有反应?** +确认 `telegram.json` 是合法 JSON,包含 `token` 和非空的 `allowedUsers`,且你的 ID 在其中。设置 `TELEGRAM_PLUGIN_DEBUG=1` 后重启 OpenCode,查看 `~/.config/opencode/telegram-plugin.log`。 ---- +**不卸载的情况下怎么关闭插件?** +在 `opencode.json(c)` 的 `plugins` 中加入 `"-telegram"`,或者删除 `telegram.json`。 -## 🇨🇳 中文说明 +## 开发 -**把手机变成 OpenCode 的遥控器。** +```sh +npm ci +npm run ci # 语法检查、单元测试、插件包校验、导入冒烟测试、打包预演 +``` -- 手机发消息 → 电脑上的 OpenCode 执行 → 回复发回手机; -- **电脑窗口里的回复,实时自动推送到手机**(订阅 `session.text.ended` 事件流,带去重); -- `/current` 一键把手机接入电脑当前正在聊的窗口,两边无缝交替; -- `/model` 在手机上点按钮切换模型;`/sessions` 切换会话;`/new`、`/abort`、`/status` 齐全; -- 纯插件形态:跑在 OpenCode 进程内,随 OpenCode 启停,**不需要任何独立常驻进程**。 +## 许可证 -安装:在 `~/.config/opencode/opencode.json` 里加 `"plugins": ["opencode-telegram-remote"]`,再创建 `~/.config/opencode/telegram.json` 填入 BotFather 的 token 和你的数字 user ID 白名单即可。 +MIT © Henry Yannis diff --git a/README.zh-Hant.md b/README.zh-Hant.md new file mode 100644 index 0000000..32d4922 --- /dev/null +++ b/README.zh-Hant.md @@ -0,0 +1,131 @@ +[简体中文](README.md) | [繁體中文](README.zh-Hant.md) | [English](README.en.md) + +# opencode-telegram-remote + +用 Telegram 在手機上遙控 OpenCode,電腦端的回覆即時推送到手機。 +A Telegram remote control for [OpenCode](https://opencode.ai) V2: chat with your sessions from your phone and get desktop replies pushed back in real time. + +[![CI](https://github.com/HenryYannis/opencode-telegram-remote/actions/workflows/ci.yml/badge.svg)](https://github.com/HenryYannis/opencode-telegram-remote/actions/workflows/ci.yml) +[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) + +## 功能 + +- **原生 OpenCode V2 外掛**:基於 `@opencode/plugin` 的 `Plugin.define` 編寫(外掛 id 為 `telegram`),在 OpenCode 伺服器中執行,隨 OpenCode 啟停,不需要額外的常駐橋接程式。 +- **手機發訊息**:一般文字會作為提示詞發送到目前聊天綁定的會話。OpenCode 處理期間機器人顯示「正在輸入…」,完成後把回覆發回手機。 +- **電腦端回覆推送到手機**:外掛監聽 OpenCode 的 `session.text.ended` 事件,電腦視窗裡產生的回覆會發送到所有綁定該會話的聊天;內建去重,同一則回覆不會發兩次。 +- **`/current`**:把手機接入你在電腦上最近檢視的會話,電腦和手機可以在同一個對話裡交替使用。 +- **切換模型**:`/model` 點按鈕切換,或用 `/model <關鍵詞>`。 +- **切換或新增會話**:`/sessions`、`/new`;用 `/abort` 中止正在執行的任務。 +- **在手機上處理權限請求**:已綁定會話裡 OpenCode 請求權限時,會收到帶 **Allow once / Always / Reject** 按鈕的訊息。 +- **白名單**:只有你列出的 Telegram 使用者 ID 能使用機器人,其他人會收到 "Unauthorized"。 + +## 環境要求 + +- OpenCode V2(外掛基於 `@opencode/plugin` 2.2 開發)。 +- Node.js 20 及以上(見 `package.json` 的 `engines.node`)。 +- 從 [@BotFather](https://t.me/BotFather) 取得的機器人 token,以及你的 Telegram 數字使用者 ID。 + +## 安裝 + +本套件暫未發布到 npm。可以用 OpenCode CLI 直接從 GitHub 安裝: + +```sh +opencode plugin add github:HenryYannis/opencode-telegram-remote +``` + +或者用 git clone 下載到本機,作為本機外掛目錄載入: + +```sh +git clone https://github.com/HenryYannis/opencode-telegram-remote.git +cd opencode-telegram-remote +npm install +``` + +然後在 `~/.config/opencode/opencode.json(c)` 裡加入該目錄的絕對路徑: + +```jsonc +{ + "plugins": ["/absolute/path/to/opencode-telegram-remote"] +} +``` + +## 設定 + +建立 `~/.config/opencode/telegram.json`: + +```json +{ + "token": "YOUR_BOT_TOKEN", + "allowedUsers": [123456789] +} +``` + +| 欄位 | 是否必填 | 說明 | +| :--- | :--- | :--- | +| `token` | 必填 | 在 [@BotFather](https://t.me/BotFather) 用 `/newbot` 建立機器人後得到的 token。 | +| `allowedUsers` | 必填,不能為空 | 允許使用機器人的 Telegram 數字使用者 ID 列表。可透過 [@userinfobot](https://t.me/userinfobot) 檢視自己的 ID。 | + +- 不需要填 chat ID:只要發送者在白名單裡,機器人就會回應。最簡單的用法是私訊你的機器人。 +- 如果檔案不存在、`token` 為空或 `allowedUsers` 為空,外掛不會啟動機器人,OpenCode 照常執行。 +- ⚠️ 白名單裡的人可以透過 OpenCode 在你的電腦上執行任務。只填你自己的 ID,並妥善保管 `telegram.json`。 +- Windows 下路徑為 `%USERPROFILE%\.config\opencode\telegram.json`。 + +可選環境變數: + +| 變數 | 作用 | +| :--- | :--- | +| `TELEGRAM_PLUGIN_DEBUG` | 設定後會把除錯記錄寫入 `~/.config/opencode/telegram-plugin.log`。 | + +## 命令 + +| 命令 | 作用 | +| :--- | :--- | +| *(一般文字)* | 發送提示詞到已綁定的會話 | +| `/current` | 接入你在電腦上最近檢視的會話 | +| `/model` | 以按鈕列出模型;`/model <關鍵詞>` 切換到第一個 ID 包含該關鍵詞的模型 | +| `/sessions` | 列出最近 10 個會話,點按鈕切換 | +| `/new` | 新增會話並綁定 | +| `/abort` | 中止已綁定會話中正在執行的任務 | +| `/status` | 顯示工作目錄、已綁定會話和最近檢視的會話 | +| `/start` | 顯示說明 | + +**一般文字發到哪個會話?** 發到目前聊天綁定的會話。如果還沒有綁定,依序使用:你在電腦上最近檢視的會話 → 最近更新的會話 → 新增一個 "Telegram remote session"。 + +**模型列表從哪來?** 來自 OpenCode 的模型列表(`ctx.model.list()`)。如果為空,再讀取 `~/.config/opencode/opencode.json` 中 `providers..models` 下的模型名稱。 + +## 電腦 → 手機同步原理 + +``` +電腦視窗中一則回覆結束 + ↓ OpenCode 發出 session.text.ended(sessionID、assistantMessageID、ordinal、text) +外掛找出綁定該會話的聊天 + ↓ 長文字按最多 3800 個字元分段 +bot.api.sendMessage → 你的手機 +``` + +回覆有兩條送達路徑:事件流;以及從 Telegram 發起提示時,在 `session.wait()` 之後讀取會話的備援路徑。兩條路徑共用一個投遞記錄(按訊息 ID 和文字段落去重),所以每則回覆只發一次。 + +## 限制 + +- 目前只支援文字,暫不支援圖片和語音。 +- 每台電腦只執行一個機器人。OpenCode 會為每個 location 載入一次外掛,外掛用鎖定檔(`~/.config/opencode/telegram-plugin.lock`)保證只有一個執行個體在輪詢 Telegram。 +- 聊天與會話的綁定保存在記憶體中,OpenCode 重啟後會清空,發送 `/current` 或 `/sessions` 重新綁定即可。 + +## 常見問題 + +**機器人沒有反應?** +確認 `telegram.json` 是有效的 JSON,包含 `token` 和非空的 `allowedUsers`,且你的 ID 在其中。設定 `TELEGRAM_PLUGIN_DEBUG=1` 後重啟 OpenCode,檢視 `~/.config/opencode/telegram-plugin.log`。 + +**不解除安裝的情況下怎麼關閉外掛?** +在 `opencode.json(c)` 的 `plugins` 中加入 `"-telegram"`,或者刪除 `telegram.json`。 + +## 開發 + +```sh +npm ci +npm run ci # 語法檢查、單元測試、外掛套件驗證、匯入冒煙測試、打包試跑 +``` + +## 授權 + +MIT © Henry Yannis From 97cbf288d30470ceaa5265b3f1554cafa081e9e1 Mon Sep 17 00:00:00 2001 From: HenryYannis <247510158+HenryYannis@users.noreply.github.com> Date: Fri, 30 Oct 2026 10:49:25 +0000 Subject: [PATCH 2/2] =?UTF-8?q?docs:=20=E7=BB=9F=E4=B8=80=E7=89=88?= =?UTF-8?q?=E6=9D=83=E7=BD=B2=E5=90=8D=EF=BC=9B=E4=BB=93=E5=BA=93=E9=93=BE?= =?UTF-8?q?=E6=8E=A5=E4=B8=8E=E5=BD=93=E5=89=8D=E4=BB=93=E5=BA=93=E5=90=8D?= =?UTF-8?q?=E4=B8=80=E8=87=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LICENSE | 2 +- README.en.md | 2 +- README.md | 2 +- README.zh-Hant.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/LICENSE b/LICENSE index 357b0a8..30eeafd 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2026 HenryYannis +Copyright (c) 2026 程小宝 (Henry Yannis) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.en.md b/README.en.md index fff83cc..c7157a6 100644 --- a/README.en.md +++ b/README.en.md @@ -128,4 +128,4 @@ npm run ci # syntax check, unit tests, package validation, smoke import, pack ## License -MIT © Henry Yannis +[MIT](LICENSE) © 2026 Henry Yannis diff --git a/README.md b/README.md index c893853..343ea4e 100644 --- a/README.md +++ b/README.md @@ -128,4 +128,4 @@ npm run ci # 语法检查、单元测试、插件包校验、导入冒烟测 ## 许可证 -MIT © Henry Yannis +[MIT](LICENSE) © 2026 程小宝 diff --git a/README.zh-Hant.md b/README.zh-Hant.md index 32d4922..38ee77b 100644 --- a/README.zh-Hant.md +++ b/README.zh-Hant.md @@ -128,4 +128,4 @@ npm run ci # 語法檢查、單元測試、外掛套件驗證、匯入冒煙 ## 授權 -MIT © Henry Yannis +[MIT](LICENSE) © 2026 程小宝