telegram-cli-local 0.1.0__tar.gz → 0.2.0__tar.gz

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 (26) hide show
  1. {telegram_cli_local-0.1.0 → telegram_cli_local-0.2.0}/.agents/skills/telegram-cli/SKILL.md +112 -6
  2. {telegram_cli_local-0.1.0 → telegram_cli_local-0.2.0}/.claude/skills/telegram-cli/SKILL.md +112 -6
  3. telegram_cli_local-0.2.0/CHANGELOG.md +64 -0
  4. {telegram_cli_local-0.1.0 → telegram_cli_local-0.2.0}/MANIFEST.in +1 -0
  5. {telegram_cli_local-0.1.0/telegram_cli_local.egg-info → telegram_cli_local-0.2.0}/PKG-INFO +157 -6
  6. {telegram_cli_local-0.1.0 → telegram_cli_local-0.2.0}/README.md +156 -5
  7. {telegram_cli_local-0.1.0 → telegram_cli_local-0.2.0}/README.ru.md +163 -5
  8. {telegram_cli_local-0.1.0 → telegram_cli_local-0.2.0}/RELEASING.md +4 -3
  9. {telegram_cli_local-0.1.0 → telegram_cli_local-0.2.0}/scripts/check_distribution.py +2 -1
  10. {telegram_cli_local-0.1.0 → telegram_cli_local-0.2.0}/tcli_skills/SKILL.md +112 -6
  11. {telegram_cli_local-0.1.0 → telegram_cli_local-0.2.0}/tcli_skills/__init__.py +1 -1
  12. {telegram_cli_local-0.1.0 → telegram_cli_local-0.2.0/telegram_cli_local.egg-info}/PKG-INFO +157 -6
  13. {telegram_cli_local-0.1.0 → telegram_cli_local-0.2.0}/telegram_cli_local.egg-info/SOURCES.txt +1 -0
  14. {telegram_cli_local-0.1.0 → telegram_cli_local-0.2.0}/tests/test_tg.py +528 -3
  15. telegram_cli_local-0.2.0/tg.py +724 -0
  16. telegram_cli_local-0.1.0/tg.py +0 -418
  17. {telegram_cli_local-0.1.0 → telegram_cli_local-0.2.0}/AGENTS.md +0 -0
  18. {telegram_cli_local-0.1.0 → telegram_cli_local-0.2.0}/CLAUDE.md +0 -0
  19. {telegram_cli_local-0.1.0 → telegram_cli_local-0.2.0}/LICENSE +0 -0
  20. {telegram_cli_local-0.1.0 → telegram_cli_local-0.2.0}/pyproject.toml +0 -0
  21. {telegram_cli_local-0.1.0 → telegram_cli_local-0.2.0}/requirements.txt +0 -0
  22. {telegram_cli_local-0.1.0 → telegram_cli_local-0.2.0}/setup.cfg +0 -0
  23. {telegram_cli_local-0.1.0 → telegram_cli_local-0.2.0}/telegram_cli_local.egg-info/dependency_links.txt +0 -0
  24. {telegram_cli_local-0.1.0 → telegram_cli_local-0.2.0}/telegram_cli_local.egg-info/entry_points.txt +0 -0
  25. {telegram_cli_local-0.1.0 → telegram_cli_local-0.2.0}/telegram_cli_local.egg-info/requires.txt +0 -0
  26. {telegram_cli_local-0.1.0 → telegram_cli_local-0.2.0}/telegram_cli_local.egg-info/top_level.txt +0 -0
@@ -98,6 +98,15 @@ Unknown commands, unknown help topics, and invalid arguments remain usage errors
98
98
  | `tcli send me "Text"` | Send literal text to Saved Messages |
99
99
  | `tcli send @username "Text"` | Send to a username |
100
100
  | `tcli send -- -1001234567890 "Text"` | Send by negative ID |
101
+ | `tcli send me --attach photo.jpg --caption "Photo"` | Upload a photo, video, audio, or any Telegram-supported local file |
102
+ | `tcli send me --attach archive.zip --as-file` | Force document upload; preserve the original file |
103
+ | `tcli download me 123 --output photo.jpg` | Download the attachment from message 123 into a new local file |
104
+ | `tcli read "Chat" --id 123 --json` | Get one message with reply and album IDs |
105
+ | `tcli read "Chat" --media document --json` | Filter media using Telegram search |
106
+ | `tcli send me --attach app.apk archive.zip --caption "App" --caption "Archive" --json` | Send files individually in order |
107
+ | `tcli send me --attach first.jpg second.jpg --album --json` | Send 2-10 compatible attachments as one album |
108
+ | `tcli download me 123 --album --output-dir downloads --json` | Download the album containing message 123 |
109
+ | `tcli edit me 123 "Corrected text" --json` | Edit outgoing message text or attachment caption |
101
110
  | `tcli watch "Chat name"` | New messages until Ctrl+C; blocks the process |
102
111
  | `tcli logout` | Revoke this CLI session and remove its session file; keep API credentials |
103
112
  | `tcli doctor` | Validate effective credentials and session-file presence locally; show paths, never secret values |
@@ -119,16 +128,37 @@ Increase `chats --limit` if necessary. Do not invent IDs. Partial names and t.me
119
128
  Limits must be positive integers. `read` does not mark messages as read.
120
129
 
121
130
  Message output: `[local date and time] sender ID or you (#message ID): text`.
122
- Missing text displays `[media or service message]`.
131
+ Downloadable media displays its type, filename (if available), MIME type, and size in bytes, alongside any caption.
132
+ Other messages without text display `[media or service message]`.
123
133
  Human-readable output removes control characters. Optional JSON preserves original text using escaped
124
134
  Unicode/control characters. Chat fields: id, name, unread_count. Message fields: id, chat_id,
125
- date (ISO 8601 with offset), sender_id (nullable), out, text (empty when absent), has_media.
135
+ date (ISO 8601 with offset), sender_id (nullable), out, text (empty when absent), has_media, media, reply_to_id, grouped_id.
136
+ reply_to_id and grouped_id are null when absent; human output also shows these IDs.
137
+ Use read --id with reply_to_id to retrieve the original message of a reply.
138
+ `media` is null for messages without a downloadable photo/document; otherwise it contains
139
+ type (photo, video, audio, voice, video_note, gif, sticker, document), name, mime_type, size (bytes),
140
+ ext, width, height, duration (seconds). Unavailable metadata fields are null.
141
+ Link previews and other Telegram media may have has_media=true with media=null.
126
142
  `chats --json` and `read --json` output arrays, including [] for no results.
127
143
  `watch --json` outputs JSONL with status/errors only on stderr.
128
144
  `read --search QUERY` uses Telegram text search in the selected chat; each page is oldest first.
129
145
  `--before ID` is exclusive; use the smallest returned ID for the next page, also with search.
130
146
  `--before` and `--reply-to` require positive message IDs from the same chat.
131
- `send` requires exactly one nonempty source: positional text, --stdin, or --file PATH.
147
+ `send` requires exactly one source: positional text, --stdin, --file PATH, or --attach PATH.
148
+ Text sources must be nonempty. --attach uploads one or more existing local files per command,
149
+ including binary documents such as .exe, .apk, .zip; attachments are never decoded as text.
150
+ Telethon selects photo/video/audio/document representation; --as-file forces a document.
151
+ --caption supplies optional text with --attach only; --as-file and --album also require --attach.
152
+ Repeat --caption in attachment order; missing captions are empty. Use --caption "" to skip one.
153
+ Without --album, files are sent individually in order. --album sends 2-10 compatible attachments
154
+ as a group via Telethon; incompatible Telegram album combinations may produce RPC errors.
155
+ A single caption belongs to the first attachment. All paths and caption counts are checked before connecting.
156
+ Captions support --format and --reply-to. File type and size limits are enforced by Telegram.
157
+ `download CHAT ID --output PATH` saves the attachment of one message in that chat.
158
+ Use IDs from read/watch. The destination parent must exist; existing files are never overwritten.
159
+ Remote filenames are metadata only and never select a local path. Failed/cancelled downloads remove
160
+ the partial destination. Download photos are Telegram's stored version, not necessarily the original.
161
+ To view the content, open the downloaded file with a local application; the CLI displays metadata.
132
162
  Stdin/files use UTF-8 with optional BOM; whitespace and line breaks are preserved, blank input rejected
133
163
  before connecting. PowerShell pipelines must emit UTF-8 (set $OutputEncoding if necessary).
134
164
  --file sends text, not an attachment. All sources support --reply-to ID and --format plain|markdown|html.
@@ -138,7 +168,7 @@ HTML supports b/strong, i/em, u, s/del, code, pre, a href, blockquote (including
138
168
  and pre/code class="language-python" for code-block language. Use actual newlines, not br tags.
139
169
  The installed Telethon parser ignores unsupported HTML tags and does not support spoiler markup.
140
170
  Formatting may trim surrounding whitespace. Use HTML for nested formatting.
141
- No attachments, editing, deletion, or interactive conversation UI.
171
+ No message deletion or interactive conversation UI.
142
172
  `doctor` is local, creates no files, and exits 1 for invalid credentials or missing session.
143
173
  File presence does not prove authorization. --connect can update the existing Telethon session.
144
174
  `watch` records the latest ID before announcing readiness, then polls every two seconds using
@@ -146,9 +176,79 @@ min_id and reverse order with no fixed batch limit. It includes sends from anoth
146
176
  and Saved Messages. Session writes are committed before idle waits to release SQLite locks.
147
177
  Messages deleted before polling cannot be seen. `watch` has no past history; prefer `read` for a one-time request.
148
178
 
179
+ ## Automation, context, filters, and editing
180
+
181
+ `read CHAT --id ID` fetches one message or fails with message_not_found. JSON remains an array
182
+ with one item. --id cannot combine with --around, --before, or search/media/filename filters; --limit applies only to history.
183
+ `read --media photo|video|document|audio|voice|video_note|gif` uses native Telegram filters;
184
+ audio means music. Filters combine with --search, --before, and --limit.
185
+ Search follows Telegram text-search semantics, not local filename/extension matching.
186
+
187
+ `edit CHAT ID TEXT`, `edit CHAT ID --file PATH`, or `edit CHAT ID --stdin` edits outgoing text
188
+ or a caption. Exactly one nonblank UTF-8 text source is required. --format plain|markdown|html
189
+ works as for send. Check that the message exists and is outgoing before calling edit_message.
190
+ Telegram enforces edit permissions and time limits; unchanged text can raise an RPC error.
191
+ Editing does not replace attachments or clear captions with empty text.
192
+
193
+ `download CHAT ID --album --output-dir DIR` downloads the album containing that message.
194
+ --output-dir requires --album, excludes --output, and must already exist.
195
+ Inspect up to ten neighboring messages on each side in chat history, match grouped_id, sort by ID.
196
+ Telegram albums have at most ten adjacent messages; message IDs can have gaps.
197
+ Save as <message_id><extension>, with .bin for missing/unsafe extensions; never use remote filenames.
198
+ Preflight all destinations before downloading, then use exclusive file creation to avoid races.
199
+ Keep completed files on failure and remove the current partial file. Missing/deleted/inaccessible
200
+ album items cannot be recovered. Download JSON keeps captions and grouped_id without sidecar files.
201
+
202
+ With --json, send outputs {"ok": true, "messages": [message objects]}, edit outputs
203
+ {"ok": true, "message": message object}, and download outputs {"ok": true, "files": [file objects]}.
204
+ File fields: message_id, chat_id, path (absolute), text (caption), grouped_id (nullable).
205
+ chats/read arrays and watch JSONL keep their existing shapes, with the added message fields.
206
+
207
+ Handled errors for commands with --json go to stderr as one JSON object:
208
+ {"ok": false, "error": {"code": "flood_wait", "message": "...", "retry_after": 17}}.
209
+ retry_after is seconds for FloodWait, null otherwise. RPC errors include rpc_type and rpc_code.
210
+ Codes: usage_error, invalid_input, configuration_error, unauthorized, chat_not_found, ambiguous_chat,
211
+ message_not_found, not_outgoing, edit_failed, not_an_album, no_attachment, file_exists, flood_wait,
212
+ rpc_error, network_error, io_error, database_error, cancelled.
213
+ Argument errors exit 2; handled failures exit 1; interruption exits 130. Watch status stays plain text
214
+ on stderr. After a partial operation, error JSON includes messages/files with confirmed completed results.
215
+ Do not automatically retry uncertain send/edit failures: inspect history to avoid duplicate actions.
216
+
217
+ ## Filename search, surrounding context, forwarding, and progress
218
+
219
+ `read CHAT --filename "*.apk" --scan-limit 1000 --limit 5 --json` matches original attachment
220
+ names locally with case-insensitive glob patterns (*, ?, [abc]). Messages without names are skipped.
221
+ --scan-limit (default 1000) bounds the newest messages inspected after Telegram search/media filters;
222
+ --limit bounds matches. Results stay oldest first. Combine with --before, --search, or --media.
223
+ No matches in the bounded scan do not prove absence across the whole chat. --scan-limit requires --filename.
224
+
225
+ `read CHAT --around ID --context N` fetches the selected message and up to N neighbors on each side
226
+ (default 5), ordered chronologically. IDs need not be consecutive. Missing anchor: message_not_found.
227
+ --around excludes --id, --before, --search, --media, --filename, and --scan-limit.
228
+ --context requires --around. --limit only applies to history and filename search.
229
+
230
+ `forward FROM_CHAT ID TO_CHAT [--json]` forwards one message, attachment and caption included,
231
+ using native Telegram forwarding without local download/upload. Standard chat selectors apply on
232
+ both sides. Preserve attribution. Telegram enforces protected-content and posting restrictions.
233
+ JSON success uses the send shape: {"ok": true, "messages": [message object]}.
234
+ Forward only on explicit user instruction with known source, message ID, and destination.
235
+ Development/testing does not authorize live forwarding. Verify history before retrying an uncertain failure.
236
+
237
+ send (attachments only) and download support --progress / --no-progress.
238
+ Default: enabled when stderr is a terminal. Progress reports bytes, percentage, and average bytes/sec
239
+ on stderr; album upload weights Telethon's per-file progress by local file sizes.
240
+ Throttle updates to twice per second, plus completion. With --json, progress is JSONL on stderr:
241
+ event="transfer_progress", operation="upload"|"download", file, transferred_bytes, total_bytes,
242
+ percent (null for unknown/zero size), bytes_per_second. Errors have ok=false and may follow progress events.
243
+ Stdout remains the final JSON result. Progress is not proof of delivery; cached transfers may emit no events.
244
+
149
245
  ## Common workflows
150
246
 
151
247
  `skills install` defaults to --agent auto: detect installed agents and copy the bundled skill only for those agents.
248
+ Default destinations are the official personal skill locations, independent of the current directory:
249
+ Codex: ~/.agents/skills/telegram-cli/SKILL.md; Claude Code: ~/.claude/skills/telegram-cli/SKILL.md.
250
+ See [OpenAI](https://learn.chatgpt.com/docs/build-skills#where-codex-loads-local-skills) and
251
+ [Anthropic](https://code.claude.com/docs/en/skills#where-skills-live).
152
252
  Detection checks PATH, native ~/.local/bin executables, standard npm/binary locations, Codex.app on macOS,
153
253
  and the OpenAI.Codex Windows Store installation. Configuration folders alone are not installation evidence.
154
254
  If neither agent is found, it creates nothing. Explicit --agent codex|claude|all bypasses detection for custom installations.
@@ -195,7 +295,9 @@ The user enters login code and 2FA password in their terminal; agent sessions mu
195
295
  Account commands fail when unauthorized rather than automatically prompting for login.
196
296
 
197
297
  Read only chats needed for the user's request; do not store private conversations in project files.
198
- Send only on the user's direct instruction with a known recipient and text.
298
+ Send, forward, or edit only on the user's direct instruction with a known recipient, message ID where needed,
299
+ and text or attachment. Development requests do not authorize live sends or edits.
300
+ Download only requested attachments into the requested local location; never execute downloaded files.
199
301
  An unambiguous prior instruction needs no extra confirmation. A development/test request does not authorize sending, even to `me`.
200
302
  Clarify ambiguous recipients before sending. Use correct shell quoting to pass text as one argument;
201
303
  never interpolate untrusted messages as executable shell code. JSON.stringify is not shell escaping.
@@ -219,8 +321,12 @@ Telethon may perform internal retries; the CLI has no custom send retry loop.
219
321
  Preserve credential validation, authorization checks, unambiguous chat resolution,
220
322
  terminal sanitization, literal outgoing text by default, disconnect in finally, and FloodWait handling.
221
323
  Update affected tests, both READMEs, and all three copies of this SKILL.md when changing commands.
324
+ Record every notable change in CHANGELOG.md under Unreleased; version the entries when releasing.
222
325
  Tests cover help without credentials, JSON/JSONL, search/pagination arguments, replies, stdin/files,
223
326
  doctor, login/logout, watch polling/cursors and cancellation, formatting selection, disconnects
224
- and handled errors including FloodWait and SQLite locks.
327
+ and handled errors including FloodWait and SQLite locks. They also cover send/download/edit JSON,
328
+ read by ID, reply/album context, media filters, ordered multi-file sends, albums, edits,
329
+ partial failures, destination collisions, safe filenames, structured usage/runtime errors,
330
+ bounded filename search, surrounding context, forwarding, and transfer progress.
225
331
  They do not verify real login,
226
332
  network watching, or message delivery. State those limits when reporting validation.
@@ -98,6 +98,15 @@ Unknown commands, unknown help topics, and invalid arguments remain usage errors
98
98
  | `tcli send me "Text"` | Send literal text to Saved Messages |
99
99
  | `tcli send @username "Text"` | Send to a username |
100
100
  | `tcli send -- -1001234567890 "Text"` | Send by negative ID |
101
+ | `tcli send me --attach photo.jpg --caption "Photo"` | Upload a photo, video, audio, or any Telegram-supported local file |
102
+ | `tcli send me --attach archive.zip --as-file` | Force document upload; preserve the original file |
103
+ | `tcli download me 123 --output photo.jpg` | Download the attachment from message 123 into a new local file |
104
+ | `tcli read "Chat" --id 123 --json` | Get one message with reply and album IDs |
105
+ | `tcli read "Chat" --media document --json` | Filter media using Telegram search |
106
+ | `tcli send me --attach app.apk archive.zip --caption "App" --caption "Archive" --json` | Send files individually in order |
107
+ | `tcli send me --attach first.jpg second.jpg --album --json` | Send 2-10 compatible attachments as one album |
108
+ | `tcli download me 123 --album --output-dir downloads --json` | Download the album containing message 123 |
109
+ | `tcli edit me 123 "Corrected text" --json` | Edit outgoing message text or attachment caption |
101
110
  | `tcli watch "Chat name"` | New messages until Ctrl+C; blocks the process |
102
111
  | `tcli logout` | Revoke this CLI session and remove its session file; keep API credentials |
103
112
  | `tcli doctor` | Validate effective credentials and session-file presence locally; show paths, never secret values |
@@ -119,16 +128,37 @@ Increase `chats --limit` if necessary. Do not invent IDs. Partial names and t.me
119
128
  Limits must be positive integers. `read` does not mark messages as read.
120
129
 
121
130
  Message output: `[local date and time] sender ID or you (#message ID): text`.
122
- Missing text displays `[media or service message]`.
131
+ Downloadable media displays its type, filename (if available), MIME type, and size in bytes, alongside any caption.
132
+ Other messages without text display `[media or service message]`.
123
133
  Human-readable output removes control characters. Optional JSON preserves original text using escaped
124
134
  Unicode/control characters. Chat fields: id, name, unread_count. Message fields: id, chat_id,
125
- date (ISO 8601 with offset), sender_id (nullable), out, text (empty when absent), has_media.
135
+ date (ISO 8601 with offset), sender_id (nullable), out, text (empty when absent), has_media, media, reply_to_id, grouped_id.
136
+ reply_to_id and grouped_id are null when absent; human output also shows these IDs.
137
+ Use read --id with reply_to_id to retrieve the original message of a reply.
138
+ `media` is null for messages without a downloadable photo/document; otherwise it contains
139
+ type (photo, video, audio, voice, video_note, gif, sticker, document), name, mime_type, size (bytes),
140
+ ext, width, height, duration (seconds). Unavailable metadata fields are null.
141
+ Link previews and other Telegram media may have has_media=true with media=null.
126
142
  `chats --json` and `read --json` output arrays, including [] for no results.
127
143
  `watch --json` outputs JSONL with status/errors only on stderr.
128
144
  `read --search QUERY` uses Telegram text search in the selected chat; each page is oldest first.
129
145
  `--before ID` is exclusive; use the smallest returned ID for the next page, also with search.
130
146
  `--before` and `--reply-to` require positive message IDs from the same chat.
131
- `send` requires exactly one nonempty source: positional text, --stdin, or --file PATH.
147
+ `send` requires exactly one source: positional text, --stdin, --file PATH, or --attach PATH.
148
+ Text sources must be nonempty. --attach uploads one or more existing local files per command,
149
+ including binary documents such as .exe, .apk, .zip; attachments are never decoded as text.
150
+ Telethon selects photo/video/audio/document representation; --as-file forces a document.
151
+ --caption supplies optional text with --attach only; --as-file and --album also require --attach.
152
+ Repeat --caption in attachment order; missing captions are empty. Use --caption "" to skip one.
153
+ Without --album, files are sent individually in order. --album sends 2-10 compatible attachments
154
+ as a group via Telethon; incompatible Telegram album combinations may produce RPC errors.
155
+ A single caption belongs to the first attachment. All paths and caption counts are checked before connecting.
156
+ Captions support --format and --reply-to. File type and size limits are enforced by Telegram.
157
+ `download CHAT ID --output PATH` saves the attachment of one message in that chat.
158
+ Use IDs from read/watch. The destination parent must exist; existing files are never overwritten.
159
+ Remote filenames are metadata only and never select a local path. Failed/cancelled downloads remove
160
+ the partial destination. Download photos are Telegram's stored version, not necessarily the original.
161
+ To view the content, open the downloaded file with a local application; the CLI displays metadata.
132
162
  Stdin/files use UTF-8 with optional BOM; whitespace and line breaks are preserved, blank input rejected
133
163
  before connecting. PowerShell pipelines must emit UTF-8 (set $OutputEncoding if necessary).
134
164
  --file sends text, not an attachment. All sources support --reply-to ID and --format plain|markdown|html.
@@ -138,7 +168,7 @@ HTML supports b/strong, i/em, u, s/del, code, pre, a href, blockquote (including
138
168
  and pre/code class="language-python" for code-block language. Use actual newlines, not br tags.
139
169
  The installed Telethon parser ignores unsupported HTML tags and does not support spoiler markup.
140
170
  Formatting may trim surrounding whitespace. Use HTML for nested formatting.
141
- No attachments, editing, deletion, or interactive conversation UI.
171
+ No message deletion or interactive conversation UI.
142
172
  `doctor` is local, creates no files, and exits 1 for invalid credentials or missing session.
143
173
  File presence does not prove authorization. --connect can update the existing Telethon session.
144
174
  `watch` records the latest ID before announcing readiness, then polls every two seconds using
@@ -146,9 +176,79 @@ min_id and reverse order with no fixed batch limit. It includes sends from anoth
146
176
  and Saved Messages. Session writes are committed before idle waits to release SQLite locks.
147
177
  Messages deleted before polling cannot be seen. `watch` has no past history; prefer `read` for a one-time request.
148
178
 
179
+ ## Automation, context, filters, and editing
180
+
181
+ `read CHAT --id ID` fetches one message or fails with message_not_found. JSON remains an array
182
+ with one item. --id cannot combine with --around, --before, or search/media/filename filters; --limit applies only to history.
183
+ `read --media photo|video|document|audio|voice|video_note|gif` uses native Telegram filters;
184
+ audio means music. Filters combine with --search, --before, and --limit.
185
+ Search follows Telegram text-search semantics, not local filename/extension matching.
186
+
187
+ `edit CHAT ID TEXT`, `edit CHAT ID --file PATH`, or `edit CHAT ID --stdin` edits outgoing text
188
+ or a caption. Exactly one nonblank UTF-8 text source is required. --format plain|markdown|html
189
+ works as for send. Check that the message exists and is outgoing before calling edit_message.
190
+ Telegram enforces edit permissions and time limits; unchanged text can raise an RPC error.
191
+ Editing does not replace attachments or clear captions with empty text.
192
+
193
+ `download CHAT ID --album --output-dir DIR` downloads the album containing that message.
194
+ --output-dir requires --album, excludes --output, and must already exist.
195
+ Inspect up to ten neighboring messages on each side in chat history, match grouped_id, sort by ID.
196
+ Telegram albums have at most ten adjacent messages; message IDs can have gaps.
197
+ Save as <message_id><extension>, with .bin for missing/unsafe extensions; never use remote filenames.
198
+ Preflight all destinations before downloading, then use exclusive file creation to avoid races.
199
+ Keep completed files on failure and remove the current partial file. Missing/deleted/inaccessible
200
+ album items cannot be recovered. Download JSON keeps captions and grouped_id without sidecar files.
201
+
202
+ With --json, send outputs {"ok": true, "messages": [message objects]}, edit outputs
203
+ {"ok": true, "message": message object}, and download outputs {"ok": true, "files": [file objects]}.
204
+ File fields: message_id, chat_id, path (absolute), text (caption), grouped_id (nullable).
205
+ chats/read arrays and watch JSONL keep their existing shapes, with the added message fields.
206
+
207
+ Handled errors for commands with --json go to stderr as one JSON object:
208
+ {"ok": false, "error": {"code": "flood_wait", "message": "...", "retry_after": 17}}.
209
+ retry_after is seconds for FloodWait, null otherwise. RPC errors include rpc_type and rpc_code.
210
+ Codes: usage_error, invalid_input, configuration_error, unauthorized, chat_not_found, ambiguous_chat,
211
+ message_not_found, not_outgoing, edit_failed, not_an_album, no_attachment, file_exists, flood_wait,
212
+ rpc_error, network_error, io_error, database_error, cancelled.
213
+ Argument errors exit 2; handled failures exit 1; interruption exits 130. Watch status stays plain text
214
+ on stderr. After a partial operation, error JSON includes messages/files with confirmed completed results.
215
+ Do not automatically retry uncertain send/edit failures: inspect history to avoid duplicate actions.
216
+
217
+ ## Filename search, surrounding context, forwarding, and progress
218
+
219
+ `read CHAT --filename "*.apk" --scan-limit 1000 --limit 5 --json` matches original attachment
220
+ names locally with case-insensitive glob patterns (*, ?, [abc]). Messages without names are skipped.
221
+ --scan-limit (default 1000) bounds the newest messages inspected after Telegram search/media filters;
222
+ --limit bounds matches. Results stay oldest first. Combine with --before, --search, or --media.
223
+ No matches in the bounded scan do not prove absence across the whole chat. --scan-limit requires --filename.
224
+
225
+ `read CHAT --around ID --context N` fetches the selected message and up to N neighbors on each side
226
+ (default 5), ordered chronologically. IDs need not be consecutive. Missing anchor: message_not_found.
227
+ --around excludes --id, --before, --search, --media, --filename, and --scan-limit.
228
+ --context requires --around. --limit only applies to history and filename search.
229
+
230
+ `forward FROM_CHAT ID TO_CHAT [--json]` forwards one message, attachment and caption included,
231
+ using native Telegram forwarding without local download/upload. Standard chat selectors apply on
232
+ both sides. Preserve attribution. Telegram enforces protected-content and posting restrictions.
233
+ JSON success uses the send shape: {"ok": true, "messages": [message object]}.
234
+ Forward only on explicit user instruction with known source, message ID, and destination.
235
+ Development/testing does not authorize live forwarding. Verify history before retrying an uncertain failure.
236
+
237
+ send (attachments only) and download support --progress / --no-progress.
238
+ Default: enabled when stderr is a terminal. Progress reports bytes, percentage, and average bytes/sec
239
+ on stderr; album upload weights Telethon's per-file progress by local file sizes.
240
+ Throttle updates to twice per second, plus completion. With --json, progress is JSONL on stderr:
241
+ event="transfer_progress", operation="upload"|"download", file, transferred_bytes, total_bytes,
242
+ percent (null for unknown/zero size), bytes_per_second. Errors have ok=false and may follow progress events.
243
+ Stdout remains the final JSON result. Progress is not proof of delivery; cached transfers may emit no events.
244
+
149
245
  ## Common workflows
150
246
 
151
247
  `skills install` defaults to --agent auto: detect installed agents and copy the bundled skill only for those agents.
248
+ Default destinations are the official personal skill locations, independent of the current directory:
249
+ Codex: ~/.agents/skills/telegram-cli/SKILL.md; Claude Code: ~/.claude/skills/telegram-cli/SKILL.md.
250
+ See [OpenAI](https://learn.chatgpt.com/docs/build-skills#where-codex-loads-local-skills) and
251
+ [Anthropic](https://code.claude.com/docs/en/skills#where-skills-live).
152
252
  Detection checks PATH, native ~/.local/bin executables, standard npm/binary locations, Codex.app on macOS,
153
253
  and the OpenAI.Codex Windows Store installation. Configuration folders alone are not installation evidence.
154
254
  If neither agent is found, it creates nothing. Explicit --agent codex|claude|all bypasses detection for custom installations.
@@ -195,7 +295,9 @@ The user enters login code and 2FA password in their terminal; agent sessions mu
195
295
  Account commands fail when unauthorized rather than automatically prompting for login.
196
296
 
197
297
  Read only chats needed for the user's request; do not store private conversations in project files.
198
- Send only on the user's direct instruction with a known recipient and text.
298
+ Send, forward, or edit only on the user's direct instruction with a known recipient, message ID where needed,
299
+ and text or attachment. Development requests do not authorize live sends or edits.
300
+ Download only requested attachments into the requested local location; never execute downloaded files.
199
301
  An unambiguous prior instruction needs no extra confirmation. A development/test request does not authorize sending, even to `me`.
200
302
  Clarify ambiguous recipients before sending. Use correct shell quoting to pass text as one argument;
201
303
  never interpolate untrusted messages as executable shell code. JSON.stringify is not shell escaping.
@@ -219,8 +321,12 @@ Telethon may perform internal retries; the CLI has no custom send retry loop.
219
321
  Preserve credential validation, authorization checks, unambiguous chat resolution,
220
322
  terminal sanitization, literal outgoing text by default, disconnect in finally, and FloodWait handling.
221
323
  Update affected tests, both READMEs, and all three copies of this SKILL.md when changing commands.
324
+ Record every notable change in CHANGELOG.md under Unreleased; version the entries when releasing.
222
325
  Tests cover help without credentials, JSON/JSONL, search/pagination arguments, replies, stdin/files,
223
326
  doctor, login/logout, watch polling/cursors and cancellation, formatting selection, disconnects
224
- and handled errors including FloodWait and SQLite locks.
327
+ and handled errors including FloodWait and SQLite locks. They also cover send/download/edit JSON,
328
+ read by ID, reply/album context, media filters, ordered multi-file sends, albums, edits,
329
+ partial failures, destination collisions, safe filenames, structured usage/runtime errors,
330
+ bounded filename search, surrounding context, forwarding, and transfer progress.
225
331
  They do not verify real login,
226
332
  network watching, or message delivery. State those limits when reporting validation.
@@ -0,0 +1,64 @@
1
+ # Changelog
2
+
3
+ All notable project changes are recorded here. New changes go under `Unreleased`;
4
+ move them into a versioned section when publishing a release.
5
+
6
+ ## Unreleased
7
+
8
+ No unreleased changes.
9
+
10
+ ## 0.2.0 - 2026-10-18
11
+
12
+ ### Added
13
+
14
+ - Bounded, case-insensitive filename glob search with `read --filename` and `--scan-limit`.
15
+ - Conversation context with `read --around ID --context N`, using history order even when IDs have gaps.
16
+ - Native forwarding of messages and attachments with `forward FROM_CHAT ID TO_CHAT`, including JSON results.
17
+ - Automatic terminal upload/download progress, explicit `--progress` / `--no-progress`, JSONL progress
18
+ events on stderr, byte counts, percentages, average transfer speed, and size-weighted album progress.
19
+ - Offline regression tests for filename search, context, forwarding restrictions, progress throttling,
20
+ album byte accounting, and clean JSON stdout.
21
+ - Include this changelog in source distributions and check new command help in clean wheel installations.
22
+
23
+ - Upload local photos, videos, audio, and arbitrary binary documents (including
24
+ `.exe`, `.apk`, and `.zip`) with `send --attach`; use `--as-file` to force document upload.
25
+ - Attachment captions with text formatting and reply targets; repeat `--caption`
26
+ to provide a separate caption for each attachment.
27
+ - Send multiple files individually in order, or group 2-10 compatible attachments
28
+ with `send --album`.
29
+ - Download individual attachments by message ID with `download --output` and
30
+ download entire albums with `download --album --output-dir`.
31
+ - Safe downloads: exclusive file creation, collision checks, ID-based album filenames,
32
+ safe extensions, and removal of the current partial file after failure or cancellation.
33
+ - Display attachment type, filename, MIME type, and size in `read` and `watch`;
34
+ expose dimensions, duration, and other metadata in JSON.
35
+ - Read a specific message with `read --id`; include reply and album IDs in message output.
36
+ - Filter history with `read --media photo|video|document|audio|voice|video_note|gif`,
37
+ combined with Telegram text search and pagination.
38
+ - Edit outgoing message text or attachment captions with `edit`, using positional
39
+ text, UTF-8 files, or stdin and optional Markdown/HTML formatting.
40
+ - JSON results for sending, editing, and downloading, including captions and album
41
+ IDs in downloaded-file records.
42
+ - Structured JSON errors on stderr with stable codes, FloodWait retry delays,
43
+ RPC details, and confirmed completed results after partial multi-file operations.
44
+ - Offline tests for binary uploads, metadata, JSON contracts, filters, edits,
45
+ ordered files and albums, validation, safe downloads, cancellation, and partial failures.
46
+ - This changelog and a requirement to update it alongside future changes.
47
+
48
+ ### Changed
49
+
50
+ - Explain in both READMEs that the project was created specifically to help AI agents
51
+ manage Telegram chats effectively.
52
+ - Expand English and Russian documentation and synchronize all three bundled/project
53
+ skill copies with the new commands and automation workflows.
54
+ - Clarify the existing official user-skill destinations in installer help and documentation:
55
+ `~/.agents/skills/telegram-cli/SKILL.md` for Codex and
56
+ `~/.claude/skills/telegram-cli/SKILL.md` for Claude Code.
57
+ Default installation still targets detected agents and backs up differing skills.
58
+
59
+ ### Compatibility
60
+
61
+ - `send --file` still sends UTF-8 file contents as text; `--attach` uploads binary files.
62
+ - Existing `chats`/`read` JSON arrays and `watch` JSONL retain their shapes, with
63
+ additional message fields. Human-readable output remains the default.
64
+ - Message deletion, inline media playback, and automatic retries remain unsupported.
@@ -1,4 +1,5 @@
1
1
  include README.ru.md
2
+ include CHANGELOG.md
2
3
  include RELEASING.md
3
4
  include AGENTS.md
4
5
  include CLAUDE.md