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/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`.