mirror of
https://github.com/larksuite/cli.git
synced 2026-07-07 17:45:15 +08:00
docs: clarify success envelope contract — judge success by ok, not code (#1730)
The stdout success envelope is {ok, identity, data, meta?} and carries no
top-level code/msg field, but wrappers following the raw OpenAPI convention
test code == 0 and misclassify every successful call as a failure. Around
write commands this defeats caller-side idempotency and causes duplicate
creates (see #1689).
Document the contract in ERROR_CONTRACT.md (success-envelope counterpart to
the error wire format), both READMEs (JSON Output Contract section), the
lark-shared skill (shared prerequisite for all skills), and add a success
response example to lark-task-create.md.
Closes #1689
This commit is contained in:
18
README.md
18
README.md
@@ -233,6 +233,24 @@ lark-cli api POST /open-apis/im/v1/messages --params '{"receive_id_type":"chat_i
|
||||
--format csv # Comma-separated values
|
||||
```
|
||||
|
||||
### JSON Output Contract
|
||||
|
||||
With `--format json` (the default), success and error envelopes are distinct.
|
||||
|
||||
Success goes to **stdout**, exit code `0`:
|
||||
|
||||
```json
|
||||
{ "ok": true, "identity": "user", "data": { "guid": "..." }, "meta": { "count": 1 } }
|
||||
```
|
||||
|
||||
Errors go to **stderr**, non-zero exit code:
|
||||
|
||||
```json
|
||||
{ "ok": false, "identity": "user", "error": { "type": "api", "subtype": "...", "code": 99991679, "message": "...", "hint": "..." } }
|
||||
```
|
||||
|
||||
To check whether a command succeeded, test `ok == true` (or the exit code) — **not** `code == 0`. Unlike raw OpenAPI responses (`{"code": 0, "msg": "ok", ...}`), the success envelope carries no `code` or `msg` field; `code` appears only inside `error` as the upstream OpenAPI code. See [errs/ERROR_CONTRACT.md](errs/ERROR_CONTRACT.md) for the full error taxonomy.
|
||||
|
||||
### Pagination
|
||||
|
||||
```bash
|
||||
|
||||
18
README.zh.md
18
README.zh.md
@@ -234,6 +234,24 @@ lark-cli api POST /open-apis/im/v1/messages --params '{"receive_id_type":"chat_i
|
||||
--format csv # 逗号分隔值
|
||||
```
|
||||
|
||||
### JSON 输出契约
|
||||
|
||||
`--format json`(默认)下,成功与错误的信封结构不同。
|
||||
|
||||
成功信封写入 **stdout**,退出码 0:
|
||||
|
||||
```json
|
||||
{ "ok": true, "identity": "user", "data": { "guid": "..." }, "meta": { "count": 1 } }
|
||||
```
|
||||
|
||||
错误信封写入 **stderr**,退出码非 0:
|
||||
|
||||
```json
|
||||
{ "ok": false, "identity": "user", "error": { "type": "api", "subtype": "...", "code": 99991679, "message": "...", "hint": "..." } }
|
||||
```
|
||||
|
||||
判断命令是否成功,请检查 `ok == true`(或进程退出码),**不要用 `code == 0`**。与原始 OpenAPI 响应(`{"code": 0, "msg": "ok", ...}`)不同,成功信封没有 `code` 和 `msg` 字段;`code` 只出现在错误信封的 `error` 内,含义是上游 OpenAPI 的 numeric code。完整错误分类见 [errs/ERROR_CONTRACT.md](errs/ERROR_CONTRACT.md)。
|
||||
|
||||
### 分页
|
||||
|
||||
```bash
|
||||
|
||||
@@ -72,6 +72,28 @@ other category. `error.type` is `"policy"`, `error.subtype` is one of
|
||||
`challenge_required` / `access_denied`, and process exit is `6` via
|
||||
`CategoryPolicy`.
|
||||
|
||||
### Success envelope (stdout)
|
||||
|
||||
For contrast: success responses render to **stdout** as an
|
||||
`output.Envelope` (`internal/output/envelope.go`), exit code `0`:
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"identity": "user",
|
||||
"data": { "guid": "e297d3d0-..." },
|
||||
"meta": { "count": 1 }
|
||||
}
|
||||
```
|
||||
|
||||
Consumers must branch on `ok` (or the process exit code). The success
|
||||
envelope has **no top-level `code` or `msg` field** — `code` exists only
|
||||
inside `error`, where it is the upstream numeric code (invariant 4).
|
||||
Wrappers that follow the raw OpenAPI convention and test `code == 0`
|
||||
will misclassify every successful call as a failure, which is
|
||||
especially dangerous around write commands (e.g. retrying a create that
|
||||
already succeeded).
|
||||
|
||||
## Categories
|
||||
|
||||
| Category | When | Exit | Typed struct |
|
||||
|
||||
@@ -146,6 +146,24 @@ lark-cli update
|
||||
|
||||
**重要**:始终使用 `lark-cli update` 更新,它会同时更新 CLI 和 AI Skills。
|
||||
|
||||
## JSON 输出契约
|
||||
|
||||
`--format json`(默认)下,成功与错误的信封结构不同:
|
||||
|
||||
成功信封写入 **stdout**(退出码 0):
|
||||
|
||||
```json
|
||||
{ "ok": true, "identity": "user", "data": { "guid": "..." }, "meta": { "count": 1 } }
|
||||
```
|
||||
|
||||
错误信封写入 **stderr**(退出码非 0):
|
||||
|
||||
```json
|
||||
{ "ok": false, "identity": "user", "error": { "type": "api", "subtype": "...", "code": 99991679, "message": "...", "hint": "..." } }
|
||||
```
|
||||
|
||||
**判断成功必须用 `ok == true`(或进程退出码 0),不要用 `code == 0`**:成功信封没有顶层 `code` / `msg` 字段,`code` 只出现在错误信封的 `error` 内,含义是上游 OpenAPI 的 numeric code。按 OpenAPI 老格式 `{"code": 0, "msg": "ok"}` 判断会把所有成功调用误判为失败;封装写入类命令(如 `task +create`)时尤其危险,误判会绕过幂等逻辑导致重复创建。
|
||||
|
||||
## 安全规则
|
||||
|
||||
- **禁止输出密钥**(appSecret、accessToken)到终端明文。
|
||||
|
||||
@@ -46,7 +46,20 @@ lark-cli task +create --summary "Test Task" --dry-run
|
||||
1. Confirm with the user: task summary, due date, assignee, and tasklist if necessary.
|
||||
- **Crucial Rule for Assignee**: If the user explicitly or implicitly says "create a task for me" (给我创建一个任务), or "help me create a task" (帮我新建/创建一个任务), you MUST assign the task to the current logged-in user. You can get the current user's `open_id` by executing `lark-cli auth status` (it already outputs JSON by default, so do not add `--json`) or `lark-cli contact +get-user` first, extracting `.identities.user.openId` (from `auth status`) or `.data.user.open_id` (from `contact +get-user`), and then passing it to the `--assignee` parameter.
|
||||
2. Execute `lark-cli task +create --summary "..." ...`
|
||||
3. Report the result: task ID and summary.
|
||||
3. Judge success by `ok == true` in the stdout JSON (the success envelope has no `code` field — do not test `code == 0`), then report the result: task ID (`data.guid`) and summary.
|
||||
|
||||
Example success response:
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"identity": "user",
|
||||
"data": {
|
||||
"guid": "e297d3d0-4b60-4a5f-a4d4-xxxxxxxxxxxx",
|
||||
"url": "https://applink.larkoffice.com/client/todo/detail?guid=e297d3d0-4b60-4a5f-a4d4-xxxxxxxxxxxx"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
> This is a **Write Operation** -- You must confirm the user's intent before executing.
|
||||
|
||||
Reference in New Issue
Block a user