$npx -y skills add larksuite/cli --skill lark-eventLark/Feishu real-time event listening / subscribing / consuming: stream events as NDJSON via lark-cli event consume <EventKey> (covers IM messages/reactions/chat changes, Approval status changes, Task updates, VC meeting started/joined/ended, Minutes generated, Whiteboard updat
| 1 | # Lark Events |
| 2 | |
| 3 | > **Prerequisite:** Read [`../lark-shared/SKILL.md`](../lark-shared/SKILL.md) first for authentication, `--as user/bot` switching, `Permission denied` handling, and safety rules. |
| 4 | |
| 5 | ## Core commands |
| 6 | |
| 7 | | Command | Purpose | |
| 8 | |------|------| |
| 9 | | `lark-cli event list [--json]` | List all subscribable EventKeys | |
| 10 | | `lark-cli event schema <EventKey> [--json]` | Show an EventKey's params and output schema | |
| 11 | | `lark-cli event consume <EventKey> [flags]` | Blocking consume; events → stdout NDJSON | |
| 12 | | `lark-cli event status [--json] [--fail-on-orphan]` | Inspect the local bus daemon status | |
| 13 | | `lark-cli event stop [--all] [--force]` | Stop the bus daemon | |
| 14 | |
| 15 | |
| 16 | ## Common flags |
| 17 | |
| 18 | | Flag | Description | |
| 19 | |---|---| |
| 20 | | `--param key=value` / `-p` | Business params (repeatable; comma-separated for multi-value). Unknown keys fail with valid names listed inline | |
| 21 | | `--jq <expr>` | jq expression to filter / transform each event; empty output skips the event | |
| 22 | | `--max-events N` | Exit after N events. Default 0 = unlimited | |
| 23 | | `--timeout D` | Exit after duration D (e.g. `30s`, `2m`). Default 0 = no timeout. Whichever of `--max-events` / `--timeout` fires first wins | |
| 24 | | `--output-dir <dir>` | Write each event as a file (relative paths only; prevents traversal) | |
| 25 | | `--quiet` | Suppress stderr diagnostics. **AI should not use this** — it silences the ready marker | |
| 26 | | `--as user\|bot\|auto` | Identity for the session (see lark-shared) | |
| 27 | |
| 28 | |
| 29 | ## Examples |
| 30 | |
| 31 | ```bash |
| 32 | # Default: stream every event for the key (no filter, no projection) |
| 33 | lark-cli event consume im.message.receive_v1 --as bot |
| 34 | |
| 35 | # Grab one sample event to inspect payload shape |
| 36 | lark-cli event consume im.message.receive_v1 --max-events 1 --timeout 30s --as bot |
| 37 | |
| 38 | # Run for 10 minutes then auto-exit |
| 39 | lark-cli event consume im.message.receive_v1 --timeout 10m --as bot |
| 40 | |
| 41 | # Consume multiple EventKeys concurrently (one shape per process, no dispatcher) |
| 42 | lark-cli event consume im.message.receive_v1 --as bot > receive.ndjson & |
| 43 | lark-cli event consume im.message.reaction.created_v1 --as bot > reaction.ndjson & |
| 44 | wait |
| 45 | |
| 46 | ``` |
| 47 | |
| 48 | ## Call flow |
| 49 | |
| 50 | 1. `lark-cli event list --json` → pick a legal key |
| 51 | 2. `lark-cli event schema <key> --json` → read `resolved_output_schema` + `jq_root_path` to determine field paths |
| 52 | 3. `lark-cli event consume <key> [--jq '<expr>']` → consume |
| 53 | |
| 54 | ## Subprocess contract |
| 55 | |
| 56 | ### Ready marker |
| 57 | |
| 58 | `event consume`'s stderr emits a fixed line `[event] ready event_key=<key>`. **Parent processes should block on stderr until this line appears, then start reading stdout.** Do not fall back to `sleep`. |
| 59 | |
| 60 | ### stdin EOF = graceful exit |
| 61 | |
| 62 | `event consume` treats stdin close as a shutdown signal (wired for AI subprocess callers). **Bounded runs are exempt: when `--max-events` or `--timeout` is set (> 0), stdin EOF is ignored and the run exits only via its own bound, timeout, or SIGTERM.** For unbounded runs, `< /dev/null` / `nohup` / systemd's default `StandardInput=null` will cause an immediate graceful exit (stderr `reason: signal`). To keep an unbounded run alive: |
| 63 | |
| 64 | - Feed stdin a source that never EOFs: `< <(tail -f /dev/null)` |
| 65 | - Or run bounded: `--max-events N` / `--timeout D` |
| 66 | |
| 67 | ### Exit codes & reason |
| 68 | |
| 69 | On exit, the last stderr line is `[event] exited — received N event(s) in Xs (reason: ...)`. |
| 70 | |
| 71 | | exit code | reason | Trigger | |
| 72 | |---|---|---| |
| 73 | | 0 | `reason: limit` | `--max-events` reached | |
| 74 | | 0 | `reason: timeout` | `--timeout` reached | |
| 75 | | 0 | `reason: signal` | Ctrl+C / SIGTERM / stdin EOF (stdin EOF applies to unbounded runs only) | |
| 76 | | 1 | JSON error envelope on stderr | Lark API business failure during pre-consume setup (for example subscription create/delete) | |
| 77 | | 2 | JSON error envelope on stderr (no `exited` line) | Validation failure (unknown EventKey, bad `--param` / `--jq`, another bus already connected) | |
| 78 | | 3 | JSON error envelope on stderr | Auth failure (missing token, missing scopes) | |
| 79 | | 4 / 5 | JSON error envelope on stderr | Network / internal failure (bus startup, handshake, file I/O) | |
| 80 | |
| 81 | Startup and runtime failures emit a structured JSON envelope on stderr: `{"ok":false,"error":{"type","subtype","param","message","hint",...}}` (the envelope may also carry top-level `identity` / `_notice` siblings). Parse `error.type` / `error.subtype` to branch (e.g. `missing_scope` carries a `missing_scopes` list), `error.param` to find |