diff --git a/skills/lark-apps/references/lark-apps-openapi-key.md b/skills/lark-apps/references/lark-apps-openapi-key.md index 37cb7d37e..39d109741 100644 --- a/skills/lark-apps/references/lark-apps-openapi-key.md +++ b/skills/lark-apps/references/lark-apps-openapi-key.md @@ -76,4 +76,4 @@ CLI 提供三种互斥的 scope 表达方式: ## 不在本 skill 范围 - OpenAPI spec 全量导出、实时日志 tail、Webhook 消费、多鉴权方式:本期不支持。 -- 身份选择、权限不足处理(`permission_violations`→`console_url`)、exit-10 审批、通用"禁输出密钥"红线、高风险操作通用框架:见 [`../lark-shared/SKILL.md`](../lark-shared/SKILL.md),不在此重复。 +- 身份选择、权限不足处理(`missing_scopes`→`console_url`)、exit-10 审批、通用"禁输出密钥"红线、高风险操作通用框架:见 [`../lark-shared/SKILL.md`](../lark-shared/SKILL.md),不在此重复。 diff --git a/skills/lark-base/SKILL.md b/skills/lark-base/SKILL.md index 3399146dc..ca1380703 100644 --- a/skills/lark-base/SKILL.md +++ b/skills/lark-base/SKILL.md @@ -85,7 +85,7 @@ metadata: ## 身份与权限降级 - 默认显式使用 `--as user` 操作用户资源;只有用户明确要求应用身份时,才直接用 `--as bot`。 -- user 身份报 scope/授权不足,或错误中包含 `permission_violations` / `hint`,先转 `lark-shared` 做用户授权恢复,不要直接降级 bot。 +- user 身份报 scope/授权不足,或错误中包含 `missing_scopes` / `hint`,先转 `lark-shared` 做用户授权恢复,不要直接降级 bot。 - user 身份报资源级无访问且无授权恢复提示时,才可用 `--as bot` 重试一次;bot 仍失败就停止重试并按权限错误处理。 - `91403` 或明确不可访问错误不要循环换身份重试。 - `+base-create` / `+base-copy` 若用 bot 身份执行,关注返回中的 `permission_grant`,并把用户是否可打开新 Base 告知用户。 diff --git a/skills/lark-base/references/lark-base-dashboard-block-get-data.md b/skills/lark-base/references/lark-base-dashboard-block-get-data.md index 8470323f8..dbf244d51 100644 --- a/skills/lark-base/references/lark-base-dashboard-block-get-data.md +++ b/skills/lark-base/references/lark-base-dashboard-block-get-data.md @@ -98,16 +98,35 @@ lark-cli base +dashboard-block-get \ ## 返回结构总览 -服务端响应外层仍然是标准 OpenAPI 包装: +CLI 输出标准成功信封(判断成功用 `ok == true` 或退出码 0,不要找 `code == 0`): ```json { - "code": 0, - "msg": "success", + "ok": true, + "identity": "user", "data": { - "dimensions": [...], - "measures": [...], - "main_data": [...] + "dimensions": [ + { + "field_name": "地区", + "alias": "dim_region" + } + ], + "measures": [ + { + "field_name": "销售额", + "alias": "me_sales" + } + ], + "main_data": [ + { + "dim_region": { + "value": "华东" + }, + "me_sales": { + "value": 12345 + } + } + ] } } ``` diff --git a/skills/lark-base/references/lark-base-data-query.md b/skills/lark-base/references/lark-base-data-query.md index 26c6e2e0b..52aa85cd3 100644 --- a/skills/lark-base/references/lark-base-data-query.md +++ b/skills/lark-base/references/lark-base-data-query.md @@ -347,28 +347,51 @@ value 使用预定义关键字机制,第一个元素为字符串常量名称 |------|------|------|------| | `format` | string | 是 | 固定为 `"flat"`,表示返回扁平化的对象数组 | -## API 出参详情 +## CLI 出参详情 -**成功时:** +**成功时**(stdout,判断成功用 `ok == true` 或退出码 0): ```json -{"code": 0, "data": {"main_data": [{"dim_city": {"value": "北京"}, "total_amount": {"value": 12345.00}}, ...]}, "msg": ""} +{ + "ok": true, + "identity": "user", + "data": { + "main_data": [ + { + "dim_city": { + "value": "北京" + }, + "total_amount": { + "value": 12345.00 + } + }, + { + "dim_city": { + "value": "上海" + }, + "total_amount": { + "value": 6789.00 + } + } + ] + } +} ``` -**失败时:** +**失败时**(stderr 类型化错误信封,非零退出码;`error.code` 是上游 API 错误码): ```json -{"code": 800004006, "data": {"error": {"code": 800004006, ...}}, "msg": "DSL validation failed"} +{"ok": false, "identity": "user", "error": {"type": "api", "subtype": "...", "code": 800004006, "message": "DSL validation failed", "hint": "..."}} ``` **Response 字段:** | 字段 | 类型 | 说明 | |------|------|------| -| `code` | int | 状态码,0 为成功 | -| `msg` | string | 错误信息 | +| `ok` | bool | 是否成功 | | `data.main_data` | []object | 查询结果数组,每个元素为一行数据 | -| `data.error` | object | 失败时的错误详情 | +| `error.code` | int | 失败时的上游 API 错误码 | +| `error.message` / `error.hint` | string | 失败原因与建议的恢复动作 | 每行数据的字段值封装在 CellValue 中: @@ -387,7 +410,7 @@ value 使用预定义关键字机制,第一个元素为字符串常量名称 ## 返回值 -命令成功后输出 `data` 字段的内容: +命令成功后,成功信封的 `data` 字段即查询结果: ```json { diff --git a/skills/lark-drive/references/lark-drive-member-add.md b/skills/lark-drive/references/lark-drive-member-add.md index 8b36d27eb..146b14311 100644 --- a/skills/lark-drive/references/lark-drive-member-add.md +++ b/skills/lark-drive/references/lark-drive-member-add.md @@ -54,7 +54,7 @@ lark-cli drive +member-add \ } ``` -批量部分失败时,`partial` 为 `true`,CLI 以非零退出码返回 `error.type=partial_failure`。检查 `error.detail` 中的 `requested_count`、`succeeded_count`、`members`、`missing_member_ids` 和可选的 `mismatched_member_ids`。响应顺序不影响匹配结果。 +批量部分失败时,`partial` 为 `true`,同一份结果以 `ok:false` 部分失败信封写到 **stdout**(stderr 不再输出单独的错误信封),CLI 以非零退出码结束。检查 `data` 中的 `requested_count`、`succeeded_count`、`members`、`missing_member_ids` 和可选的 `mismatched_member_ids`。响应顺序不影响匹配结果。 ## 行为说明 diff --git a/skills/lark-drive/references/lark-drive-pull.md b/skills/lark-drive/references/lark-drive-pull.md index 5568c8cb9..048a1a258 100644 --- a/skills/lark-drive/references/lark-drive-pull.md +++ b/skills/lark-drive/references/lark-drive-pull.md @@ -17,11 +17,11 @@ | `summary.deleted_local` | 启用 `--delete-local --yes` 时删除的本地文件数 | | `items[]` | 每个文件的明细(`rel_path` / `file_token` / `source_id` / `action` / 失败时的 `error`) | -`summary.failed > 0` 时命令以 **非零状态码**(`exit=1`,`error.type=partial_failure`)退出,且同一份 `summary + items` 会在 `error.detail` 里返回;脚本/agent 直接通过 exit code 判断成败即可,不需要再去解 `summary.failed`。 +`summary.failed > 0` 时命令以 **非零状态码**(`exit=1`)退出:同一份 `summary + items` 会以 `ok:false` 部分失败信封写到 **stdout**(字段在 `data.summary` / `data.items`,另附 `data.note` 说明失败情况),stderr 不再输出单独的错误信封;脚本/agent 直接通过 exit code 判断成败即可,不需要再去解 `summary.failed`。 ## 远端同名文件冲突 -如果 Drive 中多个条目映射到同一个 `rel_path`,默认直接失败(`error.type=duplicate_remote_path`),且不会下载、覆盖或删除任何本地文件。只有“多个 `type=file` 同名”的场景支持显式策略;`file-folder` 这类异构冲突始终直接失败。 +如果 Drive 中多个条目映射到同一个 `rel_path`,默认直接失败(stderr 类型化错误信封:`error.type=validation`、`error.subtype=failed_precondition`,`error.params[]` 逐条列出冲突的 `rel_path` 及碰撞条目),且不会下载、覆盖或删除任何本地文件。只有“多个 `type=file` 同名”的场景支持显式策略;`file-folder` 这类异构冲突始终直接失败。 | 策略 | 行为 | |------|------| @@ -80,7 +80,7 @@ lark-cli drive +pull --local-dir ./repo --folder-token fldcnxxxxxxxxx \ - `--delete-local`(无 `--yes`)→ Validate 直接报错:`--delete-local requires --yes`,没有任何下载、列表请求或删除发生。 - `--delete-local --yes`,**且下载阶段全部成功** → 扫一遍 `--local-dir` 下所有常规文件,把不在云端清单里的逐个 `os.Remove`。**只删常规文件,不删目录**:远端文件夹被删除后,对应本地目录会保留空壳。 -- `--delete-local --yes`,**但下载阶段有任何条目失败** → **跳过整个删除阶段**,命令以 `partial_failure` 非零退出。设计意图:避免出现"前面下载失败、后面继续删本地文件"的半同步状态;操作者修好下载错误后再重跑即可。 +- `--delete-local --yes`,**但下载阶段有任何条目失败** → **跳过整个删除阶段**,命令以 `ok:false` 部分失败结果非零退出。设计意图:避免出现"前面下载失败、后面继续删本地文件"的半同步状态;操作者修好下载错误后再重跑即可。 - 远端同名文件冲突且使用默认 `fail` → 在下载阶段前失败,删除阶段不会运行。 - 不传 `--delete-local` → `summary.deleted_local` 永远是 0;命令对本地"多余"文件视而不见。 diff --git a/skills/lark-drive/references/lark-drive-push.md b/skills/lark-drive/references/lark-drive-push.md index 0d7b881a7..0b8d7a2cb 100644 --- a/skills/lark-drive/references/lark-drive-push.md +++ b/skills/lark-drive/references/lark-drive-push.md @@ -24,7 +24,7 @@ ## 远端同名文件冲突 -如果 Drive 中多个条目映射到同一个 `rel_path`,默认直接失败(`error.type=duplicate_remote_path`),且不会上传、覆盖或进入 `--delete-remote` 删除阶段。只有“多个 `type=file` 同名”的场景支持显式策略;`file-folder` 这类异构冲突始终直接失败。 +如果 Drive 中多个条目映射到同一个 `rel_path`,默认直接失败(stderr 类型化错误信封:`error.type=validation`、`error.subtype=failed_precondition`,`error.params[]` 逐条列出冲突的 `rel_path` 及碰撞条目),且不会上传、覆盖或进入 `--delete-remote` 删除阶段。只有“多个 `type=file` 同名”的场景支持显式策略;`file-folder` 这类异构冲突始终直接失败。 | 策略 | 行为 | |------|------| diff --git a/skills/lark-drive/references/lark-drive-status.md b/skills/lark-drive/references/lark-drive-status.md index 69fdcd799..5ea8a2341 100644 --- a/skills/lark-drive/references/lark-drive-status.md +++ b/skills/lark-drive/references/lark-drive-status.md @@ -19,7 +19,7 @@ ## 远端同名文件冲突 -如果 Drive 中多个条目映射到同一个 `rel_path`,`+status` 会在下载/hash 前直接失败,返回 `error.type=duplicate_remote_path`,并在 `error.detail.duplicates_remote[]` 中列出该路径下所有冲突条目的 `file_token`、`type`、名称、大小和时间字段;其中 `created_time`、`modified_time` 缺失时会省略,`size` 在缺失或为 `0` 时都可能被省略。不要把这种情况当成普通 `modified`;它表示同步域本身有歧义,需要先整理云端结构,或在 `+pull` / `+push` 中仅对“duplicate file”场景显式选择冲突策略。 +如果 Drive 中多个条目映射到同一个 `rel_path`,`+status` 会在下载/hash 前直接失败,在 stderr 返回类型化错误信封(`error.type=validation`、`error.subtype=failed_precondition`);`error.params[]` 每条的 `name` 是冲突的 `rel_path`,`reason` 枚举该路径下所有碰撞条目(`type` + `file_token`)。不要把这种情况当成普通 `modified`;它表示同步域本身有歧义,需要先整理云端结构,或在 `+pull` / `+push` 中仅对“duplicate file”场景显式选择冲突策略(`error.hint` 也给出了同样的恢复选项)。 ## 命令 @@ -76,20 +76,18 @@ lark-cli drive +status \ ```json { "ok": false, + "identity": "user", "error": { - "type": "duplicate_remote_path", - "message": "multiple Drive entries map to the same rel_path", - "detail": { - "duplicates_remote": [ - { - "rel_path": "dup.txt", - "entries": [ - {"file_token": "", "type": "file", "name": "dup.txt", "size": 5, "created_time": "1730000000", "modified_time": "1730000000"}, - {"file_token": "", "type": "folder", "name": "dup.txt", "created_time": "1730000060", "modified_time": "1730000060"} - ] - } - ] - } + "type": "validation", + "subtype": "failed_precondition", + "message": "1 rel_path(s) map to multiple Drive entries", + "hint": "resolve the duplicate remote files first: re-run +pull with --on-duplicate-remote=rename (downloads each with a hashed suffix), or use --on-duplicate-remote=newest|oldest (supported by +pull/+sync/+push) to pick one, or delete the extra remote files; a plain retry will not help", + "params": [ + { + "name": "dup.txt", + "reason": "2 Drive entries collide here: file , folder " + } + ] } } ``` diff --git a/skills/lark-minutes/SKILL.md b/skills/lark-minutes/SKILL.md index c04ecd837..3ae961508 100644 --- a/skills/lark-minutes/SKILL.md +++ b/skills/lark-minutes/SKILL.md @@ -120,9 +120,9 @@ lark-cli minutes +todo --minute-token --as user --todos '[ **更新 / 删除前**:先用 `minutes +detail --minute-tokens --todo` 读取 `todos[].todo_id`(按 `content` 匹配目标条目;列表顺序不保证稳定,**不要**用"第 2 条"代替 `todo_id`)。 -**无编辑权限**:若 CLI 返回 `error.type=no_edit_permission`,表示对**这条妙记**没有编辑权,应请所有者授权;**不要**误走 `auth login --scope`。 +**无编辑权限**:若 CLI 返回稳定字段 `error.subtype=permission_denied`,且 `error.code` 为 `40005`(`+todo` / `+word-replace` 等编辑接口)或 `2091005`(如标题更新),表示对**这条妙记**没有编辑权,应请所有者授权;**不要**误走 `auth login --scope`。`error.message` 只作人读说明,不要用它做分支判断。 -**逐字稿关键词替换无命中**:`minutes +word-replace` 时,若 CLI 返回 `error.type=words_not_found`,表示传入的 `source_word` 在该妙记逐字稿中**一个都没匹配到**,未做任何替换。这是**参数问题不是权限问题**:先用 `minutes +detail --minute-tokens --transcript` 读取当前逐字稿,核对 `source_word` 的精确写法与大小写后重试。 +**逐字稿关键词替换无命中**:`minutes +word-replace` 时,若 CLI 返回稳定字段 `error.code=40001` 且 `error.subtype=not_found`,表示传入的 `source_word` 在该妙记逐字稿中**一个都没匹配到**,未做任何替换。这是**参数问题不是权限问题**:先用 `minutes +detail --minute-tokens --transcript` 读取当前逐字稿,核对 `source_word` 的精确写法与大小写后重试。`error.message` 只作人读说明,不要用它做分支判断。 **替换 AI 总结全文**:见 [minutes +summary](references/lark-minutes-summary.md)。 diff --git a/skills/lark-minutes/references/lark-minutes-todo.md b/skills/lark-minutes/references/lark-minutes-todo.md index d86bcd6d6..441c95fee 100644 --- a/skills/lark-minutes/references/lark-minutes-todo.md +++ b/skills/lark-minutes/references/lark-minutes-todo.md @@ -126,8 +126,8 @@ lark-cli minutes +todo --minute-token obcnxxxxxxxxxxxxxxxxxxxx --operation add - | 未指定操作 | 单条模式传 `--operation`,或批量传 `--todos` | | `--todos` 与单条 flags 冲突 | 二选一 | | `todos[i]` 校验失败 | 检查该条 `operation` 与字段组合 | -| `error.type` = `no_edit_permission` | **妙记资源无编辑权**:向妙记所有者申请该妙记的编辑/协作权限;**不要**走 `auth login --scope` | -| 缺少 OAuth scope(`permission_violations` 含 `minutes:minutes:update`) | `lark-cli auth login --scope "minutes:minutes:update"` | +| `error.code=40005` 且 `error.subtype=permission_denied` | **妙记资源无编辑权**:向妙记所有者申请该妙记的编辑/协作权限;**不要**走 `auth login --scope`;`error.message` 只作人读说明 | +| 缺少 OAuth scope(`error.missing_scopes` 含 `minutes:minutes:update`) | `lark-cli auth login --scope "minutes:minutes:update"` | ## 参考 diff --git a/skills/lark-shared/SKILL.md b/skills/lark-shared/SKILL.md index e78ddd496..48ba61262 100644 --- a/skills/lark-shared/SKILL.md +++ b/skills/lark-shared/SKILL.md @@ -69,7 +69,7 @@ LARKSUITE_CLI_NO_UPDATE_NOTIFIER=1 LARKSUITE_CLI_NO_SKILLS_NOTIFIER=1 lark-cli a 遇到权限相关错误时,**根据当前身份类型采取不同解决方案**。 错误响应中包含关键信息: -- `permission_violations`:列出缺失的 scope (N选1) +- `missing_scopes`:列出缺失的 scope (N选1) - `console_url`:飞书开发者后台的权限配置链接 - `hint`:建议的修复命令 @@ -178,22 +178,22 @@ lark-cli 对高风险写操作(`risk: "high-risk-write"`)有强制确认门 ```json { "ok": false, + "identity": "bot", "error": { - "type": "confirmation_required", + "type": "confirmation", + "subtype": "confirmation_required", "message": "drive +delete requires confirmation", "hint": "add --yes to confirm", - "risk": { - "level": "high-risk-write", - "action": "drive +delete" - } + "risk": "high-risk-write", + "action": "drive +delete" } } ``` **遇到这种情况,不要当普通错误放弃。** 按以下流程处理: -1. **识别**:看到子进程 exit code = `10` 且 stderr JSON 里 `error.type == "confirmation_required"` -2. **向用户确认**:把 `error.risk.action` 和关键参数展示给用户,明确告知"这是高风险操作",等待用户显式同意 +1. **识别**:看到子进程 exit code = `10` 且 stderr JSON 里 `error.type == "confirmation"`、`error.subtype == "confirmation_required"` +2. **向用户确认**:把 `error.action`、`error.risk` 和关键参数展示给用户,明确告知"这是高风险操作",等待用户显式同意 3. **用户同意** → 在你**原始 argv 的末尾追加 `--yes`** 后重试 4. **用户拒绝** → 终止流程,不要擅自改写参数或跳过门禁 diff --git a/skills/lark-slides/references/examples.md b/skills/lark-slides/references/examples.md index b85394b09..d46437563 100644 --- a/skills/lark-slides/references/examples.md +++ b/skills/lark-slides/references/examples.md @@ -65,15 +65,15 @@ lark-cli slides xml_presentations get --as user --params '{ ```json { - "code": 0, + "ok": true, + "identity": "user", "data": { "xml_presentation": { "presentation_id": "slides_example_presentation_id", "revision_id": 3, "content": "..." } - }, - "msg": "success" + } } ``` @@ -94,12 +94,12 @@ lark-cli slides xml_presentation.slide create --as user --params '{ ```json { - "code": 0, + "ok": true, + "identity": "user", "data": { "slide_id": "slide_example_id", "revision_id": 100 - }, - "msg": "success" + } } ``` @@ -116,11 +116,11 @@ lark-cli slides xml_presentation.slide delete --as user --params '{ ```json { - "code": 0, + "ok": true, + "identity": "user", "data": { "revision_id": 101 - }, - "msg": "success" + } } ``` diff --git a/skills/lark-slides/references/lark-slides-screenshot.md b/skills/lark-slides/references/lark-slides-screenshot.md index 23557fcb9..9935657d7 100644 --- a/skills/lark-slides/references/lark-slides-screenshot.md +++ b/skills/lark-slides/references/lark-slides-screenshot.md @@ -66,7 +66,8 @@ lark-cli slides +screenshot --as user \ ```json { - "code": 0, + "ok": true, + "identity": "user", "data": { "xml_presentation_id": "slides_example_presentation_id", "output_dir": ".lark-slides/screenshots", @@ -79,8 +80,7 @@ lark-cli slides +screenshot --as user \ "size": 12345 } ] - }, - "msg": "success" + } } ``` diff --git a/skills/lark-slides/references/lark-slides-xml-presentation-slide-create.md b/skills/lark-slides/references/lark-slides-xml-presentation-slide-create.md index d636b0aa9..a0ad45ec1 100644 --- a/skills/lark-slides/references/lark-slides-xml-presentation-slide-create.md +++ b/skills/lark-slides/references/lark-slides-xml-presentation-slide-create.md @@ -141,12 +141,12 @@ lark-cli slides xml_presentation.slide create --as user \ ```json { - "code": 0, + "ok": true, + "identity": "user", "data": { "slide_id": "slide_example_id", "revision_id": 100 - }, - "msg": "success" + } } ``` diff --git a/skills/lark-slides/references/lark-slides-xml-presentation-slide-delete.md b/skills/lark-slides/references/lark-slides-xml-presentation-slide-delete.md index da2e7f3e3..a787cca2b 100644 --- a/skills/lark-slides/references/lark-slides-xml-presentation-slide-delete.md +++ b/skills/lark-slides/references/lark-slides-xml-presentation-slide-delete.md @@ -61,11 +61,11 @@ lark-cli slides xml_presentation.slide delete --as user --params '{"xml_presenta ```json { - "code": 0, + "ok": true, + "identity": "user", "data": { "revision_id": 100 - }, - "msg": "success" + } } ``` diff --git a/skills/lark-slides/references/lark-slides-xml-presentation-slide-get.md b/skills/lark-slides/references/lark-slides-xml-presentation-slide-get.md index 4d2af6143..6e1d18f7f 100644 --- a/skills/lark-slides/references/lark-slides-xml-presentation-slide-get.md +++ b/skills/lark-slides/references/lark-slides-xml-presentation-slide-get.md @@ -65,15 +65,15 @@ lark-cli slides xml_presentation.slide get --as user --params '{ ```json { - "code": 0, + "ok": true, + "identity": "user", "data": { "slide": { "slide_id": "slide_example_id", "content": "