Files
jasonhzhang b2dfa0f1cc feat!: 重构 CLI 架构与命令模型,重做鉴权体系并扩展服务能力
架构:
- 单 crate 拆分为 Cargo workspace,按职责分为三个 crate
- wecom:argv 调度、服务发现、schema 命令树、指令处理、沙箱 FS
- wecom-cli:入口装配、鉴权、配置与日志
- wecom-transport:传输后端、信封、端点目录、长任务轮询

命令模型:
- 调用格式改为 `<service> [resource...] <method> [flags]`
- 服务目录与方法 schema 由服务端下发并本地缓存
- 请求体支持 schema 命名参数、`--json`、`--set` 三种组合方式
- 新增 `--doc` / `--schema` / `--dry-run` 文档、预览与调试能力
- 新增 `--page-count` 自动分页与 `--output` / `--output-dir` 落盘
- 新增 `+` 前缀本地 helper 与内建 `schema`、`cache` 命令

鉴权:
- 命令收敛为 `auth init` / `auth show`,扫码为默认接入方式
- 凭据统一存放于 credentials.enc(AES-256-GCM,0600)
- 密钥优先使用系统 keyring,不可用时回退本地密钥文件
- token 失效时静默换取新 token 并重放一次请求
- 旧版凭据文件在启动时自动迁移

输出与约定:
- 错误以结构化 JSON 输出到 stdout,日志与提示一律走 stderr
- 明确退出码 0 成功、1 运行时错误、2 用法错误
- `--version` 输出携带发行渠道、构建时间与 commit id
- 新增按天滚动的 JSON Lines 日志目录与额外请求头注入
- 新增可选配置文件 config.json,环境变量优先级高于配置文件
- `--json` / `--set` 中的非法 JSON 自动修复并输出前后对照
- 文件落盘由 schema 指令与响应类型决定,默认写入临时目录

能力与 Skills:
- 新增邮件、在线表格、智能文档、微盘、媒体等服务品类
- 文档能力增强:搜索、重命名、成员权限与加入规则管理
- 内置 Skills 扩充至 14 个,改为按需引用的分层结构

工程:
- 引入 lefthook 管理 Git 钩子,pnpm 升级至 11
- 补齐 library-level 与 process-level 双层 e2e 框架
- 重写开发说明与 CLI 命令参考文档

BREAKING CHANGE:
- 调用格式由 `<category> <method> '<json>'` 改为服务/资源/方法路径
- 接口名与参数整体更名,脚本需按 `--help` / `--doc` 逐个核对迁移
- 品类标识调整:`msg` → `message`,`schedule` → `calendar`
- `wecom-cli init` 移除,改用 `wecom-cli auth init`
- `auth show --auth-status` 改为 `auth show --status`
- 错误输出由 stderr 文本改为 stdout 结构化 JSON
- `WECOM_CLI_LOG_FILE` 移除,改用 `WECOM_CLI_LOG_DIR`(传目录)
- 移除 MCP 传输后端与 JSON-RPC 模式
- 移除 service_base_url_override、access_token 等废弃配置
- 落盘规则改变:由 schema 指令与响应类型决定,可用 `--output` 覆盖
2026-08-14 14:50:44 +00:00

12 KiB
Raw Permalink Blame History

AGENTS.md

面向 AI Agent 与贡献者的仓库导览:快速定位关键代码、理解核心机制、正确构建与测试。 本文只描述当前实现;改动代码后若结构或机制发生变化,请同步更新本文。

项目概述

wecom-cli 是企业微信官方 CLI(Rust 实现,经 npm 包 @wecom/cli 分发),覆盖消息、邮件、在线文档、智能文档、在线表格、智能表格、待办、日程、会议、微盘、通讯录等办公能力。仓库同时内置 skills/ 下的 Agent Skills,供 AI Agent 调用 CLI 完成业务操作。

CLI 通过 discovery 协议从服务端动态下发服务目录与方法 schema,再在本地构建 clap 命令树。命令模型(按 Client::run 的调度顺序):

wecom-cli --version | --help                       # 版本与帮助
wecom-cli auth <init|show>                         # 扩展命令:bin 侧经 ClientBuilder::command() 挂载
wecom-cli cache <status|clear>                     # 内建命令:discovery 缓存管理(help 中隐藏)
wecom-cli schema <list|get>                        # 内建命令:服务/方法 schema(help 中隐藏)
wecom-cli <service> --doc | --schema               # 服务级文档(service 由 discovery 下发)
wecom-cli <service> [resource...] <method> [flags] # 远程方法调用(方法参数由 schema 生成)
wecom-cli <service> +<helper> [flags]              # 本地 helper+ 前缀,HelperRegistry 调度)

仓库结构

Cargo workspaceresolver = "3"edition 2024+ pnpm workspace(仅管理 packages/* 平台二进制包):

路径 说明
crates/wecom/ 核心库(lib):Client/ClientBuilder、argv 调度、discovery 与缓存、schema 驱动命令树、指令处理、输出路由、沙箱 FS
crates/wecom-cli/ 二进制(bin):main.rs 装配入口、auth 鉴权体系、config/env/logging、WecomBackend
crates/wecom-transport/ 传输层:TransportBackend trait、reqwest HTTP 后端、信封 trait、端点目录泛型、长任务轮询
bin/wecom.js npm 入口脚本:定位并 exec 当前平台的二进制
packages/* 各平台 npm 二进制包(optionalDependencies 分发:darwin/linux × x64/arm64、win32-x64
skills/* 内置 Agent Skills14 个,导航见 docs/skills.md
docs/ 持续维护的使用与开发文档(入口 docs/README.md

模块职责

crates/wecomlib

模块 职责
client/ Client/ClientBuilderbuilder.rs);run.rsCliRun 负责 argv 调度;invoke.rs/upload.rs 程序化调用;custom_command.rs 扩展命令点;catalog.rs 定义 EndpointKey 内建默认与 PayloadStringReq 请求信封
service/ 服务调用链:handler.rs 服务内分发(helper 优先于 method);command/ 由 schema 构建 clap 子命令树(build.rs/schema_clap.rs)并装配请求体(assemble.rs,命名参数 + --json + --set);execute.rs 执行与游标分页;output.rs 输出路由;preview.rs --dry-rundoc.rs --docalias.rs path_alias 隐藏别名;service_handle.rs/method_handle.rs 程序化句柄
registry/ discovery 服务目录、schema 拉取与缓存(<config_dir>/cacheTTL 60 秒)
schema/ schema 类型、解析、TS 文档生成(ts_doc.rs
directive/ x-wecom-* 指令:UploadMedia(媒体上传)、UploadMultipart(表单上传)、Save(响应字段落盘);请求前与响应后各收集处理一次
builtins/ 媒体上传的内建实现(upload_media.rs
helpers/ Helper trait 与 HelperRegistry:以 + 前缀挂载在任意命令路径上的本地命令
fs/ 沙箱文件系统 Fs(按 readable/writable roots 校验)、PathResolver 路径解析、文件名清洗
constants.rs CLI_INFO/CliInfo:编译期注入的版本信息(--version 输出与 X-WeCom-Cli-Info 请求头)
error.rs lib 层统一错误(错误码段 893000893099);后台 errcode 经 transport 透传
telemetry/ lib 侧 telemetry 事件

ClientBuilder 主要配置点:transportendpoint_catalog(整体/逐 key 覆写端点目录)、command(扩展顶层命令,优先于同名服务)、helperbin_namecwd/home_dir/tmp_dirreadable_dirs/writable_dirs(沙箱)、path_resolver

crates/wecom-clibin

模块 职责
main.rs 装配入口:加载 .envconfig.json → 初始化日志与 telemetry → 构建 transport 与 Clientclient.run(argv);命令未找到时在 stderr 追加 skill 更新提示
auth/ 鉴权体系:credentials.rs 单一凭据总账 credentials.encbot + tokenAES-256-GCM0600);crypto/ 密钥管理(系统 keyring,回退 .encryption_key 文件);qrcode.rs 扫码会话(终端/Unicode/PNG 渲染,轮询 3s、5 分钟超时);bootstrap.rs botid+secret 签名换 tokensha256(secret+bot_id+time+nonce));legacy_migration.rs 启动时旧版 bot.enc 自动迁移(失败静默降级、旧文件保留)
cmd/auth.rs auth init / auth show 的 clap 定义与处理,经 CustomCommand 挂载
transport/ backend.rs WecomBackend:按 endpoint 的 AuthRequirement 动态注入 Authorization: Bearer,命中 853004 时静默刷新 token 并重放一次(仅 JSON 载荷可重放);catalog.rs 产品层端点目录覆写;envelope.rs 网关扁平响应信封 NestedResFlatRescapability.rs 鉴权能力标记
config.rs config.json 解析(全字段可选)与环境变量应用;env 优先级高于配置文件
env.rs WECOM_CLI_* 环境变量常量
logging.rs WECOM_CLI_LOG_LEVELstderr 文本日志)与 WECOM_CLI_LOG_DIRJSON Lines 按天滚动,前缀 ww.logUTC+8
telemetry.rs JSON 自动修复监听:修复成功时向 stderr 输出修复前后对照
error.rs bin 层统一错误(错误码段 893200893299

crates/wecom-transport(传输层)

模块 职责
traits.rs / transport.rs / builder.rs TransportBackend 开放 trait、Transport 统一句柄、TransportBuilder
http/ reqwest HTTP 后端;HttpEndpoint;信封双轴 trait RequestEnvelope/ResponseEnvelope 及默认实现 PassthroughReq/GatewayRespolling.rs 长任务轮询;resumable.rs 断点续传下载
http_client/ reqwest 封装(请求/响应/流式 body)
common/ EndpointEndpointCatalog<K>/CatalogKey 泛型端点目录、PollEndpointRequestOptionsExtensions 扩展袋、统一错误(段 893100–893199
dispatch.rs TransportRequestIntoFuture 驱动)、轮询事件 PollEvent/PollCallback
telemetry/ CaptureScope 捕获域,供 bin 侧挂载事件监听

关键机制

  • 服务发现/service/discovery 下发服务目录与 schema;结果缓存于 <config_dir>/cacheTTL 60 秒),cache status/cache clear 管理。
  • 信封双轴:请求侧 RequestEnvelope::wrap 与响应侧 ResponseEnvelope::parse 为正交 trait,挂在 HttpEndpoint 上。transport 仅含默认实现;网关扁平协议(请求 {"payload": "<stringified-json>"}、响应 {errcode, errmsg, results_json})由产品层注入:PayloadStringReqwecom/src/client/catalog.rsNestedRes/FlatReswecom-cli/src/transport/envelope.rs
  • 端点目录:非 schema 驱动的 endpoint(服务发现、媒体上传/下载、轮询、schema 方法默认信封)统一登记在 EndpointCatalogEndpointKey::builtin_default 提供内建默认,wecom-clitransport::endpoint_catalog() 覆写(附鉴权能力与扁平信封)。
  • 鉴权注入WecomBackend 按 endpoint 的 need_auth 动态注入 Bearer tokenneed_auth=false 不注入);token 失效(853004)用 bot 凭据静默换 token 并重放一次。
  • 长任务轮询:响应含 taskid 时按 long_task_poll 配置轮询(PollClawLongTaskpolling_interval_ms/task_timeout),超时返回错误。
  • 指令schema 中的 x-wecom-* 指令在请求前(媒体上传、multipart)与响应后(file-save、octet-stream 落盘)由 directive/ 处理。
  • 输出路由:默认 compact JSON 到 stdout--output/-o 写文件、--output-dir 写目录(返回 DownloadResult JSON);--page-count 自动分页并输出 NDJSON。
  • JSON 修复--json/--set 中的非法 JSON 经 jsonrepair 自动修复,bin 侧监听在 stderr 输出修复前后对照。
  • 错误模型:三层嵌套 wecom_cli::Error::Wecom(wecom::Error::Transport(wecom_transport::Error));错误码段 893000893099 / 893100893199 / 893200893299,共享兜底 893999;后台 errcode 原样透传;后台返回 10021 时渲染当前命令 help 并以退出码 2 返回。退出码约定:0 成功/帮助/版本,1 运行时错误,2 用法错误。
  • 沙箱 FS:文件读写经 Fs 按沙箱根校验(如 auth init --output-qrcode 仅允许解析后落在当前目录内的路径,相对/绝对皆可)。

构建与测试

常用命令(pnpm 脚本封装 cargo,定义见 package.json):

pnpm fmt         # rustfmt +nightly 格式化全部 Rust 代码
pnpm lint        # cargo clippy --workspace --all-targets -- -D warnings
pnpm test        # cargo test --workspace --all-targets --features custom-endpoint
pnpm check       # cargo check --workspace --all-targets

# 本地构建并运行
cargo run -p wecom-cli -- --help

e2e 套件(规范见 docs/e2e/):

cargo test -p wecom --test e2e                                    # library-level
cargo test -p wecom --test e2e --features custom-endpoint         # 含 custom-endpoint 用例
cargo test -p wecom-cli --test e2e --features custom-endpoint     # process-level(须带 feature
cargo test -p wecom --test e2e run::method_call                   # 单个用例

Git 钩子由 lefthook 管理(pnpm install 时自动安装):pre-commit 跑 rustfmt --check / clippy / eslintcommit-msg 跑 commitlintConventional Commits),pre-push 跑 pnpm test + pnpm check

测试约定

  • 单元测试随源码 #[cfg(test)] 模块组织。
  • e2e 分两层:library-levelcrates/wecom/test-e2e/wiremock)与 process-levelcrates/wecom-cli/test-e2e/assert_cmd + mockito)。每个用例为 cases/<group>/<NNN>-<slug>/{desc.md,test.rs}desc.md 规范见 docs/e2e/DESC_SPEC.md,代码生成手册见 docs/e2e/CODEGEN.md
  • custom-endpoint 为内部 feature(注入 WECOM_CLI_BASE_URL 等测试端点),仅用于开发与 e2e,不随发布构建启用,也不写入用户文档。

文档地图

文档 内容
README.md 项目首页(功能范围、安装、快速开始)
docs/cli-reference.md CLI 使用参考:命令模型、auth、参数与 flag、运行时路径、环境变量、退出码
docs/skills.md 内置 Agent Skills 导航
docs/development.md 仓库结构与本地开发说明
docs/e2e/ e2e 框架方案、desc.md 规范与生成手册
docs/skill-trimming-guide.md Skill 精简指南

维护约定

  • 文档只描述现状,不记录历史实现与变更过程(变更历史归 CHANGELOG.md 与 git)。
  • 同一主题只保留一个主入口,其余页面通过链接复用,避免多处维护漂移。
  • 用户可见行为(命令、flag、环境变量、路径、错误码)变化时,同步更新 docs/cli-reference.md;结构或机制变化时,同步更新本文与 docs/development.md