- 移除 TodoItem 中的 priority、created_at 和 updated_at 字段 - 强制每个任务都必须有唯一 id,且由用户负责生成 - 修改合并模式逻辑,merge=true 下保留未提及的旧任务 - 支持已完成和已取消任务重新激活(状态改回 pending 或 in_progress) - 禁止 in_progress 状态退回到 pending,必须标记为 completed 或 cancelled - 优化状态转换校验,允许特定状态间合法切换 - 简化任务变更消息,移除详细的新增/更新/移除统计 - 更新文档和示例,明确 id 必须由用户生成和使用 - 修复和补充测试,增强状态转换和合并模式验证 - 调整任务时间戳生成逻辑,统一使用当前时间及索引 - 该变更提供更合理的任务状态机械及管理模式,提升稳定性和易用性
86 lines
4.2 KiB
Markdown
86 lines
4.2 KiB
Markdown
# IM Events
|
|
|
|
> **Prerequisite:** Read [`../SKILL.md`](../SKILL.md) first for the `event consume` essentials (commands, subprocess contract, jq usage).
|
|
>
|
|
> **Heads-up for AI agents**: this key's `.content` is **NOT** the raw OAPI payload shape your training data may suggest. `lark-cli` runs a Process hook (`convertlib`) that flattens the V2 envelope and **pre-renders** `.content` to human-readable text for `text` / `post` / `image` / `file` / `audio` / etc. Only `interactive` (cards) keeps the raw JSON string. Don't blindly `fromjson`.
|
|
|
|
## Key catalog (11)
|
|
|
|
| EventKey | Purpose |
|
|
|---|---|
|
|
| `im.message.receive_v1` | Receive IM messages |
|
|
| `im.message.message_read_v1` | User read a bot's **p2p** message (group messages don't fire this) |
|
|
| `im.message.reaction.created_v1` | Reaction added to a message |
|
|
| `im.message.reaction.deleted_v1` | Reaction removed from a message |
|
|
| `im.chat.updated_v1` | Chat settings changed (owner, avatar, name, permissions, etc.) |
|
|
| `im.chat.disbanded_v1` | Chat disbanded |
|
|
| `im.chat.member.bot.added_v1` | Bot added to a chat |
|
|
| `im.chat.member.bot.deleted_v1` | Bot removed from a chat |
|
|
| `im.chat.member.user.added_v1` | User joined a chat (including topic chats) |
|
|
| `im.chat.member.user.deleted_v1` | User left voluntarily **or** was removed |
|
|
| `im.chat.member.user.withdrawn_v1` | Pending chat invite withdrawn (inviter canceled; user never actually joined) |
|
|
|
|
> **Shape**: `im.message.receive_v1` is the only flat key (fields at `.xxx`); the other 10 are V2-enveloped (fields at `.event.xxx`).
|
|
|
|
## Gotchas (`im.message.receive_v1`)
|
|
|
|
**sender_id is open_id only**: the event payload carries no display name. Call the contact API separately if you need the sender's name.
|
|
|
|
**`.content` shape depends on `message_type`** (this key uses a flat Custom schema; see [`events/im/message_receive.go`](../../../events/im/message_receive.go)):
|
|
|
|
| message_type | `.content` shape | How to read |
|
|
|---|---|---|
|
|
| `text` / `post` / `image` / `file` / `audio` / `sticker` / `share_chat` / `share_user` / `media` / `system` | Human-readable text (convertlib-processed; `@mentions` resolved to display names) | Use `.content` directly |
|
|
| `interactive` (card) | Raw card JSON string (structured actions can't be losslessly flattened) | `.content \| fromjson` to get the card object |
|
|
|
|
**Do not blindly `fromjson`** — for non-interactive messages it fails with `jq: fromjson cannot be applied to "hello"` because `.content` isn't JSON-encoded.
|
|
|
|
```bash
|
|
# text: .content is plain text — no fromjson needed
|
|
lark-cli event consume im.message.receive_v1 --as bot \
|
|
--jq 'select(.message_type=="text") | .content'
|
|
|
|
# interactive: .content is a JSON string — fromjson to parse
|
|
lark-cli event consume im.message.receive_v1 --as bot \
|
|
--jq 'select(.message_type=="interactive") | .content | fromjson'
|
|
```
|
|
|
|
## On-demand filter recipes
|
|
|
|
> **Default = no `--jq`.** Run `lark-cli event consume im.message.receive_v1 --as bot` to see every message. The recipes below are only for cases where the user has asked to narrow the stream.
|
|
|
|
### 1. Filter by chat type (p2p vs group)
|
|
|
|
`chat_type` is an enum with values `p2p` / `group`.
|
|
|
|
```bash
|
|
# p2p only (direct messages)
|
|
lark-cli event consume im.message.receive_v1 --as bot \
|
|
--jq 'select(.chat_type=="p2p") | {from: .sender_id, msg: .content}'
|
|
|
|
# group only
|
|
lark-cli event consume im.message.receive_v1 --as bot \
|
|
--jq 'select(.chat_type=="group") | {chat: .chat_id, from: .sender_id, msg: .content}'
|
|
```
|
|
|
|
### 2. Filter by message type
|
|
|
|
```bash
|
|
# text only — content is plain human-readable text
|
|
lark-cli event consume im.message.receive_v1 --as bot \
|
|
--jq 'select(.message_type=="text") | .content'
|
|
|
|
# interactive (card) only — parse the card body
|
|
lark-cli event consume im.message.receive_v1 --as bot \
|
|
--jq 'select(.message_type=="interactive") | .content | fromjson'
|
|
```
|
|
|
|
### 3. Filter by sender (only one user's messages)
|
|
|
|
```bash
|
|
# example: only messages from the given open_id
|
|
lark-cli event consume im.message.receive_v1 --as bot\
|
|
--jq 'select(.sender_id=="ou_xxxxxxxxxxxxxxxxxxxxxxxxxx") | {msg_id: .message_id, text: .content}'
|
|
```
|
|
|
|
Get your own open_id via `lark-cli contact +get-user --as user`; other users' via `lark-cli contact +search-user`. |