Simplify install with one-click scripts; honor HTTP(S)_PROXY for Telegram.
Add install.ps1/install.sh, shrink README to script-first flow, register bot commands, and route API calls through undici EnvHttpProxyAgent when a proxy is set (v0.2.2). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -2,201 +2,153 @@
|
|||||||
|
|
||||||
[English](#english) · [中文](#中文)
|
[English](#english) · [中文](#中文)
|
||||||
|
|
||||||
**Keywords / 关键词:** Telegram · Bot · Mobile · Remote · Channel · Sessions · Bind · Unbind · Remove · Clear · DeepSeek Harness · DSH · Cordis · dsh-plugin · Agent · Live session · 手机 · 远程 · 遥控器 · 会话列表 · 附着 · 解绑 · 白名单 · 安装
|
Telegram **手机遥控器** for DeepSeek Harness:附着本机正在跑的 Web 会话,与电脑 **同轨迹、双向可见**(Codex-style)。
|
||||||
|
|
||||||
DeepSeek Harness **手机遥控器**:用 Telegram Bot **附着本机正在运行的 Web 会话**(与 Web **同轨迹、双向可见**)。对标 Codex phone remote——本机会话是真相源,手机不另开平行对话。
|
**Keywords:** Telegram · Bot · Mobile · Remote · DSH · Cordis · dsh-plugin · sessions · bind
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 中文
|
## 中文
|
||||||
|
|
||||||
### 这是什么(30 秒看懂)
|
### 30 秒理解
|
||||||
|
|
||||||
1. 电脑上先用 `dsh web` 打开一个对话(保持开着)。
|
1. 电脑 `dsh web` 开着,并打开一个对话
|
||||||
2. 手机 Telegram 找你的 Bot,发 `/sessions`,点选那个对话。
|
2. 手机 Bot 发 `/sessions`,点选该对话
|
||||||
3. 之后手机发的话,会进**同一个**电脑会话;电脑上的回复,手机会同步看到。
|
3. 之后手机 ↔ Web 走**同一条**轨迹
|
||||||
|
|
||||||
| | 旧「平行桥」 | **本插件** |
|
|
||||||
|---|---|---|
|
|
||||||
| 会话 | Telegram 另开一个 agent | 附着电脑里 **正在跑的** 会话 |
|
|
||||||
| Web | 不通 | 手机与 Web **同一条轨迹** |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 安装前请准备(缺一不可)
|
### 一键安装(推荐)
|
||||||
|
|
||||||
请用笔或备忘录记下三样东西:
|
**先准备两样东西:**
|
||||||
|
|
||||||
| # | 准备什么 | 怎么拿 |
|
| 准备 | 怎么拿 |
|
||||||
|---|---|---|
|
|---|---|
|
||||||
| 1 | 电脑已能打开 DeepSeek Harness 网页 | 终端运行 `dsh web`,浏览器能打开(常见 `http://127.0.0.1:3080`) |
|
| Bot Token | Telegram 搜 `@BotFather` → `/newbot` → 复制 token |
|
||||||
| 2 | Telegram **Bot Token** | 手机打开 Telegram → 搜 `@BotFather` → `/newbot` 按提示创建 → 复制一长串类似 `123456:AA...` 的 token |
|
| 数字 User ID | 搜 `@userinfobot` → Start → 复制纯数字 |
|
||||||
| 3 | 你的 Telegram **数字 User ID** | 搜 `@userinfobot` → 点 Start → 它会回复一串**纯数字**(不是 @用户名) |
|
|
||||||
|
|
||||||
> 安全提醒:Token 相当于钥匙,**不要发到公开群、不要提交到 GitHub**。若已泄露,去 BotFather 用 `/revoke` 作废并换新。
|
> Token 不要发到公开群;泄露了去 BotFather `/revoke`。
|
||||||
|
|
||||||
|
#### Windows(PowerShell)
|
||||||
|
|
||||||
|
**方式 A — 远程一键(交互输入 Token / User ID):**
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
irm https://raw.githubusercontent.com/hi-wenw/dsh-telegram-channel/master/scripts/install.ps1 | iex
|
||||||
|
```
|
||||||
|
|
||||||
|
**方式 B — 带参数(不交互):**
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git clone https://github.com/hi-wenw/dsh-telegram-channel.git
|
||||||
|
cd dsh-telegram-channel
|
||||||
|
.\scripts\install.ps1 -Token '这里粘贴Token' -UserId '这里粘贴数字ID'
|
||||||
|
```
|
||||||
|
|
||||||
|
脚本会自动:
|
||||||
|
|
||||||
|
1. 写入用户环境变量 `DSH_TELEGRAM_TOKEN`、`DSH_TELEGRAM_ALLOWED_USER_IDS`
|
||||||
|
2. 给 profile 补上 `allowBuilds`(防止 pnpm 拦截)
|
||||||
|
3. 执行 `dsh plugin --profile web add github:hi-wenw/dsh-telegram-channel`
|
||||||
|
|
||||||
|
**不会**再 `insert` 同名插件行(避免 `duplicate loader entry id`)。
|
||||||
|
|
||||||
|
#### macOS / Linux
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export DSH_TELEGRAM_TOKEN='你的Token'
|
||||||
|
export DSH_TELEGRAM_ALLOWED_USER_IDS='你的数字ID'
|
||||||
|
curl -fsSL https://raw.githubusercontent.com/hi-wenw/dsh-telegram-channel/master/scripts/install.sh | bash
|
||||||
|
```
|
||||||
|
|
||||||
|
或克隆后:`./scripts/install.sh --token '...' --user-id '...'`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 安装步骤(照着做即可)
|
### 安装后只用三步
|
||||||
|
|
||||||
下面假设你用 **Windows**,命令在 **PowerShell** 或 **CMD** 里执行。
|
|
||||||
|
|
||||||
#### 第 1 步:安装插件到 web 配置
|
|
||||||
|
|
||||||
打开终端,复制粘贴整行后回车:
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
dsh plugin --profile web add github:hi-wenw/dsh-telegram-channel
|
|
||||||
```
|
|
||||||
|
|
||||||
**成功时**大致会看到安装完成、没有红色大段报错。
|
|
||||||
|
|
||||||
**如果报错出现 `allowBuilds` / `ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED`:**
|
|
||||||
|
|
||||||
1. 用记事本打开这个文件(没有就新建):
|
|
||||||
`C:\Users\wenw\.dsh\profiles\web\pnpm-workspace.yaml`
|
|
||||||
2. 在文件里加入(或合并)下面内容(路径以报错里打印的为准;若报错给了更长一行,用报错那一行):
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
packages:
|
|
||||||
- .
|
|
||||||
|
|
||||||
nodeLinker: hoisted
|
|
||||||
autoInstallPeers: false
|
|
||||||
|
|
||||||
allowBuilds:
|
|
||||||
dsh-telegram-channel: true
|
|
||||||
```
|
|
||||||
|
|
||||||
3. 保存文件,再重新执行第 1 步那条 `dsh plugin ... add ...` 命令。
|
|
||||||
|
|
||||||
> 说明:从 **v0.2.1** 起,仓库已自带编译好的 `lib/`,一般**不需要**再改 `allowBuilds`。若你装到的仍是旧版缓存,可先执行下面「第 1b 步」再装。
|
|
||||||
|
|
||||||
#### 第 1b 步(可选):清掉旧失败缓存后再装
|
|
||||||
|
|
||||||
若刚才失败过,可先:
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
dsh plugin --profile web remove dsh-telegram-channel
|
|
||||||
```
|
|
||||||
|
|
||||||
然后再执行第 1 步。仍失败时,用本地目录安装(最稳):
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
git clone https://github.com/hi-wenw/dsh-telegram-channel.git D:\gitData\dsh-telegram-channel
|
|
||||||
dsh plugin --profile web add D:\gitData\dsh-telegram-channel
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 第 2 步:设置 Bot Token(推荐环境变量)
|
|
||||||
|
|
||||||
**当前 PowerShell 窗口临时生效**(关窗口会丢,适合先试通):
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
$env:DSH_TELEGRAM_TOKEN = "这里粘贴你的BotFather_Token"
|
|
||||||
```
|
|
||||||
|
|
||||||
**想长期生效(用户级环境变量)**:
|
|
||||||
|
|
||||||
1. Win 键搜索「编辑系统环境变量」→「环境变量」。
|
|
||||||
2. 在「用户变量」点「新建」:
|
|
||||||
- 变量名:`DSH_TELEGRAM_TOKEN`
|
|
||||||
- 变量值:粘贴 BotFather 给你的 token
|
|
||||||
3. 确定保存后,**关掉所有旧终端**,新开一个终端。
|
|
||||||
|
|
||||||
#### 第 3 步:写入白名单(只允许你自己用)
|
|
||||||
|
|
||||||
打开(没有就新建)profile 补丁文件,常见路径:
|
|
||||||
|
|
||||||
`C:\Users\wenw\.dsh\profiles\web\cordis.patch.yml`
|
|
||||||
|
|
||||||
写入下面内容,把 `123456789` 换成你的 **数字 User ID**:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- insert:
|
|
||||||
- id: dsh-telegram-channel
|
|
||||||
name: dsh-telegram-channel
|
|
||||||
config:
|
|
||||||
token: ""
|
|
||||||
allowedUserIds: [123456789]
|
|
||||||
```
|
|
||||||
|
|
||||||
注意:
|
|
||||||
|
|
||||||
- `allowedUserIds` 里必须是**数字**,两边是方括号。
|
|
||||||
- `token: ""` 表示继续用环境变量里的 `DSH_TELEGRAM_TOKEN`(推荐)。
|
|
||||||
- 若插件安装时已经自动插入过同名行,不要重复两份;在已有行上改 `allowedUserIds` 即可。
|
|
||||||
|
|
||||||
也可用示例文件对照:仓库里的 `examples/telegram-agent/cordis.patch.example.yml`。
|
|
||||||
|
|
||||||
#### 第 4 步:启动(或重启)DSH Web
|
|
||||||
|
|
||||||
**重要:改完环境变量 / 补丁后,必须重新开一次 profile。**
|
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
|
# 1. 关掉旧终端,新开一个,然后:
|
||||||
dsh web
|
dsh web
|
||||||
|
|
||||||
|
# 2. 浏览器打开一个对话(保持运行)
|
||||||
|
|
||||||
|
# 3. 手机对 Bot:
|
||||||
|
# /start → /sessions → 点选 → 正常聊天
|
||||||
```
|
```
|
||||||
|
|
||||||
等终端没有报错,浏览器能打开 Harness 页面。
|
输入框旁的 **/** 菜单应有:`start` `sessions` `status` `unbind` `help`。
|
||||||
|
|
||||||
#### 第 5 步:电脑上先开一个对话
|
|
||||||
|
|
||||||
在 Web 页面里 **新建或打开一个会话**,随便让它处于可用状态(这就是手机要遥控的「本机会话」)。
|
|
||||||
|
|
||||||
> 如果 Web 里一个会话都没有,手机发 `/sessions` 会提示「当前没有正在运行的本机会话」。
|
|
||||||
|
|
||||||
#### 第 6 步:手机连上 Bot
|
|
||||||
|
|
||||||
1. 打开 Telegram,搜索你创建的 Bot(BotFather 给你的名字)。
|
|
||||||
2. 点 **Start** / 发送 `/start`。
|
|
||||||
3. 发送 `/sessions`。
|
|
||||||
4. 点按钮,选择电脑上那个会话(「已附着…」)。
|
|
||||||
5. 发一句普通话,例如:`你好,请回复收到`。
|
|
||||||
6. 看手机是否收到回复,并回到电脑 Web:**应是同一条对话轨迹**。
|
|
||||||
|
|
||||||
常用命令:
|
|
||||||
|
|
||||||
| 命令 | 作用 |
|
| 命令 | 作用 |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `/sessions` 或 `/list` | 列出本机 live 会话并选择附着 |
|
| `/sessions` | 列出并附着本机 live 会话 |
|
||||||
| `/status` | 看当前绑了谁 |
|
| `/status` | 当前绑定 |
|
||||||
| `/unbind` 或 `/disconnect` | 断开手机绑定(**不关闭**电脑会话) |
|
| `/unbind` | 只断开手机,**不关**电脑会话 |
|
||||||
| `/help` | 帮助 |
|
| `/help` | 帮助 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 配置项一览
|
### 手工安装(可选)
|
||||||
|
|
||||||
| 键 | 默认 | 含义 |
|
若不想跑脚本:
|
||||||
|---|---|---|
|
|
||||||
| `token` | 空 → 读 `DSH_TELEGRAM_TOKEN` | Bot token |
|
```powershell
|
||||||
| `allowedUserIds` | `[]` | 白名单;空 = 谁都不能用 |
|
# 用户环境变量(或当前会话 $env:...)
|
||||||
| `allowAllUsers` | `false` | `true` 时谁都能聊(仅调试) |
|
# DSH_TELEGRAM_TOKEN = BotFather token
|
||||||
| `maxMessageLength` | `4096` | 单条消息分片长度 |
|
# DSH_TELEGRAM_ALLOWED_USER_IDS = 数字ID
|
||||||
| `pollingTimeoutSec` | `30` | 长轮询超时(秒) |
|
|
||||||
|
dsh plugin --profile web add github:hi-wenw/dsh-telegram-channel
|
||||||
|
dsh web
|
||||||
|
```
|
||||||
|
|
||||||
|
本地目录安装:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
dsh plugin --profile web add D:\path\to\dsh-telegram-channel
|
||||||
|
```
|
||||||
|
|
||||||
|
需要改 YAML 白名单时,**只能按 id 覆盖**,不要再 `insert` 同名 id:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- id: dsh-telegram-channel
|
||||||
|
config:
|
||||||
|
token: ""
|
||||||
|
allowedUserIds: [123456789]
|
||||||
|
```
|
||||||
|
|
||||||
|
示例:`examples/telegram-agent/cordis.patch.example.yml`。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 故障排查(对照表)
|
### 配置
|
||||||
|
|
||||||
| 你看到的现象 | 怎么处理 |
|
| 键 / 环境变量 | 含义 |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `allowBuilds` / `ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED` | 见上文「第 1 步」补 `pnpm-workspace.yaml`,或改用本地目录安装;并确认装的是 **v0.2.1+** |
|
| `token` / `DSH_TELEGRAM_TOKEN` | Bot token |
|
||||||
| 日志 `missing bot token`;Bot 完全不说话 | 检查 `DSH_TELEGRAM_TOKEN` 是否设置;**新开终端**再 `dsh web` |
|
| `allowedUserIds` / `DSH_TELEGRAM_ALLOWED_USER_IDS` | 白名单;都空 = 谁都不能用 |
|
||||||
| 回复「无权限。」 | `allowedUserIds` 是否写错;必须是 @userinfobot 给的数字 ID |
|
| `allowAllUsers` | `true` 仅调试 |
|
||||||
| `/sessions` 说没有会话 | 先在 Web 打开对话并保持 `dsh web` 运行 |
|
| `maxMessageLength` | 默认 4096 |
|
||||||
| 「尚未绑定」 | 先 `/sessions` 点选 |
|
| `pollingTimeoutSec` | 默认 30 |
|
||||||
| 「会话已不在本机运行」 | Web 已关掉该会话;重新开再 `/sessions` |
|
|
||||||
| Telegram 401 | Token 错了或被 revoke;去 BotFather 换新 |
|
若本机用了 HTTP(S)_PROXY 访问 Telegram,插件会自动走代理(无需再设 `NODE_USE_ENV_PROXY`)。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 安全
|
### 故障排查
|
||||||
|
|
||||||
- 白名单默认 **谁都不允许**,必须填你的 ID。
|
| 现象 | 处理 |
|
||||||
- Token 优先放环境变量,不要写进 Git。
|
|---|---|
|
||||||
- `/unbind` 只断开手机,不会结束电脑上的 agent。
|
| `allowBuilds` / `ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED` | 再跑一遍安装脚本,或手工在 `~\.dsh\profiles\web\pnpm-workspace.yaml` 加 `allowBuilds.dsh-telegram-channel: true` |
|
||||||
|
| `duplicate loader entry id: dsh-telegram-channel` | 用户 patch **不要 insert** 同名 id;用上面的 `- id:` 覆盖,或只用环境变量白名单 |
|
||||||
|
| 手机完全没回复 / ConnectTimeout | 打开本地代理(如 7890),重启 `dsh web` |
|
||||||
|
| `missing bot token` | 检查环境变量;**新开终端**再 `dsh web` |
|
||||||
|
| 「无权限」 | User ID 必须是 `@userinfobot` 的数字 |
|
||||||
|
| `/sessions` 无会话 | 先在 Web 打开对话 |
|
||||||
|
| Telegram 401 | Token 错了或被 revoke |
|
||||||
|
|
||||||
### 贡献者开发
|
---
|
||||||
|
|
||||||
|
### 开发
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
git clone https://github.com/hi-wenw/dsh-telegram-channel.git
|
git clone https://github.com/hi-wenw/dsh-telegram-channel.git
|
||||||
@@ -216,36 +168,42 @@ npm run build
|
|||||||
|
|
||||||
### What this is
|
### What this is
|
||||||
|
|
||||||
Telegram **mobile remote** for **live** DeepSeek Harness Web agents in the same `dsh web` process. Desktop/Web is the source of truth (Codex-style). Telegram **attaches**; it does not create a parallel hidden agent.
|
Telegram **mobile remote** for **live** DeepSeek Harness Web agents. Desktop/Web is the source of truth; the phone **attaches** (no parallel hidden agent).
|
||||||
|
|
||||||
### Install (Windows)
|
### One-click install (Windows)
|
||||||
|
|
||||||
1. Prerequisites: working `dsh web`, BotFather **token**, numeric Telegram **user id** (`@userinfobot`).
|
```powershell
|
||||||
2. Install:
|
irm https://raw.githubusercontent.com/hi-wenw/dsh-telegram-channel/master/scripts/install.ps1 | iex
|
||||||
|
```
|
||||||
|
|
||||||
|
Or with params after clone:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\scripts\install.ps1 -Token '...' -UserId '123456789'
|
||||||
|
```
|
||||||
|
|
||||||
|
The script sets user env vars, ensures `allowBuilds`, and runs `dsh plugin add`. Then:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
dsh web
|
||||||
|
# open a Web chat → phone: /sessions → bind
|
||||||
|
```
|
||||||
|
|
||||||
|
### Unix
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export DSH_TELEGRAM_TOKEN='...'
|
||||||
|
export DSH_TELEGRAM_ALLOWED_USER_IDS='123456789'
|
||||||
|
curl -fsSL https://raw.githubusercontent.com/hi-wenw/dsh-telegram-channel/master/scripts/install.sh | bash
|
||||||
|
```
|
||||||
|
|
||||||
|
### Manual
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
dsh plugin --profile web add github:hi-wenw/dsh-telegram-channel
|
dsh plugin --profile web add github:hi-wenw/dsh-telegram-channel
|
||||||
```
|
```
|
||||||
|
|
||||||
If pnpm prints `allowBuilds` / `ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED`, add under `C:\Users\<you>\.dsh\profiles\web\pnpm-workspace.yaml`:
|
Allowlist via `DSH_TELEGRAM_ALLOWED_USER_IDS` (preferred) or id-targeted YAML override — **never** re-`insert` the same plugin id.
|
||||||
|
|
||||||
```yaml
|
|
||||||
allowBuilds:
|
|
||||||
dsh-telegram-channel: true
|
|
||||||
```
|
|
||||||
|
|
||||||
Then re-run the install command. **v0.2.1+** ships prebuilt `lib/` so this is usually unnecessary.
|
|
||||||
|
|
||||||
Fallback (most reliable):
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
git clone https://github.com/hi-wenw/dsh-telegram-channel.git
|
|
||||||
dsh plugin --profile web add <absolute-path-to-clone>
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Set token: `$env:DSH_TELEGRAM_TOKEN = "..."`.
|
|
||||||
4. Patch `allowedUserIds` in `~\.dsh\profiles\web\cordis.patch.yml` (see example above).
|
|
||||||
5. Restart `dsh web`, open a Web conversation, then on phone: `/sessions` → bind → chat.
|
|
||||||
|
|
||||||
### License
|
### License
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
- insert:
|
# 插件安装时已自动 insert。用户 patch 只需按 id 覆盖 config(不要再 insert 同名 id)。
|
||||||
- id: dsh-telegram-channel
|
- id: dsh-telegram-channel
|
||||||
name: dsh-telegram-channel
|
config:
|
||||||
config:
|
token: ''
|
||||||
token: ''
|
allowedUserIds: [123456789]
|
||||||
allowedUserIds: [123456789]
|
|
||||||
|
|||||||
@@ -51,9 +51,21 @@ export class TelegramBridge {
|
|||||||
this.ctx.logger.error(this.redact(err));
|
this.ctx.logger.error(this.redact(err));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
void this.client.setMyCommands([
|
||||||
|
{ command: 'start', description: '欢迎与用法' },
|
||||||
|
{ command: 'sessions', description: '列出并附着本机 live 会话' },
|
||||||
|
{ command: 'status', description: '查看当前绑定' },
|
||||||
|
{ command: 'unbind', description: '断开手机绑定(不关闭本机会话)' },
|
||||||
|
{ command: 'help', description: '显示帮助' },
|
||||||
|
]).then(() => {
|
||||||
|
this.ctx.logger.info('dsh-telegram-channel: bot commands registered');
|
||||||
|
}).catch((err) => {
|
||||||
|
this.ctx.logger.warn(`dsh-telegram-channel: setMyCommands failed: ${this.redact(err)}`);
|
||||||
|
});
|
||||||
if (!this.polling) {
|
if (!this.polling) {
|
||||||
this.polling = true;
|
this.polling = true;
|
||||||
this.pollAbort = new AbortController();
|
this.pollAbort = new AbortController();
|
||||||
|
this.ctx.logger.info('dsh-telegram-channel: long-polling started');
|
||||||
this.pollPromise = this.pollLoop();
|
this.pollPromise = this.pollLoop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+6
@@ -35,6 +35,10 @@ export interface InlineKeyboardButton {
|
|||||||
export interface InlineKeyboardMarkup {
|
export interface InlineKeyboardMarkup {
|
||||||
inline_keyboard: InlineKeyboardButton[][];
|
inline_keyboard: InlineKeyboardButton[][];
|
||||||
}
|
}
|
||||||
|
export interface TelegramBotCommand {
|
||||||
|
command: string;
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
export interface TelegramClientOptions {
|
export interface TelegramClientOptions {
|
||||||
fetch?: typeof fetch;
|
fetch?: typeof fetch;
|
||||||
baseUrl?: string;
|
baseUrl?: string;
|
||||||
@@ -46,6 +50,7 @@ export interface TelegramClientLike {
|
|||||||
sendMessage(chatId: number, text: string, parseMode?: string, replyMarkup?: InlineKeyboardMarkup): Promise<TelegramMessage>;
|
sendMessage(chatId: number, text: string, parseMode?: string, replyMarkup?: InlineKeyboardMarkup): Promise<TelegramMessage>;
|
||||||
sendChatAction(chatId: number, action: string): Promise<boolean>;
|
sendChatAction(chatId: number, action: string): Promise<boolean>;
|
||||||
answerCallbackQuery(callbackQueryId: string, text?: string): Promise<boolean>;
|
answerCallbackQuery(callbackQueryId: string, text?: string): Promise<boolean>;
|
||||||
|
setMyCommands(commands: TelegramBotCommand[]): Promise<boolean>;
|
||||||
}
|
}
|
||||||
export declare class TelegramClient implements TelegramClientLike {
|
export declare class TelegramClient implements TelegramClientLike {
|
||||||
private readonly token;
|
private readonly token;
|
||||||
@@ -60,4 +65,5 @@ export declare class TelegramClient implements TelegramClientLike {
|
|||||||
sendMessage(chatId: number, text: string, parseMode?: string, replyMarkup?: InlineKeyboardMarkup): Promise<TelegramMessage>;
|
sendMessage(chatId: number, text: string, parseMode?: string, replyMarkup?: InlineKeyboardMarkup): Promise<TelegramMessage>;
|
||||||
sendChatAction(chatId: number, action: string): Promise<boolean>;
|
sendChatAction(chatId: number, action: string): Promise<boolean>;
|
||||||
answerCallbackQuery(callbackQueryId: string, text?: string): Promise<boolean>;
|
answerCallbackQuery(callbackQueryId: string, text?: string): Promise<boolean>;
|
||||||
|
setMyCommands(commands: TelegramBotCommand[]): Promise<boolean>;
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-1
@@ -1,3 +1,25 @@
|
|||||||
|
import { EnvHttpProxyAgent, fetch as undiciFetch } from 'undici';
|
||||||
|
function resolveProxyUrl() {
|
||||||
|
return (process.env.HTTPS_PROXY
|
||||||
|
|| process.env.HTTP_PROXY
|
||||||
|
|| process.env.https_proxy
|
||||||
|
|| process.env.http_proxy
|
||||||
|
|| undefined);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Node's global `fetch` ignores HTTP(S)_PROXY unless `NODE_USE_ENV_PROXY=1`.
|
||||||
|
* Undici's EnvHttpProxyAgent honors the env vars (and NO_PROXY).
|
||||||
|
*/
|
||||||
|
function createDefaultFetch() {
|
||||||
|
if (!resolveProxyUrl())
|
||||||
|
return globalThis.fetch;
|
||||||
|
const agent = new EnvHttpProxyAgent();
|
||||||
|
const proxied = ((input, init) => undiciFetch(input, {
|
||||||
|
...init,
|
||||||
|
dispatcher: agent,
|
||||||
|
}));
|
||||||
|
return proxied;
|
||||||
|
}
|
||||||
export class TelegramClient {
|
export class TelegramClient {
|
||||||
token;
|
token;
|
||||||
fetchImpl;
|
fetchImpl;
|
||||||
@@ -8,7 +30,7 @@ export class TelegramClient {
|
|||||||
throw new Error('bot token is required');
|
throw new Error('bot token is required');
|
||||||
}
|
}
|
||||||
this.token = token;
|
this.token = token;
|
||||||
this.fetchImpl = options.fetch ?? fetch;
|
this.fetchImpl = options.fetch ?? createDefaultFetch();
|
||||||
this.baseUrl = options.baseUrl ?? 'https://api.telegram.org';
|
this.baseUrl = options.baseUrl ?? 'https://api.telegram.org';
|
||||||
this.pollingTimeoutSec = options.pollingTimeoutSec ?? 30;
|
this.pollingTimeoutSec = options.pollingTimeoutSec ?? 30;
|
||||||
}
|
}
|
||||||
@@ -69,4 +91,7 @@ export class TelegramClient {
|
|||||||
body.text = text;
|
body.text = text;
|
||||||
return this.call('answerCallbackQuery', body);
|
return this.call('answerCallbackQuery', body);
|
||||||
}
|
}
|
||||||
|
async setMyCommands(commands) {
|
||||||
|
return this.call('setMyCommands', { commands });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-1
@@ -9,6 +9,18 @@ export const Config = Schema.object({
|
|||||||
maxMessageLength: Schema.number().default(4096),
|
maxMessageLength: Schema.number().default(4096),
|
||||||
pollingTimeoutSec: Schema.number().default(30),
|
pollingTimeoutSec: Schema.number().default(30),
|
||||||
});
|
});
|
||||||
|
function resolveAllowedUserIds(config) {
|
||||||
|
if (config.allowedUserIds && config.allowedUserIds.length > 0) {
|
||||||
|
return config.allowedUserIds;
|
||||||
|
}
|
||||||
|
const raw = process.env.DSH_TELEGRAM_ALLOWED_USER_IDS ?? '';
|
||||||
|
return raw
|
||||||
|
.split(/[,;\s]+/)
|
||||||
|
.map((part) => part.trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
.map((part) => Number(part))
|
||||||
|
.filter((n) => Number.isFinite(n) && n > 0);
|
||||||
|
}
|
||||||
export function apply(ctx, config) {
|
export function apply(ctx, config) {
|
||||||
const token = (config.token && config.token.length > 0)
|
const token = (config.token && config.token.length > 0)
|
||||||
? config.token
|
? config.token
|
||||||
@@ -19,7 +31,7 @@ export function apply(ctx, config) {
|
|||||||
}
|
}
|
||||||
const bridge = new TelegramBridge(ctx, {
|
const bridge = new TelegramBridge(ctx, {
|
||||||
token,
|
token,
|
||||||
allowedUserIds: config.allowedUserIds ?? [],
|
allowedUserIds: resolveAllowedUserIds(config),
|
||||||
allowAllUsers: config.allowAllUsers ?? false,
|
allowAllUsers: config.allowAllUsers ?? false,
|
||||||
maxMessageLength: config.maxMessageLength ?? 4096,
|
maxMessageLength: config.maxMessageLength ?? 4096,
|
||||||
pollingTimeoutSec: config.pollingTimeoutSec ?? 30,
|
pollingTimeoutSec: config.pollingTimeoutSec ?? 30,
|
||||||
|
|||||||
Generated
+693
@@ -0,0 +1,693 @@
|
|||||||
|
{
|
||||||
|
"name": "dsh-telegram-channel",
|
||||||
|
"version": "0.2.1",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "dsh-telegram-channel",
|
||||||
|
"version": "0.2.1",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"undici": "^7.29.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@deepseek-ai/cordis": "^4.0.1",
|
||||||
|
"@deepseek-ai/dsh-agent": "^0.1.0-rc.6",
|
||||||
|
"@deepseek-ai/dsh-llm": "^0.0.1-rc.1",
|
||||||
|
"@deepseek-ai/dsh-session": "^0.0.1-rc.1",
|
||||||
|
"@deepseek-ai/schemastery": "^3.18.1",
|
||||||
|
"@types/node": "^22.0.0",
|
||||||
|
"tsx": "^4.19.0",
|
||||||
|
"typescript": "^5.9.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=22"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@deepseek-ai/cordis": "^4.0.1",
|
||||||
|
"@deepseek-ai/dsh-agent": "^0.1.0-rc.6",
|
||||||
|
"@deepseek-ai/dsh-llm": "^0.0.1-rc.1",
|
||||||
|
"@deepseek-ai/dsh-session": "^0.0.1-rc.1",
|
||||||
|
"@deepseek-ai/schemastery": "^3.18.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@deepseek-ai/cordis": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@deepseek-ai/cordis/-/cordis-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-YBdskTU2Po1kru3GgcUWUbkTsPMA9LkSQDAY8rBkFJeajdgcQad3QPJZE26JyK99Xb6HaASvoXg2DSUTeN/0Nw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@deepseek-ai/cosmokit": "^1.8.2",
|
||||||
|
"@standard-schema/spec": "^1.1.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"cordis": "bin.js"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@deepseek-ai/cordis-plugin-include": "^1.0.6",
|
||||||
|
"@deepseek-ai/cordis-plugin-loader": "^1.0.2"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@deepseek-ai/cordis-plugin-include": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@deepseek-ai/cordis-plugin-loader": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@deepseek-ai/cosmokit": {
|
||||||
|
"version": "1.8.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@deepseek-ai/cosmokit/-/cosmokit-1.8.2.tgz",
|
||||||
|
"integrity": "sha512-muBOKtSrUKU5m/xpq8ZXWL6hQ/jgd4PhU2PqH97bcxIiLEJfNwZOGQEx4t/aS/GgxRAR+ra9pMHPMtTHU4sqqA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@deepseek-ai/dsh-agent": {
|
||||||
|
"version": "0.1.0-rc.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-agent/-/dsh-agent-0.1.0-rc.6.tgz",
|
||||||
|
"integrity": "sha512-vtqq2pWTrzn0dKfj5kREZRpP82AwtGjGx9V1lYnKvF+Uc/a8zyWbSvjDE7V1d3YQAQJzs2cWO31hURWDekDXIA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@deepseek-ai/cordis": "^4.0.1",
|
||||||
|
"@deepseek-ai/dsh-invariants": "^0.1.0-rc.6",
|
||||||
|
"@deepseek-ai/dsh-llm": "^0.1.0-rc.6",
|
||||||
|
"@deepseek-ai/dsh-scope": "^0.1.0-rc.6",
|
||||||
|
"@deepseek-ai/dsh-session": "^0.1.0-rc.6",
|
||||||
|
"@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.6",
|
||||||
|
"@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@deepseek-ai/dsh-llm": {
|
||||||
|
"version": "0.0.1-rc.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-llm/-/dsh-llm-0.0.1-rc.1.tgz",
|
||||||
|
"integrity": "sha512-mRJj07IQNfRReGrhpMpL8AONiYKqfwzxvepg/ut9Wkj8oH2BuoftPS4cMnnXFFCUlYql04/sezwDLriYks/bmw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"@deepseek-ai/schemastery": "^3.18.1-rc.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@deepseek-ai/cordis": "^4.0.1-rc.1",
|
||||||
|
"@deepseek-ai/dsh-attachment": "^0.0.1-rc.1",
|
||||||
|
"@deepseek-ai/dsh-brand": "^0.0.1-rc.1",
|
||||||
|
"@deepseek-ai/dsh-invariants": "^0.0.1-rc.1",
|
||||||
|
"@deepseek-ai/dsh-timeout": "^0.0.1-rc.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@deepseek-ai/dsh-session": {
|
||||||
|
"version": "0.0.1-rc.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session/-/dsh-session-0.0.1-rc.1.tgz",
|
||||||
|
"integrity": "sha512-P3xE+0jDPMImdWhRi3e5ByhkA6LFTiabQwcK+Ofy763tWajDsadWpvONkc5Imd61thpVtXzH3uu25rZFvT5cfw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@deepseek-ai/cordis": "^4.0.1-rc.1",
|
||||||
|
"@deepseek-ai/dsh-brand": "^0.0.1-rc.1",
|
||||||
|
"@deepseek-ai/dsh-invariants": "^0.0.1-rc.1",
|
||||||
|
"@deepseek-ai/dsh-llm": "^0.0.1-rc.1",
|
||||||
|
"@deepseek-ai/dsh-scope": "^0.0.1-rc.1",
|
||||||
|
"@deepseek-ai/dsh-type-meta": "^0.0.1-rc.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@deepseek-ai/schemastery": {
|
||||||
|
"version": "3.18.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@deepseek-ai/schemastery/-/schemastery-3.18.1.tgz",
|
||||||
|
"integrity": "sha512-Qn0FCSwCQnpnj6SB31I6i2sIKgKWnkbJM8O0EU91Gv2UsYVvtZTl6IA0sCwk2e2MZf5S8w5hpq9QkeVvK9qwxg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@deepseek-ai/cosmokit": "^1.8.2",
|
||||||
|
"@standard-schema/spec": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/aix-ppc64": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==",
|
||||||
|
"cpu": [
|
||||||
|
"ppc64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"aix"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/android-arm": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/android-arm64": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/android-x64": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/darwin-arm64": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/darwin-x64": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/freebsd-arm64": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"freebsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/freebsd-x64": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"freebsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-arm": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-arm64": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-ia32": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==",
|
||||||
|
"cpu": [
|
||||||
|
"ia32"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-loong64": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==",
|
||||||
|
"cpu": [
|
||||||
|
"loong64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-mips64el": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==",
|
||||||
|
"cpu": [
|
||||||
|
"mips64el"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-ppc64": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==",
|
||||||
|
"cpu": [
|
||||||
|
"ppc64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-riscv64": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==",
|
||||||
|
"cpu": [
|
||||||
|
"riscv64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-s390x": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==",
|
||||||
|
"cpu": [
|
||||||
|
"s390x"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-x64": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/netbsd-arm64": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"netbsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/netbsd-x64": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"netbsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/openbsd-arm64": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"openbsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/openbsd-x64": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"openbsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/openharmony-arm64": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"openharmony"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/sunos-x64": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"sunos"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/win32-arm64": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/win32-ia32": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==",
|
||||||
|
"cpu": [
|
||||||
|
"ia32"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/win32-x64": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@standard-schema/spec": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@types/node": {
|
||||||
|
"version": "22.20.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.1.tgz",
|
||||||
|
"integrity": "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": "~6.21.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/esbuild": {
|
||||||
|
"version": "0.28.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz",
|
||||||
|
"integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==",
|
||||||
|
"dev": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"esbuild": "bin/esbuild"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@esbuild/aix-ppc64": "0.28.2",
|
||||||
|
"@esbuild/android-arm": "0.28.2",
|
||||||
|
"@esbuild/android-arm64": "0.28.2",
|
||||||
|
"@esbuild/android-x64": "0.28.2",
|
||||||
|
"@esbuild/darwin-arm64": "0.28.2",
|
||||||
|
"@esbuild/darwin-x64": "0.28.2",
|
||||||
|
"@esbuild/freebsd-arm64": "0.28.2",
|
||||||
|
"@esbuild/freebsd-x64": "0.28.2",
|
||||||
|
"@esbuild/linux-arm": "0.28.2",
|
||||||
|
"@esbuild/linux-arm64": "0.28.2",
|
||||||
|
"@esbuild/linux-ia32": "0.28.2",
|
||||||
|
"@esbuild/linux-loong64": "0.28.2",
|
||||||
|
"@esbuild/linux-mips64el": "0.28.2",
|
||||||
|
"@esbuild/linux-ppc64": "0.28.2",
|
||||||
|
"@esbuild/linux-riscv64": "0.28.2",
|
||||||
|
"@esbuild/linux-s390x": "0.28.2",
|
||||||
|
"@esbuild/linux-x64": "0.28.2",
|
||||||
|
"@esbuild/netbsd-arm64": "0.28.2",
|
||||||
|
"@esbuild/netbsd-x64": "0.28.2",
|
||||||
|
"@esbuild/openbsd-arm64": "0.28.2",
|
||||||
|
"@esbuild/openbsd-x64": "0.28.2",
|
||||||
|
"@esbuild/openharmony-arm64": "0.28.2",
|
||||||
|
"@esbuild/sunos-x64": "0.28.2",
|
||||||
|
"@esbuild/win32-arm64": "0.28.2",
|
||||||
|
"@esbuild/win32-ia32": "0.28.2",
|
||||||
|
"@esbuild/win32-x64": "0.28.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fsevents": {
|
||||||
|
"version": "2.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
|
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||||
|
"dev": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsx": {
|
||||||
|
"version": "4.23.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.12.tgz",
|
||||||
|
"integrity": "sha512-FDf4L4sYzKtzWYhU/Xm0AQFdTjdIxNo9ElTf2mxXM6k8YMHXzYUe4yODVaXP4V9uMFbVg8c0qyBccK2OOxb45Q==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"esbuild": "~0.28.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"tsx": "dist/cli.mjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.0.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"fsevents": "~2.3.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/typescript": {
|
||||||
|
"version": "5.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||||
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bin": {
|
||||||
|
"tsc": "bin/tsc",
|
||||||
|
"tsserver": "bin/tsserver"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/undici": {
|
||||||
|
"version": "7.29.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz",
|
||||||
|
"integrity": "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20.18.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/undici-types": {
|
||||||
|
"version": "6.21.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||||
|
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
-8
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "dsh-telegram-channel",
|
"name": "dsh-telegram-channel",
|
||||||
"version": "0.2.1",
|
"version": "0.2.2",
|
||||||
"description": "DeepSeek Harness Telegram mobile remote: bind live Web sessions (Codex-style), same trajectory, /sessions picker, unbind/clear — dsh-plugin",
|
"description": "DeepSeek Harness Telegram mobile remote: bind live Web sessions (Codex-style), same trajectory, /sessions picker, unbind/clear — dsh-plugin",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"telegram",
|
"telegram",
|
||||||
@@ -41,6 +41,7 @@
|
|||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"lib",
|
"lib",
|
||||||
|
"scripts",
|
||||||
"cordis.patch.yml",
|
"cordis.patch.yml",
|
||||||
"README.md",
|
"README.md",
|
||||||
"LICENSE"
|
"LICENSE"
|
||||||
@@ -59,22 +60,25 @@
|
|||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@deepseek-ai/cordis": "^4.0.1",
|
"@deepseek-ai/cordis": "^4.0.1",
|
||||||
"@deepseek-ai/schemastery": "^3.18.1",
|
|
||||||
"@deepseek-ai/dsh-agent": "^0.1.0-rc.6",
|
"@deepseek-ai/dsh-agent": "^0.1.0-rc.6",
|
||||||
"@deepseek-ai/dsh-llm": "^0.0.1-rc.1",
|
"@deepseek-ai/dsh-llm": "^0.0.1-rc.1",
|
||||||
"@deepseek-ai/dsh-session": "^0.0.1-rc.1"
|
"@deepseek-ai/dsh-session": "^0.0.1-rc.1",
|
||||||
|
"@deepseek-ai/schemastery": "^3.18.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^22.0.0",
|
|
||||||
"tsx": "^4.19.0",
|
|
||||||
"typescript": "^5.9.0",
|
|
||||||
"@deepseek-ai/cordis": "^4.0.1",
|
"@deepseek-ai/cordis": "^4.0.1",
|
||||||
"@deepseek-ai/schemastery": "^3.18.1",
|
|
||||||
"@deepseek-ai/dsh-agent": "^0.1.0-rc.6",
|
"@deepseek-ai/dsh-agent": "^0.1.0-rc.6",
|
||||||
"@deepseek-ai/dsh-llm": "^0.0.1-rc.1",
|
"@deepseek-ai/dsh-llm": "^0.0.1-rc.1",
|
||||||
"@deepseek-ai/dsh-session": "^0.0.1-rc.1"
|
"@deepseek-ai/dsh-session": "^0.0.1-rc.1",
|
||||||
|
"@deepseek-ai/schemastery": "^3.18.1",
|
||||||
|
"@types/node": "^22.0.0",
|
||||||
|
"tsx": "^4.19.0",
|
||||||
|
"typescript": "^5.9.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22"
|
"node": ">=22"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"undici": "^7.29.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,155 @@
|
|||||||
|
#Requires -Version 5.1
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
One-click install for dsh-telegram-channel (DeepSeek Harness Telegram remote).
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
1) Writes user env: DSH_TELEGRAM_TOKEN + DSH_TELEGRAM_ALLOWED_USER_IDS
|
||||||
|
2) Ensures allowBuilds for the plugin (belt-and-suspenders)
|
||||||
|
3) Runs: dsh plugin --profile <name> add <source>
|
||||||
|
Does NOT edit cordis.patch.yml (avoids duplicate loader entry).
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
# Interactive (prompts for token + user id)
|
||||||
|
irm https://raw.githubusercontent.com/hi-wenw/dsh-telegram-channel/master/scripts/install.ps1 | iex
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
.\scripts\install.ps1 -Token '123:AA...' -UserId '7057906059'
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
# Install from this cloned repo instead of GitHub
|
||||||
|
.\scripts\install.ps1 -Token '...' -UserId '...' -Local
|
||||||
|
#>
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[string] $Token = $env:DSH_TELEGRAM_TOKEN,
|
||||||
|
[string] $UserId = $env:DSH_TELEGRAM_ALLOWED_USER_IDS,
|
||||||
|
[string] $ProfileName = 'web',
|
||||||
|
[string] $Source = 'github:hi-wenw/dsh-telegram-channel',
|
||||||
|
[switch] $Local,
|
||||||
|
[switch] $NoPersist
|
||||||
|
)
|
||||||
|
|
||||||
|
Set-StrictMode -Version Latest
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
function Write-Step([string] $Message) {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "==> $Message" -ForegroundColor Cyan
|
||||||
|
}
|
||||||
|
|
||||||
|
function Ensure-Command([string] $Name) {
|
||||||
|
if (-not (Get-Command $Name -ErrorAction SilentlyContinue)) {
|
||||||
|
throw "找不到命令 '$Name'。请先安装并确保 DeepSeek Harness CLI(dsh)在 PATH 中。"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Set-UserEnv([string] $Name, [string] $Value) {
|
||||||
|
Set-Item -Path "Env:$Name" -Value $Value
|
||||||
|
if (-not $NoPersist) {
|
||||||
|
[Environment]::SetEnvironmentVariable($Name, $Value, 'User')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Ensure-AllowBuilds([string] $ProfileDir) {
|
||||||
|
$path = Join-Path $ProfileDir 'pnpm-workspace.yaml'
|
||||||
|
$block = @'
|
||||||
|
allowBuilds:
|
||||||
|
dsh-telegram-channel: true
|
||||||
|
'@
|
||||||
|
if (-not (Test-Path -LiteralPath $path)) {
|
||||||
|
$content = @"
|
||||||
|
packages:
|
||||||
|
- .
|
||||||
|
|
||||||
|
nodeLinker: hoisted
|
||||||
|
autoInstallPeers: false
|
||||||
|
|
||||||
|
$block
|
||||||
|
"@
|
||||||
|
Set-Content -LiteralPath $path -Value $content -Encoding utf8
|
||||||
|
Write-Host "已创建 $path (allowBuilds)"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$raw = Get-Content -LiteralPath $path -Raw
|
||||||
|
if ($raw -match '(?m)^\s*dsh-telegram-channel\s*:\s*true\s*$') {
|
||||||
|
Write-Host "allowBuilds 已存在,跳过"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($raw -match '(?m)^allowBuilds\s*:') {
|
||||||
|
if ($raw -notmatch '(?m)^allowBuilds\s*:[\s\S]*?dsh-telegram-channel\s*:') {
|
||||||
|
$raw = $raw -replace '(?m)^(allowBuilds\s*:)', "`$1`r`n dsh-telegram-channel: true"
|
||||||
|
$out = ($raw.TrimEnd() + "`r`n")
|
||||||
|
Set-Content -LiteralPath $path -Value $out -Encoding utf8
|
||||||
|
Write-Host "已写入 allowBuilds.dsh-telegram-channel → $path"
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Add-Content -LiteralPath $path -Value "`r`n$block`r`n" -Encoding utf8
|
||||||
|
Write-Host "已追加 allowBuilds → $path"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "dsh-telegram-channel installer" -ForegroundColor Green
|
||||||
|
Write-Host "Profile: $ProfileName"
|
||||||
|
|
||||||
|
Ensure-Command 'dsh'
|
||||||
|
|
||||||
|
if (-not $Token) {
|
||||||
|
$Token = Read-Host '粘贴 BotFather 的 Bot Token(不要发到公开群)'
|
||||||
|
}
|
||||||
|
$Token = ([string]$Token).Trim()
|
||||||
|
if (-not $Token) { throw '缺少 Bot Token。' }
|
||||||
|
|
||||||
|
if (-not $UserId) {
|
||||||
|
$UserId = Read-Host '粘贴你的 Telegram 数字 User ID(@userinfobot)'
|
||||||
|
}
|
||||||
|
$UserId = ([string]$UserId).Trim()
|
||||||
|
if ($UserId -notmatch '^\d+(?:\s*,\s*\d+)*$') {
|
||||||
|
throw "User ID 必须是数字(多个用逗号分隔),收到: '$UserId'"
|
||||||
|
}
|
||||||
|
$UserId = ($UserId -replace '\s+', '')
|
||||||
|
|
||||||
|
Write-Step '写入用户环境变量(当前进程 + 用户级永久)'
|
||||||
|
Set-UserEnv 'DSH_TELEGRAM_TOKEN' $Token
|
||||||
|
Set-UserEnv 'DSH_TELEGRAM_ALLOWED_USER_IDS' $UserId
|
||||||
|
Write-Host "DSH_TELEGRAM_TOKEN = (已设置,长度 $($Token.Length))"
|
||||||
|
Write-Host "DSH_TELEGRAM_ALLOWED_USER_IDS = $UserId"
|
||||||
|
if ($NoPersist) {
|
||||||
|
Write-Host '(-NoPersist:未写入用户级环境变量)' -ForegroundColor Yellow
|
||||||
|
} else {
|
||||||
|
Write-Host '已写入用户级环境变量。请关闭旧终端后再开新的。' -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
|
||||||
|
$dshHome = if ($env:DSH_HOME) { $env:DSH_HOME } else { Join-Path $env:USERPROFILE '.dsh' }
|
||||||
|
$profileDir = Join-Path $dshHome "profiles\$ProfileName"
|
||||||
|
if (-not (Test-Path -LiteralPath $profileDir)) {
|
||||||
|
throw "找不到 profile 目录: $profileDir (请先成功跑过一次 dsh web)"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Step '确保 pnpm allowBuilds(防止 git 依赖 prepare 被拦)'
|
||||||
|
Ensure-AllowBuilds $profileDir
|
||||||
|
|
||||||
|
if ($Local) {
|
||||||
|
$scriptRoot = if ($PSScriptRoot) { $PSScriptRoot } else { Split-Path -Parent $MyInvocation.MyCommand.Path }
|
||||||
|
$repoRoot = Resolve-Path (Join-Path $scriptRoot '..')
|
||||||
|
$Source = $repoRoot.Path
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Step "安装插件: dsh plugin --profile $ProfileName add $Source"
|
||||||
|
& dsh plugin --profile $ProfileName add $Source
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
throw "dsh plugin add 失败(exit=$LASTEXITCODE)。可尝试: dsh plugin --profile $ProfileName remove dsh-telegram-channel 后再跑本脚本。"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host '安装完成。接下来:' -ForegroundColor Green
|
||||||
|
Write-Host ' 1. 关掉所有旧终端,新开 PowerShell'
|
||||||
|
Write-Host ' 2. 确认代理(若需要访问 Telegram)已开启'
|
||||||
|
Write-Host ' 3. 运行: dsh web'
|
||||||
|
Write-Host ' 4. 浏览器打开一个对话'
|
||||||
|
Write-Host ' 5. 手机对 Bot 发 /start → /sessions → 点选附着'
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host '命令菜单应出现: /start /sessions /status /unbind /help'
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# One-click-ish install for dsh-telegram-channel (macOS / Linux).
|
||||||
|
# Usage:
|
||||||
|
# export DSH_TELEGRAM_TOKEN='123:AA...'
|
||||||
|
# export DSH_TELEGRAM_ALLOWED_USER_IDS='7057906059'
|
||||||
|
# curl -fsSL https://raw.githubusercontent.com/hi-wenw/dsh-telegram-channel/master/scripts/install.sh | bash
|
||||||
|
# Or:
|
||||||
|
# ./scripts/install.sh --token '...' --user-id '...'
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
PROFILE_NAME="${DSH_PROFILE:-web}"
|
||||||
|
SOURCE="${DSH_TELEGRAM_SOURCE:-github:hi-wenw/dsh-telegram-channel}"
|
||||||
|
TOKEN="${DSH_TELEGRAM_TOKEN:-}"
|
||||||
|
USER_ID="${DSH_TELEGRAM_ALLOWED_USER_IDS:-}"
|
||||||
|
LOCAL=0
|
||||||
|
NO_PERSIST=0
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--token) TOKEN="${2:-}"; shift 2 ;;
|
||||||
|
--user-id) USER_ID="${2:-}"; shift 2 ;;
|
||||||
|
--profile) PROFILE_NAME="${2:-}"; shift 2 ;;
|
||||||
|
--source) SOURCE="${2:-}"; shift 2 ;;
|
||||||
|
--local) LOCAL=1; shift ;;
|
||||||
|
--no-persist) NO_PERSIST=1; shift ;;
|
||||||
|
-h|--help)
|
||||||
|
sed -n '2,12p' "$0"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*) echo "Unknown arg: $1" >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if ! command -v dsh >/dev/null 2>&1; then
|
||||||
|
echo "dsh not found in PATH" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$TOKEN" ]]; then
|
||||||
|
read -r -p "Bot Token: " TOKEN
|
||||||
|
fi
|
||||||
|
if [[ -z "$USER_ID" ]]; then
|
||||||
|
read -r -p "Telegram numeric User ID: " USER_ID
|
||||||
|
fi
|
||||||
|
USER_ID="$(echo "$USER_ID" | tr -d '[:space:]')"
|
||||||
|
if ! [[ "$USER_ID" =~ ^[0-9]+(,[0-9]+)*$ ]]; then
|
||||||
|
echo "User ID must be numeric (comma-separated ok)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
export DSH_TELEGRAM_TOKEN="$TOKEN"
|
||||||
|
export DSH_TELEGRAM_ALLOWED_USER_IDS="$USER_ID"
|
||||||
|
|
||||||
|
persist_env() {
|
||||||
|
local name="$1" value="$2"
|
||||||
|
local line="export ${name}=$(printf %q "$value")"
|
||||||
|
for f in "$HOME/.bashrc" "$HOME/.zshrc"; do
|
||||||
|
[[ -f "$f" ]] || continue
|
||||||
|
if grep -q "^export ${name}=" "$f" 2>/dev/null; then
|
||||||
|
# portable-ish replace
|
||||||
|
tmp="$(mktemp)"
|
||||||
|
grep -v "^export ${name}=" "$f" >"$tmp" || true
|
||||||
|
echo "$line" >>"$tmp"
|
||||||
|
mv "$tmp" "$f"
|
||||||
|
else
|
||||||
|
echo "$line" >>"$f"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "$NO_PERSIST" -eq 0 ]]; then
|
||||||
|
persist_env DSH_TELEGRAM_TOKEN "$TOKEN"
|
||||||
|
persist_env DSH_TELEGRAM_ALLOWED_USER_IDS "$USER_ID"
|
||||||
|
echo "Wrote exports to ~/.bashrc and/or ~/.zshrc (if present)."
|
||||||
|
fi
|
||||||
|
|
||||||
|
DSH_HOME="${DSH_HOME:-$HOME/.dsh}"
|
||||||
|
PROFILE_DIR="$DSH_HOME/profiles/$PROFILE_NAME"
|
||||||
|
if [[ ! -d "$PROFILE_DIR" ]]; then
|
||||||
|
echo "Profile dir missing: $PROFILE_DIR (run dsh web once first)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
WS="$PROFILE_DIR/pnpm-workspace.yaml"
|
||||||
|
if [[ ! -f "$WS" ]]; then
|
||||||
|
cat >"$WS" <<'EOF'
|
||||||
|
packages:
|
||||||
|
- .
|
||||||
|
|
||||||
|
nodeLinker: hoisted
|
||||||
|
autoInstallPeers: false
|
||||||
|
|
||||||
|
allowBuilds:
|
||||||
|
dsh-telegram-channel: true
|
||||||
|
EOF
|
||||||
|
elif ! grep -q 'dsh-telegram-channel:' "$WS"; then
|
||||||
|
if grep -q '^allowBuilds:' "$WS"; then
|
||||||
|
awk '
|
||||||
|
BEGIN{done=0}
|
||||||
|
/^allowBuilds:/{print; print " dsh-telegram-channel: true"; done=1; next}
|
||||||
|
{print}
|
||||||
|
END{if(!done){print ""; print "allowBuilds:"; print " dsh-telegram-channel: true"}}
|
||||||
|
' "$WS" >"$WS.tmp" && mv "$WS.tmp" "$WS"
|
||||||
|
else
|
||||||
|
printf '\nallowBuilds:\n dsh-telegram-channel: true\n' >>"$WS"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$LOCAL" -eq 1 ]]; then
|
||||||
|
SOURCE="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==> dsh plugin --profile $PROFILE_NAME add $SOURCE"
|
||||||
|
dsh plugin --profile "$PROFILE_NAME" add "$SOURCE"
|
||||||
|
|
||||||
|
cat <<EOF
|
||||||
|
|
||||||
|
Install done. Next:
|
||||||
|
1. Open a new shell (so env vars load)
|
||||||
|
2. Run: dsh web
|
||||||
|
3. Open a Web conversation
|
||||||
|
4. On phone: /start → /sessions → bind
|
||||||
|
|
||||||
|
EOF
|
||||||
@@ -87,9 +87,21 @@ export class TelegramBridge {
|
|||||||
this.ctx.logger.error(this.redact(err))
|
this.ctx.logger.error(this.redact(err))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
void this.client.setMyCommands([
|
||||||
|
{ command: 'start', description: '欢迎与用法' },
|
||||||
|
{ command: 'sessions', description: '列出并附着本机 live 会话' },
|
||||||
|
{ command: 'status', description: '查看当前绑定' },
|
||||||
|
{ command: 'unbind', description: '断开手机绑定(不关闭本机会话)' },
|
||||||
|
{ command: 'help', description: '显示帮助' },
|
||||||
|
]).then(() => {
|
||||||
|
this.ctx.logger.info('dsh-telegram-channel: bot commands registered')
|
||||||
|
}).catch((err) => {
|
||||||
|
this.ctx.logger.warn(`dsh-telegram-channel: setMyCommands failed: ${this.redact(err)}`)
|
||||||
|
})
|
||||||
if (!this.polling) {
|
if (!this.polling) {
|
||||||
this.polling = true
|
this.polling = true
|
||||||
this.pollAbort = new AbortController()
|
this.pollAbort = new AbortController()
|
||||||
|
this.ctx.logger.info('dsh-telegram-channel: long-polling started')
|
||||||
this.pollPromise = this.pollLoop()
|
this.pollPromise = this.pollLoop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+38
-1
@@ -1,3 +1,5 @@
|
|||||||
|
import { EnvHttpProxyAgent, fetch as undiciFetch } from 'undici'
|
||||||
|
|
||||||
export interface TelegramUser {
|
export interface TelegramUser {
|
||||||
id: number
|
id: number
|
||||||
is_bot?: boolean
|
is_bot?: boolean
|
||||||
@@ -42,6 +44,11 @@ export interface InlineKeyboardMarkup {
|
|||||||
inline_keyboard: InlineKeyboardButton[][]
|
inline_keyboard: InlineKeyboardButton[][]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TelegramBotCommand {
|
||||||
|
command: string
|
||||||
|
description: string
|
||||||
|
}
|
||||||
|
|
||||||
export interface TelegramClientOptions {
|
export interface TelegramClientOptions {
|
||||||
fetch?: typeof fetch
|
fetch?: typeof fetch
|
||||||
baseUrl?: string
|
baseUrl?: string
|
||||||
@@ -59,6 +66,32 @@ export interface TelegramClientLike {
|
|||||||
): Promise<TelegramMessage>
|
): Promise<TelegramMessage>
|
||||||
sendChatAction(chatId: number, action: string): Promise<boolean>
|
sendChatAction(chatId: number, action: string): Promise<boolean>
|
||||||
answerCallbackQuery(callbackQueryId: string, text?: string): Promise<boolean>
|
answerCallbackQuery(callbackQueryId: string, text?: string): Promise<boolean>
|
||||||
|
setMyCommands(commands: TelegramBotCommand[]): Promise<boolean>
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveProxyUrl(): string | undefined {
|
||||||
|
return (
|
||||||
|
process.env.HTTPS_PROXY
|
||||||
|
|| process.env.HTTP_PROXY
|
||||||
|
|| process.env.https_proxy
|
||||||
|
|| process.env.http_proxy
|
||||||
|
|| undefined
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Node's global `fetch` ignores HTTP(S)_PROXY unless `NODE_USE_ENV_PROXY=1`.
|
||||||
|
* Undici's EnvHttpProxyAgent honors the env vars (and NO_PROXY).
|
||||||
|
*/
|
||||||
|
function createDefaultFetch(): typeof fetch {
|
||||||
|
if (!resolveProxyUrl()) return globalThis.fetch
|
||||||
|
const agent = new EnvHttpProxyAgent()
|
||||||
|
const proxied = ((input: RequestInfo | URL, init?: RequestInit) =>
|
||||||
|
undiciFetch(input as string | URL, {
|
||||||
|
...(init as Record<string, unknown>),
|
||||||
|
dispatcher: agent,
|
||||||
|
})) as unknown as typeof fetch
|
||||||
|
return proxied
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TelegramClient implements TelegramClientLike {
|
export class TelegramClient implements TelegramClientLike {
|
||||||
@@ -72,7 +105,7 @@ export class TelegramClient implements TelegramClientLike {
|
|||||||
throw new Error('bot token is required')
|
throw new Error('bot token is required')
|
||||||
}
|
}
|
||||||
this.token = token
|
this.token = token
|
||||||
this.fetchImpl = options.fetch ?? fetch
|
this.fetchImpl = options.fetch ?? createDefaultFetch()
|
||||||
this.baseUrl = options.baseUrl ?? 'https://api.telegram.org'
|
this.baseUrl = options.baseUrl ?? 'https://api.telegram.org'
|
||||||
this.pollingTimeoutSec = options.pollingTimeoutSec ?? 30
|
this.pollingTimeoutSec = options.pollingTimeoutSec ?? 30
|
||||||
}
|
}
|
||||||
@@ -143,4 +176,8 @@ export class TelegramClient implements TelegramClientLike {
|
|||||||
if (text !== undefined) body.text = text
|
if (text !== undefined) body.text = text
|
||||||
return this.call<boolean>('answerCallbackQuery', body)
|
return this.call<boolean>('answerCallbackQuery', body)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async setMyCommands(commands: TelegramBotCommand[]): Promise<boolean> {
|
||||||
|
return this.call<boolean>('setMyCommands', { commands })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-1
@@ -21,6 +21,19 @@ export const Config: Schema<TelegramChannelConfig> = Schema.object({
|
|||||||
pollingTimeoutSec: Schema.number().default(30),
|
pollingTimeoutSec: Schema.number().default(30),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function resolveAllowedUserIds(config: TelegramChannelConfig): number[] {
|
||||||
|
if (config.allowedUserIds && config.allowedUserIds.length > 0) {
|
||||||
|
return config.allowedUserIds
|
||||||
|
}
|
||||||
|
const raw = process.env.DSH_TELEGRAM_ALLOWED_USER_IDS ?? ''
|
||||||
|
return raw
|
||||||
|
.split(/[,;\s]+/)
|
||||||
|
.map((part) => part.trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
.map((part) => Number(part))
|
||||||
|
.filter((n) => Number.isFinite(n) && n > 0)
|
||||||
|
}
|
||||||
|
|
||||||
export function apply(ctx: Context, config: TelegramChannelConfig): void {
|
export function apply(ctx: Context, config: TelegramChannelConfig): void {
|
||||||
const token = (config.token && config.token.length > 0)
|
const token = (config.token && config.token.length > 0)
|
||||||
? config.token
|
? config.token
|
||||||
@@ -33,7 +46,7 @@ export function apply(ctx: Context, config: TelegramChannelConfig): void {
|
|||||||
}
|
}
|
||||||
const bridge = new TelegramBridge(ctx, {
|
const bridge = new TelegramBridge(ctx, {
|
||||||
token,
|
token,
|
||||||
allowedUserIds: config.allowedUserIds ?? [],
|
allowedUserIds: resolveAllowedUserIds(config),
|
||||||
allowAllUsers: config.allowAllUsers ?? false,
|
allowAllUsers: config.allowAllUsers ?? false,
|
||||||
maxMessageLength: config.maxMessageLength ?? 4096,
|
maxMessageLength: config.maxMessageLength ?? 4096,
|
||||||
pollingTimeoutSec: config.pollingTimeoutSec ?? 30,
|
pollingTimeoutSec: config.pollingTimeoutSec ?? 30,
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ test('apply without token does not throw and does not start effect', () => {
|
|||||||
effects.push(name)
|
effects.push(name)
|
||||||
return () => {}
|
return () => {}
|
||||||
},
|
},
|
||||||
logger: { error() {}, warn() {} },
|
logger: { info() {}, error() {}, warn() {} },
|
||||||
agents: {},
|
agents: {},
|
||||||
} as any
|
} as any
|
||||||
const prev = process.env.DSH_TELEGRAM_TOKEN
|
const prev = process.env.DSH_TELEGRAM_TOKEN
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ function fakeClient(
|
|||||||
},
|
},
|
||||||
sendChatAction: async () => true,
|
sendChatAction: async () => true,
|
||||||
answerCallbackQuery: async () => true,
|
answerCallbackQuery: async () => true,
|
||||||
|
setMyCommands: async () => true,
|
||||||
...overrides,
|
...overrides,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -56,7 +57,7 @@ function makeAgent(id: string, followups: UserMessage[]) {
|
|||||||
test('unauthorized user gets denied', async () => {
|
test('unauthorized user gets denied', async () => {
|
||||||
const sent: SentMessage[] = []
|
const sent: SentMessage[] = []
|
||||||
const ctx = {
|
const ctx = {
|
||||||
logger: { warn() {}, error() {} },
|
logger: { info() {}, warn() {}, error() {} },
|
||||||
agents: { list: () => [], roots: () => [], get: () => undefined },
|
agents: { list: () => [], roots: () => [], get: () => undefined },
|
||||||
on() { return () => {} },
|
on() { return () => {} },
|
||||||
}
|
}
|
||||||
@@ -75,7 +76,7 @@ test('plain text without bind prompts NEED_BIND and does not create', async () =
|
|||||||
const sent: SentMessage[] = []
|
const sent: SentMessage[] = []
|
||||||
let createCalled = false
|
let createCalled = false
|
||||||
const ctx = {
|
const ctx = {
|
||||||
logger: { warn() {}, error() {} },
|
logger: { info() {}, warn() {}, error() {} },
|
||||||
agents: {
|
agents: {
|
||||||
list: () => [],
|
list: () => [],
|
||||||
roots: () => [],
|
roots: () => [],
|
||||||
@@ -99,7 +100,7 @@ test('plain text without bind prompts NEED_BIND and does not create', async () =
|
|||||||
test('/sessions with no live agents shows NO_LIVE', async () => {
|
test('/sessions with no live agents shows NO_LIVE', async () => {
|
||||||
const sent: SentMessage[] = []
|
const sent: SentMessage[] = []
|
||||||
const ctx = {
|
const ctx = {
|
||||||
logger: { warn() {}, error() {} },
|
logger: { info() {}, warn() {}, error() {} },
|
||||||
agents: { list: () => [], roots: () => [], get: () => undefined },
|
agents: { list: () => [], roots: () => [], get: () => undefined },
|
||||||
on() { return () => {} },
|
on() { return () => {} },
|
||||||
}
|
}
|
||||||
@@ -119,7 +120,7 @@ test('/sessions lists live agents with bind callbacks', async () => {
|
|||||||
const followups: UserMessage[] = []
|
const followups: UserMessage[] = []
|
||||||
const agent = makeAgent('live-aaa', followups)
|
const agent = makeAgent('live-aaa', followups)
|
||||||
const ctx = {
|
const ctx = {
|
||||||
logger: { warn() {}, error() {} },
|
logger: { info() {}, warn() {}, error() {} },
|
||||||
agents: {
|
agents: {
|
||||||
list: () => [agent],
|
list: () => [agent],
|
||||||
roots: () => [agent],
|
roots: () => [agent],
|
||||||
@@ -145,7 +146,7 @@ test('callback bind then plain text followups live agent; mirror assistant to ch
|
|||||||
const agent = makeAgent('live-bbb', followups)
|
const agent = makeAgent('live-bbb', followups)
|
||||||
let sessionListener: ((session: { id: ReturnType<typeof SessionId> }, event: unknown) => void) | undefined
|
let sessionListener: ((session: { id: ReturnType<typeof SessionId> }, event: unknown) => void) | undefined
|
||||||
const ctx = {
|
const ctx = {
|
||||||
logger: { warn() {}, error() {} },
|
logger: { info() {}, warn() {}, error() {} },
|
||||||
agents: {
|
agents: {
|
||||||
list: () => [agent],
|
list: () => [agent],
|
||||||
roots: () => [agent],
|
roots: () => [agent],
|
||||||
@@ -202,7 +203,7 @@ test('/unbind clears binding without needing create/dispose', async () => {
|
|||||||
const followups: UserMessage[] = []
|
const followups: UserMessage[] = []
|
||||||
const agent = makeAgent('live-ccc', followups)
|
const agent = makeAgent('live-ccc', followups)
|
||||||
const ctx = {
|
const ctx = {
|
||||||
logger: { warn() {}, error() {} },
|
logger: { info() {}, warn() {}, error() {} },
|
||||||
agents: {
|
agents: {
|
||||||
list: () => [agent],
|
list: () => [agent],
|
||||||
roots: () => [agent],
|
roots: () => [agent],
|
||||||
|
|||||||
Reference in New Issue
Block a user