Releases: QMahyar/tele-cli
Releases · QMahyar/tele-cli
Release list
v0.12.0
0.12.0 - 2026-09-08
Full audit ship: six new capabilities, a release supply chain (SBOM + build provenance), and roughly forty fixes from the five-domain adversarial audit (kernel, commands, streams, security, release engineering). Every done capability row is contract-tested against the real CLI surface.
Added
msg export- per-chat history export:tele msg export --account A --chat X [--format txt|jsonl] [--out FILE] [--limit N] [--offset-id M] [--since T] [--until T]. One message JSON object per line (default) or a human transcript;--outfiles are created with private permissions and sensitive basenames are refused; channel rows carry an additivelinkt.me permalink (https://t.me/<user>/<id>orhttps://t.me/c/<internal>/<id>); rows carrycount/scanned/truncatedwhen writing to a file. Also routed as a serve/MCPmsg exportop (Read lane, unbounded like download).msg get --replied- with a single--id, fetches the message the target replies to via grammers'get_reply_to_message(resolves cross-chat discussion parents for channel-post comments) and embeds it as an additivereplied_toobject. Rejected for--idsbatches; absent when there is no parent. Serve/MCP:GetParams.replied.profile photos- profile photo history viaiter_profile_photos:tele profile photos [--user USER] [--limit N]. Rows carry{id, date, size, sizes[], current}(photos.getUserPhotos for users, chat-photos sweep for channels/supergroups). Serve/MCP:profile photosop.chat permissions- participant rights read-back:tele chat permissions --chat X --user U. Full admin-rights flag map (12 write-side flags), full banned-rights map (22 flags +until_dateas RFC 3339), creator rights, plusrank/can_edit/kicked_by/promoted_bywhere provided; basic groups degrade to the participant role with an explanatory note. Serve/MCP:chat permissionsop.msg send --file -- streamed stdin uploads viaupload_stream:--file-size <BYTES>(exact stdin byte count) and--file-name <NAME>required; same 2 GiB cap; cannot be combined with other--filepaths or albums;--file-size/--file-nameare rejected when no stdin upload is present.- MCP resources -
tele mcpnow advertises the MCPresourcescapability with three read-only context resources:tele://skill(the embedded SKILL.md, same bytes astele skill print),tele://profile(bound account profile as JSON), andtele://dialogs(first 100 dialogs as JSON). Available in full and--read-onlymodes; unknown URIs fail with a clean-32602listing the valid set. - Release supply chain - every release target ships an SPDX SBOM (anchore/sbom-action) and a build-provenance attestation (actions/attest-build-provenance); both actions are SHA-pinned and the token scope is limited to the build job.
docs/release.mddocumentsgh attestation verifyand corrects the manual npm-publish fallback to reproduce the CI staging (publishing from the barenpm/directory would ship a launcher that can never find a binary). - Skill versioning - the installed
SKILL.mdcompatibility line is stamped from the binary version andtele skill installwarns when an existing install predates the running binary; a contract test pins the stamp toCargo.tomlso it cannot drift again.
Fixed
Kernel and executor
- FTS5 message cache:
INSERT OR REPLACEno longer silently bypasses the sync triggers -PRAGMA recursive_triggers = ONat open, with anfts5vocab/integrity-checkregression test that fails without it. - Token bucket: idle time no longer banks credit - the refill anchor advances while the bucket is full and refills are bounded by the remaining room, so a long idle gap cannot mint an instant full refill or keep over-minting afterwards.
- Replay dedupe (
CappedMap): re-delivered updates refresh their eviction position, so a redelivered update is no longer re-emitted as new when its original entry rotates out. - Peer eviction set is bounded (1024, clear-on-full) instead of permanent and unbounded.
+phonetargets now require at least 5 digits (including country code):+1can no longer trigger a realcontacts.ImportContactsside effect; parenthesized/dotted phone spellings classify consistently betweenparse_targetandclassify_target.- Per-account fan-out:
msg download,msg export,story send, andtakeout exportrun without the 300s per-account budget (matching the documented serve lane table - the old cap killed legitimate mid-transfer work and reported exit 3), and timed-out account tasks are aborted instead of left running. - Proxy URLs: IPv6 hosts are bracket-wrapped (
socks5://[::1]:9050) instead of producing a malformed authority. --tagwarns on tagged accounts that have no session file yet instead of skipping them silently.config.tomlwrites fsync the temp file before rename (no zero-length config on crash); the missing-HOME panic prints an actionable, scrubbed message on stderr.- Session import: stale
-wal/-shmsidecars of the previous database are deleted before the rename (a hot WAL from a crashed run would be replayed onto the imported session), and the account lock now covers only the copy+probe+install window instead of the whole source read. - Cache open: directory creation and permission hardening run via
spawn_blockinginstead of blocking the async runtime.
Messaging
msg deletereports the server's real affected count (partialwhen some ids were not deleted) instead of fabricating"deleted": N.msg download --allresume no longer permanently skips the checkpoint boundary: two-bound checkpoints (last_message_id+max_seen_id), local-timezone--since/--untildate handling, and an additivetruncatedflag.msg get --idsbatch fetch (single-RPC chunks of 100, additivemissing_ids).msg search --from meuses the server-side own-messages filter.msg send --split Nchunks oversized text into sequential UTF-16-aware messages (paragraph-preferred cuts).listen --count Nand--until <ts>finite-stream exits (combined across accounts, stderr notice, exit 0).listen: the connect semaphore no longer starves accounts at--parallel 1; gap detection uses the incomingpts_count(grammers continuity rule) and gap/peer state now survives reconnects; stream task panics surface their payload; filter applicability is consistent and documented (direction/pattern filters suppress action-family rows instead of silently bypassing them).chat settings --noforwardsactually works:messages.toggleNoForwardsexists at layer 227 and is now wired (the old rejection claimed the layer lacked it).admin-log --untilrejects post-2038 timestamps instead of silently wrapping viaas i32and disabling pagination early-stop;--sinceis now counted against the limit inside collection so it can no longer hide matching events.
Chats and contacts
chat createno longer reports failure after server-side success onUpdates::Combinedresponses (the retry path duplicated chats).contact addno longer reports first-time adds as failures (min-usercontact:falseresponse is a warning).--signaturesno longer clears author profiles (writessignature_profilestoo).chat requests:--userwith--linkis rejected instead of silently ignoring the link scope.chat kick:--banno longer overrides an explicit--rights view_messagesvalue;--demoterejects--preset/--rights(they were silently discarded); empty--rightsis rejected instead of promoting nobody.- Bare invite hashes are canonicalized to full
https://t.me/+...URLs where the API expects a link (--edit/--importers), while--checkstill extracts the hash. dialog --folderpagination anchors per-page and album bundling no longer drops entries.dialog folder-createverifies the written filter afterUpdateDialogFilter(a racing creator overwriting the id now surfaces an honest error) and counts Chatlist folders when allocating ids.dialog draftsdocs pinned to the exact channel-id form (the-100Bot-API convention, matching numeric--chat).
Accounts, privacy, and security
- Login: inverted
session_existed_beforefixed (failed logins deleted good sessions) across the code and staged paths. - Staged login:
--stage resend/--stage cancel-code, 303 DC migration on sign-in/resend/cancel and change-phone flows (auto home-DC switch + one retry), 2FA accepts piped stdin like the code step, takeout start clears stale export artifacts. account deletepurges session, pending secrets, and config entry after server-side delete;--dry-runis reachable without--yes.privacy set --replace(revocation) added; merge mode rejects a user resolved on both the allow and deny sides (alias-proof: username vs numeric id of the same person).phone --confirm-codedry-run redacts the OTP code andphone_code_hash; one-time secrets on argv (--confirm-code/--phone-hash) warn about process listings like--phonedoes;--show-tokenbypasses the log scrubber so the promised login URI actually prints in quiet mode.account sessions --terminatedry-run applies the same current-session guard as the real run instead of promising a refused action.- Upload exfiltration guard blocks
.session.export/.session.tmp;export-sessionrefuses a hard link to the live session (file-identity comparison). - Callback button
data_strdecodes lossy UTF-8 (invalid bytes become U+FFFD) instead of an empty string, consistent with listen rows and the click selector. rand_seedmixes a process-wide call counter: same-tick topic creations no longer collide onrandom_id.
Streams and serving
stream.resyncnow arms on every StreamError (auto-catch-up after a broken stream) and completion guards use bounded retries, so a saturated driver cannot silently drop final envelopes (10s drain budget doc...
v0.11.3
0.11.3 - 2026-09-04
Fixed
dialog folder-create: the 12-char title cap and peer-requirement validation now also apply on the CLI path (previously only serve/MCP enforced them).
v0.11.2
0.11.2 - 2026-09-04
Fixed
dialog folder-create: titles over 12 characters are rejected offline naming the Telegram cap, instead of the server's misleadingMESSAGE_TOO_LONG.- Pinned the embedded
skill.mdasset to LF in.gitattributessoinclude_str!output matches the contract tests on Windows CRLF checkouts (pre-existing CI failure on main).
Note
- npm 0.11.1 was published from an intermediate commit and lacks only the folder-title offline validation; 0.11.2 supersedes it.
v0.11.1
0.11.1 - 2026-09-04
Fixed
cache search: hyphenated queries no longer crash with a raw SQLite error; user queries are escaped as FTS5 phrases (LIVE-TESTno longer parses as column syntax).cache sync:media_kindnow stores clean labels (document,photo, …) matchingmsg get, instead of the Rust Debug format.msg send --schedule: relative durations (90s,30m,24h,7d,2w, and+-prefixed variants) are now accepted, matchingchat invite --expire; negative durations are rejected.dialog folder-create: new--include-chat/--pin-chat/--exclude-chatflags; rule-only folders with no peers are rejected offline with a clear error instead of the server's obscureMESSAGE_TOO_LONG.- RPC errors
PREMIUM_ACCOUNT_REQUIREDandMESSAGE_TOO_LONGnow carry a short plain-language hint appended to the message;codeandnameare unchanged.
v0.11.0
0.11.0 - 2026-09-04
Added
tele dialog folders/folder-create/folder-delete/folder-reorder: list, create, delete, and reorder chat folders (dialog filters) viamessages.{getDialogFilters,updateDialogFilter,updateDialogFiltersOrder}.tele msg scheduled/scheduled-delete/scheduled-send: list scheduled messages (messages.getScheduledHistory), delete them, or send them immediately.tele cache sync/search/stats/clear: per-account local SQLite message cache ({app}/cache/{name}.cache.db) with FTS5 full-text search for offline queries.- Serve/MCP surface grows 67 → 78 routed ops (
cachegroup + 4 dialog folder ops + 3 msg scheduled ops).
Fixed
docs/getting-started.md: npm install command now matches the published@qmahyar/teleclipackage name.docs/CONTRIBUTING.md: removed the stale hardcoded test count.docs/examples.md: added MCP/Cursor setup,tele serveembedding recipe, agent skill, local cache, folders, and scheduled-message recipes.README.md: added the Changelog to the documentation table.
v0.10.0
0.10.0 - 2026-09-02
Changed
- Renamed the command from
teleclitoteleend to end: cargo builds bothteleand ateleclialias; the npm package installsteleas the primary bin withteleclikept as a deprecated alias for one transition cycle; release archives, bundled binaries, and the npm launcher now usetelenames; help text, completions, README, and docs all saytele. - App data directory renamed from
~/.config/telecli/%APPDATA%\teleclito~/.config/tele/%APPDATA%\tele.telemigrates an existing legacyteleclidata directory automatically on first run (one-time rename; aTELE_APP_DIRoverride skips migration).
v0.9.0
0.9.0 - 2026-09-02
Added
tele skillprints an embedded SKILL.md (Agent Skills spec: frontmatter, normative usage rules, 16-group command map, JSON envelope, recipes) to stdout — an agent loads it into context in one command.tele skill install [--dir PATH] [--force]writes the skill totele/SKILL.mdunder detected agent skill directories (.claude/skills,.config/opencode/skills,.cursor/skills) or a custom dir; overwrites are refused without--force; nothing detected and no--diris a usage error.- README now leads with install and quick start; new "For agents" section covering
tele skilland MCP.
Changed
- README rewritten as a concise front door (482 → 180 lines): command tables replaced by
tele --helppointers, every count verified (16 groups, 67 MCP tools, 25 raw methods, 13 build targets); stale session-report artifacts (SHIPPED.md,implementation-summary.md) removed. docs/getting-started.md: removed the falsecargo install tele-cliinstruction (the crate is not on crates.io).
v0.8.0
0.8.0 - 2026-09-02
Fixed
tele serve: omitting"account"in params while serving multiple accounts now returns aServeErrornaming the served accounts instead of silently targeting the alphabetically-first one (including mutating ops). Single-account serve keeps the implicit default.stream.resyncwith multiple accounts and no"account"now resyncs every account, matching the documented contract.- Error taxonomy survives the
ClientGuard::connectboundary: a badconfig.tomlnow exits 1 with JSON kindConfigError(was exit 3 / genericError); auth failures keep exit 4. TeleError::Timeout(e.g.msg get --watch) now exits 3 (runtime outcome) instead of 1 (usage); runtime request-state failures — message not found, no poll/media/reply markup, poll closed — now exit 3 asInvocationerrors instead of exit-1 usage errors acrossmsg get/vote/click/send copy-from/download.tele listennow honors--parallel(andparallel_max): concurrent account connections are capped by a semaphore held for each task's lifetime; previously every selected account connected concurrently.- Album event
idsno longer truncate i64 message ids pasti32::MAX(wrapping cast →try_from). - Runtime-thread panics are no longer swallowed silently: the panic message (scrubbed) is logged to stderr and the process exits 3; a clap derive-conversion failure now degrades to the standard usage-error path instead of panicking.
- Session filesystem paths are no longer embedded in user-facing
account export-session/ Telethon-import errors (full path only at--verbosedebug level). account import-sessionno longer buffers the entire source file into memory; it validates the 16-byte SQLite header, then streams through a private-mode (0600/user-DACL) temp file.- Session files (including the main SQLite auth-key file) are created with private permissions from first open; every startup sweep-tightens permissions on all files under
sessions/, covering restores from backup with wide permissions. - A missing
.envis created 0600/user-DACL on firstcredentials()call, closing the default-permissions creation race. - Sensitive-file upload blocklist hardened:
credentials.bak,vault.kdbx.bak,my.env,my.credentials.json, embeddedid_rsanames are now rejected; lookalikes such asenv.exampleandmy_envremain allowed. - Stale
.part-*download temps owned by the current process are no longer swept mid-download. - Executor outcome errors with unprintable messages log
<unprintable error>instead of an empty reason. tele topic close/reopen/delete/pinaccount-selection errors now name the actual subcommand (e.g.topic close requires --account …).- Unknown
--eventserrors list valid events plainly instead of printing a RustDebugslice. - Internal milestone codename
serve-Aremoved from help text and errors; root help drops the internal client-library name.
Changed
- Removed the
unicode-segmentationdependency (emoji validation uses the existing 4-byte single-codepoint rule). - Net −41 lines: one generic
CappedDedupe<K>replaces the byte-identical serve/listen dedupe structs; sharedtruncate_texthelper replaces copies in msg/stories; deleted dead wrappers (base64_encode,print_envelope,print_json_resultdelegation); tmp-dir hash no longer folds in the pid already present in the name. --previewonmsg sendis hidden from help (it was a no-op flag; preview is on by default,--no-previewdisables).tele completions --helpnow describes each shell variant.
v0.7.0
0.7.0 - 2026-08-31
Fixed
- Removed the
unsafestruct-layout hack in peer-cache eviction (entities.rs):purge_peerno longer reinterpret-castsSqliteSessionas a fake layout-matched struct to run SQL. Stale peer cache entries are now evicted in-memory via a process-global eviction set consulted by the cache lookups. - Replaced the hand-rolled FIPS SHA-256 in
session.rswith thesha2crate (Sha256::digest), removing ~70 lines of hand-written compression code while keeping the same checksum output. - Destructive commands now require an explicit account selection:
msg delete,chat kick,chat leave, anddialog deleterefuse to run against all sessions implicitly and error withrequires --account <name> or --tag <tag>unless--account/--tagis given. - Collapsed the four duplicated usage-error JSON-envelope blocks in
main.rsinto oneemit_usage_error(machine, dry_run, command, message)helper. - Replaced 14 duplicated
match emit_row(...)broken-pipe-handling blocks inlisten.rswith anemit_row_or_stophelper plus a pureemit_stops_streamdecision function.
v0.6.8
0.6.8 - 2026-08-28
Fixed
- Flaky session tests on CI: replaced
tokio::sync::Mutexwithstd::sync::MutexforTEST_ENV_LOCKto eliminate race conditions between parallel test threads mutatingTELE_APP_DIRenv var. The sync mutex properly blocks the calling OS thread. Poisoned-mutex recovery ensures cascading panics don't break subsequent tests.