diff --git a/CHANGELOG.md b/CHANGELOG.md index 77889f3..70106e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,14 +7,28 @@ Notable changes to `@leemour/tg-cli`. One section per version, newest first; ver ### What's new +- **The bundled agent instructions explain how to find agreements, prepare meetings and recommend contacts.** + Agents check archive coverage, compare group and personal chats, distinguish people with the same name, + and retain a draft when sending is refused. + - **`tg messages link` and read-only MCP `tg_messages_link` return a message permalink and locator.** Channels and supergroups preserve thread context; private links require access and grant no membership. Dialogs, basic groups and Saved Messages return a locator. Offline validates the stored message without connecting; locators for another account are refused. Singular `link` differs from conversation-graph `links`. +### Changed — may break scripts + +- **`tg commands [path...] --json` can describe one command or group.** For example, + `tg commands messages search --json` includes global options and exit codes alongside that command. + Without a path the full tree is unchanged; scoped responses add `scope` and `inheritedOptions`. + Inspect different command paths in separate calls. + ### Fixed +- Commands opening the local archive together wait briefly for initialization instead of failing + immediately when another process holds its write lock. Persistent locks still fail normally. + - Voice transcription downloads use the history connection and close it before local recognition, avoiding a second connection for `messages list --transcribe`, `inbox` and `review`. diff --git a/README.md b/README.md index b8dc80d..58cc602 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ tg bot list --check # every bot on this computer - **Messages and chats.** Send, edit, delete and pin, to a chat by id or by title, or to a person as `user:`; `--md`, `--html`, a file or a photo. `bot store fetch` imports older channel and supergroup messages; `messages list` reads what this bot sent, received or imported on this computer. + History import uses a separate MTProto session; private chats and basic groups are unsupported. - **Admins, members, buttons, the menu, webhooks.** `bot chats admins`, `bot chats members remove`, `bot callbacks answer`, `bot commands`, `bot webhooks` — the same commands `max bot` has. - **`bot watch`** prints what happens in the bot's chats as it arrives, and keeps it: that is the diff --git a/docs/commands.md b/docs/commands.md index 9b48a93..da57b9e 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -1907,12 +1907,16 @@ tg doctor report create [options] ## `tg commands` -every command, option and exit code as JSON — what an agent reads instead of --help +commands, options and exit codes as JSON — inspect one command path per call ```sh -tg commands +tg commands [path] ``` +| Argument | | What it is | +|---|---|---| +| `path` | optional | one command path, for example: messages search; inspect other groups in separate calls. | + ## `tg complete` shell completion: `tg complete zsh` prints the script to source diff --git a/docs/mcp.md b/docs/mcp.md index 7667519..f4e391c 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -196,13 +196,14 @@ no fields, only the one button. The client's own window shows the arguments as t | `tg_messages_photo` | `tg messages download` | a message's photo as an image to look at, up to 512 KB; anything else is refused with the `tg messages download` command that saves it | | `tg_messages_transcribe` | `tg messages transcribe` | a voice message as text — by Telegram (Premium or the weekly trial), else by a speech model on this machine; `local: true` skips Telegram; `pending: true` means Telegram was not finished within a minute; a missing model is refused with `tg models audio download`, never downloaded | | `tg_messages_search` | `tg messages search` | search what this machine has kept; never asks Telegram | -| `tg_messages_send` | `tg messages send`, `--reply-to`, `--topic` | send, by `messages.send`; `reply_to` answers a message; `send_id` repeats a send whose outcome was unknown; `silent`, `no_preview` and `md` as `--silent`, `--no-preview` and `--md`; `topic` picks a forum topic; `at_time` sends it later — never retried, the confirmation form shows the clock time; `file` or `photo` attaches a path from this machine, the text as the caption (`as_file` keeps a video a file), `voice` sends an Ogg Opus file as a voice message — hidden files, `~/.ssh`, tg's own folders and the message store are refused, with no way around it over MCP | +| `tg_messages_link` | `tg messages link` | a permalink where supported and an account-scoped locator; read-only; a link grants no chat membership | +| `tg_messages_send` | `tg messages send`, `--reply-to`, `--topic` | send, by `messages.send`; `reply_to` answers a message and must belong to the chosen topic; `send_id` repeats a send whose outcome was unknown in the same chat and topic; `silent`, `no_preview` and `md` as `--silent`, `--no-preview` and `--md`; `topic` picks a forum topic; `at_time` sends it later — never retried, the confirmation form shows the clock time; `file` or `photo` attaches a path from this machine, the text as the caption (`as_file` keeps a video a file), `voice` sends an Ogg Opus file as a voice message — hidden files, `~/.ssh`, tg's own folders and the message store are refused, with no way around it over MCP | | `tg_messages_edit` | `tg messages edit` | the new text of the owner's own message, by `messages.edit`; `md` as `--md`; repeating it changes nothing | | `tg_chats_mark_read` | `tg chats mark-read` | mark a chat read, to its newest message or `until` one, by `chats.mark-read` — the other side sees it | | `tg_messages_delete` | `tg messages delete` | up to 10 messages from the owner's view, by `messages.delete` — a form first by default; never for everyone; each counts toward the hourly limit | | `tg_reactions_add`, `tg_reactions_remove` | `tg reactions add`, `remove` | the owner's reaction on one message, by `reactions`; the confirmation form shows the emoji | | `tg_polls_show` | `tg polls show` | a poll and its answer ids; a read tool | -| `tg_polls_vote`, `tg_polls_close`, `tg_polls_create` | `tg polls vote`, `close`, `create` | vote by answer id (`polls.vote`), close the owner's own poll (`polls.close`), create one (`polls.create`, with `send_id` for a retry and `revote` to let people change their vote, and `topic` to choose a forum topic) | +| `tg_polls_vote`, `tg_polls_close`, `tg_polls_create` | `tg polls vote`, `close`, `create` | vote by answer id (`polls.vote`), close the owner's own poll (`polls.close`), create one (`polls.create`, with `send_id` for a retry in the same chat and topic, `revote` to let people change their vote, and `topic` to choose an open forum topic) | | `tg_messages_forward` | `tg messages forward` | one message into another chat (`to`), by `messages.forward`; `send_id` repeats a forward whose outcome was unknown | | `tg_messages_pin`, `tg_messages_unpin` | `tg messages pin`, `unpin` | pin one message, quietly unless `notify`, by `messages.pin` and `messages.unpin` | | `tg_chats_create`, `tg_chats_join`, `tg_chats_leave` | `tg chats create`, `join`, `leave` | make a group or channel with these people, join one by its link, leave one — the others see each | diff --git a/docs/usage.md b/docs/usage.md index f46144a..8321672 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -24,6 +24,10 @@ before `tg store fetch --last 100`. An agent can read `tg skill show` wit use `tg setup --agent codex` to select its skill explicitly. `tg setup --help` explains the flags. Nothing more is needed to read. +To discover the arguments for a task, use `tg commands messages search --json` for one command +or `tg commands messages --json` for a group. Both include global options and exit codes. +Inspect each command path in a separate call; `tg commands --json` returns the whole tree. + ## Log in `tg setup` is the first-run command. It defaults to automatic app registration and QR login; @@ -211,8 +215,9 @@ tg models audio download parakeet-v3 # once, checked against the sha256 this v | `gigaam-v3-ctc` | Russian — a little faster, rougher with capital letters | 225 MB | `--model` picks another model for one command, beside `--transcribe` or in `messages transcribe`; `transcribeWith` and `speechModel` in the settings -choose the defaults ([configuration.md](configuration.md)). A transcript is kept in the local store, -so asking again answers at once. `--transcribe` can take minutes. +choose the defaults ([configuration.md](configuration.md)). A transcript is kept in the local store +and reused by message lists, inboxes and reviews. Calling `messages transcribe` again can request +a new transcript or run recognition again. `--transcribe` can take minutes. ### Files diff --git a/package.json b/package.json index 6e700e3..b07992f 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ }, "dependencies": { "@leemour/cli-core": "0.17.0", - "@leemour/cli-messaging": "0.139.0", + "@leemour/cli-messaging": "0.140.0", "@mtcute/node": "0.32.3", "commander": "15.0.0", "valibot": "1.5.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 016b37f..2a2b31e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,8 +12,8 @@ importers: specifier: 0.17.0 version: 0.17.0(commander@15.0.0)(typescript@7.0.2) '@leemour/cli-messaging': - specifier: 0.139.0 - version: 0.139.0(@leemour/cli-core@0.17.0(commander@15.0.0)(typescript@7.0.2))(commander@15.0.0)(typescript@7.0.2) + specifier: 0.140.0 + version: 0.140.0(@leemour/cli-core@0.17.0(commander@15.0.0)(typescript@7.0.2))(commander@15.0.0)(typescript@7.0.2) '@mtcute/node': specifier: 0.32.3 version: 0.32.3 @@ -443,8 +443,8 @@ packages: '@leemour/cli-messaging-sqlite@1.0.0': resolution: {integrity: sha512-NFJMG+/2BWIb3JdOMgyV8SFsB7Fuv3wLtUmMt08GZ4KTpgu0WuA7qQmQE6appEgJJuF/97vHj6+AuXw2z3HMHw==} - '@leemour/cli-messaging@0.139.0': - resolution: {integrity: sha512-v+16FOS85sJpdWYpZU73+u5kssC6vJqbIZ0LTJBQ5lMScEGyPSi7IjNtBwLeU1T2pJTLp9jEpXVoU5iB5GOnBg==} + '@leemour/cli-messaging@0.140.0': + resolution: {integrity: sha512-zruYLqNVoN2YmyOmvbFqCd/YMloaRf/1JLmVZv2QrLBxlvorPaEks6mq7vYm/M9cEhAyn9aoTkAj8+mEZl6hvA==} engines: {node: ^22.16.0 || >=24} hasBin: true peerDependencies: @@ -1981,7 +1981,7 @@ snapshots: '@leemour/cli-messaging-sqlite@1.0.0': {} - '@leemour/cli-messaging@0.139.0(@leemour/cli-core@0.17.0(commander@15.0.0)(typescript@7.0.2))(commander@15.0.0)(typescript@7.0.2)': + '@leemour/cli-messaging@0.140.0(@leemour/cli-core@0.17.0(commander@15.0.0)(typescript@7.0.2))(commander@15.0.0)(typescript@7.0.2)': dependencies: '@bomb.sh/tab': 0.0.22(commander@15.0.0) '@huggingface/tokenizers': 0.2.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 78a298b..2c37fef 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -7,6 +7,6 @@ allowBuilds: lefthook: true minimumReleaseAgeExclude: - '@leemour/cli-core@0.7.0 || 0.9.0 || 0.12.0 || 0.14.0 || 0.15.0 || 0.16.0 || 0.17.0' - - '@leemour/cli-messaging@0.1.0 || 0.2.0 || 0.3.0 || 0.4.0 || 0.5.0 || 0.6.0 || 0.7.0 || 0.8.0 || 0.9.0 || 0.11.0 || 0.12.0 || 0.14.0 || 0.15.0 || 0.16.0 || 0.17.0 || 0.18.0 || 0.19.0 || 0.20.0 || 0.21.0 || 0.22.0 || 0.23.0 || 0.24.0 || 0.25.0 || 0.27.0 || 0.29.0 || 0.30.0 || 0.31.0 || 0.34.0 || 0.35.0 || 0.37.0 || 0.38.0 || 0.39.0 || 0.40.0 || 0.41.0 || 0.42.0 || 0.43.0 || 0.44.0 || 0.45.0 || 0.46.0 || 0.47.0 || 0.48.0 || 0.49.0 || 0.50.0 || 0.51.0 || 0.52.0 || 0.53.0 || 0.54.0 || 0.57.0 || 0.61.0 || 0.67.0 || 0.70.0 || 0.73.0 || 0.74.0 || 0.75.0 || 0.76.0 || 0.77.0 || 0.78.0 || 0.80.0 || 0.81.0 || 0.82.0 || 0.83.0 || 0.84.0 || 0.85.0 || 0.87.0 || 0.88.0 || 0.89.0 || 0.90.0 || 0.91.0 || 0.92.0 || 0.93.0 || 0.94.0 || 0.95.0 || 0.96.0 || 0.97.0 || 0.98.0 || 0.99.0 || 0.103.0 || 0.104.0 || 0.106.0 || 0.108.0 || 0.109.0 || 0.111.0 || 0.112.0 || 0.113.0 || 0.119.0 || 0.120.0 || 0.121.0 || 0.123.0 || 0.125.0 || 0.126.0 || 0.127.0 || 0.129.0 || 0.132.0 || 0.134.0 || 0.135.0 || 0.136.0 || 0.137.0 || 0.139.0' + - '@leemour/cli-messaging@0.1.0 || 0.2.0 || 0.3.0 || 0.4.0 || 0.5.0 || 0.6.0 || 0.7.0 || 0.8.0 || 0.9.0 || 0.11.0 || 0.12.0 || 0.14.0 || 0.15.0 || 0.16.0 || 0.17.0 || 0.18.0 || 0.19.0 || 0.20.0 || 0.21.0 || 0.22.0 || 0.23.0 || 0.24.0 || 0.25.0 || 0.27.0 || 0.29.0 || 0.30.0 || 0.31.0 || 0.34.0 || 0.35.0 || 0.37.0 || 0.38.0 || 0.39.0 || 0.40.0 || 0.41.0 || 0.42.0 || 0.43.0 || 0.44.0 || 0.45.0 || 0.46.0 || 0.47.0 || 0.48.0 || 0.49.0 || 0.50.0 || 0.51.0 || 0.52.0 || 0.53.0 || 0.54.0 || 0.57.0 || 0.61.0 || 0.67.0 || 0.70.0 || 0.73.0 || 0.74.0 || 0.75.0 || 0.76.0 || 0.77.0 || 0.78.0 || 0.80.0 || 0.81.0 || 0.82.0 || 0.83.0 || 0.84.0 || 0.85.0 || 0.87.0 || 0.88.0 || 0.89.0 || 0.90.0 || 0.91.0 || 0.92.0 || 0.93.0 || 0.94.0 || 0.95.0 || 0.96.0 || 0.97.0 || 0.98.0 || 0.99.0 || 0.103.0 || 0.104.0 || 0.106.0 || 0.108.0 || 0.109.0 || 0.111.0 || 0.112.0 || 0.113.0 || 0.119.0 || 0.120.0 || 0.121.0 || 0.123.0 || 0.125.0 || 0.126.0 || 0.127.0 || 0.129.0 || 0.132.0 || 0.134.0 || 0.135.0 || 0.136.0 || 0.137.0 || 0.139.0 || 0.140.0' - '@leemour/cli-messaging-sqlite@1.0.0' - '@leemour/cli-messaging-onnx@1.0.0' diff --git a/skills/tg-cli/SKILL.md b/skills/tg-cli/SKILL.md index 7d8c251..a24c247 100644 --- a/skills/tg-cli/SKILL.md +++ b/skills/tg-cli/SKILL.md @@ -8,10 +8,13 @@ description: Set up Telegram and read or send messages in the owner's personal a `tg` works with the owner's **real personal account**. A mistake here does not fail a test; it writes to a living person. One call, one action: connect, do it, print, exit. -The full list of commands and flags is **`tg commands --json`**: the whole tree in one answer — -arguments, flags (whether each takes a value, whether it is required), exit codes, and `mutates: -true` on the commands that change something in Telegram. `tg --help` is the same for a person. This -file holds what the help cannot say: the traps and the boundaries. +Read this skill, then discover only the commands relevant to the task. **`tg commands messages +search --json`** describes one command; **`tg commands messages --json`** describes that group. +Both include arguments, options, global options and exit codes. Use `tg --help` for a +shorter explanation. Command words form one path, not a list of groups: inspect different groups +in separate calls. **`tg commands --json`** returns the entire tree when you need an overview; +do not read it in full before every task. `mutates: true` identifies writes; `local: true` limits +those writes to this machine. This file holds the traps and boundaries. ## Installation readiness @@ -161,6 +164,25 @@ summary; news digests remain separate future work. Permission: `messages.evidenc ## The usual path +Choose a path from the user's task rather than reading recent messages by default: + +- **Find an agreement or document:** find the relevant chat IDs, then search the local archive. + Inspect search coverage and `store status`; `messages list` alone is only a recent window. + Follow promising hits with `messages context` or `messages show` and cite their locators. + Check related chats for a later correction. Empty hits, an empty chat and `hasMore: false` + never establish complete Telegram history. If missing history matters, explain the gap. + Fetch only an authorized chat and bounded period/amount; inspect `store fetch --estimate` + before a download. Offline cannot fetch missing history. +- **Prepare for a meeting:** find project groups and the participants' personal chats. A DM's + title need not contain the project name. Compare dated group messages with relevant DMs; + a later confirmation can close an old blocker. Use `messages evidence` for a brief, inspect + coverage and follow its cursor. Distinguish decisions, open questions and inferred dates. +- **Recommend a person:** compare actual evidence of relevant experience across chats. Match + message sender IDs to `contacts show` and relevant personal chats; two identical display + names are not one person. Past availability is not current availability. Prepare a draft + unless the owner explicitly asks to send it to the identified recipient. If sending is + refused by permissions, stop and keep the draft; do not change settings or switch profiles. + The ids below are made up — use the real ones from the previous answer. ```sh