@will-17173/telegram-cli 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +241 -61
- package/README.zh-CN.md +250 -73
- package/dist/account/account-authenticator.js +95 -0
- package/dist/account/account-authenticator.js.map +1 -0
- package/dist/account/account-context.js +7 -0
- package/dist/account/account-context.js.map +1 -1
- package/dist/account/account-name.js +17 -0
- package/dist/account/account-name.js.map +1 -0
- package/dist/account/account-presets.js +20 -3
- package/dist/account/account-presets.js.map +1 -1
- package/dist/account/account-store.js +277 -37
- package/dist/account/account-store.js.map +1 -1
- package/dist/cli/app.js +12 -1
- package/dist/cli/app.js.map +1 -1
- package/dist/cli/output.js +21 -6
- package/dist/cli/output.js.map +1 -1
- package/dist/cli/secure-input.js +408 -0
- package/dist/cli/secure-input.js.map +1 -0
- package/dist/commands/account-options.js +37 -7
- package/dist/commands/account-options.js.map +1 -1
- package/dist/commands/account.js +192 -66
- package/dist/commands/account.js.map +1 -1
- package/dist/commands/archive.js +151 -0
- package/dist/commands/archive.js.map +1 -0
- package/dist/commands/config.js +119 -12
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/contact.js +58 -0
- package/dist/commands/contact.js.map +1 -0
- package/dist/commands/data.js +14 -7
- package/dist/commands/data.js.map +1 -1
- package/dist/commands/dialog.js +156 -0
- package/dist/commands/dialog.js.map +1 -0
- package/dist/commands/folder.js +113 -0
- package/dist/commands/folder.js.map +1 -0
- package/dist/commands/group-write.js +128 -0
- package/dist/commands/group-write.js.map +1 -0
- package/dist/commands/group.js +43 -7
- package/dist/commands/group.js.map +1 -1
- package/dist/commands/notification.js +76 -0
- package/dist/commands/notification.js.map +1 -0
- package/dist/commands/query.js +22 -15
- package/dist/commands/query.js.map +1 -1
- package/dist/commands/telegram-runner.js +40 -18
- package/dist/commands/telegram-runner.js.map +1 -1
- package/dist/commands/telegram.js +172 -109
- package/dist/commands/telegram.js.map +1 -1
- package/dist/commands/time-range.js +39 -0
- package/dist/commands/time-range.js.map +1 -0
- package/dist/commands/types.js +3 -2
- package/dist/commands/types.js.map +1 -1
- package/dist/config/credential-store.js +24 -4
- package/dist/config/credential-store.js.map +1 -1
- package/dist/config/env.js +4 -1
- package/dist/config/env.js.map +1 -1
- package/dist/group-commands/catalog.js +79 -0
- package/dist/group-commands/catalog.js.map +1 -0
- package/dist/group-commands/executor.js +102 -0
- package/dist/group-commands/executor.js.map +1 -0
- package/dist/group-commands/parser.js +268 -0
- package/dist/group-commands/parser.js.map +1 -0
- package/dist/group-commands/tokenize.js +51 -0
- package/dist/group-commands/tokenize.js.map +1 -0
- package/dist/group-commands/types.js +2 -0
- package/dist/group-commands/types.js.map +1 -0
- package/dist/index.js +0 -0
- package/dist/listen-commands/catalog.js +61 -0
- package/dist/listen-commands/catalog.js.map +1 -0
- package/dist/listen-commands/dispatch.js +46 -0
- package/dist/listen-commands/dispatch.js.map +1 -0
- package/dist/listen-commands/match.js +113 -0
- package/dist/listen-commands/match.js.map +1 -0
- package/dist/presenters/group.js +40 -0
- package/dist/presenters/group.js.map +1 -1
- package/dist/presenters/human.js +135 -0
- package/dist/presenters/human.js.map +1 -1
- package/dist/presenters/ink/display-width.js +45 -7
- package/dist/presenters/ink/display-width.js.map +1 -1
- package/dist/presenters/ink/group-command-confirm.js +13 -0
- package/dist/presenters/ink/group-command-confirm.js.map +1 -0
- package/dist/presenters/ink/group-command-result.js +23 -0
- package/dist/presenters/ink/group-command-result.js.map +1 -0
- package/dist/presenters/ink/listen-command-menu.js +38 -0
- package/dist/presenters/ink/listen-command-menu.js.map +1 -0
- package/dist/presenters/ink/listen-scroll.js +9 -4
- package/dist/presenters/ink/listen-scroll.js.map +1 -1
- package/dist/presenters/ink/listen.js +572 -52
- package/dist/presenters/ink/listen.js.map +1 -1
- package/dist/presenters/ink/mouse-scroll.js +12 -0
- package/dist/presenters/ink/mouse-scroll.js.map +1 -1
- package/dist/presenters/ink/secure-input.js +68 -0
- package/dist/presenters/ink/secure-input.js.map +1 -0
- package/dist/presenters/ink/use-group-command.js +186 -0
- package/dist/presenters/ink/use-group-command.js.map +1 -0
- package/dist/presenters/listen-message.js +23 -6
- package/dist/presenters/listen-message.js.map +1 -1
- package/dist/presenters/logical-message.js +78 -0
- package/dist/presenters/logical-message.js.map +1 -0
- package/dist/presenters/markdown.js +54 -0
- package/dist/presenters/markdown.js.map +1 -0
- package/dist/presenters/structured.js +8 -3
- package/dist/presenters/structured.js.map +1 -1
- package/dist/services/account-session-service.js +241 -0
- package/dist/services/account-session-service.js.map +1 -0
- package/dist/services/archive-layout.js +61 -0
- package/dist/services/archive-layout.js.map +1 -0
- package/dist/services/archive-manifest.js +187 -0
- package/dist/services/archive-manifest.js.map +1 -0
- package/dist/services/archive-markdown.js +383 -0
- package/dist/services/archive-markdown.js.map +1 -0
- package/dist/services/archive-service.js +718 -0
- package/dist/services/archive-service.js.map +1 -0
- package/dist/services/archive-types.js +2 -0
- package/dist/services/archive-types.js.map +1 -0
- package/dist/services/attachment-download.js +7 -2
- package/dist/services/attachment-download.js.map +1 -1
- package/dist/services/auto-download-coordinator.js +2 -4
- package/dist/services/auto-download-coordinator.js.map +1 -1
- package/dist/services/contact-service.js +78 -0
- package/dist/services/contact-service.js.map +1 -0
- package/dist/services/dialog-service.js +140 -0
- package/dist/services/dialog-service.js.map +1 -0
- package/dist/services/folder-service.js +200 -0
- package/dist/services/folder-service.js.map +1 -0
- package/dist/services/group-service.js.map +1 -1
- package/dist/services/group-write-service.js +225 -0
- package/dist/services/group-write-service.js.map +1 -0
- package/dist/services/listen-album-aggregator.js +9 -29
- package/dist/services/listen-album-aggregator.js.map +1 -1
- package/dist/services/listen-attachment.js +23 -6
- package/dist/services/listen-attachment.js.map +1 -1
- package/dist/services/listen-composer-command.js +102 -0
- package/dist/services/listen-composer-command.js.map +1 -0
- package/dist/services/listen-reply-resolver.js +126 -0
- package/dist/services/listen-reply-resolver.js.map +1 -0
- package/dist/services/message-service.js +17 -1
- package/dist/services/message-service.js.map +1 -1
- package/dist/services/notification-service.js +142 -0
- package/dist/services/notification-service.js.map +1 -0
- package/dist/services/query-service.js +59 -3
- package/dist/services/query-service.js.map +1 -1
- package/dist/services/reply-context.js +29 -0
- package/dist/services/reply-context.js.map +1 -0
- package/dist/services/write-access-policy.js +19 -0
- package/dist/services/write-access-policy.js.map +1 -0
- package/dist/storage/message-db.js +241 -5
- package/dist/storage/message-db.js.map +1 -1
- package/dist/telegram/archive-types.js +2 -0
- package/dist/telegram/archive-types.js.map +1 -0
- package/dist/telegram/client-factory.js +51 -11
- package/dist/telegram/client-factory.js.map +1 -1
- package/dist/telegram/contact-types.js +10 -0
- package/dist/telegram/contact-types.js.map +1 -0
- package/dist/telegram/dialog-types.js +2 -0
- package/dist/telegram/dialog-types.js.map +1 -0
- package/dist/telegram/errors.js +14 -0
- package/dist/telegram/errors.js.map +1 -0
- package/dist/telegram/fake-group-management.js +122 -0
- package/dist/telegram/fake-group-management.js.map +1 -1
- package/dist/telegram/folder-types.js +13 -0
- package/dist/telegram/folder-types.js.map +1 -0
- package/dist/telegram/group-types.js +40 -0
- package/dist/telegram/group-types.js.map +1 -1
- package/dist/telegram/group-write-types.js +29 -0
- package/dist/telegram/group-write-types.js.map +1 -0
- package/dist/telegram/mtcute-archive.js +190 -0
- package/dist/telegram/mtcute-archive.js.map +1 -0
- package/dist/telegram/mtcute-client.js +73 -12
- package/dist/telegram/mtcute-client.js.map +1 -1
- package/dist/telegram/mtcute-contacts.js +90 -0
- package/dist/telegram/mtcute-contacts.js.map +1 -0
- package/dist/telegram/mtcute-dialogs.js +186 -0
- package/dist/telegram/mtcute-dialogs.js.map +1 -0
- package/dist/telegram/mtcute-folders.js +318 -0
- package/dist/telegram/mtcute-folders.js.map +1 -0
- package/dist/telegram/mtcute-group-helpers.js +56 -0
- package/dist/telegram/mtcute-group-helpers.js.map +1 -0
- package/dist/telegram/mtcute-group-invites.js +82 -0
- package/dist/telegram/mtcute-group-invites.js.map +1 -0
- package/dist/telegram/mtcute-group-management.js +60 -31
- package/dist/telegram/mtcute-group-management.js.map +1 -1
- package/dist/telegram/mtcute-group-members.js +158 -0
- package/dist/telegram/mtcute-group-members.js.map +1 -0
- package/dist/telegram/mtcute-group-settings.js +146 -0
- package/dist/telegram/mtcute-group-settings.js.map +1 -0
- package/dist/telegram/mtcute-group-topics.js +63 -0
- package/dist/telegram/mtcute-group-topics.js.map +1 -0
- package/dist/telegram/mtcute-message-normalizer.js +63 -0
- package/dist/telegram/mtcute-message-normalizer.js.map +1 -0
- package/dist/telegram/mtcute-notifications.js +101 -0
- package/dist/telegram/mtcute-notifications.js.map +1 -0
- package/dist/telegram/notification-types.js +11 -0
- package/dist/telegram/notification-types.js.map +1 -0
- package/dist/telegram/raw-message.js +46 -0
- package/dist/telegram/raw-message.js.map +1 -0
- package/dist/telegram/types.js +6 -1
- package/dist/telegram/types.js.map +1 -1
- package/package.json +20 -10
package/README.zh-CN.md
CHANGED
|
@@ -4,46 +4,117 @@
|
|
|
4
4
|
|
|
5
5
|
一个 TypeScript 命令行客户端,用于同步 Telegram 聊天记录、监听实时消息、搜索本地存储的消息,并在终端中查看群组信息。
|
|
6
6
|
|
|
7
|
-
##
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
- 从限制下载的频道中下载附件。
|
|
15
|
-
- 搜索、筛选、汇总和导出本地存储的消息。
|
|
7
|
+
## 你可以做什么
|
|
8
|
+
|
|
9
|
+
- 管理多个 Telegram 账号,并隔离各账号的会话和消息数据库。
|
|
10
|
+
- 查看未读聊天,并直接读取或搜索消息,且不保存到本地。
|
|
11
|
+
- 将聊天记录同步到 SQLite,用于离线搜索、筛选、分析和导出。
|
|
12
|
+
- 将指定聊天增量归档为 Markdown 文件,并可选择下载附件。
|
|
13
|
+
- 监听实时消息并下载收到的附件。
|
|
16
14
|
- 通过命令行发送、编辑和删除消息。
|
|
17
|
-
-
|
|
18
|
-
-
|
|
15
|
+
- 查看联系人、通知设置、聊天文件夹、群组、成员、管理员、邀请链接和论坛话题。
|
|
16
|
+
- 禁用 Telegram 远端写操作,同时保留只读命令和本地命令。
|
|
17
|
+
- 在脚本和智能体工作流中使用人类可读、JSON、YAML 或 Markdown 输出。
|
|
19
18
|
|
|
20
|
-
## 为 AI
|
|
19
|
+
## 为 AI 智能体设计
|
|
21
20
|
|
|
22
|
-
Telegram CLI 为 AI
|
|
21
|
+
Telegram CLI 为 AI 智能体提供基于命令的 Telegram 和本地消息访问接口。通过 `tg account add` 完成账号认证后,智能体无需操作浏览器即可执行在线命令和本地命令。
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
以下接口适合智能体工作流:
|
|
25
24
|
|
|
26
|
-
- JSON 和 YAML
|
|
27
|
-
-
|
|
28
|
-
- `--account <name>`
|
|
25
|
+
- JSON 和 YAML 输出让智能体直接读取结构化数据,而不是解析终端表格。
|
|
26
|
+
- 非零退出码和结构化错误码让智能体能够检测并处理失败。
|
|
27
|
+
- `--account <name>` 可以明确指定账号,且不会改变当前账号。
|
|
29
28
|
- 本地搜索和分析命令无需重新连接 Telegram,即可查询已同步消息。
|
|
30
29
|
|
|
31
|
-
|
|
30
|
+
例如,智能体可以搜索指定账号,并将结果作为 JSON 解析:
|
|
32
31
|
|
|
33
32
|
```sh
|
|
34
33
|
tg search "release" --account work --json
|
|
35
34
|
```
|
|
36
35
|
|
|
36
|
+
### Agent skill
|
|
37
|
+
|
|
38
|
+
安装 [`using-telegram-cli`](https://skills.sh/will-17173/telegram-cli/using-telegram-cli) 技能,可以指导受支持的 AI 编程智能体完成账号认证、消息同步与查询、结构化输出自动化,并安全处理 Telegram 写操作:
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
npx skills add https://github.com/will-17173/telegram-cli \
|
|
42
|
+
--skill using-telegram-cli
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
如需让技能跨项目可用,请添加 `--global`,避免将其安装到当前项目中。
|
|
46
|
+
|
|
37
47
|
## 安装
|
|
38
48
|
|
|
39
49
|
Telegram CLI 需要 Node.js 22 或更高版本。
|
|
40
50
|
|
|
41
|
-
|
|
51
|
+
通过 npm 全局安装:
|
|
42
52
|
|
|
43
53
|
```sh
|
|
44
54
|
npm install -g @will-17173/telegram-cli
|
|
45
55
|
```
|
|
46
56
|
|
|
57
|
+
## 快速开始
|
|
58
|
+
|
|
59
|
+
登录账号、检查状态并列出聊天:
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
tg account add
|
|
63
|
+
tg status
|
|
64
|
+
tg chats
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
从 `tg chats` 的结果中选择聊天名称、用户名或 ID,然后同步并搜索消息:
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
tg sync <chat>
|
|
71
|
+
tg search "keyword" --chat <chat>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
你还可以批量同步聊天、监听实时消息或发送消息:
|
|
75
|
+
|
|
76
|
+
```sh
|
|
77
|
+
tg sync-all --max-chats 20 --delay 1
|
|
78
|
+
tg listen <chat-or-id> --auto-download
|
|
79
|
+
tg send <chat> "Hello from tg"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## 在线读取与管理 Telegram
|
|
83
|
+
|
|
84
|
+
`history`、`sync` 和 `sync-all` 会从 Telegram 获取消息,并保存到本地 SQLite 数据库。`read`、`search-online` 和 `inbox` 直接查询 Telegram,不会保存查询结果。`inbox` 列出有未读消息的聊天,但不会把消息标记为已读。
|
|
85
|
+
|
|
86
|
+
```sh
|
|
87
|
+
tg inbox --markdown
|
|
88
|
+
tg read @team --since 7d --until 2d
|
|
89
|
+
tg search-online release --chat @team --json
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
时间边界支持以 `s`、`m`、`h`、`d` 或 `w` 结尾的相对时长。例如,`7d` 表示命令启动前七天。绝对时间使用包含时区的 ISO 8601 时间戳,例如 `2026-07-13T00:00:00Z`。`--since` 必须早于 `--until`。
|
|
93
|
+
|
|
94
|
+
以下命令可以查看联系人、通知设置、文件夹和群组对话框,且不会修改远端状态:
|
|
95
|
+
|
|
96
|
+
```sh
|
|
97
|
+
tg contact list
|
|
98
|
+
tg contact info +8613800000000
|
|
99
|
+
tg notification info @team
|
|
100
|
+
tg folder list
|
|
101
|
+
tg folder info 2
|
|
102
|
+
tg group list --admin
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
以下命令会修改 Telegram 远端状态:
|
|
106
|
+
|
|
107
|
+
```sh
|
|
108
|
+
tg notification mute @team 8h
|
|
109
|
+
tg notification unmute @team
|
|
110
|
+
tg folder chat add Work @team
|
|
111
|
+
tg folder chat remove Work @team
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
使用 `tg config write-access off` 可阻止这些修改。通过 `tg config write-access on` 恢复远端写操作。
|
|
115
|
+
|
|
116
|
+
文件夹命令接受标题或数字文件夹 ID。文件夹标题不一定唯一。请先运行 `tg folder list`,再将返回的 ID 用于 `tg folder info`、`tg folder chat add` 或 `tg folder chat remove`。
|
|
117
|
+
|
|
47
118
|
## 配置
|
|
48
119
|
|
|
49
120
|
配置个人 Telegram API 凭据是可选的。如需使用自己的凭据,请先在 [my.telegram.org](https://my.telegram.org) 创建,然后通过以下命令保存:
|
|
@@ -74,9 +145,7 @@ tg config set --proxy socks5://127.0.0.1:1080
|
|
|
74
145
|
TG_PROXY=http://127.0.0.1:8080 tg status
|
|
75
146
|
```
|
|
76
147
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
所选代理会应用于账号登录和所有需要连接 Telegram 的命令,并非只应用于示例中的单个命令。代理 URL 可能包含用户名和密码或 MTProxy secret,因此应视为敏感信息。CLI 输出不会打印已配置的代理 URL。在命令行中直接输入包含凭据的代理 URL,可能会使其留在 shell 历史记录中,或通过进程检查被看到。请通过受到适当保护的环境或 secret 加载机制提供 `TG_PROXY`,或以其他方式避免将明文 secret 写入共享的 shell 历史记录和脚本。
|
|
148
|
+
Telegram CLI 支持 SOCKS4、SOCKS5、HTTP、HTTPS 和 MTProxy。代理会应用于账号登录和所有需要连接 Telegram 的命令。包含凭据的代理 URL 应视为敏感信息。
|
|
80
149
|
|
|
81
150
|
如需以人类可读、JSON 或 YAML 格式查看生效配置,请运行:
|
|
82
151
|
|
|
@@ -87,9 +156,9 @@ tg config list --yaml
|
|
|
87
156
|
tg config list --show-secrets
|
|
88
157
|
```
|
|
89
158
|
|
|
90
|
-
该命令报告的是生效配置,而非 `config.json` 的原始内容。API
|
|
159
|
+
该命令报告的是生效配置,而非 `config.json` 的原始内容。API hash 默认脱敏;`--show-secrets` 只会显示完整的 API hash。
|
|
91
160
|
|
|
92
|
-
|
|
161
|
+
安全的代理端点详情仍然可见,但代理用户名、密码和凭据查询参数始终会被脱敏,即使使用 `--show-secrets`。
|
|
93
162
|
|
|
94
163
|
运行 `tg account add` 完成身份验证并创建本地会话。其他命令不会启动交互式登录流程。
|
|
95
164
|
|
|
@@ -99,37 +168,6 @@ tg config list --show-secrets
|
|
|
99
168
|
export DATA_DIR=/path/to/tg-cli-data
|
|
100
169
|
```
|
|
101
170
|
|
|
102
|
-
## 快速开始
|
|
103
|
-
|
|
104
|
-
```sh
|
|
105
|
-
# 添加并登录第一个账号
|
|
106
|
-
tg account add
|
|
107
|
-
|
|
108
|
-
# 检查身份验证状态
|
|
109
|
-
tg status
|
|
110
|
-
|
|
111
|
-
# 列出聊天,然后在出现 `<chat>` 的位置使用聊天名称、用户名或 ID
|
|
112
|
-
tg chats
|
|
113
|
-
|
|
114
|
-
# 将聊天记录保存到本地
|
|
115
|
-
tg sync <chat>
|
|
116
|
-
|
|
117
|
-
# 搜索已同步到本地的消息
|
|
118
|
-
tg search "keyword" --chat <chat>
|
|
119
|
-
|
|
120
|
-
# 同步全部聊天
|
|
121
|
-
tg sync-all --max-chats 20 --delay 1
|
|
122
|
-
|
|
123
|
-
# 监听实时消息并自动下载收到的附件
|
|
124
|
-
tg listen <chat-or-id> --auto-download
|
|
125
|
-
|
|
126
|
-
# 使用纯文本输出、下载附件并隐藏消息中的附件摘要
|
|
127
|
-
tg listen <chat-or-id> --no-interactive --auto-download --no-media
|
|
128
|
-
|
|
129
|
-
# 发送消息
|
|
130
|
-
tg send <chat> "Hello from tg"
|
|
131
|
-
```
|
|
132
|
-
|
|
133
171
|
## 发送消息和附件
|
|
134
172
|
|
|
135
173
|
`send` 必须指定 `<chat>`。可以发送纯文本、一个或多个文件,或带说明文字的文件:
|
|
@@ -149,6 +187,33 @@ tg send <chat> "Group caption" --file ./photo.jpg --file ./clip.mp4
|
|
|
149
187
|
|
|
150
188
|
Telegram 决定可接受的文件组合和媒体组数量限制。如果 Telegram 拒绝所请求的组合或数量,命令会返回错误,不会静默拆分为多条消息或多个媒体组。
|
|
151
189
|
|
|
190
|
+
## 将聊天归档为 Markdown
|
|
191
|
+
|
|
192
|
+
`archive` 必须指定明确范围。请传入一个或多个聊天 ID 或用户名,或者使用 `--all`,但不能同时使用这两种方式。
|
|
193
|
+
|
|
194
|
+
命令默认使用当前账号,也可通过 `--account <name>` 临时选择账号。归档默认写入该账号数据目录下的 `archive`。使用 `--output <路径>` 可以指定其他目录。
|
|
195
|
+
|
|
196
|
+
```sh
|
|
197
|
+
# 首次归档并下载附件:此前七天
|
|
198
|
+
tg archive @team --download-media
|
|
199
|
+
|
|
200
|
+
# 自定义范围(相对时长或带时区的 ISO 时间)
|
|
201
|
+
tg archive @team --since 30d --until 2026-07-13T00:00:00Z
|
|
202
|
+
|
|
203
|
+
# 归档所有聊天的完整可用历史并下载附件
|
|
204
|
+
tg archive --all --full --download-media
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
首次运行默认归档此前七天。使用 `--since` 和 `--until` 可以选择其他范围。`--full` 会取消起始时间限制,且不能与 `--since` 同时使用。
|
|
208
|
+
|
|
209
|
+
后续运行会将新消息追加到现有归档。使用 `--rebuild` 可以替换所选的 Markdown 文件。未指定新范围时,重建会复用归档的初始范围。
|
|
210
|
+
|
|
211
|
+
使用 `--download-media` 可以将附件保存到归档目录的 `media/` 下。增量运行会重试仍然缺失的引用附件。
|
|
212
|
+
|
|
213
|
+
任一聊天或附件失败时,命令返回 `archive_partial_failure`,保留其他聊天的成功结果,并以状态码 1 退出。自动化场景建议使用 `--json` 或 `--yaml`,检查 `completed`、`failed` 和 `warnings`。
|
|
214
|
+
|
|
215
|
+
大量历史和媒体请求可能触发 Telegram flood wait 或其他速率限制。媒体下载可以独立失败。已成功归档的消息仍保留在磁盘上,警告会指出失败的附件。
|
|
216
|
+
|
|
152
217
|
## 多账号
|
|
153
218
|
|
|
154
219
|
每个 Telegram 账号都有独立持久化的身份验证会话和本地消息数据库。通过以下命令交互式登录并添加账号:
|
|
@@ -157,23 +222,37 @@ Telegram 决定可接受的文件组合和媒体组数量限制。如果 Telegra
|
|
|
157
222
|
tg account add
|
|
158
223
|
```
|
|
159
224
|
|
|
160
|
-
|
|
225
|
+
添加的第一个账号会自动成为当前账号。继续添加其他账号时不会自动切换,可通过以下命令查看或更改选择:
|
|
161
226
|
|
|
162
227
|
```sh
|
|
163
228
|
# 列出已添加的账号
|
|
164
229
|
tg account list
|
|
165
230
|
|
|
166
|
-
#
|
|
231
|
+
# 查看当前账号
|
|
167
232
|
tg account current
|
|
168
233
|
|
|
169
|
-
#
|
|
234
|
+
# 从交互式列表中选择默认账号
|
|
235
|
+
tg account switch
|
|
236
|
+
|
|
237
|
+
# 按名称设置默认账号
|
|
170
238
|
tg account switch <name>
|
|
171
239
|
|
|
172
240
|
# 删除账号及其本地会话和数据
|
|
173
241
|
tg account remove <name> --force
|
|
174
242
|
```
|
|
175
243
|
|
|
176
|
-
|
|
244
|
+
显式登出可以结束远端会话,同时保留已添加账号、账号设置和本地消息。`--yes` 可以跳过确认提示。
|
|
245
|
+
|
|
246
|
+
再次登录需要交互式终端(TTY),并会创建或替换本地 Telegram 会话。脚本和非交互智能体会收到 `interaction_required` 错误。
|
|
247
|
+
|
|
248
|
+
```sh
|
|
249
|
+
tg account logout work --yes
|
|
250
|
+
tg account login work
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
在交互式终端中,`tg account switch` 会列出已添加账号、标记当前账号,并接受账号序号。编写脚本或使用 `--json`、`--yaml`、非交互式输入时,请传入 `<name>`。
|
|
254
|
+
|
|
255
|
+
各命令默认使用当前账号。支持 `--account` 的命令可以临时指定另一个已添加的账号,且不会改变当前账号:
|
|
177
256
|
|
|
178
257
|
```sh
|
|
179
258
|
tg chats --account <name>
|
|
@@ -185,9 +264,9 @@ tg search "keyword" --account <name>
|
|
|
185
264
|
|
|
186
265
|
Telegram API 凭据对所有已添加账号生效,添加其他账号时无需单独配置 API 凭据。
|
|
187
266
|
|
|
188
|
-
##
|
|
267
|
+
## 群组管理
|
|
189
268
|
|
|
190
|
-
`group`
|
|
269
|
+
`group` 命令同时支持只读查询,以及成员、管理员、群设置、邀请链接、论坛话题和消息管理。请通过各命令组的帮助查看可用操作:
|
|
191
270
|
|
|
192
271
|
```sh
|
|
193
272
|
# 群组详情
|
|
@@ -201,20 +280,75 @@ tg group member <chat> <user>
|
|
|
201
280
|
|
|
202
281
|
# 管理员审计日志;--user 和 --type 均可重复指定
|
|
203
282
|
tg group audit <chat> --query invite --user <user> --type member_invited --type invite_changed --limit 100 --account alice --json
|
|
283
|
+
|
|
284
|
+
# 管理示例(chat 参数位于操作参数之前)
|
|
285
|
+
tg group member ban @team @alice --yes
|
|
286
|
+
tg group admin transfer-owner @team @newowner --yes
|
|
287
|
+
tg group chat slowmode @team 30s
|
|
288
|
+
tg group topic --help
|
|
204
289
|
```
|
|
205
290
|
|
|
291
|
+
确认转移所有权后,命令会安全提示输入 Telegram 双重身份验证(2FA)密码。密码绝不会来自 CLI 参数、stdin 输入或环境变量等自动化来源。安全提示仅接受交互式终端输入,不接受管道输入。请勿自动操作该提示。
|
|
292
|
+
|
|
206
293
|
`group members` 的 `--type` 恰好支持以下七种筛选器:`recent`、`all`、`admins`、`banned`、`restricted`、`bots` 和 `contacts`。默认使用 `recent` 并返回 100 条结果;`--limit` 可设为 1 到 200。Telegram 可能返回少于其报告总数的成员,因此单页结果不保证包含整个群组的全部成员。
|
|
207
294
|
|
|
208
|
-
`group audit` 要求当前账号具有群组管理员权限。`--limit` 的范围是 1 到 500,默认返回 100 条事件。可重复的 `--user` 用于筛选操作发起者。可重复的 `--type`
|
|
295
|
+
`group audit` 要求当前账号具有群组管理员权限。`--limit` 的范围是 1 到 500,默认返回 100 条事件。可重复的 `--user` 用于筛选操作发起者。可重复的 `--type` 支持以下事件组:
|
|
296
|
+
|
|
297
|
+
- **群组**:`info_changed`、`settings_changed`
|
|
298
|
+
- **成员**:`member_joined`、`member_left`、`member_invited`、`member_banned`、`member_unbanned`、`member_restricted`、`member_unrestricted`
|
|
299
|
+
- **管理员**:`admin_promoted`、`admin_demoted`
|
|
300
|
+
- **消息**:`message_deleted`、`message_edited`、`message_pinned`
|
|
301
|
+
- **邀请与话题**:`invite_changed`、`topic_changed`
|
|
302
|
+
- **其他**:`other`
|
|
209
303
|
|
|
210
|
-
|
|
304
|
+
查询和管理操作默认输出人类可读内容;支持 `--json` 或 `--yaml` 的操作会输出结构化成功或错误结果。失败时进程退出状态非零。命令默认使用当前账号;`--account <name>` 可仅为本次调用选择另一个已添加账号,且不会改变当前账号。
|
|
305
|
+
|
|
306
|
+
管理操作分为 `member`、`admin`、`chat`、`invite`、`topic` 和 `message` 六个命令组。成员目标必须显式使用 `@username` 或 Telegram 数字用户 ID。时长支持 `s`、`m`、`h`、`d` 后缀;支持关闭的设置还可使用 `off`。例如 `tg group member mute @team @alice 2h --yes` 会临时禁言,`tg group chat slowmode @team off` 会关闭慢速模式。
|
|
307
|
+
|
|
308
|
+
有破坏风险的 CLI 操作在缺少 `--yes` 时会直接拒绝,且不会连接 Telegram。永久删除群组还必须用 `--confirm-title` 提供完全一致的当前群名;交互式 `listen` 模式则通过 Ink 弹窗确认。管理操作需要对应的管理员权限,部分操作还要求超级群组、论坛或群主身份。
|
|
309
|
+
|
|
310
|
+
查询成员详情请优先使用规范路由 `tg group member info <chat> <user>`。旧形式 `tg group member <chat> <user>` 仍保留,但当群名等于 `ban`、`mute`、`info` 等保留操作名时会产生歧义,必须使用规范路由。
|
|
311
|
+
|
|
312
|
+
## 监听模式中的斜杠命令
|
|
313
|
+
|
|
314
|
+
交互式 `tg listen` 会在同一个菜单中展示所有支持的斜杠命令,包括 `/reply` 和完整的群管理命令目录。群管理命令沿用原有语法,无需重复当前群组:
|
|
315
|
+
|
|
316
|
+
```text
|
|
317
|
+
/reply <消息ID> <内容>
|
|
318
|
+
/member mute @alice 2h
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
输入 `/` 会打开统一命令菜单,并优先显示 `/reply`。匹配顺序依次为完整匹配、前缀匹配和有序模糊匹配,因此 `/rep`、`/rpy` 都能找到 `/reply`,`/ban` 能找到 `/member ban`。使用**上方向键**和**下方向键**移动。**Tab** 补全选中的命令。**Enter** 补全未完成的命令或执行完整命令。**Esc** 关闭菜单、结果或确认框。
|
|
322
|
+
|
|
323
|
+
群管理命令原有的可用性和权限检查保持不变:不可用操作仍会禁用,有风险的操作会打开确认弹窗,删除群组还会要求输入完全一致的群名。监听多个群组时,必须先用 `--send-to <chat>` 明确发送目标,例如 `tg listen @team @ops --send-to @team`,之后才能使用群管理命令。
|
|
211
324
|
|
|
212
325
|
## 在线命令与本地命令
|
|
213
326
|
|
|
214
|
-
在线命令会连接 Telegram
|
|
327
|
+
在线命令会连接 Telegram,因此需要有效的账号会话:
|
|
328
|
+
|
|
329
|
+
- `read`、`search-online` 和 `inbox` 返回结果,但不保存到本地。
|
|
330
|
+
- `history`、`sync`、`sync-all` 和 `refresh` 将获取的消息保存到 SQLite。
|
|
331
|
+
- `contact`、`notification`、`folder`、`info` 和 `group` 用于查看或管理 Telegram 数据。
|
|
332
|
+
- `archive` 读取 Telegram 历史,并将 Markdown 文件写入本地。
|
|
333
|
+
- `send`、`edit` 和 `delete` 修改 Telegram 消息。
|
|
334
|
+
- `listen` 保持连接,以接收消息和执行交互操作。
|
|
335
|
+
|
|
336
|
+
全局在线搜索和大规模归档可能触发 Telegram flood wait 或其他速率限制。
|
|
215
337
|
|
|
216
338
|
本地命令只读取或修改所选账号的消息数据库,不会连接 Telegram。这类命令包括 `search`、`recent`、`stats`、`top`、`timeline`、`today`、`filter`、`export` 和 `purge`。
|
|
217
339
|
|
|
340
|
+
## 查看最近消息
|
|
341
|
+
|
|
342
|
+
`tg recent` 默认显示最近 24 小时内存储的 50 条消息。你可以按聊天或发送者筛选,也可以调整时间范围和数量:
|
|
343
|
+
|
|
344
|
+
```sh
|
|
345
|
+
tg recent --chat <chat> --sender <sender> --hours 6 --limit 100
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
人类可读输出会将每个 Telegram 媒体组合并为一行,并汇总其中的附件。`ID` 列列出该行包含的所有原始消息 ID。如果回复目标已存储在本地同一聊天中,输出会显示原消息的时间、发送者、ID 和文本。否则会标出本地缺失的消息 ID。
|
|
349
|
+
|
|
350
|
+
JSON 和 YAML 输出保留已存储消息的结构,便于脚本处理。`recent` 只读取本地 SQLite 数据,不会连接 Telegram。
|
|
351
|
+
|
|
218
352
|
## 命令参考
|
|
219
353
|
|
|
220
354
|
运行内置帮助以查看完整且最新的命令列表:
|
|
@@ -228,16 +362,30 @@ tg --help
|
|
|
228
362
|
| 命令 | 用途 |
|
|
229
363
|
| --- | --- |
|
|
230
364
|
| `tg account add` | 登录并添加另一个 Telegram 账号。 |
|
|
231
|
-
| `tg account list` |
|
|
232
|
-
| `tg account current` |
|
|
233
|
-
| `tg account switch
|
|
365
|
+
| `tg account list` | 列出已添加的账号及当前状态。 |
|
|
366
|
+
| `tg account current` | 查看当前账号。 |
|
|
367
|
+
| `tg account switch [name]` | 交互式选择默认账号,或按名称设置账号。 |
|
|
234
368
|
| `tg account remove <name> --force` | 删除账号及其本地会话和数据。 |
|
|
369
|
+
| `tg account logout <name> --yes` / `tg account login <name>` | 非交互确认登出,或交互式重新认证并创建新的本地会话;本地消息会保留。 |
|
|
235
370
|
| `tg whoami` | 显示当前登录账号的基本信息。 |
|
|
236
371
|
| `tg config set --api-id <id> --api-hash <hash>` | 持久化保存 Telegram API 凭据。 |
|
|
237
372
|
| `tg config set --proxy <url>` | 为账号登录及所有需要连接 Telegram 的命令保存可选代理。 |
|
|
238
|
-
| `tg config list [--show-secrets]` |
|
|
373
|
+
| `tg config list [--show-secrets]` | 显示生效配置值及其来源。代理凭据始终保持脱敏。 |
|
|
374
|
+
| `tg config write-access [status\|on\|off]` | 查看或控制远端 Telegram 写操作权限。 |
|
|
239
375
|
| `tg status` | 检查 Telegram 账户是否已完成身份验证。 |
|
|
240
376
|
| `tg chats` | 列出可用聊天。 |
|
|
377
|
+
| `tg inbox` | 在线列出未读聊天,且不把消息标记为已读。 |
|
|
378
|
+
| `tg read <chat> [--since <time>] [--until <time>]` | 读取 Telegram 最近消息,不持久化到本地。 |
|
|
379
|
+
| `tg search-online <query> [--chat <chat>]` | 在 Telegram 全局或单个聊天内搜索,不持久化结果。 |
|
|
380
|
+
| `tg contact list` / `tg contact info <user_or_phone>` | 列出联系人,或按 ID、用户名、手机号查询联系人。 |
|
|
381
|
+
| `tg dialog inbox` / `tg dialog read <chat>` | 通过 `dialog` 命令组使用 `inbox` 和 `read`。 |
|
|
382
|
+
| `tg dialog search <query>` / `tg dialog groups` | 通过 `dialog` 命令组在线搜索消息或列出群组对话框。 |
|
|
383
|
+
| `tg notification info <chat>` | 查看聊天的通知设置。 |
|
|
384
|
+
| `tg notification mute <chat> [duration]` | 临时或永久关闭聊天通知。 |
|
|
385
|
+
| `tg notification unmute <chat>` | 恢复聊天通知。 |
|
|
386
|
+
| `tg folder list` / `tg folder info <folder>` | 列出文件夹或查看指定文件夹。 |
|
|
387
|
+
| `tg folder chat add <folder> <chat>` | 将显式聊天添加到文件夹。 |
|
|
388
|
+
| `tg folder chat remove <folder> <chat>` | 从文件夹移除显式聊天。 |
|
|
241
389
|
| `tg history <chat> -n <limit>` | 获取并保存完整聊天历史(默认最多 1000 条)。 |
|
|
242
390
|
| `tg sync <chat>` | 将聊天消息同步到本地存储。 |
|
|
243
391
|
| `tg sync-all` | 从全部聊天同步消息,按本地已同步进度做增量更新。 |
|
|
@@ -249,35 +397,64 @@ tg --help
|
|
|
249
397
|
| `tg recent`, `tg today`, `tg stats`, `tg top`, `tg timeline` | 浏览本地消息数据。 |
|
|
250
398
|
| `tg filter <keywords>` | 按关键词筛选本地消息(支持按聊天和时间范围过滤)。 |
|
|
251
399
|
| `tg export <chat>` | 导出本地存储的消息。 |
|
|
400
|
+
| `tg archive <chat ...>` / `tg archive --all` | 将指定聊天或全部聊天增量归档为 Markdown 文件。 |
|
|
252
401
|
| `tg send <chat> [message] [--file <path> ...]` | 发送文本、文件或带说明文字的媒体组。 |
|
|
253
402
|
| `tg edit <chat> <msgId> <text>` | 编辑消息。 |
|
|
254
403
|
| `tg delete <chat> <msgIds...>` | 删除一条或多条消息。 |
|
|
255
404
|
| `tg purge <chat> --yes` | 移除某个聊天在本地存储的消息。 |
|
|
256
405
|
| `tg info <chat>` | 查看聊天元信息。 |
|
|
257
406
|
| `tg group info <chat>` | 查看普通群组或超级群组的只读详情。 |
|
|
407
|
+
| `tg group list [--admin]` | 列出普通群组、超级群组和频道对话框;`--admin` 仅保留自己管理或拥有的聊天。 |
|
|
258
408
|
| `tg group members <chat> [--type <type>] [--query <text>] [--limit <count>]` | 列出并筛选成员(默认 `recent`、100 条;最大 200 条)。 |
|
|
259
409
|
| `tg group member <chat> <user>` | 查看单个成员的角色、权限和限制。 |
|
|
260
410
|
| `tg group audit <chat> [--query <text>] [--user <user>] [--type <type>] [--limit <count>]` | 查询管理员审计日志(默认 100 条;最大 500 条)。 |
|
|
411
|
+
| `tg group member/admin/chat/invite/topic/message --help` | 按类别查找群组管理操作。 |
|
|
261
412
|
|
|
262
413
|
所有同步类命令都会写入本地 SQLite 数据库。`sync-all` 和 `refresh` 根据本地已保存的消息 ID 增量处理多个聊天。
|
|
263
414
|
|
|
264
|
-
|
|
415
|
+
有限结果命令支持 `--json`、`--yaml` 和 `--markdown` 输出。未指定格式时,非交互输出仍默认使用 YAML。交互式终端使用富文本人类可读输出。
|
|
416
|
+
|
|
417
|
+
有限结果命令成功时写入 stdout。JSON/YAML 结构化失败按请求的格式写入 stdout。输出格式冲突同样写入 stdout,并使用稳定的 YAML 信封。人类可读和 Markdown 失败信息写入 stderr。所有失败都会设置非零退出状态。
|
|
418
|
+
|
|
419
|
+
`listen` 是无界数据流,因此不适用这些有限结果输出规则。
|
|
265
420
|
|
|
266
421
|
常用选项:
|
|
267
422
|
|
|
268
423
|
| 选项 | 用途 |
|
|
269
424
|
| --- | --- |
|
|
270
|
-
| `--account <name>` |
|
|
271
|
-
| `--json` / `--yaml` |
|
|
425
|
+
| `--account <name>` | 临时使用已添加的账号,不改变当前账号。 |
|
|
426
|
+
| `--json` / `--yaml` / `--markdown` | 为有限结果命令选择 JSON、YAML 或 Markdown 输出。 |
|
|
272
427
|
| `-v`, `--verbose` | 启用调试日志。 |
|
|
273
428
|
| `-V`, `--version` | 输出当前安装版本。 |
|
|
274
429
|
|
|
275
430
|
使用 `tg <command> --help` 查看命令专用选项。例如,`listen` 支持自动重连和纯文本模式,`search` 支持发送者、时间、正则表达式和结果数量筛选。
|
|
276
431
|
|
|
432
|
+
### 错误码
|
|
433
|
+
|
|
434
|
+
结构化输出会在 `error.code` 中提供稳定的顶层命令错误码,并在可用时附带操作相关详情:
|
|
435
|
+
|
|
436
|
+
- **账号:** `account_logged_out`、`account_identity_mismatch`、`interaction_required`
|
|
437
|
+
- **联系人:** `contact_not_found`
|
|
438
|
+
- **通知和文件夹:** `invalid_notification_duration`、`folder_not_found`、`ambiguous_folder`、`folder_operation_unsupported`
|
|
439
|
+
- **群组所有权:** `password_required`、`password_invalid`、`password_too_fresh`、`session_too_fresh`
|
|
440
|
+
- **归档:** `archive_account_mismatch`、`archive_failed`、`archive_partial_failure`。附件失败但归档保留部分结果时,顶层错误码为 `archive_partial_failure`,命令以非零状态退出;每条媒体警告的 `archive_media_failed` 位于 `error.details.warnings[].code`。
|
|
441
|
+
- **写操作安全和速率限制:** `write_access_disabled`、`flood_wait`
|
|
442
|
+
|
|
443
|
+
### 远端写操作安全
|
|
444
|
+
|
|
445
|
+
运行 `tg config write-access status` 可以查看当前设置。使用 `tg config write-access off` 可阻止发送、编辑、删除、通知、文件夹和群组命令修改 Telegram。本地数据库操作、配置修改和 Telegram 读取操作仍可使用。
|
|
446
|
+
|
|
447
|
+
测试或维护结束后,运行 `tg config write-access on` 恢复远端写操作。
|
|
448
|
+
|
|
277
449
|
### 同步与监听行为
|
|
278
450
|
|
|
451
|
+
以下规则说明同步、监听、回复和下载功能如何影响本地数据与终端输出。
|
|
452
|
+
|
|
279
453
|
- `sync-all` 和 `refresh` 是写入本地数据库的批量同步流程,不是只读命令。
|
|
280
454
|
- `listen` 会实时打印每条到达消息;可用 `--no-media` 关闭附件摘要显示。
|
|
455
|
+
- Telegram 媒体组会显示为一条收到的消息,并合并附件摘要。
|
|
456
|
+
- 回复输出会在本地原消息可用时显示其上下文,否则标出缺失的消息 ID。
|
|
457
|
+
- 在交互式 `listen` 中,可用 `/reply <消息ID> <内容>` 回复消息;通过可重复的 `--file <路径>` 添加附件,包含空格的路径需要使用引号。
|
|
281
458
|
- 联系人卡片会在附件摘要中显示可用的姓名和手机号。联系人卡片不属于可下载附件,使用 `--no-media` 时不会显示。
|
|
282
459
|
- `listen --auto-download` 同时支持交互式和纯文本模式,附件保存在 `~/Downloads/telegram-cli`,最多同时下载 3 个附件。
|
|
283
460
|
- 下载时保留 Telegram 提供的文件名。无文件名时,依次根据 MIME 类型、媒体类型推断扩展名,最后回退为 `.bin`。
|
|
@@ -285,6 +462,8 @@ tg --help
|
|
|
285
462
|
|
|
286
463
|
## 故障排查
|
|
287
464
|
|
|
465
|
+
按照以下步骤解决常见的账号、会话和 API 凭据问题。
|
|
466
|
+
|
|
288
467
|
### 没有可用的当前账号
|
|
289
468
|
|
|
290
469
|
如果命令返回 `account_required`,请添加账号或选择已有账号:
|
|
@@ -326,8 +505,6 @@ accounts/<name>/messages.db
|
|
|
326
505
|
|
|
327
506
|
请将持久化配置、`.env`、Telegram 凭据、会话文件和 SQLite 数据视为敏感信息,切勿与他人分享或将它们提交到版本控制中。
|
|
328
507
|
|
|
329
|
-
除 API 凭据外,`config.json` 文件还可能包含可选的 `proxy` 设置。CLI 的成功和错误输出不会打印已保存的代理 URL,但代理 URL 可能包含凭据或 MTProxy secret,因此仍须保护 `config.json`、环境和 shell 历史记录。
|
|
330
|
-
|
|
331
508
|
## 开发
|
|
332
509
|
|
|
333
510
|
本项目使用 pnpm:
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { TelegramClient } from '@mtcute/node';
|
|
2
|
+
import { getTelegramCredentials, getTelegramProxy } from '../config/env.js';
|
|
3
|
+
import { telegramTransportOptions } from '../telegram/proxy.js';
|
|
4
|
+
import { createInterruptScope, isCliInputError, readSecret, readVisibleInput, } from '../cli/secure-input.js';
|
|
5
|
+
export async function authenticateAccountAt(sessionPath, createClient = createAccountAuthClient) {
|
|
6
|
+
const client = createClient(sessionPath);
|
|
7
|
+
const input = createAuthenticationInput();
|
|
8
|
+
try {
|
|
9
|
+
await client.start(input.options);
|
|
10
|
+
const user = await client.getMe();
|
|
11
|
+
return {
|
|
12
|
+
user,
|
|
13
|
+
close: () => client.destroy(),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
await client.destroy().catch(() => undefined);
|
|
18
|
+
throwAccountLoginError(error);
|
|
19
|
+
}
|
|
20
|
+
finally {
|
|
21
|
+
input.close();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function createAuthenticationInput() {
|
|
25
|
+
const interrupt = createInterruptScope();
|
|
26
|
+
return {
|
|
27
|
+
options: {
|
|
28
|
+
phone: () => readVisibleInput('Phone number: ', { signal: interrupt.signal }),
|
|
29
|
+
code: () => readVisibleInput('Login code: ', { signal: interrupt.signal }),
|
|
30
|
+
password: () => readSecret('2FA password: ', { signal: interrupt.signal }),
|
|
31
|
+
codeSentCallback: () => {
|
|
32
|
+
process.stderr.write('Login code sent.\n');
|
|
33
|
+
},
|
|
34
|
+
invalidCodeCallback: (type) => {
|
|
35
|
+
process.stderr.write(type === 'code'
|
|
36
|
+
? 'Invalid login code. Please try again.\n'
|
|
37
|
+
: 'Invalid 2FA password. Please try again.\n');
|
|
38
|
+
},
|
|
39
|
+
abortSignal: interrupt.signal,
|
|
40
|
+
},
|
|
41
|
+
close: interrupt.dispose,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export function mapAuthUser(user) {
|
|
45
|
+
const displayName = user.displayName?.trim();
|
|
46
|
+
const displayNameFallback = [
|
|
47
|
+
user.firstName,
|
|
48
|
+
user.lastName,
|
|
49
|
+
].filter((value) => value != null && value.trim().length > 0).join(' ');
|
|
50
|
+
const username = user.username?.trim() || `user-${user.id}`;
|
|
51
|
+
const phone = (user.phoneNumber ?? '').replace(/\D/g, '') || String(user.id);
|
|
52
|
+
const preferredName = user.username?.trim().toLowerCase() || '';
|
|
53
|
+
const name = preferredName.length > 0 ? preferredName : phone;
|
|
54
|
+
const resolvedDisplayName = displayName && displayName.length > 0
|
|
55
|
+
? displayName
|
|
56
|
+
: displayNameFallback;
|
|
57
|
+
return {
|
|
58
|
+
user_id: user.id,
|
|
59
|
+
username: username.toLowerCase(),
|
|
60
|
+
phone,
|
|
61
|
+
display_name: resolvedDisplayName.length > 0 ? normalizeDisplayName(resolvedDisplayName) : username,
|
|
62
|
+
name,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function createAccountAuthClient(sessionPath) {
|
|
66
|
+
const credentials = getTelegramCredentials();
|
|
67
|
+
return new TelegramClient({
|
|
68
|
+
apiId: credentials.apiId,
|
|
69
|
+
apiHash: credentials.apiHash,
|
|
70
|
+
storage: sessionPath,
|
|
71
|
+
...telegramTransportOptions(getTelegramProxy()),
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
function normalizeDisplayName(displayName) {
|
|
75
|
+
const normalized = displayName.trim().replace(/\s+/g, ' ');
|
|
76
|
+
const words = normalized.split(' ');
|
|
77
|
+
for (let len = 1; len * 2 <= words.length; len += 1) {
|
|
78
|
+
if (words.length !== len * 2)
|
|
79
|
+
continue;
|
|
80
|
+
const first = words.slice(0, len).join(' ');
|
|
81
|
+
const second = words.slice(len).join(' ');
|
|
82
|
+
if (first === second)
|
|
83
|
+
return first;
|
|
84
|
+
}
|
|
85
|
+
return normalized;
|
|
86
|
+
}
|
|
87
|
+
function throwAccountLoginError(cause) {
|
|
88
|
+
if (isCliInputError(cause))
|
|
89
|
+
throw cause;
|
|
90
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
91
|
+
const error = new Error(message, { cause });
|
|
92
|
+
error.code = 'account_login_failed';
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=account-authenticator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-authenticator.js","sourceRoot":"","sources":["../../src/account/account-authenticator.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,6 +15,13 @@ export function resolveAccountContext(input = {}) {
|
|
|
15
15
|
}
|
|
16
16
|
return toAccountContext(dataDir, account);
|
|
17
17
|
}
|
|
18
|
+
export function resolveAuthenticatedAccountContext(input = {}) {
|
|
19
|
+
const context = resolveAccountContext(input);
|
|
20
|
+
if (context.authState === 'logged_out') {
|
|
21
|
+
throw new Error(`account_logged_out: account "${context.name}" is logged out`);
|
|
22
|
+
}
|
|
23
|
+
return context;
|
|
24
|
+
}
|
|
18
25
|
function explicitOrCurrent(explicitName, currentAccount) {
|
|
19
26
|
const explicit = explicitName?.trim();
|
|
20
27
|
return explicit ? explicit : currentAccount ?? undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"account-context.js","sourceRoot":"","sources":["../../src/account/account-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAOvD,MAAM,UAAU,qBAAqB,CAAC,QAAgC,EAAE;IACtE,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,UAAU,EAAE,CAAA;IAC3E,MAAM,KAAK,GAAG,IAAI,YAAY,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC,CAAA;IAC/D,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,EAAE,CAAA;IAC7B,MAAM,IAAI,GAAG,iBAAiB,CAAC,KAAK,CAAC,YAAY,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAA;IAE5E,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAA;IAC9D,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC/B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,+BAA+B,IAAI,GAAG,CAAC,CAAA;IACzD,CAAC;IAED,OAAO,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;AAC3C,CAAC;AAED,SAAS,iBAAiB,CAAC,YAAgC,EAAE,cAA6B;IACxF,MAAM,QAAQ,GAAG,YAAY,EAAE,IAAI,EAAE,CAAA;IACrC,OAAO,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,cAAc,IAAI,SAAS,CAAA;AAC1D,CAAC"}
|
|
1
|
+
{"version":3,"file":"account-context.js","sourceRoot":"","sources":["../../src/account/account-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAOvD,MAAM,UAAU,qBAAqB,CAAC,QAAgC,EAAE;IACtE,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,UAAU,EAAE,CAAA;IAC3E,MAAM,KAAK,GAAG,IAAI,YAAY,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC,CAAA;IAC/D,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,EAAE,CAAA;IAC7B,MAAM,IAAI,GAAG,iBAAiB,CAAC,KAAK,CAAC,YAAY,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAA;IAE5E,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAA;IAC9D,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC/B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,+BAA+B,IAAI,GAAG,CAAC,CAAA;IACzD,CAAC;IAED,OAAO,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;AAC3C,CAAC;AAED,MAAM,UAAU,kCAAkC,CAAC,QAAgC,EAAE;IACnF,MAAM,OAAO,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAA;IAC5C,IAAI,OAAO,CAAC,SAAS,KAAK,YAAY,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CAAC,gCAAgC,OAAO,CAAC,IAAI,iBAAiB,CAAC,CAAA;IAChF,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,SAAS,iBAAiB,CAAC,YAAgC,EAAE,cAA6B;IACxF,MAAM,QAAQ,GAAG,YAAY,EAAE,IAAI,EAAE,CAAA;IACrC,OAAO,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,cAAc,IAAI,SAAS,CAAA;AAC1D,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const PATH_SEPARATOR = /[/\\]/u;
|
|
2
|
+
const CONTROL_CHARACTER = /[\u0000-\u001f\u007f-\u009f]/u;
|
|
3
|
+
export function isSafeAccountName(value) {
|
|
4
|
+
return typeof value === 'string'
|
|
5
|
+
&& value.trim().length > 0
|
|
6
|
+
&& value !== '.'
|
|
7
|
+
&& value !== '..'
|
|
8
|
+
&& !PATH_SEPARATOR.test(value)
|
|
9
|
+
&& !CONTROL_CHARACTER.test(value)
|
|
10
|
+
&& value.normalize('NFC') === value;
|
|
11
|
+
}
|
|
12
|
+
export function assertSafeAccountName(value) {
|
|
13
|
+
if (!isSafeAccountName(value)) {
|
|
14
|
+
throw new Error('account_store_error: invalid account name');
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=account-name.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-name.js","sourceRoot":"","sources":["../../src/account/account-name.ts"],"names":[],"mappings":"AAAA,MAAM,cAAc,GAAG,QAAQ,CAAA;AAC/B,MAAM,iBAAiB,GAAG,+BAA+B,CAAA;AAEzD,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC9C,OAAO,OAAO,KAAK,KAAK,QAAQ;WAC3B,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;WACvB,KAAK,KAAK,GAAG;WACb,KAAK,KAAK,IAAI;WACd,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC;WAC3B,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC;WAC9B,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,KAAK,CAAA;AACvC,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAc;IAClD,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAA;IAC9D,CAAC;AACH,CAAC"}
|