From 4fb1d96da3eaf5a8fe971c97b7ea34db068e1498 Mon Sep 17 00:00:00 2001 From: luozhixiong Date: Tue, 16 Jun 2026 15:22:33 +0800 Subject: [PATCH] docs(lark-im): reconcile slimmed skill and thinned references with main Rebased onto main v1.0.54, which added IM content after this branch forked. Fold main's new facts into the slimmed/gotcha-only form and fix drift: - SKILL.md: compact the newly-merged chat.user_setting / chat.managers / chat.moderation API resources to the api_compact `action`(identity) form (consistent with the rest; regen-equivalent), and note the opt-in `--download-resources` flag on the three message-pulling shortcuts. - chat-search: fix stale `--sort-by` -> `--sort`, add `--chat-modes`, and fold the "`--sort` is always descending" caution (#1302/#1317). - chat-messages-list: note `--order` is the only sort axis (no field sort). - messages-send: split @mention by message type; interactive cards are not normalized and need card-native `` syntax (#1419). - flag-cancel: document best-effort double-cancel (feed layer skipped with a stderr warning when chat type is undeterminable). - feed-group-list-item / query-item: p2p cards omit chat_name; resolve via chats/batch_query -> p2p_target_id -> contact lookup. - message-enrichment: add the `--download-resources` contract (merge_forward container-id 234003 trap, fail-silent isolation, no extra scope) (#1245). Docs only; no Go/--help/Desc changes. --- skill-template/domains/im.md | 2 +- skills/lark-im/SKILL.md | 11 ++++------- .../lark-im/references/lark-im-chat-messages-list.md | 2 +- skills/lark-im/references/lark-im-chat-search.md | 3 ++- .../references/lark-im-feed-group-list-item.md | 2 +- .../references/lark-im-feed-group-query-item.md | 2 +- skills/lark-im/references/lark-im-flag-cancel.md | 2 +- .../lark-im/references/lark-im-message-enrichment.md | 9 +++++++++ skills/lark-im/references/lark-im-messages-send.md | 9 ++++++--- 9 files changed, 26 insertions(+), 16 deletions(-) diff --git a/skill-template/domains/im.md b/skill-template/domains/im.md index afd05511..2862d076 100644 --- a/skill-template/domains/im.md +++ b/skill-template/domains/im.md @@ -24,7 +24,7 @@ lark-cli im +chat-messages-list --chat-id oc_xxx --as user # GOOD: sender = rea ### Default message enrichment -The four message-pulling shortcuts auto-attach `reactions` (+ `update_time` for edited messages) — no separate `reactions.batch_query` (needs `im:message.reactions:read`); `--no-reactions` opts out. Contract: [`references/lark-im-message-enrichment.md`](references/lark-im-message-enrichment.md). +The four message-pulling shortcuts auto-attach `reactions` (+ `update_time` for edited messages) — no separate `reactions.batch_query` (needs `im:message.reactions:read`); `--no-reactions` opts out. `+chat-messages-list` / `+messages-mget` / `+threads-messages-list` also accept `--download-resources` (opt-in, off by default) to fetch message binaries into `./lark-im-resources/`. Contract: [`references/lark-im-message-enrichment.md`](references/lark-im-message-enrichment.md). ### Flag Types diff --git a/skills/lark-im/SKILL.md b/skills/lark-im/SKILL.md index 64a9b4c8..f69f8770 100644 --- a/skills/lark-im/SKILL.md +++ b/skills/lark-im/SKILL.md @@ -65,7 +65,7 @@ lark-cli im +chat-messages-list --chat-id oc_xxx --as user # GOOD: sender = rea ### Default message enrichment -The four message-pulling shortcuts auto-attach `reactions` (+ `update_time` for edited messages) — no separate `reactions.batch_query` (needs `im:message.reactions:read`); `--no-reactions` opts out. Contract: [`references/lark-im-message-enrichment.md`](references/lark-im-message-enrichment.md). +The four message-pulling shortcuts auto-attach `reactions` (+ `update_time` for edited messages) — no separate `reactions.batch_query` (needs `im:message.reactions:read`); `--no-reactions` opts out. `+chat-messages-list` / `+messages-mget` / `+threads-messages-list` also accept `--download-resources` (opt-in, off by default) to fetch message binaries into `./lark-im-resources/`. Contract: [`references/lark-im-message-enrichment.md`](references/lark-im-message-enrichment.md). ### Flag Types @@ -103,18 +103,15 @@ lark-cli im [flags] # 调用 API ### chat.user_setting - - `batch_query` — 批量查询当前用户在群内的个人偏好设置 (e.g. `is_muted` mutes normal messages, `is_mute_at_all` mutes @all messages); up to 10 chats per request. Identity: `user` only (`user_access_token`); the caller must be in each target chat. - - `batch_update` — 批量更新当前用户在群内的个人偏好设置 (e.g. `is_muted` mutes normal messages, `is_mute_at_all` mutes @all messages); up to 10 chats per request. Identity: `user` only (`user_access_token`); the caller must be in each target chat. +`batch_query`(user) · `batch_update`(user) ### chat.managers - - `add_managers` — 指定群管理员。Identity: supports `user` and `bot`; only the group owner can add managers; max 10 managers per chat (20 for super-large chats), and at most 5 bots per request. - - `delete_managers` — 删除群管理员。Identity: supports `user` and `bot`; only the group owner can remove managers; max 50 users or 5 bots per request. +`add_managers`(user/bot) · `delete_managers`(user/bot) ### chat.moderation - - `get` — 获取群成员发言权限。Identity: supports `user` and `bot`; the caller must be in the target chat and belong to the same tenant. - - `update` — 更新群发言权限。Identity: supports `user` and `bot`; only the group owner (or creator bot with `im:chat:operate_as_owner`) can update; the caller must be in the chat. +`get`(user/bot) · `update`(user/bot) ### messages diff --git a/skills/lark-im/references/lark-im-chat-messages-list.md b/skills/lark-im/references/lark-im-chat-messages-list.md index 7dbe68fd..738b8d62 100644 --- a/skills/lark-im/references/lark-im-chat-messages-list.md +++ b/skills/lark-im/references/lark-im-chat-messages-list.md @@ -11,7 +11,7 @@ Supports both `--as user` (default) and `--as bot`. Auto-resolves the p2p `chat_ - **`--user-id` (DM by open_id) is user-identity only — and the constraint is silent until you hit it.** The p2p-resolution endpoint requires user identity; with `--as bot` it errors. For bot identity, look up the p2p `chat_id` yourself and pass `--chat-id`. - **`P2P chat not found for this user`** means no DM exists *for the current identity* with that user — not a bad ID. Confirm the DM relationship under the identity you're calling as. - **Resolve a chat name → `chat_id` via [`+chat-search`](lark-im-chat-search.md) first**, then pass `--chat-id`. **Do NOT use `im chats search` or `+chat-list`** — those are not search APIs and won't locate the target. -- **`--order` defaults to `desc`** (newest first); pass `--order asc` for chronological reading. (Note: the flag is `--order`, not `--sort`.) +- **`--order` defaults to `desc`** (newest first); pass `--order asc` for chronological reading. (Note: the flag is `--order`, not `--sort`.) It is the **only** sort axis — messages are always ordered by creation time. There is no field sort: `--sort sender` (or any field) is rejected. If asked to group/sort by sender, fetch with `--order` and aggregate client-side, and say so (local post-processing, not a CLI/API sort). - **Image content is a placeholder, not bytes**: images render as `[Image: img_xxx]`; files/audio/video carry resource keys. Nothing downloads unless you pass `--download-resources` (writes to `./lark-im-resources/`) or use [`im +messages-resources-download`](lark-im-messages-resources-download.md). ## Thread expansion (`thread_id`) diff --git a/skills/lark-im/references/lark-im-chat-search.md b/skills/lark-im/references/lark-im-chat-search.md index f3882f44..a13936e3 100644 --- a/skills/lark-im/references/lark-im-chat-search.md +++ b/skills/lark-im/references/lark-im-chat-search.md @@ -2,7 +2,7 @@ > **Prerequisite:** Read [`../lark-shared/SKILL.md`](../../lark-shared/SKILL.md) first for authentication, global parameters, and safety rules. -Maps to `lark-cli im +chat-search`. **Run `lark-cli im +chat-search --help` for the authoritative flag list (`--query` / `--member-ids` / `--search-types` / `--sort-by` / `--page-size` / `--page-token` / `--is-manager` / `--exclude-muted` / `--disable-search-by-user`), limits, and enums.** This file covers only what `--help` cannot. +Maps to `lark-cli im +chat-search`. **Run `lark-cli im +chat-search --help` for the authoritative flag list (`--query` / `--member-ids` / `--search-types` / `--chat-modes` / `--sort` / `--page-size` / `--page-token` / `--is-manager` / `--exclude-muted` / `--disable-search-by-user`), limits, and enums.** This file covers only what `--help` cannot. ## Gotchas @@ -11,6 +11,7 @@ Maps to `lark-cli im +chat-search`. **Run `lark-cli im +chat-search --help` for - `--query` containing `-` is auto-wrapped in quotes. - **On empty results, do NOT fall back to `+chat-list` / `GET /chats`** — list is not a search API (returns all chats unfiltered, won't locate the target). Refine the keyword or check visibility under the current identity instead. - Supports `--as user` (default) and `--as bot` (bot needs bot capability enabled). +- **`--sort` is always descending** (`create_time` / `update_time` / `member_count`, high→low). There is no ascending option. If the user asks for "fewest first / ascending / 从少到多", tell them the search API doesn't support ascending and re-sort the fetched page client-side — do **NOT** invent `member_count_asc` or pass `asc` (rejected). ## `--exclude-muted` (user identity only) diff --git a/skills/lark-im/references/lark-im-feed-group-list-item.md b/skills/lark-im/references/lark-im-feed-group-list-item.md index 1d288c62..80c899ed 100644 --- a/skills/lark-im/references/lark-im-feed-group-list-item.md +++ b/skills/lark-im/references/lark-im-feed-group-list-item.md @@ -9,7 +9,7 @@ Maps to `lark-cli im +feed-group-list-item`. **Run `lark-cli im +feed-group-list ## Gotchas - **`chat_name` enrichment is unconditional → needs a second scope.** A v1 feed card's `feed_id` is always a chat ID (`oc_xxx`), so the shortcut always issues a follow-up `chats/batch_query` and injects `chat_name` into each entry of **both** `items[]` and `deleted_items[]`. There is no single-scope, un-enriched path — so this needs `im:chat:read` **in addition to** `im:feed_group_v1:read` (vs. `+feed-group-list`, which needs only the read scope). -- **Unresolvable cards silently omit `chat_name`** — a soft-deleted chat or one you can't see just lacks the field; the command still exits 0. Do not treat a missing `chat_name` as an error. +- **Unresolvable cards silently omit `chat_name`** — a soft-deleted chat or one you can't see just lacks the field; the command still exits 0. Do not treat a missing `chat_name` as an error. **p2p (direct) cards also omit it** (the server returns an empty `name`; clients show the partner's display name instead) — if you need a label, fetch the chat via `chats/batch_query`, read `p2p_target_id`, and resolve it with a contact lookup. - **Dual-list response.** Like `+feed-group-list`, results split into `items[]` (live) and `deleted_items[]` (soft-deleted); `--page-all` merges both. Incremental-sync consumers must read both. - **`--page-token` wins over `--page-all`** when both are set — you get exactly that one page. diff --git a/skills/lark-im/references/lark-im-feed-group-query-item.md b/skills/lark-im/references/lark-im-feed-group-query-item.md index 3b29ca03..49285923 100644 --- a/skills/lark-im/references/lark-im-feed-group-query-item.md +++ b/skills/lark-im/references/lark-im-feed-group-query-item.md @@ -10,7 +10,7 @@ Maps to `lark-cli im +feed-group-query-item`. **Run `lark-cli im +feed-group-que - **Lightweight ID lookup — prefer it over the list methods when you already hold the IDs.** Use this when you have the `feed_id`s (the `oc_xxx` you passed to `batch_add_item`); reserve `+feed-group-list-item` (paginated, heavier) for discovering IDs you don't have. **No pagination** for this method. - **`chat_name` enrichment is unconditional → needs a second scope.** Resolves `chat_name` for each card exactly as `+feed-group-list-item` does (follow-up `chats/batch_query`, injected into both `items[]` and `deleted_items[]`). So this needs `im:chat:read` **in addition to** `im:feed_group_v1:read`; there is no un-enriched path. -- **Unresolvable cards silently omit `chat_name`** — soft-deleted or no-permission chats just lack the field; the command still exits 0. +- **Unresolvable cards silently omit `chat_name`** — soft-deleted or no-permission chats just lack the field; the command still exits 0. **p2p (direct) cards also omit it** (server returns an empty `name`); to label one, fetch the chat via `chats/batch_query`, read `p2p_target_id`, and resolve it with a contact lookup. ## HELP-GAP — not yet in `--help`/schema; keep until CLI adds it diff --git a/skills/lark-im/references/lark-im-flag-cancel.md b/skills/lark-im/references/lark-im-flag-cancel.md index f7765f75..68a3cd52 100644 --- a/skills/lark-im/references/lark-im-flag-cancel.md +++ b/skills/lark-im/references/lark-im-flag-cancel.md @@ -7,7 +7,7 @@ Maps to `lark-cli im +flag-cancel`. **Run `lark-cli im +flag-cancel --help` for ## Gotchas - **Default is double-cancel (both layers)**: omitting `--flag-type` best-effort cancels both the message-layer flag `(default, message)` and the feed-layer flag `(thread, feed)` or `(msg_thread, feed)`. The server treats cancel of a non-existent flag idempotently — no error — so double-cancel is safe even when only one layer has a flag. -- **Feed-layer `item_type` is determined by `chat_mode`**: `topic` chat → `item_type=thread`; regular `group` chat → `item_type=msg_thread`. The double-cancel path auto-detects this (requires `im:chat:read`). When calling single-layer feed cancel with `--flag-type feed`, you must supply `--item-type` explicitly. +- **Feed-layer `item_type` is determined by `chat_mode`**: `topic` chat → `item_type=thread`; regular `group` chat → `item_type=msg_thread`. The double-cancel path auto-detects this (requires `im:chat:read`). **Best-effort, not all-or-nothing**: the message layer is always removed; the feed layer is removed only when the chat type can be determined — otherwise a warning is printed on stderr and the feed layer is silently skipped (the command still exits 0). When calling single-layer feed cancel with `--flag-type feed`, you must supply `--item-type` explicitly. - **Idempotent**: repeated cancel calls on an already-unflagged message succeed silently. - **Do NOT call `+flag-list` for verification**: a success response means the flag was removed. Paginating `+flag-list` to confirm is expensive and unnecessary. - **Finding a message ID**: use `+messages-search --query ""` to locate the message and extract `message_id`. Do NOT use `+flag-list` — it requires full pagination and won't reliably locate the message. diff --git a/skills/lark-im/references/lark-im-message-enrichment.md b/skills/lark-im/references/lark-im-message-enrichment.md index 37678a5d..409fb57f 100644 --- a/skills/lark-im/references/lark-im-message-enrichment.md +++ b/skills/lark-im/references/lark-im-message-enrichment.md @@ -13,6 +13,15 @@ Cross-cutting behavior shared by the message-pulling shortcuts. `--help` documen - **Requires `im:message.reactions:read`.** Declared in each shortcut's scopes, so the pre-flight surfaces `missing_scope` before sending. Bots registered before this scope existed need an incremental authorization in the developer console (a user re-login picking up the scope is enough for user identity). - **High-N pulls are batched, not serialized.** Reaction lookups split into batches of ≤20 ids (server cap) dispatched with bounded concurrency (≤4 in flight), so e.g. 550 ids → 28 batches finish in a few round-trips, not tens of seconds. Don't add your own throttling/looping on top. +## Resource auto-download (`--download-resources`, opt-in) + +`+chat-messages-list` / `+messages-mget` / `+threads-messages-list` accept `--download-resources` (**off by default** — omitted = no `resources` block and zero extra requests). When set, eligible resources (`image`/`file`/`audio`/`video`/`media` + post-embedded; **stickers excluded** — Feishu can't fetch them) download into `./lark-im-resources/`, and each message gains a `resources` array of `{message_id, key, type, local_path, size_bytes}`. + +- **`merge_forward` trap**: for a resource inside a forwarded message, `message_id` is the **top-level container** id, not the sub-item's — the download endpoint rejects sub-item ids with `234003 File not in msg`. Thread replies each get their own block. +- **Fail-silent isolation**: one resource that fails to download is flagged `"error": true` + a single stderr `warning: resource_download_failed: …`; the message and other resources are unaffected (exit 0). +- Deduped by `(message_id, file_key)`, bounded concurrency (≤3), output confined to `./lark-im-resources/` (path-separator / `..` / absolute `file_key` rejected). +- **No extra scope**: uses `im:message:readonly`, already declared by the listing commands; works under user and bot identity. For one-off fetches use [`+messages-resources-download`](lark-im-messages-resources-download.md). + ## Thread-replies expansion caps (mget / chat-messages-list only) Any returned message carrying a `thread_id` triggers a fetch of that thread's replies, attached as a `thread_replies` array on the host (distinct threads fetched with ≤4 concurrent). Two caps gate it: diff --git a/skills/lark-im/references/lark-im-messages-send.md b/skills/lark-im/references/lark-im-messages-send.md index 3021774a..ed8db3ba 100644 --- a/skills/lark-im/references/lark-im-messages-send.md +++ b/skills/lark-im/references/lark-im-messages-send.md @@ -31,10 +31,13 @@ For multi-line text, indentation, code blocks, or literal backslashes, use shell lark-cli im +messages-send --chat-id oc_xxx --text $'Build failed\nBranch: feature/x\nAction: check logs' ``` -## @Mention format (text / post) +## @Mention format (differs by message type) -- Recommended: `name`; @all: ``. -- The shortcut normalizes `` / `` into `user_id`, but author your examples with `user_id`. +The shortcut only normalizes mentions for `text` and `post`; **`interactive` card content is passed through verbatim**, so cards must use the card-native syntax — this asymmetry is the trap. + +- **`text`**: `name` (inner name optional); @all: ``. The shortcut also normalizes `` / `` into `user_id`, but author examples with `user_id`. +- **`post`**: same inline form inside a `text`/`md` element, or a dedicated node `{"tag":"at","user_id":"ou_xxx"}` (`"all"` for everyone). +- **`interactive` (card)**: NOT normalized — use card-native `` inside a `lark_md`/`markdown` element: single ``, multiple ``, by email ``. ## Common mistakes (the non-obvious ones)