@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.
Files changed (197) hide show
  1. package/README.md +241 -61
  2. package/README.zh-CN.md +250 -73
  3. package/dist/account/account-authenticator.js +95 -0
  4. package/dist/account/account-authenticator.js.map +1 -0
  5. package/dist/account/account-context.js +7 -0
  6. package/dist/account/account-context.js.map +1 -1
  7. package/dist/account/account-name.js +17 -0
  8. package/dist/account/account-name.js.map +1 -0
  9. package/dist/account/account-presets.js +20 -3
  10. package/dist/account/account-presets.js.map +1 -1
  11. package/dist/account/account-store.js +277 -37
  12. package/dist/account/account-store.js.map +1 -1
  13. package/dist/cli/app.js +12 -1
  14. package/dist/cli/app.js.map +1 -1
  15. package/dist/cli/output.js +21 -6
  16. package/dist/cli/output.js.map +1 -1
  17. package/dist/cli/secure-input.js +408 -0
  18. package/dist/cli/secure-input.js.map +1 -0
  19. package/dist/commands/account-options.js +37 -7
  20. package/dist/commands/account-options.js.map +1 -1
  21. package/dist/commands/account.js +192 -66
  22. package/dist/commands/account.js.map +1 -1
  23. package/dist/commands/archive.js +151 -0
  24. package/dist/commands/archive.js.map +1 -0
  25. package/dist/commands/config.js +119 -12
  26. package/dist/commands/config.js.map +1 -1
  27. package/dist/commands/contact.js +58 -0
  28. package/dist/commands/contact.js.map +1 -0
  29. package/dist/commands/data.js +14 -7
  30. package/dist/commands/data.js.map +1 -1
  31. package/dist/commands/dialog.js +156 -0
  32. package/dist/commands/dialog.js.map +1 -0
  33. package/dist/commands/folder.js +113 -0
  34. package/dist/commands/folder.js.map +1 -0
  35. package/dist/commands/group-write.js +128 -0
  36. package/dist/commands/group-write.js.map +1 -0
  37. package/dist/commands/group.js +43 -7
  38. package/dist/commands/group.js.map +1 -1
  39. package/dist/commands/notification.js +76 -0
  40. package/dist/commands/notification.js.map +1 -0
  41. package/dist/commands/query.js +22 -15
  42. package/dist/commands/query.js.map +1 -1
  43. package/dist/commands/telegram-runner.js +40 -18
  44. package/dist/commands/telegram-runner.js.map +1 -1
  45. package/dist/commands/telegram.js +172 -109
  46. package/dist/commands/telegram.js.map +1 -1
  47. package/dist/commands/time-range.js +39 -0
  48. package/dist/commands/time-range.js.map +1 -0
  49. package/dist/commands/types.js +3 -2
  50. package/dist/commands/types.js.map +1 -1
  51. package/dist/config/credential-store.js +24 -4
  52. package/dist/config/credential-store.js.map +1 -1
  53. package/dist/config/env.js +4 -1
  54. package/dist/config/env.js.map +1 -1
  55. package/dist/group-commands/catalog.js +79 -0
  56. package/dist/group-commands/catalog.js.map +1 -0
  57. package/dist/group-commands/executor.js +102 -0
  58. package/dist/group-commands/executor.js.map +1 -0
  59. package/dist/group-commands/parser.js +268 -0
  60. package/dist/group-commands/parser.js.map +1 -0
  61. package/dist/group-commands/tokenize.js +51 -0
  62. package/dist/group-commands/tokenize.js.map +1 -0
  63. package/dist/group-commands/types.js +2 -0
  64. package/dist/group-commands/types.js.map +1 -0
  65. package/dist/index.js +0 -0
  66. package/dist/listen-commands/catalog.js +61 -0
  67. package/dist/listen-commands/catalog.js.map +1 -0
  68. package/dist/listen-commands/dispatch.js +46 -0
  69. package/dist/listen-commands/dispatch.js.map +1 -0
  70. package/dist/listen-commands/match.js +113 -0
  71. package/dist/listen-commands/match.js.map +1 -0
  72. package/dist/presenters/group.js +40 -0
  73. package/dist/presenters/group.js.map +1 -1
  74. package/dist/presenters/human.js +135 -0
  75. package/dist/presenters/human.js.map +1 -1
  76. package/dist/presenters/ink/display-width.js +45 -7
  77. package/dist/presenters/ink/display-width.js.map +1 -1
  78. package/dist/presenters/ink/group-command-confirm.js +13 -0
  79. package/dist/presenters/ink/group-command-confirm.js.map +1 -0
  80. package/dist/presenters/ink/group-command-result.js +23 -0
  81. package/dist/presenters/ink/group-command-result.js.map +1 -0
  82. package/dist/presenters/ink/listen-command-menu.js +38 -0
  83. package/dist/presenters/ink/listen-command-menu.js.map +1 -0
  84. package/dist/presenters/ink/listen-scroll.js +9 -4
  85. package/dist/presenters/ink/listen-scroll.js.map +1 -1
  86. package/dist/presenters/ink/listen.js +572 -52
  87. package/dist/presenters/ink/listen.js.map +1 -1
  88. package/dist/presenters/ink/mouse-scroll.js +12 -0
  89. package/dist/presenters/ink/mouse-scroll.js.map +1 -1
  90. package/dist/presenters/ink/secure-input.js +68 -0
  91. package/dist/presenters/ink/secure-input.js.map +1 -0
  92. package/dist/presenters/ink/use-group-command.js +186 -0
  93. package/dist/presenters/ink/use-group-command.js.map +1 -0
  94. package/dist/presenters/listen-message.js +23 -6
  95. package/dist/presenters/listen-message.js.map +1 -1
  96. package/dist/presenters/logical-message.js +78 -0
  97. package/dist/presenters/logical-message.js.map +1 -0
  98. package/dist/presenters/markdown.js +54 -0
  99. package/dist/presenters/markdown.js.map +1 -0
  100. package/dist/presenters/structured.js +8 -3
  101. package/dist/presenters/structured.js.map +1 -1
  102. package/dist/services/account-session-service.js +241 -0
  103. package/dist/services/account-session-service.js.map +1 -0
  104. package/dist/services/archive-layout.js +61 -0
  105. package/dist/services/archive-layout.js.map +1 -0
  106. package/dist/services/archive-manifest.js +187 -0
  107. package/dist/services/archive-manifest.js.map +1 -0
  108. package/dist/services/archive-markdown.js +383 -0
  109. package/dist/services/archive-markdown.js.map +1 -0
  110. package/dist/services/archive-service.js +718 -0
  111. package/dist/services/archive-service.js.map +1 -0
  112. package/dist/services/archive-types.js +2 -0
  113. package/dist/services/archive-types.js.map +1 -0
  114. package/dist/services/attachment-download.js +7 -2
  115. package/dist/services/attachment-download.js.map +1 -1
  116. package/dist/services/auto-download-coordinator.js +2 -4
  117. package/dist/services/auto-download-coordinator.js.map +1 -1
  118. package/dist/services/contact-service.js +78 -0
  119. package/dist/services/contact-service.js.map +1 -0
  120. package/dist/services/dialog-service.js +140 -0
  121. package/dist/services/dialog-service.js.map +1 -0
  122. package/dist/services/folder-service.js +200 -0
  123. package/dist/services/folder-service.js.map +1 -0
  124. package/dist/services/group-service.js.map +1 -1
  125. package/dist/services/group-write-service.js +225 -0
  126. package/dist/services/group-write-service.js.map +1 -0
  127. package/dist/services/listen-album-aggregator.js +9 -29
  128. package/dist/services/listen-album-aggregator.js.map +1 -1
  129. package/dist/services/listen-attachment.js +23 -6
  130. package/dist/services/listen-attachment.js.map +1 -1
  131. package/dist/services/listen-composer-command.js +102 -0
  132. package/dist/services/listen-composer-command.js.map +1 -0
  133. package/dist/services/listen-reply-resolver.js +126 -0
  134. package/dist/services/listen-reply-resolver.js.map +1 -0
  135. package/dist/services/message-service.js +17 -1
  136. package/dist/services/message-service.js.map +1 -1
  137. package/dist/services/notification-service.js +142 -0
  138. package/dist/services/notification-service.js.map +1 -0
  139. package/dist/services/query-service.js +59 -3
  140. package/dist/services/query-service.js.map +1 -1
  141. package/dist/services/reply-context.js +29 -0
  142. package/dist/services/reply-context.js.map +1 -0
  143. package/dist/services/write-access-policy.js +19 -0
  144. package/dist/services/write-access-policy.js.map +1 -0
  145. package/dist/storage/message-db.js +241 -5
  146. package/dist/storage/message-db.js.map +1 -1
  147. package/dist/telegram/archive-types.js +2 -0
  148. package/dist/telegram/archive-types.js.map +1 -0
  149. package/dist/telegram/client-factory.js +51 -11
  150. package/dist/telegram/client-factory.js.map +1 -1
  151. package/dist/telegram/contact-types.js +10 -0
  152. package/dist/telegram/contact-types.js.map +1 -0
  153. package/dist/telegram/dialog-types.js +2 -0
  154. package/dist/telegram/dialog-types.js.map +1 -0
  155. package/dist/telegram/errors.js +14 -0
  156. package/dist/telegram/errors.js.map +1 -0
  157. package/dist/telegram/fake-group-management.js +122 -0
  158. package/dist/telegram/fake-group-management.js.map +1 -1
  159. package/dist/telegram/folder-types.js +13 -0
  160. package/dist/telegram/folder-types.js.map +1 -0
  161. package/dist/telegram/group-types.js +40 -0
  162. package/dist/telegram/group-types.js.map +1 -1
  163. package/dist/telegram/group-write-types.js +29 -0
  164. package/dist/telegram/group-write-types.js.map +1 -0
  165. package/dist/telegram/mtcute-archive.js +190 -0
  166. package/dist/telegram/mtcute-archive.js.map +1 -0
  167. package/dist/telegram/mtcute-client.js +73 -12
  168. package/dist/telegram/mtcute-client.js.map +1 -1
  169. package/dist/telegram/mtcute-contacts.js +90 -0
  170. package/dist/telegram/mtcute-contacts.js.map +1 -0
  171. package/dist/telegram/mtcute-dialogs.js +186 -0
  172. package/dist/telegram/mtcute-dialogs.js.map +1 -0
  173. package/dist/telegram/mtcute-folders.js +318 -0
  174. package/dist/telegram/mtcute-folders.js.map +1 -0
  175. package/dist/telegram/mtcute-group-helpers.js +56 -0
  176. package/dist/telegram/mtcute-group-helpers.js.map +1 -0
  177. package/dist/telegram/mtcute-group-invites.js +82 -0
  178. package/dist/telegram/mtcute-group-invites.js.map +1 -0
  179. package/dist/telegram/mtcute-group-management.js +60 -31
  180. package/dist/telegram/mtcute-group-management.js.map +1 -1
  181. package/dist/telegram/mtcute-group-members.js +158 -0
  182. package/dist/telegram/mtcute-group-members.js.map +1 -0
  183. package/dist/telegram/mtcute-group-settings.js +146 -0
  184. package/dist/telegram/mtcute-group-settings.js.map +1 -0
  185. package/dist/telegram/mtcute-group-topics.js +63 -0
  186. package/dist/telegram/mtcute-group-topics.js.map +1 -0
  187. package/dist/telegram/mtcute-message-normalizer.js +63 -0
  188. package/dist/telegram/mtcute-message-normalizer.js.map +1 -0
  189. package/dist/telegram/mtcute-notifications.js +101 -0
  190. package/dist/telegram/mtcute-notifications.js.map +1 -0
  191. package/dist/telegram/notification-types.js +11 -0
  192. package/dist/telegram/notification-types.js.map +1 -0
  193. package/dist/telegram/raw-message.js +46 -0
  194. package/dist/telegram/raw-message.js.map +1 -0
  195. package/dist/telegram/types.js +6 -1
  196. package/dist/telegram/types.js.map +1 -1
  197. package/package.json +20 -10
package/README.md CHANGED
@@ -4,22 +4,21 @@
4
4
 
5
5
  A TypeScript command-line client for syncing Telegram chats, listening to live messages, searching locally stored messages, and inspecting groups from the terminal.
6
6
 
7
- ## Features
7
+ ## What you can do
8
8
 
9
- - Sign in to Telegram and inspect the current account or available chats.
10
9
  - Manage multiple Telegram accounts with isolated sessions and message databases.
11
- - Fetch chat history into a local SQLite database for fast, offline search.
12
- - Sync one chat incrementally or sync many chats with a single command.
13
- - Listen for new messages in real time, with optional attachment summaries.
14
- - Download attachments from channels that restrict content saving.
15
- - Search, filter, summarize, and export locally stored messages.
10
+ - Inspect unread chats and read or search messages without storing them locally.
11
+ - Sync chat history to SQLite for offline search, filtering, analysis, and export.
12
+ - Archive selected chats as incremental Markdown files, with optional attachment downloads.
13
+ - Listen for new messages and download incoming attachments.
16
14
  - Send, edit, and delete messages from the command line.
17
- - Inspect group details, members, and administrator audit events without changing the group.
18
- - Use human-readable output or structured JSON/YAML where supported.
15
+ - Inspect contacts, notification settings, chat folders, groups, members, administrators, invites, and forum topics.
16
+ - Disable remote Telegram mutations while keeping read-only and local commands available.
17
+ - Use human-readable, JSON, YAML, or Markdown output in scripts and agent workflows.
19
18
 
20
19
  ## Built for AI agents
21
20
 
22
- Telegram CLI gives AI agents a command-based interface to Telegram and locally synced messages. After a human authenticates an account with `tg account add`, an agent can run online and local commands without browser automation.
21
+ Telegram CLI gives AI agents a command-based interface to Telegram and locally synced messages. After you authenticate an account with `tg account add`, an agent can run online and local commands without browser automation.
23
22
 
24
23
  The CLI supports agent workflows through these interfaces:
25
24
 
@@ -34,19 +33,94 @@ For example, an agent can search one account and parse the result as JSON:
34
33
  tg search "release" --account work --json
35
34
  ```
36
35
 
36
+ ### Agent skill
37
+
38
+ Install the [`using-telegram-cli`](https://skills.sh/will-17173/telegram-cli/using-telegram-cli) skill to teach a supported AI coding agent how to authenticate accounts, synchronize and query messages, automate structured output, and guard Telegram write operations:
39
+
40
+ ```sh
41
+ npx skills add https://github.com/will-17173/telegram-cli \
42
+ --skill using-telegram-cli
43
+ ```
44
+
45
+ Add `--global` to make the skill available across projects instead of installing it into the current project.
46
+
37
47
  ## Installation
38
48
 
39
49
  Telegram CLI requires Node.js 22 or later.
40
50
 
41
- After the package is published to npm, install it globally with:
51
+ Install the package globally from npm:
42
52
 
43
53
  ```sh
44
54
  npm install -g @will-17173/telegram-cli
45
55
  ```
46
56
 
57
+ ## Quick start
58
+
59
+ Authenticate an account, check its status, and list its chats:
60
+
61
+ ```sh
62
+ tg account add
63
+ tg status
64
+ tg chats
65
+ tg chats --group
66
+ tg chats --channel
67
+ tg chats --user
68
+ ```
69
+
70
+ Choose a chat name, username, or ID from `tg chats`, then sync and search its messages:
71
+
72
+ ```sh
73
+ tg sync <chat>
74
+ tg search "keyword" --chat <chat>
75
+ ```
76
+
77
+ You can also sync multiple chats, listen for incoming messages, or send a message:
78
+
79
+ ```sh
80
+ tg sync-all --max-chats 20 --delay 1
81
+ tg listen <chat-or-id> --auto-download
82
+ tg send <chat> "Hello from tg"
83
+ ```
84
+
85
+ ## Read and manage Telegram online
86
+
87
+ `history`, `sync`, and `sync-all` fetch Telegram messages and store them in the local SQLite database. `read`, `search-online`, and `inbox` query Telegram directly without storing their results. `inbox` lists chats with unread messages without marking them as read.
88
+
89
+ ```sh
90
+ tg inbox --markdown
91
+ tg read @team --since 7d --until 2d
92
+ tg search-online release --chat @team --json
93
+ ```
94
+
95
+ Time bounds accept relative durations ending in `s`, `m`, `h`, `d`, or `w`. For example, `7d` means seven days before the command starts. Absolute bounds use ISO 8601 timestamps with a time zone, such as `2026-07-13T00:00:00Z`. The `--since` value must be earlier than `--until`.
96
+
97
+ You can also inspect contacts, notification settings, folders, and group dialogs without changing remote state:
98
+
99
+ ```sh
100
+ tg contact list
101
+ tg contact info +8613800000000
102
+ tg notification info @team
103
+ tg folder list
104
+ tg folder info 2
105
+ tg group list --admin
106
+ ```
107
+
108
+ The following commands modify Telegram remotely:
109
+
110
+ ```sh
111
+ tg notification mute @team 8h
112
+ tg notification unmute @team
113
+ tg folder chat add Work @team
114
+ tg folder chat remove Work @team
115
+ ```
116
+
117
+ Use `tg config write-access off` to block these mutations. Restore them with `tg config write-access on`.
118
+
119
+ Folder commands accept either a title or numeric folder ID. Folder titles are not necessarily unique. Run `tg folder list` first, then use the returned ID with `tg folder info`, `tg folder chat add`, or `tg folder chat remove`.
120
+
47
121
  ## Configuration
48
122
 
49
- Configuring personal Telegram API credentials is optional. To use your own, create them at [my.telegram.org](https://my.telegram.org), then save them with:
123
+ Personal Telegram application programming interface (API) credentials are optional. To use your own, create them at [my.telegram.org](https://my.telegram.org), then save them with:
50
124
 
51
125
  ```sh
52
126
  tg config set --api-id <id> --api-hash <hash>
@@ -74,9 +148,7 @@ For a one-command override, set `TG_PROXY` in the command environment:
74
148
  TG_PROXY=http://127.0.0.1:8080 tg status
75
149
  ```
76
150
 
77
- Supported proxy forms are `socks4://`, `socks5://`, `http://`, and `https://` proxy URLs, plus MTProxy links in the forms `tg://proxy?...` and `https://t.me/proxy?...`. A non-empty `TG_PROXY` value, after trimming surrounding whitespace, overrides the persisted proxy. If `TG_PROXY` is empty or unset, the CLI falls back to the stored proxy; if neither is configured, it connects directly.
78
-
79
- The selected proxy applies to account login and every Telegram-backed command, not only the command used in the example. Proxy URLs can contain usernames and passwords or MTProxy secrets, so treat them as sensitive. CLI output does not print the configured proxy URL. A credential-bearing proxy URL entered literally on a command line may remain in shell history or be visible through process inspection. Provide `TG_PROXY` through an appropriately protected environment or secret-loading mechanism, or otherwise avoid placing literal secrets in shared shell histories and scripts.
151
+ Telegram CLI supports SOCKS4, SOCKS5, HTTP, HTTPS, and MTProxy. The proxy applies to account login and every Telegram-backed command. Treat proxy URLs that contain credentials as sensitive.
80
152
 
81
153
  To inspect the effective configuration in human-readable, JSON, or YAML format, run:
82
154
 
@@ -87,9 +159,9 @@ tg config list --yaml
87
159
  tg config list --show-secrets
88
160
  ```
89
161
 
90
- This reports the effective configuration rather than the raw contents of `config.json`. API credentials are resolved from environment variables first, then stored configuration, then the built-in default. The proxy is resolved independently from `TG_PROXY` first, then stored configuration, then remains absent when neither is configured.
162
+ This reports the effective configuration rather than the raw contents of `config.json`. The API hash is masked by default; `--show-secrets` reveals only the full API hash.
91
163
 
92
- The output reports exactly five fields: the effective API ID, API hash, credential source, proxy URL, and proxy source. The API hash is masked by default; use `--show-secrets` to display it in full. The proxy URL is always printed in full and may contain credentials or an MTProxy secret, so avoid writing `config list` output to logs or sharing it. `tg config list` does not create a Telegram client or make a network connection.
164
+ Safe proxy endpoint details remain visible, but proxy usernames, passwords, and credential query parameters are always masked, even with `--show-secrets`.
93
165
 
94
166
  Run `tg account add` to authenticate and create a local session. Other commands never start the interactive login flow.
95
167
 
@@ -99,37 +171,6 @@ You can override the root directory for configuration, account sessions, and mes
99
171
  export DATA_DIR=/path/to/tg-cli-data
100
172
  ```
101
173
 
102
- ## Quick start
103
-
104
- ```sh
105
- # Add and authenticate the first account
106
- tg account add
107
-
108
- # Check authentication status
109
- tg status
110
-
111
- # List chats, then use a chat name, username, or ID where `<chat>` appears
112
- tg chats
113
-
114
- # Save a chat's history locally
115
- tg sync <chat>
116
-
117
- # Search the locally synced messages
118
- tg search "keyword" --chat <chat>
119
-
120
- # Sync across all chats
121
- tg sync-all --max-chats 20 --delay 1
122
-
123
- # Listen for new messages and automatically download incoming attachments
124
- tg listen <chat-or-id> --auto-download
125
-
126
- # Use plain output, download attachments, and hide their message summaries
127
- tg listen <chat-or-id> --no-interactive --auto-download --no-media
128
-
129
- # Send a message
130
- tg send <chat> "Hello from tg"
131
- ```
132
-
133
174
  ## Send messages and attachments
134
175
 
135
176
  `send` requires `<chat>`. Send text, one or more files, or files with a caption:
@@ -149,6 +190,33 @@ tg send <chat> "Group caption" --file ./photo.jpg --file ./clip.mp4
149
190
 
150
191
  Telegram determines which file combinations and group sizes it accepts. If Telegram rejects the requested combination or limit, the command returns an error and does not silently split the files into separate messages or groups.
151
192
 
193
+ ## Archive chats as Markdown
194
+
195
+ `archive` requires an explicit scope. Pass one or more chat IDs or usernames, or use `--all`, but don't combine them.
196
+
197
+ The command uses the current account unless you pass `--account <name>`. It writes to that account's `archive` directory by default. Use `--output <path>` to select another directory.
198
+
199
+ ```sh
200
+ # Initial archive with attachments: the preceding seven days
201
+ tg archive @team --download-media
202
+
203
+ # Custom range (relative durations or ISO timestamps with zones)
204
+ tg archive @team --since 30d --until 2026-07-13T00:00:00Z
205
+
206
+ # Full available history for every chat, including attachments
207
+ tg archive --all --full --download-media
208
+ ```
209
+
210
+ The first run archives the preceding seven days. Use `--since` and `--until` to select another range. Use `--full` to remove the lower bound; you can't combine it with `--since`.
211
+
212
+ Later runs append new messages to the existing archive. Use `--rebuild` to replace each selected Markdown file. Without a new range, rebuilding reuses the archive's initial range.
213
+
214
+ Use `--download-media` to store attachments in the archive's `media/` directory. Incremental runs retry referenced media that is still missing.
215
+
216
+ Chat or attachment failures produce `archive_partial_failure`, preserve successful chat results, and exit with status 1. Use `--json` or `--yaml` in automation and inspect `completed`, `failed`, and `warnings`.
217
+
218
+ Large history and media requests can trigger Telegram flood waits or other rate limits. Media downloads can fail independently. Successfully archived messages remain on disk, and warnings identify failed attachments.
219
+
152
220
  ## Multiple accounts
153
221
 
154
222
  Each Telegram account has its own persisted authentication session and local message database. Add and authenticate an account interactively with:
@@ -166,13 +234,27 @@ tg account list
166
234
  # Show the current account
167
235
  tg account current
168
236
 
169
- # Set the default account used by commands
237
+ # Choose the default account from an interactive list
238
+ tg account switch
239
+
240
+ # Set the default account by name
170
241
  tg account switch <name>
171
242
 
172
243
  # Remove an account and its local session/data
173
244
  tg account remove <name> --force
174
245
  ```
175
246
 
247
+ Log out explicitly to end the remote session without deleting the account, its settings, or locally stored messages. The `--yes` option confirms logout without a prompt.
248
+
249
+ Logging in again requires an interactive terminal (TTY) and creates or replaces the local Telegram session. Scripts and non-interactive agents receive an `interaction_required` error.
250
+
251
+ ```sh
252
+ tg account logout work --yes
253
+ tg account login work
254
+ ```
255
+
256
+ In an interactive terminal, `tg account switch` lists registered accounts, marks the current one, and accepts its number. Pass `<name>` when scripting or using `--json`, `--yaml`, or non-interactive input.
257
+
176
258
  Commands use the current account by default. Commands that support `--account` can target another registered account for one invocation without changing the current account:
177
259
 
178
260
  ```sh
@@ -185,9 +267,9 @@ Account names are shown by `tg account list`; they are normally derived from the
185
267
 
186
268
  Telegram API credentials apply to every registered account. You don't need to configure separate API credentials when adding another account.
187
269
 
188
- ## Read-only group management
270
+ ## Group management
189
271
 
190
- The `group` command inspects groups and supergroups through four read-only operations:
272
+ The `group` command supports read-only inspection and management of members, administrators, chat settings, invite links, forum topics, and messages. Use each command group's help to see its actions:
191
273
 
192
274
  ```sh
193
275
  # Group details
@@ -201,20 +283,75 @@ tg group member <chat> <user>
201
283
 
202
284
  # Administrator audit log; --user and --type can be repeated
203
285
  tg group audit <chat> --query invite --user <user> --type member_invited --type invite_changed --limit 100 --account alice --json
286
+
287
+ # Management examples (the chat argument comes before action arguments)
288
+ tg group member ban @team @alice --yes
289
+ tg group admin transfer-owner @team @newowner --yes
290
+ tg group chat slowmode @team 30s
291
+ tg group topic --help
204
292
  ```
205
293
 
294
+ After confirmation, ownership transfer securely prompts for the Telegram two-factor authentication (2FA) password. The password is never a CLI argument, stdin input, or environment automation source. The secure prompt accepts it only from an interactive terminal, not piped input. Don't automate this prompt.
295
+
206
296
  `group members` accepts exactly these seven `--type` filters: `recent`, `all`, `admins`, `banned`, `restricted`, `bots`, and `contacts`. It defaults to `recent` and 100 results; `--limit` accepts 1 through 200. Telegram can return fewer members than its reported total, so a page is not guaranteed to enumerate the whole group.
207
297
 
208
- `group audit` requires group administrator rights. Its `--limit` range is 1 through 500, with a default of 100 events. Its repeatable `--user` filter selects action authors. The repeatable `--type` filter accepts exactly these 17 stable grouped event types: `info_changed`, `settings_changed`, `member_joined`, `member_left`, `member_invited`, `member_banned`, `member_unbanned`, `member_restricted`, `member_unrestricted`, `admin_promoted`, `admin_demoted`, `message_deleted`, `message_edited`, `message_pinned`, `invite_changed`, `topic_changed`, and `other`.
298
+ `group audit` requires group administrator rights. Its `--limit` range is 1 through 500, with a default of 100 events. Its repeatable `--user` filter selects action authors. The repeatable `--type` filter accepts these event groups:
299
+
300
+ - **Chat**: `info_changed`, `settings_changed`
301
+ - **Members**: `member_joined`, `member_left`, `member_invited`, `member_banned`, `member_unbanned`, `member_restricted`, `member_unrestricted`
302
+ - **Administrators**: `admin_promoted`, `admin_demoted`
303
+ - **Messages**: `message_deleted`, `message_edited`, `message_pinned`
304
+ - **Invites and topics**: `invite_changed`, `topic_changed`
305
+ - **Other**: `other`
306
+
307
+ Inspection and management actions use human-readable output by default; actions that expose `--json` or `--yaml` provide structured success or error output. Failures set a nonzero exit status. They use the current account unless `--account <name>` selects another registered account for that invocation.
209
308
 
210
- All four commands use human-readable output by default and support `--json` or `--yaml`. They use the current account unless `--account <name>` selects another registered account for that invocation; the explicit selection does not change the current account. These commands are strictly read-only: they do not kick, ban, restrict, promote, edit settings, or otherwise change a group.
309
+ Management actions are grouped under `member`, `admin`, `chat`, `invite`, `topic`, and `message`. Member targets must be explicit `@username` values or numeric Telegram user IDs. Durations accept `s`, `m`, `h`, and `d` suffixes, or `off` where disabling is supported. For example, `tg group member mute @team @alice 2h --yes` temporarily mutes a member, while `tg group chat slowmode @team off` disables slow mode.
310
+
311
+ Potentially destructive CLI actions refuse to connect to Telegram unless `--yes` is present. Permanently deleting a chat additionally requires `--confirm-title` with the exact current title. Interactive listen mode presents these confirmations in an Ink modal. Management requires the relevant administrator permission, and some actions require a supergroup, forum, or creator role.
312
+
313
+ Use `tg group member info <chat> <user>` as the canonical member-details route. The legacy `tg group member <chat> <user>` form remains available, but a chat name matching a reserved member action such as `ban`, `mute`, or `info` is ambiguous and requires the canonical route.
314
+
315
+ ## Slash commands while listening
316
+
317
+ Interactive `tg listen` presents every supported slash command in one menu. This includes `/reply` and the complete group-management catalog; group commands use the same management grammar without repeating the selected chat:
318
+
319
+ ```text
320
+ /reply <message-id> <content>
321
+ /member mute @alice 2h
322
+ ```
323
+
324
+ Typing `/` opens the unified command menu, with reply first. Matching ranks exact paths, prefixes, then ordered fuzzy matches, so `/rep` and `/rpy` find `/reply`, while `/ban` finds `/member ban`. Use **Up** and **Down** to move through matches. **Tab** completes the selected command. **Enter** completes an incomplete selection or runs a complete command. **Esc** closes the menu, result, or confirmation.
325
+
326
+ Group-command availability and permission checks are unchanged: unavailable actions remain disabled, risky actions open a confirmation modal, and chat deletion also asks for the exact title. When listening to more than one chat, set an unambiguous outgoing target with `--send-to <chat>` before using group commands, for example `tg listen @team @ops --send-to @team`.
211
327
 
212
328
  ## Online and local commands
213
329
 
214
- Online commands connect to Telegram and require a valid session. These include `status`, `whoami`, `chats`, `history`, `sync`, `sync-all`, `refresh`, `info`, `group info`, `group members`, `group member`, `group audit`, `send`, `edit`, `delete`, and `listen`.
330
+ Online commands connect to Telegram and require a valid session:
331
+
332
+ - `read`, `search-online`, and `inbox` return results without storing them locally.
333
+ - `history`, `sync`, `sync-all`, and `refresh` persist fetched messages in SQLite.
334
+ - `contact`, `notification`, `folder`, `info`, and `group` inspect or manage Telegram data.
335
+ - `archive` reads Telegram history and writes Markdown files locally.
336
+ - `send`, `edit`, and `delete` modify Telegram messages.
337
+ - `listen` keeps a connection open for incoming messages and interactive actions.
338
+
339
+ Global online searches and large archives can trigger Telegram flood waits or other rate limits.
215
340
 
216
341
  Local commands read or modify the selected account's message database without connecting to Telegram. These include `search`, `recent`, `stats`, `top`, `timeline`, `today`, `filter`, `export`, and `purge`.
217
342
 
343
+ ## Review recent messages
344
+
345
+ `tg recent` shows messages stored during the last 24 hours, with a default limit of 50. Filter the results by chat or sender, or change the time window and limit:
346
+
347
+ ```sh
348
+ tg recent --chat <chat> --sender <sender> --hours 6 --limit 100
349
+ ```
350
+
351
+ Human-readable output groups each Telegram media group into one row and summarizes its attachments. The `ID` column lists every source message ID in that row. Replies include the original message's time, sender, ID, and text when the target exists locally in the same chat. Otherwise, the output identifies the missing local message ID.
352
+
353
+ JSON and YAML output keep the stored-message structure for scripts. `recent` reads local SQLite data and does not connect to Telegram.
354
+
218
355
  ## Command reference
219
356
 
220
357
  Run the built-in help for the complete, current command list:
@@ -230,14 +367,28 @@ Common commands:
230
367
  | `tg account add` | Authenticate and register another Telegram account. |
231
368
  | `tg account list` | List registered accounts and show which one is current. |
232
369
  | `tg account current` | Show the current account. |
233
- | `tg account switch <name>` | Set the default account used by commands. |
370
+ | `tg account switch [name]` | Select the default account interactively or set it by name. |
234
371
  | `tg account remove <name> --force` | Remove an account and its local session/data. |
372
+ | `tg account logout <name> --yes` / `tg account login <name>` | Confirm logout non-interactively, or reauthenticate interactively into a new local session; local messages are retained. |
235
373
  | `tg status` | Check whether the Telegram account is authenticated. |
236
374
  | `tg whoami` | Show basic authenticated account information. |
237
375
  | `tg config set --api-id <id> --api-hash <hash>` | Save Telegram API credentials for persistent use. |
238
376
  | `tg config set --proxy <url>` | Save an optional proxy for account login and Telegram-backed commands. |
239
- | `tg config list [--show-secrets]` | Show effective configuration values and sources; the proxy URL is always visible. |
240
- | `tg chats` | List available chats. |
377
+ | `tg config list [--show-secrets]` | Show effective configuration values and sources. Proxy credentials remain masked. |
378
+ | `tg config write-access [status\|on\|off]` | Inspect or gate remote Telegram mutations. |
379
+ | `tg chats [--group\|--channel\|--user]` | List available chats, optionally filtered by type (`--group` includes supergroups). |
380
+ | `tg inbox` | List unread dialogs online without marking messages read. |
381
+ | `tg read <chat> [--since <time>] [--until <time>]` | Read recent Telegram messages without persisting them locally. |
382
+ | `tg search-online <query> [--chat <chat>]` | Search Telegram globally or within one chat without persisting results. |
383
+ | `tg contact list` / `tg contact info <user_or_phone>` | List contacts or resolve one by ID, username, or phone. |
384
+ | `tg dialog inbox` / `tg dialog read <chat>` | Use the dialog-family routes for `inbox` and `read`. |
385
+ | `tg dialog search <query>` / `tg dialog groups` | Search online messages or list group dialogs through the dialog family. |
386
+ | `tg notification info <chat>` | Show notification settings for a chat. |
387
+ | `tg notification mute <chat> [duration]` | Mute notifications temporarily or indefinitely. |
388
+ | `tg notification unmute <chat>` | Restore notifications for a chat. |
389
+ | `tg folder list` / `tg folder info <folder>` | List folders or inspect one folder. |
390
+ | `tg folder chat add <folder> <chat>` | Add an explicit chat to a folder. |
391
+ | `tg folder chat remove <folder> <chat>` | Remove an explicit chat from a folder. |
241
392
  | `tg history <chat> -n <limit>` | Fetch and store full chat history (default up to 1000 messages). |
242
393
  | `tg sync <chat>` | Incrementally sync new messages for one chat. |
243
394
  | `tg sync-all` | Sync messages from all chats, using local last-message IDs for incremental updates. |
@@ -249,35 +400,64 @@ Common commands:
249
400
  | `tg recent`, `tg today`, `tg stats`, `tg top`, `tg timeline` | Explore local message data. |
250
401
  | `tg filter <keywords>` | Filter local messages by keyword with optional chat/hour filters. |
251
402
  | `tg export <chat>` | Export local messages from a chat. |
403
+ | `tg archive <chat ...>` / `tg archive --all` | Archive selected or all chats as incremental Markdown files. |
252
404
  | `tg send <chat> [message] [--file <path> ...]` | Send text, files, or a captioned media group. |
253
405
  | `tg edit <chat> <msgId> <text>` | Edit a message. |
254
406
  | `tg delete <chat> <msgIds...>` | Delete one or more messages. |
255
407
  | `tg purge <chat> --yes` | Remove a chat's locally stored messages. |
256
408
  | `tg info <chat>` | Show metadata for a Telegram chat. |
257
409
  | `tg group info <chat>` | Show read-only group or supergroup details. |
410
+ | `tg group list [--admin]` | List group, supergroup, and channel dialogs; `--admin` keeps only chats you administer or own. |
258
411
  | `tg group members <chat> [--type <type>] [--query <text>] [--limit <count>]` | List and filter members (default `recent`, limit 100; maximum 200). |
259
412
  | `tg group member <chat> <user>` | Show one member's role, rights, and restrictions. |
260
413
  | `tg group audit <chat> [--query <text>] [--user <user>] [--type <type>] [--limit <count>]` | Query the administrator audit log (default 100; maximum 500). |
414
+ | `tg group member/admin/chat/invite/topic/message --help` | Discover group management actions by family. |
261
415
 
262
416
  All sync-like commands write to local SQLite storage. The `sync-all` and `refresh` commands process multiple chats based on locally stored message IDs.
263
417
 
264
- Many commands support `--json` or `--yaml` for structured output. Failed commands return a nonzero exit code, so scripts can detect errors without parsing human-readable text.
418
+ Finite commands support explicit `--json`, `--yaml`, and `--markdown` output. Without an explicit format, non-interactive output remains YAML. Interactive terminals use rich human-readable output.
419
+
420
+ Successful finite output is written to stdout. JSON/YAML structured failures are written to stdout in the requested format. Output-format conflicts also use stdout and a stable YAML envelope. Human-readable and Markdown failures are written to stderr. Every failure sets a nonzero exit status.
421
+
422
+ The `listen` command is an unbounded stream, so these finite-output rules don't apply to it.
265
423
 
266
424
  Common options:
267
425
 
268
426
  | Option | Purpose |
269
427
  | --- | --- |
270
428
  | `--account <name>` | Use a registered account without changing the current account. |
271
- | `--json` / `--yaml` | Emit structured output when the command supports it. |
429
+ | `--json` / `--yaml` / `--markdown` | Select JSON, YAML, or Markdown output for a finite command. |
272
430
  | `-v`, `--verbose` | Enable debug logging. |
273
431
  | `-V`, `--version` | Print the installed version. |
274
432
 
275
433
  Use `tg <command> --help` to inspect command-specific options. For example, `listen` supports reconnection and plain-text modes, while `search` supports sender, time, regular-expression, and result-limit filters.
276
434
 
435
+ ### Error codes
436
+
437
+ Structured output exposes stable top-level command errors under `error.code`, with operation-specific details where available:
438
+
439
+ - **Accounts:** `account_logged_out`, `account_identity_mismatch`, `interaction_required`
440
+ - **Contacts:** `contact_not_found`
441
+ - **Notifications and folders:** `invalid_notification_duration`, `folder_not_found`, `ambiguous_folder`, `folder_operation_unsupported`
442
+ - **Group ownership:** `password_required`, `password_invalid`, `password_too_fresh`, `session_too_fresh`
443
+ - **Archive:** `archive_account_mismatch`, `archive_failed`, `archive_partial_failure`. When an attachment fails but the archive retains partial results, the top-level code is `archive_partial_failure`, the command exits nonzero, and each media warning uses `archive_media_failed` under `error.details.warnings[].code`.
444
+ - **Write safety and rate limits:** `write_access_disabled`, `flood_wait`
445
+
446
+ ### Remote write safety
447
+
448
+ Run `tg config write-access status` to inspect the current setting. Use `tg config write-access off` to block remote mutations made by send, edit, delete, notification, folder, and group commands. Local database operations, configuration changes, and Telegram reads remain available.
449
+
450
+ Run `tg config write-access on` to restore remote mutations after testing or maintenance.
451
+
277
452
  ### Sync and listen behavior
278
453
 
454
+ These rules describe how synchronization, listening, replies, and downloads affect local data and terminal output.
455
+
279
456
  - `sync-all` and `refresh` are batch operations for local persistence; they are not read-only.
280
457
  - `listen` prints a concise separator for each incoming message and can optionally suppress attachment summaries.
458
+ - Telegram media groups appear as one incoming message with a combined attachment summary.
459
+ - Reply output includes the original message's local context when available, or identifies the missing message ID.
460
+ - In interactive `listen`, reply with `/reply <message-id> <content>`. Add attachments with repeatable `--file <path>` options; quote paths that contain spaces.
281
461
  - Contact cards show the available name and phone number in attachment summaries. They aren't downloadable attachments and are hidden by `--no-media`.
282
462
  - `listen --auto-download` works in both interactive and plain-text modes, saves attachments to `~/Downloads/telegram-cli`, and runs at most three downloads concurrently.
283
463
  - Downloads keep Telegram-provided filenames. Unnamed downloads use a MIME-derived extension, then the media-kind extension, then `.bin`.
@@ -285,6 +465,8 @@ Use `tg <command> --help` to inspect command-specific options. For example, `lis
285
465
 
286
466
  ## Troubleshooting
287
467
 
468
+ Use these steps to resolve common account, session, and API credential errors.
469
+
288
470
  ### No active account
289
471
 
290
472
  If a command reports `account_required`, add an account or select an existing one:
@@ -326,8 +508,6 @@ accounts/<name>/messages.db
326
508
 
327
509
  Treat persisted configuration, `.env`, Telegram credentials, session files, and SQLite data as sensitive. Never share them or commit them to version control.
328
510
 
329
- The `config.json` file may contain an optional `proxy` setting in addition to API credentials. CLI success and error output does not print the stored proxy URL, but you must still protect `config.json`, the environment, and shell history because proxy URLs can contain credentials or MTProxy secrets.
330
-
331
511
  ## Development
332
512
 
333
513
  This project uses pnpm: