Repository navigation
feat: 对照官方 CLI 全量对齐——修复契约缺陷、补齐能力、技能与版本绑定(v1.42.0) - #183
Merged
Merged
Conversation
- body_plain_text/body_html/body_preview 默认解码为明文(兼容带/不带 padding), body_plain_text 额外清除 ANSI/控制/BiDi/零宽字符,防终端注入 - 新增 --raw-body 保留 API 原始编码(兼容旧消费方) - 文本模式输出可读的邮件头 + 正文(优先由 HTML 还原段落,服务端纯文本会折叠换行) - 解码使用 UseNumber,保留大整数精度
…screenshot,create 带页面 对齐官方 shortcuts/slides 并照搬其实测契约: - 写页面命令的 lint 开关以 lint_xml 放在请求体(放 query 会被网关丢弃),--no-lint 关闭; 4000153 lint 拒绝与 3350001 给出可执行提示 - replace-slide:block_replace 根元素自动注入 id(缺失实测 3350001)、<shape> 补 <content/>、 兼容别名规范化并输出 normalizations、拒绝 str_replace,透出 failed_part_index/failed_reason/issues - update-slide:整页替换,根 id 与 --slide-id 不一致拒绝,剥掉过期 <note id>(实测 "block is not NoteBlock"),failed_reason 按失败退出 - add-slide / update-slide / create 的 <img src="@path"> 占位图自动上传替换 file_token - create 支持 --slides(JSON 数组)/ --slide(可重复)一次最多 10 页,逐页添加,失败时报告进度 - delete-slide 走确认门禁(非交互需 --yes);screenshot 支持页码/slide_id 与 --content 直接渲染 - 各写命令支持 --dry-run,@file / - 读 stdin 绕开 shell 转义
新增 *TATError(Error() 文本不变)与 IsCredentialRejected:invalid_client / unauthorized_client 及 20002(secret 无效)、20048(应用不存在)、99991543、10014 视为 App 凭证被确定性拒绝,打鉴权标签(原先退出码 1);5xx/临时错误不受影响。
…be 凭证探测 - --app-secret-stdin:从 stdin 读取 App Secret(终端下不回显),避免进入 shell 历史与 ps; 与 --app-secret 互斥,stdin 为空报用法错误 - --probe:写入前用该凭证换取一次 tenant_access_token(5s 超时,对齐官方 init_probe.go); 服务端明确拒绝时退出码 3 且不写配置/不创建 profile,网络或临时错误只告警 - config init 新增 --app-id / --app-secret-stdin / --base-url 预填模板(无参数时行为不变) - profile add 在读 stdin / 探测前先校验名字与是否已存在
- callMailAPI 改用 CheckAPIResponse:随 HTTP 400 下发的业务错误(如 4038)保留业务码与 log_id, HasAPICode 可用;错误信息去掉 query 参数 - GetMailDraftRaw 读取实测的 data.draft.message.raw(旧实现只读 data.raw/data.draft.raw,永远为空), 缺少 raw 时报错而非返回空串
- 引用块使用解码后的原文(优先由 HTML 还原段落),纯文本引用清理控制字符; HTML 模式引用块(飞书 history-quote-wrapper 结构)中原文/主题/显示名全部 HTML 转义,消除注入点 - In-Reply-To/References 规范化为 <id>;回复与转发写 X-LMS-Reply-To-Message-Id(原邮件 message_id) - 回复地址优先 Reply-To;支持回复自己发出的邮件(回复原收件人,reply-all 保持 To/Cc 区分);按邮箱去重 - 地址统一经 net/mail 规范编码(显示名含逗号加引号、非 ASCII 走 RFC 2047);--to 等支持 "Doe, John" <x> 写法 - send/draft-create/reply/reply-all/forward 新增 --attach(扩展名黑名单、EML 编码后 ≤25MB) - forward 默认携带原邮件普通附件(预签名链接下载,不带鉴权头,https+SSRF 防护), 新增 --html/--plain-text/--no-original-attachments;超大附件提示未携带
- 新增 internal/mailmime:保序保折行的最小改动 EML 解析/序列化(未修改内容逐字节保留) - draft-edit 先 GET format=raw,只修改显式传入的 --to/--cc/--bcc/--subject/--body/--from/--from-name, In-Reply-To/References/X-LMS 头、附件、内联图原样保留;替换正文默认保留回复/转发引用块(--drop-quote 删除) - 识别服务端为纯文本草稿合成的未转义 HTML 备选,按纯文本处理 - --to/--subject/--body 不再必填(至少指定一项修改);--cc "" 清空抄送
--inline-images-auto-scan 的图片本就随 EML 以 multipart/related 嵌入,旧实现额外上传到云盘 (file_token 从未使用),白白多一次请求并要求 drive 权限与 open_id,移除该步骤及未用的 UploadMailInlineImage
- meeting-ids 路径与官方 vc +notes 一致,始终经录制接口补 minute_token(best-effort) - 输出新增 note_id、note_display_type(normal/unified/unknown),便于路由到 vc note transcript 或 doc export verbatim 文档 - 纪要详情失败(如 121005 无权限)、会议无纪要时记入 hint,不再静默丢弃
- tenant_access_token 换取返回 429 时读取 Retry-After(秒数或 HTTP-date,上限 5s,缺省 1s) 等待后重试一次,超过剩余超时直接报错 - token.json 解析失败的错误附带文件路径与 auth login / auth logout 修复建议
- convertEvent 处理全天日程 date(含排他结束日换算),get-event/list-events 不再输出空起止 - get-event 改走 HTTP 并补 self_rsvp_status、vchat.meeting_url、reminders;--share-link / event-share 输出分享链接 - freebusy 改用 freebusy/batch:默认当前登录用户、排序合并重叠区间,新增多人与 free/common_free 视图 - delete-event/update-event 先读取日程判型并说明影响范围,新增 --apply-to single|all|this-and-following; this-and-following 新序列把 COUNT 换算为 UNTIL,避免变成无限重复 - update-event 要求 --start/--end 成对(实测单边更新服务端返回成功但不生效) - create/update/delete-event、attendee add/remove 支持 --as(默认 auto),event-reply 必需 User Token - create-event --calendar-id 默认 primary,支持 --attendee-ids(失败回滚)与 --vchat;attendee 支持会议室、移除与 --type 过滤 - 新增 event-transfer;日历业务错误先解析业务码(search_event/suggestion/room_find/mget_instance)
修正 delete-event 与技能文档对重复日程删除语义互相矛盾的描述(实测:主体 ID 删序列不级联例外,实例 ID 只删一次), 修正 attendee add 可加会议室的错误说法(现已支持 --room-ids)
…wiki 场景 - DriveTaskCheckStatus 新增 Ready/Failed/Pending,删除任务返回的 fail 识别为失败终态 - 导出/导入/移动轮询:查询瞬时失败继续轮询,限流立即停止,全部失败返回 DrivePollError;调用方附带 --as 的续查命令 - drive task-result 新增 wiki_move / wiki_move_to_drive / wiki_delete_space 场景(新增 GetWikiMoveTask) - CreateExportTask、task_check、metas/batch_query、docs_ai fetch 先解析业务码再判 HTTP 状态 - 导出文件下载改为流式 + 重试 + 原子写 - 分页续翻提示中的 page_token 按 shell 规则加引号
- comment list 新增 --page-token/--page-all/--page-limit,has_more 时 stderr 提示 page_token; 新增 --solved-status/--comment-scope 过滤(服务端 is_solved/is_whole) - comment list 输出 content(正文可读文本)与服务端原始 reply_list(过去 reply_list 从未填充,正文丢失); 回复按 create_time 排序后取根回复作为正文 - comment reply list:content 渲染 @user_id 与文档链接(过去只拼 text_run),新增 elements 原始结构,支持分页 - CreateCommentReply / CreateNewComment 及新增读接口改用 CheckAPIResponse,业务码随 HTTP 400 下发时 返回 code=N 而不是 HTTP 400 原文
…comment 支持 sheet/slides/base/file 锚点 - comment get(过去帮助里列出但命令不存在)与 batch-get 走 comments/batch_query(实测单条 GET 端点对 docx 返回 1069307) - comment reply update:整体替换回复内容(--text / --content),--dry-run;1069303/1069302 给出身份与链接提示 - comment reply react:添加/取消表情回应,--emoji 按平台枚举本地校验(区分大小写) - drive add-comment:新增 --type,--block-id 支持 sheet 单元格 <sheetId>!<cell>、slides <type>!<xml-id>、 bitable 记录 <table>!<record>!<view>,file 全文评论;wiki 解包后支持上述类型; text 元素合计 10000 字符本地预检;--content 解析错误按用法错误退出(exit 2)
- 身份:读命令 --as user|bot|auto(默认 user);note transcript 仅 User; meeting-join/leave 仅 Bot(传 --user-access-token 报错) - vc note transcript:按纪要类型分流(normal 读 verbatim 文档 / unified 走统一逐字稿), format=markdown|plain_text、locale、翻页与 121002 提示 - meeting-events:events 字段、--page-all、拒绝 9 位会议号、120002/120003 说明 - 新增 vc meeting list-active、meeting-join --call-id/--action - minutes get 选择性产物与逐字稿写文件、2091005 申请权限需先征得同意 - minutes search 新参数名与 participant-ids/me、固定 create_time_desc 排序 - vc notes 新增 note_id / note_display_type / hint;新增逐字稿读取工作流 - evals 同步 join/leave 仅 Bot 的预期
…、评论分页/过滤/编辑/表情与锚点评论 - 修正 perm 工作流中「User Token 不适用于权限 API」的错误说法,补 1063004/1063002 排障 - comment 工作流补 get/batch-get、reply update/react、分页过滤与输出结构说明 - drive 工作流补 add-comment 的 sheet/slides/base/file 锚点示例与 apply-permission 1063006/1063007 说明
…t 与凭证探测、create-app 品牌切换
- ListMessagesOptions 新增 OnlyThreadRootMessages,群聊容器下发 only_thread_root_messages=true (对齐官方 im_chat_messages_list.go):话题群回复不再同时出现在 items 与 thread_replies, 也不再占用翻页额度;回复统一由 ExpandThreadReplies 展开。 - 消息列表/详情/mget/群搜索/书签/消息搜索/文档搜索/drive 搜索等调用点改为 ParseAPIResponse:业务错误随 HTTP 4xx 下发时保留 code/log_id,HasAPICode 分支可用。
- BaseV3Call/BitableV1Call 先解析飞书业务信封:业务错误随 HTTP 4xx 下发时
仍保留 code=N 与 data.error.hint/path,并可 AsAPIError 取 log_id 等诊断
- 新增 BaseV3CallAny,返回非对象 data(视图 group/sort/visible_fields 为数组)
- 800004135(按接口方法限流,请求未执行)按 1s/2s/4s 有限重试
- 去掉对所有接口 data 顶层 "{" 开头字符串的反序列化(会误改用户名称/描述),
改为 UnwrapBaseRoleData 只用于角色接口:解开多层 data、检查内层 code、
解码 base_roles 每项二次序列化的 JSON
服务端对 thread 容器忽略 start_time/end_time,且历史帮助写的是毫秒(服务端要秒)。 现不再把时间范围发给服务端,按消息 create_time 本地过滤当前页(秒/毫秒/RFC3339/日期均可, 结束时间含整秒边界),has_more 时 stderr 提示继续翻页;起点晚于终点按用法错误退出。
- 列表模式 --folder inbox/收件箱/自定义名称 解析为 folder_id(此前原样透传被服务端 4038 拒绝),--label 同理 - 新增 --max(1-400,--page-size 为别名)内部自动翻页,重复 page_token 防护 - 列表路径经 batch_get(format=metadata) 补全 时间/发件人/主题;搜索路径取搜索元信息 - 文本模式输出表格并提示下一页;JSON 保留 items,新增 messages/count/mailbox_id,has_more/page_token 为翻页后的状态 - --list-folders/--list-labels 文本模式输出表格
对齐官方 im +messages-send/+messages-reply:--markdown 正文与 msg_type 为 text/post 的 --content/--content-file 也修正 <at id=...>/<at open_id=...>/<at user_id=.../> 写法。 JSON 消息体先解码再逐字符串规范化后重新编码(不转义 HTML、保留数字精度), 避免直接正则替换 JSON 串写入未转义的双引号;无改动时原样返回。
P0: - record list 默认显式下发 limit=100(服务端不传只给 20 条),has_more 时输出 next_offset 并在 stderr 提示;新增 --page-all 按 offset 翻页(rev 变化告警、 表结构变化报错、空页防死循环、1000 页上限),--limit 校验 1-2000 - field list / view list / table list 按 total 取全(每页 500,按 id 去重:实测字段 列表跨页顺序不稳定);table list 显式 --offset/--limit 时保留单页并提示续翻 - record batch-delete 上限 500→200(实测 201 报 800010701),超出自动按 200 条 串行分批,失败即停并注明已删除条数 - form field delete 新增 --keep-field(只移除题目、保留字段与数据);不带时视为 危险操作:stderr 明确提示删除整列数据,走确认门禁(非交互需 --yes,dry-run 免确认) - bitable create/copy 文本模式按平铺响应打印 base_token/name/URL - 视图配置 get/set 输出解包后的 data(group/sort/visible_fields 原先输出整个信封), visible-fields set 支持直接传数组,--help 改为 base/v3 结构 - role list/get/create/update/delete 走角色专用解包 P1/P2: - --base-token 接受 /base/、/wiki/ 链接(wiki 经 node_by_token 换出并校验 obj_type) - 新增 bitable resolve --url(/base/ ?table= 经 blocks/list 判型、/wiki/、/record/、 表单分享链接)与 bitable block list - bitable create 新增 --table-name/--fields;table create 新增 --fields - workflow/form/dashboard list 未传 --page-token 时自动翻页(重复游标防护) - record list/search 与 view-sort-set 的排序条件 ≤10 本地校验 - data-query 本地校验 datasource 与 dimensions/measures,--help 改为实测可用 DSL
随 HTTP 4xx 下发的业务码(如 400002577 应用不存在)过去被报成 "HTTP 400: body", 按业务码分支的恢复提示走不到。
…--wait - html-publish 过去只返回 release_id,拿不到构建结果与访问链接;--wait 每 20s 轮询 release 直到 finished(输出 online_url)/ failed(输出 error_logs 并非零退出), 进入人工审批(current_status=PENDING)时停止并提示审批链接,超时报告当前状态 - release get 展平 data.release,current_node_info 的 camelCase 统一为 snake_case(对齐官方) - release list 支持 --status/--page-size/--page-token,has_more 时 stderr 提示续翻游标 - html-publish / release get 校验 app_ 前缀(meta_token 提示先 apps get 换 app_id)
- --app-type 改为 html / frontend / full_stack;旧写法 HTML 等保留为兼容别名(归一为小写,stderr 提示) - FEISHU_CLI_AGENT_NAME(兼容 LARKSUITE_CLI_AGENT_NAME)非空时请求体带 source_agent - apps list 去掉 Hidden,新增 --keyword / --ownership / --app-type,manifest hidden_commands 同步移除 - 修正 apps 帮助中 --scope"替换"的错误说法:auth login 是增量授权
业务错误随 HTTP 400/403 下发时返回带 log_id 的 *APIError,1063013(降级需审批)、 1063002(无权限)等密级标签专门提示真正可达
…/表单分享设置
- dashboard block create 的 --type 补 ranking(排行榜)、nps(NPS 图,需评分字段),
二者缺 --data-config 时本地报错
- block create/update 新增 --position(12 列栅格 {x,y,w,h},四键必须为数字)
- 新增 dashboard block get-data(GET dashboards/blocks/:block_id/data,读取图表计算结果)
- 新增 dashboard share get/update 与 form share get/update(base/v3 share 端点,
update 每次只改一个字段,布尔字段支持 =false 显式关闭)
- 导入层按 MediaRef 补齐资源:图片/附件/视频的 feishu://media/<token> 先下载原素材再上传到新块并 replace_image/replace_file(跨文档 token 直接绑定会报 1770013);保留原显示宽高与对齐;附件上传到 View 块下的 File 块(建 File 块服务端返回外层 View);下载失败时把空块替换为占位文本并计入 failures - <whiteboard token> 复制源画板:Mermaid/PlantUML 生成的画板按 section 节点里的 syntax 源码重新导入, 其余逐节点复制,都失败时插入源画板图片(whiteboard_as_image),再失败才占位并计入 failures - 分栏:不再显式创建 grid_column(1770028),列内容写入建 Grid 时服务端生成的列,并清理列内自动空块 - 建块被拒(1770001/1770028/1770030/99992402)的批次逐块隔离,问题块计入 failures(kind=blocks), 其余内容照常写入;权限/文档不存在等致命错误停止后续建块,但仍走完输出(-o json 含 document_id/url/ partial_failure/failures)并以退出码 1 结束;doc add 共用嵌套创建、分栏与资源补齐逻辑 - --document-id 接受 /docx/、/wiki/ URL;JSON 新增 file_*、whiteboard_*、blocks_failed 统计
doc export -o 指定输出文件时,下载的图片/视频/画板引用改写为相对输出文件所在目录的路径 (--assets-dir 可为任意相对/绝对路径),doc import 按 Markdown 目录解析相对路径即可原地再导入; 输出到 stdout 时保持相对当前目录。含空白/括号的路径在 Markdown 链接中用 <...> 包裹。
- doc get/blocks/add/add-board/add-callout/update/delete/batch-update/table 的文档参数接入 resolveDocxArg, 接受 docx token、/docx/ URL 与 /wiki/ URL(wiki 自动解析为底层 docx);doc delete 的 <block_id> 与文档参数 相同时视为文档根块 - doc export-file 接入 resolveResourceArg:/docx/、/sheets/、/base/ URL 按路径推断 --doc-type,与显式 --doc-type 冲突时报错,/wiki/ URL 解包为底层文档 - doc --help 按读取/创建导入/编辑分组列出全部子命令(补 read、history、add-board、add-callout、batch-update) - doc media-download --help 补充单个素材 100MB 上限说明
… 帮助默认值 - markdown patch 与 overwrite 一致:未传 --name 且读不到远端文件名时拒绝写回,不再以 <token>.md 静默改名; 新增 --name 显式指定写回文件名,dry-run 计划同步 - markdown create/fetch/overwrite/patch/diff 的参数校验错误统一用 clierr.Usagef(退出码 2) - markdown diff --help 中 --format 默认值不再显示为 json(缺省输出 unified diff 文本)
- import 工作流与 doc-guide:扩展标签表改为 token 素材复用/画板复制/表格引用降级为链接;分栏与嵌套引用、 列表多段落、单元格公式的新行为;roundtrip 两条路径(token 与 --download-images)均可原地再导入; 失败判定补充 blocks/file/whiteboard/sheet/bitable 等 kind 与阶段一失败仍输出 JSON - export:--download-images -o 时资源路径相对输出文件;export-file 接受 URL - write/read:doc get/blocks/add/... 与 import --document-id 接受 URL(htmlbox 除外);分栏可由 doc import/add 写入 - markdown:patch 读不到远端名 fail-closed、参数错误退出码 2、diff --format 缺省为文本 - CLAUDE.md「Markdown ↔ 飞书文档双向转换」同步支持语法与往返说明
实测单次建块请求出现第 6 个画板即 1770035 resource count exceed limit,与文档已有画板数无关; 图片、附件不受此限。doc export 的 Markdown 含较多 <whiteboard token> 时,doc import 在第二批中止、 doc add 直接失败。blockBatchRanges 按「≤50 块且 ≤5 画板」切批,1770035 同时加入逐块隔离兜底, 并在错误提示中说明上限。技能文档补充 doc add 不把 Mermaid 代码块转画板。
…高亮说明 本地引擎导出会把 _ * 等转义成 \_,按原文搜索 ANCHOR_TOKEN 之类的词此前无法命中; doc blocks --raw 实际输出纯文本(raw_content)而非 JSON;doc get/blocks 已接受链接,删除过时说法; <mark> 高亮实际以下划线近似导入,CLAUDE.md/README 如实说明;表格导出已知问题按往返实测更新。
- AtomicWriteFile / AtomicWriteFrom 入口先调用 ValidateOutputPath,任何经它写出的用户文件 都不会落进 ~/.ssh、~/.feishu-cli、/etc 等敏感目录(用法错误,不留临时文件) - 新增 AtomicWriteFileTrusted / AtomicWriteFromTrusted,仅供 CLI 自管路径使用; config create-app --save 写 ~/.feishu-cli/config.yaml 改用 Trusted 变体 - 新增 MkdirAll(校验后建目录)与 StatInputFile / OpenInputFile / ReadInputFile / InputFileError: 输入文件敏感目录、不存在、是目录、无权限读取统一为带路径的中文用法错误(退出码 2) - readLocalInputFile 改走 safefile.ReadInputFile;safeOutputPath 把 "." / ".." 文件名收敛为 "_"
- GetBoardImage 请求前校验输出路径,目录/文件改走 safefile.MkdirAll + AtomicWriteFile(原为 os.WriteFile) - DownloadFromPresignedURL 发起下载前校验输出目录,建目录改走 safefile.MkdirAll - 上传入口(IM 图片/文件、云盘上传与覆盖、素材上传、文档素材、多维表格附件、表格图片、OKR 图片、 任务附件、导入素材)函数入口兜底 ValidateInputPath,命令层漏校验时也不会把凭证发往远端 - 原生 Markdown 上传 / diff 读取与画板图表文件读取改走 safefile(敏感目录、不存在、是目录为用法错误) - whiteboard-cli 本地引擎读取的源文件同样校验;邮件内嵌图片在 home 安全根内仍拒绝 ~/.ssh 等凭证目录
- --download-images 建资源目录改走 safefile.MkdirAll(敏感 --assets-dir 报用法错误、不下载) - 视频资源文件名来自文档内容,路径分隔符替换为 "_","."/".." 回退默认名,防止经 "../" 写出 --assets-dir
- output.ParseOptions 解析 -o 时即校验(命令在发请求前解析选项),Render 写文件改走 safefile.AtomicWriteFile 兜底 - event consume --output-dir 的相对路径同样按敏感目录拒绝名单校验(cwd 为家目录时的 .ssh 等), 建目录改走 safefile.MkdirAll
此前 doc export -o ~/.ssh/x.md 会真实写入敏感目录,markdown fetch / doc export-file / drive export 等先发请求(甚至先建导出任务)后才处理路径。现在: - doc export(-o、--assets-dir)、doc export-file、drive export / export-download、markdown fetch、 wiki export / export-tree(含 --assets-dir)、sheet export、board svg-export / export-code / image、 board update --snapshot、doc media-download、file download、drive download / version-get、 msg resource-download、minutes download、vc notes --output-dir、bitable record download-attachment 在 token 刷新、wiki 解析、创建导出任务等任何网络请求之前校验输出位置,违规为用法错误(退出码 2) - 默认落在当前目录的输出(doc export-file / sheet export 未传 -o)在创建导出任务前校验 - 写入改走 safefile.AtomicWriteFile / MkdirAll(board svg-export、export-code、update --snapshot、 markdown fetch、wiki export / export-tree 原为 os.WriteFile 非原子写) - markdown fetch 存到目录、wiki export 默认 /tmp/<标题>.md 时文件名收敛为单段,防止远端名含 "/" 越出目录 - msg resource-download 按服务端文件名改名前对最终路径再校验 - drive pull / push / status 的 --local-dir 拒绝敏感目录(cwd 为家目录时的 .ssh 也在 cwd 子树内), 并先于 --delete-* 的 --yes 确认检查;--local-dir 不存在 / 不是目录改为用法错误 - skills install --dir 解析符号链接后拒绝敏感目录 - bitable record upload-attachment 的 --file 敏感目录检查前移到 wiki 链接解析之前(dry-run 不要求文件存在)
此前 doc import ~/.ssh/x.md、doc add <id> ~/.ssh/x.md 读本地文件不走 ValidateInputPath, 文件不存在时退出码 1。现在: - doc import / doc add / doc update / doc batch-update / doc htmlbox --html-file / doc media-insert、 markdown create / overwrite / diff、board update / import / create-notes / svg-import / upload-image、 drive upload / import、file upload、media upload、doc import-file、msg send/reply/edit 的 --image / --file / --attachment / --content-file、task upload-attachment、slides media-upload、 okr upload-image、sheet import-md、sheet image write-batch --manifest、bitable record --from-file、 perm batch-add --members-file 统一拒绝敏感目录;不存在 / 是目录 / 无权限读取为带路径的用法错误(退出码 2) - doc add / doc update / doc batch-update 先读本地文件再解析 wiki 链接;drive upload、slides media-upload、 markdown diff 等在任何网络请求(含 token 刷新)之前完成本地文件检查 - doc import 解析 Markdown 引用的本地图片 / 附件时拒绝敏感目录(按绝对路径判断,../images/a.png 这类相对 Markdown 目录的引用照常放行),被拒的单张图片计入 failures,不影响整篇 - apps html-publish --path 及目录内每个文件拒绝敏感目录(不受 --allow-sensitive 影响,dry-run 同样非零退出) - board import 的本地图表文件:敏感目录在 dry-run 前拒绝,存在性检查在联网前完成 - markdown create 先检查 --content-file 再按文件名推断 --name,目录参数给出"是目录"而不是名字后缀错误 - doc add 缺少源、doc update 缺少内容、drive upload / import 的参数错误改为用法错误(退出码 2)
- agent-contract:校验先于任何网络请求、覆盖的输出/输入参数、Markdown 引用图片计入 failures、 输入文件不存在/是目录/无权限同为退出码 2 - docs export:wiki export 默认文件名收敛规则;敏感输出目录联网前拒绝 - drive 镜像:--local-dir 拒绝敏感目录且先于 --delete-* 确认检查 - event:--output-dir 相对路径同样拒绝敏感目录
board export-code / svg-export、drive export 此前返回 1,与 markdown fetch、doc media-download 的 2 不一致; board 两条命令改为在发请求前就拒绝,不再先拉取画板再报错。
v2.0.0 含不兼容的行为变更,按 Go 大版本规则模块路径须带 /v2 后缀,否则 go install ...@latest 会忽略 v2 tag、继续安装 v1.x。改写全部 import;构建脚本注入的是 main.Version,不受影响; go install 产物名仍为 feishu-cli。 BREAKING CHANGE: go install 改为 github.com/riba2534/feishu-cli/v2@latest
9 个 SKILL.md 的 compatibility、README 配套版本与 go install 说明、CLAUDE.md 中的 v1.42+ 标注统一为 v2.0; 迁移指南逐条给出受影响的旧用法与改法(退出码、--yes、日历/任务身份、bitable 默认条数与输出结构、 search docs 翻页、邮件正文、user_id、OKR 周期、话题群回复、逐字稿文件、export-code 覆盖、api 错误输出等)。
This reverts commit 9795f79.
版本号升级为 v2.0.0,但模块路径保持 github.com/riba2534/feishu-cli(不加 /v2)。按 Go 版本规则 go install 无法安装 v2 tag,README 与迁移指南改为说明这一点并指向一键安装脚本、Release 包或源码编译; 同步把 calendar_common.go 注释中的版本号改为 v2.0。
按维护者决定继续使用 1.x 版本号(模块路径不变,go install @latest 照常可用):SKILL.md compatibility、 README、CLAUDE.md、注释与脚本示例中的版本号恢复为 v1.42;CHANGELOG 保留「从 v1.41 及以前升级」迁移指南, 去掉 go install 一行。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概述
对照飞书官方 CLI(
larksuite/cli)做的一次全量对齐。按 11 个领域逐项比对源码与服务端契约,修复了一批"代码自洽、但与服务端实际行为不符"的缺陷,补齐了官方已有、本项目缺失的高价值能力。本项目比官方更稳妥的设计都原样保留,包括:
api --page-all出错即失败。这次修复的大部分缺陷,
gofmt、go vet、go test都发现不了,每一条都是用编译后的二进制在真实飞书环境里复现、修复再复验的。发版号为 v1.42.0(按维护者决定继续使用 1.x,模块路径不变,
go install ...@latest照常可用);9 个 SKILL.md 的compatibility已同步为 v1.42.0+。下文"行为变更"中的条目会改变部分旧用法,
CHANGELOG.md的[Unreleased]开头有迁移指南,逐条列出受影响的旧用法和改法;退出码分类保留。== 1的脚本需要调整--yes(或--force)时 exit 10 且不执行。此前打印"操作已取消"后 exit 0,Agent 会误判为成功--as auto(已登录即本人身份);calendar event-reply改为必须 Userrecord list默认 100 条(原 20 条且无提示);table/field/view list 返回全量;视图配置 get/set 直接输出数组;role输出去掉外层datadelete-rows/delete-cols/protect的--start/--end按文档语义换算为接口口径(原来会多删一行 / 保护范围错位)doc import部分失败 exit 1;content-update纯文本选择器改为文本级替换,块级模式多处命中 exit 2--raw-body保留原值);draft-edit改为局部修改vc bot meeting-join/leave仅支持 Bot;minutes get --with-artifacts的逐字稿改为写入文件file delete改为异步并轮询msg history只返回根消息;user search --query改走 v3 接口,不再返回user_idcycle list默认查 v2 用户周期(与cycle detail的 ID 一致),旧的租户周期用--tenant--raw例外)search docs改走 Search v2:每页最多 20 条(原 50),翻页改用--page-token,--offset大于 0 时报用法错误board export-code --output-path的目标文件已存在时默认报错,覆盖需要加--overwrite(原来静默覆盖)主要修复
会丢数据或有安全风险的
drive push --if-exists overwrite原来是先删后传。现在带 file_token 原地覆盖:token、链接、协作者、评论都保留。实测覆盖后 token 不变;旧版 token 会变。sheet delete-rows --start 2原来会删掉第 2、3 两行。实测现在只删第 3 行。doc content-update replace_all "旧"→"新"原来会覆盖整段。现在是文本级替换,粗体等样式也保留。另外,本地导出的 Markdown 写回时,原来画板会被静默清空;现在先转换,无法转换的直接拒绝。--keep-field和确认门禁。apps html-publish原来会把.git一起打包发布到公网。~/.ssh、~/.aws、~/.feishu-cli、/etc等敏感目录。与服务端契约不符的
get_node迁移到node_by_token。?from=/wiki/不会再误导解析。api --data和表格写入中的大整数不再被舍入。In-Reply-To补尖括号;draft-edit不再丢失回复头和附件。vc note transcript按官方协议重写;meeting-events原来文本模式永远显示 0 条;妙记搜索固定排序后翻页不再漏条。auth status --verify刷新 token 时加锁;刷新失败按错误码分类。table-put覆盖写入后,数值被存成了文本。补齐的能力(节选,完整列表见 CHANGELOG)
content-update支持--block-id和本地资源;doc read --engine docs_ai --with-ids;doc create --content;doc history。apps html-publish --wait,可拿到访问链接或构建错误。--apply-to、分享链接、参会人管理。vc meeting list-active。@file/stdin 统一输入、附件区、msg edit、联系人 v3 搜索。skills install:技能内嵌进二进制,与 CLI 版本严格配套;doctor检测技能版本漂移;--help末尾指向相关技能;update命令、auth scopes;make release-package、make check-privacy。技能目录 review 与文档实测(本轮追加)
技能目录(9 个领域技能逐条核对;依据是新二进制的
--help、源码和实跑结果)修正过时或错误的说法:身份、默认值、输出字段、退出码,以及示例的参数与取值。
新增 Agent 调用契约
feishu-cli-platform/.../auth/references/agent-contract.md,内容包括:各领域 SKILL.md 末尾统一指向它。
内容按命令归属迁移:
msg、chat之间互相调整;drive add-comment迁到 comment;drive apply-permission和drive secure-label迁到 perm;drive search迁到 platform/search。跨工作流的命令组必须使用显式前缀,命令组的
--help会列出全部相关工作流。make check-skills会强制检查这两条。身份表
identity.md按--help逐条核对过。9 个 description 统一改为单行,结构为"能力 → 何时用 → 不用于"。
评测数据:
trigger-evals.json替换 17 条,仍是每个领域 8 个正例;trigger-boundary-evals.json新增 11 条;evals.json为新增的命令组补了 21 条用例。review 中顺带修复的 Go 缺陷
msg read-users:已登录时必然失败。改用原始请求,新增--as。file version create:数字 status 解析错误,会把成功误报为失败,导致重复建版本。vc notes在会议号和日历路径下也会补拉纪要产物;minutes download同批同名文件自动改名。--format只接受服务端支持的取值;thread-modify的错误提示改为指向thread-trash。search docs迁移到官方使用的 Search v2 端点:每页最多 20 条,翻页用--page-token。okr comment create --select-all配--content-json时选区为空;board export-code原来静默覆盖已有文件,现在需要--overwrite;文档转换器(这些都是全块类型往返实测时发现的)
doc export导出的<image/file token>、<whiteboard token>、视频重新导入时,原来整篇报 1770001 失败。现在下载原素材重新上传,画板按源码重建或复制节点。--download-images时资源路径改为相对输出文件。doc add则直接失败。doc read --keyword能命中导出时被转义的词。本地路径安全(E2E 实测发现的 P0,已系统性修复)
doc export <文档> -o ~/.ssh/x.md会真实写入~/.ssh。markdown fetch、doc export-file、drive export等十余个命令也有问题:要么先发请求或先建导出任务再处理路径,要么不经校验直接写文件;doc import、doc add读取本地文件时也不校验路径。doc export -o到敏感目录、--assets-dir、markdown fetch、export-file、drive export、board image、api -o、drive pull --local-dir,以及输入文件不存在或是目录:AF_INET连接数为 0,仅有查询本机 nscd 的AF_UNIX连接(对照组有 19 次AF_INET);api -o、auth status、skills install。飞书文档 / 画板 E2E 实测(两条独立 lane,只用新建的
fp-test-*资源,测完已删除并确认1770003 resource deleted)文档往返:78 项。往返矩阵覆盖:
journey降级、PlantUML、SVG;content-update全部 10 种模式、doc history、原生 Markdown 文件、PDF/DOCX 导出。二次往返除 token 外一致。实测中发现的 8 个问题已全部修复并复测,包括上面的 1770035、关键词搜索和本地路径安全。
画板:43/43 通过,覆盖:
svg-import、upload-image、nodes、image、lint、export-code(含--overwrite);update --overwrite --snapshot、clone(connector 重映射)、delete;svg_to_board.py五步管道(21 个节点,lint 0.90);doc htmlbox全生命周期。技能和 CLAUDE.md 里关于 Mermaid 的旧禁令已删除:字面花括号、方括号内冒号、
par...and...end、11 个参与者的时序图,以及带skinparam、缩进、可见性标记的 PlantUML。删除依据是doc import实测,这些写法全部一次渲染成画板。会议与妙记只做了一项只读调用:用维护者指定的妙记取逐字稿。其余领域按维护者的分工只做静态核对(对齐官方 CLI 的底层 API),没有实际调用。
验证
gofmt -l cmd internalgo vet ./...go test ./...go test -race ./...make check-skillsmake check-privacymake release-package VERSION=v1.42.0-rc集成分支真实回归摘要(写操作只针对新建的 fp-test-* 资源,验证后已删除)
--yes:exit 10,未执行。-o ~/.ssh/x:exit 2,文件未创建。permission_grant=granted;replace_all文本级替换,段落其余文字和样式保留;NOTE callout 为浅蓝;带画板占位的导出写回被拒绝,并列出行号。Sheet1!前缀可用;delete-rows --start 2只删第 3 行;1000000 与 15 位整数原值回读;table-put时分秒往返一致。--page-all拿到 150 条、无重复;批量删除 120 条成功;resolve判型正确。task complete幂等;审批稀疏分页给出续翻提示。event consume:加了 timeout 后,stdin EOF 不再导致提前退出。--markdown @file样式归一、--attachment、msg edit、Bot 身份 reaction、资源下载用服务端文件名、stdin 输入。未能真实验证的部分(只有单测覆盖)
按默认方案处理的决策点(如需调整请告知)
sheet_ai端点。图表、条件格式、透视表依赖它,列为后续。--engine docs_ai、doc create --content。--wait),db/file/env 等约 90 个命令暂不做。合并后需要人工处理的一项
回归时留下了一个无法自动删除的测试日程:
fp-test-att,2026-11-30 07:00–07:30。它的组织者被转给了应用机器人,而应用没有租户级的日历删除权限。这个日程只出现在本人和机器人的日历上,请在飞书客户端手动删除。