better-tg-cli 0.17.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/LICENSE +22 -0
- package/README.md +202 -0
- package/SKILL.md +56 -0
- package/dist/telegram.mjs +11 -0
- package/package.json +59 -0
- package/reference.md +126 -0
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "better-tg-cli",
|
|
3
|
+
"version": "0.17.0",
|
|
4
|
+
"description": "Unofficial agent-friendly Telegram client for the command line (MTProto, layer 229)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/telegram.mjs",
|
|
7
|
+
"bin": {
|
|
8
|
+
"telegram": "dist/telegram.mjs"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "node scripts/gen-version.mjs && tsc --noEmit && rm -rf dist && bun scripts/bundle.mjs node",
|
|
12
|
+
"prepublishOnly": "npm run build",
|
|
13
|
+
"test": "vitest run",
|
|
14
|
+
"test:watch": "vitest",
|
|
15
|
+
"pretest": "node scripts/gen-version.mjs",
|
|
16
|
+
"typecheck": "tsc --noEmit"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"telegram",
|
|
20
|
+
"cli",
|
|
21
|
+
"mtproto",
|
|
22
|
+
"agent",
|
|
23
|
+
"ai-agent",
|
|
24
|
+
"claude-code",
|
|
25
|
+
"skill"
|
|
26
|
+
],
|
|
27
|
+
"author": "Sergei Polin (fork of skillhq/telegram by Derek Rein)",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/TheVilfer/better-tg-cli.git"
|
|
32
|
+
},
|
|
33
|
+
"homepage": "https://github.com/TheVilfer/better-tg-cli#readme",
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/TheVilfer/better-tg-cli/issues"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/node": "^22.0.0",
|
|
39
|
+
"big-integer": "^1.6.52",
|
|
40
|
+
"commander": "^14.0.0",
|
|
41
|
+
"teleproto": "^1.229.0",
|
|
42
|
+
"typescript": "^5.7.0",
|
|
43
|
+
"vitest": "^5.0.2"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=20"
|
|
47
|
+
},
|
|
48
|
+
"files": [
|
|
49
|
+
"dist/telegram.mjs",
|
|
50
|
+
"SKILL.md",
|
|
51
|
+
"reference.md",
|
|
52
|
+
"LICENSE",
|
|
53
|
+
"README.md"
|
|
54
|
+
],
|
|
55
|
+
"publishConfig": {
|
|
56
|
+
"access": "public",
|
|
57
|
+
"provenance": true
|
|
58
|
+
}
|
|
59
|
+
}
|
package/reference.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Telegram CLI — behaviour reference
|
|
2
|
+
|
|
3
|
+
Every flag is listed by `telegram help-all` (or `telegram help-all -g <word>`), generated from the
|
|
4
|
+
code. This file only covers behaviour that the flag list can't tell you.
|
|
5
|
+
|
|
6
|
+
## Reading
|
|
7
|
+
|
|
8
|
+
- `read` pages through history, so `--since/--until/--before/--after` return exact ranges on busy
|
|
9
|
+
chats. `-n` caps the count (default 50). Order is newest first; `--asc` flips it.
|
|
10
|
+
- `--unread` starts after the dialog's read marker and still obeys `-n`. It does not mark the
|
|
11
|
+
messages read; use `mark-read <chat>` for that.
|
|
12
|
+
- `--thread <id>` reads comments under a channel post, or replies to a message in a group.
|
|
13
|
+
Channel comments live in the linked discussion group, so the output reports `threadChatId`.
|
|
14
|
+
Reply there with `telegram reply <threadChatId> <commentId> ...`.
|
|
15
|
+
- `--topic <id>` reads a forum topic. List topics with `telegram topics <chat>`.
|
|
16
|
+
- `--from` works with plain reads and threads. `search --from` needs `--chat`, because Telegram
|
|
17
|
+
global search has no sender filter.
|
|
18
|
+
- `get <chat> <ids...>` fetches exact messages. Missing IDs go to stderr in text mode, or to a
|
|
19
|
+
`missing` field in JSON.
|
|
20
|
+
- `search "" --chat X --type photo` lists every photo in a chat. Types: photo, video, media,
|
|
21
|
+
document, url, voice, audio, gif, round, location, contact, pinned, mentions.
|
|
22
|
+
`--type mentions` without `--chat` finds where you were @mentioned.
|
|
23
|
+
- Media shows as `[📷 photo]`, `[📎 document name.pdf · 1.2 MB]`, and so on. `download <chat> <id>`
|
|
24
|
+
saves the file. In JSON, `media` has `kind`, `fileName`, `mimeType`, `size`, `width`, `height`
|
|
25
|
+
and `duration`.
|
|
26
|
+
- A long post costs as many tokens as its text. Use `--max-text 200` for skimming, then
|
|
27
|
+
`get <chat> <id>` for the posts that matter.
|
|
28
|
+
|
|
29
|
+
## Output
|
|
30
|
+
|
|
31
|
+
- Off a TTY (agents and pipes), output is compact: one line per item with the ID first, JSON on
|
|
32
|
+
one line, and null or empty fields dropped. Set `TG_JSON_PRETTY=1` to indent JSON.
|
|
33
|
+
- Message line format: `#id YYYY-MM-DD HH:MM Sender ↩replyTo 💬comments: [media] text`. Continuation lines
|
|
34
|
+
are indented. The sender is omitted when it is the chat itself, as in channel posts.
|
|
35
|
+
- Chat line format: `id type [muted,archived] unread=N Title @username | preview`.
|
|
36
|
+
- JSON shapes:
|
|
37
|
+
|
|
38
|
+
| Command | Shape |
|
|
39
|
+
|---|---|
|
|
40
|
+
| `chats`, `contacts`, `members` | array |
|
|
41
|
+
| `read`, `get` | `{chatTitle, messages[], threadChatId?, missing?}` |
|
|
42
|
+
| `search` | array of `{chatTitle?, messages[]}`; global hits add `chatId` and `chatTitle` to each message |
|
|
43
|
+
| `inbox` | `{totalUnread, chatsWithUnread, chats[]}` (totals cover all chats, `chats` is cut to `-n`) |
|
|
44
|
+
| `info` | object |
|
|
45
|
+
| `topics` | `{chatTitle, topics[]}` |
|
|
46
|
+
|
|
47
|
+
## Writing (needs write access; every write goes to `~/.config/tg/audit.jsonl`)
|
|
48
|
+
|
|
49
|
+
- `write-access on [--for 30m|2h|1d]` asks the user: a y/N prompt on a terminal, otherwise a macOS
|
|
50
|
+
dialog (it times out as "no" after 2 minutes). `--for` switches writes off again automatically.
|
|
51
|
+
`write-access off` needs no confirmation. The flag lives in Keychain, not in the config file.
|
|
52
|
+
|
|
53
|
+
- Pass `-` as the text argument (`send`, `reply`, `edit`, `send-file -c`) to read the text from
|
|
54
|
+
stdin: `printf '%s' "$text" | telegram send @user -`. This avoids shell quoting problems.
|
|
55
|
+
- `--html` is the reliable formatting mode: `<b>`, `<i>`, `<a href>`, `<code>`, `<pre>`.
|
|
56
|
+
`--markdown` uses the GramJS dialect (`**bold**`, `` `code` ``), where `[text](url)` links do
|
|
57
|
+
NOT work.
|
|
58
|
+
- `send --schedule 2h` (or an ISO date) schedules a message. `--silent` sends without a
|
|
59
|
+
notification sound.
|
|
60
|
+
- `delete` revokes for everyone by default. `--just-me` deletes only on your side. IDs are comma
|
|
61
|
+
separated.
|
|
62
|
+
- `forward <from> <ids> <to>`: `--drop-author` hides the source.
|
|
63
|
+
- `pin` is silent by default (`--notify` pings members). `unpin <chat>` with no ID unpins
|
|
64
|
+
everything.
|
|
65
|
+
- `poll <chat> "Q" A B C` takes `--multiple`, `--quiz --correct N` (1-based) and `--public`.
|
|
66
|
+
`vote <chat> <id> 2` also counts options from 1.
|
|
67
|
+
|
|
68
|
+
### Bot buttons
|
|
69
|
+
|
|
70
|
+
`read` shows keyboards as `[index] label (type)`. Press one with `click <chat> <msgId> <index|label>`.
|
|
71
|
+
After a callback, `click` re-reads the message and prints the bot's toast/alert, the edited text,
|
|
72
|
+
new buttons and any new bot messages. Navigate bot menus by pressing a button and reading the new
|
|
73
|
+
menu.
|
|
74
|
+
|
|
75
|
+
| Button type | `click` does |
|
|
76
|
+
|---|---|
|
|
77
|
+
| callback | sends the callback, shows the answer and the updated message |
|
|
78
|
+
| game | returns the game URL |
|
|
79
|
+
| reply-keyboard text | sends the label as a message |
|
|
80
|
+
| url / url_auth / webview | prints the URL, never opens it |
|
|
81
|
+
| switch-inline | prints the query, does not send it |
|
|
82
|
+
| copy | prints the copied text |
|
|
83
|
+
| request phone / geo / poll / peer, buy | refused on purpose (privacy, payments) |
|
|
84
|
+
|
|
85
|
+
Buttons that need 2FA take `--password`. `--no-wait` skips waiting for the bot's reply.
|
|
86
|
+
|
|
87
|
+
### Admin
|
|
88
|
+
|
|
89
|
+
- `promote <group> <user>` takes `--rank "Title"` and `--add-admins`.
|
|
90
|
+
- `transfer-owner` is irreversible and interactive: it asks you to retype the group name (`-y`
|
|
91
|
+
skips this) and prompts for your 2FA password. It works for supergroups and channels only.
|
|
92
|
+
Telegram blocks it for about 24 hours after a new login and about 7 days after a 2FA change.
|
|
93
|
+
Never script it.
|
|
94
|
+
|
|
95
|
+
## Live and export
|
|
96
|
+
|
|
97
|
+
- `watch [chat] -t 30 -n 10 --json` streams new messages as JSON lines. Always pass `-t` or `-n`
|
|
98
|
+
when running unattended. A second `telegram` process that writes while `watch` runs can steal
|
|
99
|
+
its update stream.
|
|
100
|
+
- `sync --chat X --output DIR` writes markdown. It takes `--days N` (default 7),
|
|
101
|
+
`--since/--until` and `--all` for full history. `--media` downloads files into `<chat>/media/`.
|
|
102
|
+
- `sync --resume` is incremental. Checkpoints are per chat ID in `DIR/.sync-meta.json`. A resumed
|
|
103
|
+
run fetches everything after the checkpoint and ignores the default `--days` window.
|
|
104
|
+
|
|
105
|
+
## Chat identifiers
|
|
106
|
+
|
|
107
|
+
`me` / `self` / `saved` / `Saved Messages` / `Избранное` → your Saved Messages. A numeric ID must
|
|
108
|
+
exactly match a dialog ID (the `id` from `chats`). `@username` resolves exactly. Anything else
|
|
109
|
+
matches titles: exact first, then substring. For writes, prefer an ID or @username.
|
|
110
|
+
|
|
111
|
+
## Troubleshooting
|
|
112
|
+
|
|
113
|
+
- `Not configured`: the user must log in themselves with `telegram auth` (their own keys from
|
|
114
|
+
my.telegram.org) or `telegram auth --invite` (a token from the maintainer). It is interactive:
|
|
115
|
+
it needs a phone code and 2FA, so never run it for them.
|
|
116
|
+
|
|
117
|
+
- `command not found: telegram`: run `brew install thevilfer/tap/better-tg-cli` or `npm install -g better-tg-cli`, or build this folder (`npm install && npm run build && npm install -g .`, needs Bun)
|
|
118
|
+
Never install `@skillhq/telegram` from npm: it is the old GramJS build, and bot replies show
|
|
119
|
+
as `(no text)`.
|
|
120
|
+
- `Write access is disabled`: the account is read-only on purpose, or a `--for` window expired. Ask
|
|
121
|
+
the user, then run `telegram write-access on --for 1h`; they confirm it in a dialog.
|
|
122
|
+
- `CHANNELS_TOO_MUCH` on `join`: the account hit Telegram's channel limit, so leave some first.
|
|
123
|
+
- `Could not find the input entity`: the ID is not in your dialogs. Use `@username` or open the
|
|
124
|
+
chat first.
|
|
125
|
+
- Bot reply shows as `(no text)` with `MessageMediaUnsupported`: the TL layer is behind, so bump
|
|
126
|
+
`teleproto`.
|