架构: - 单 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` 覆盖
12 KiB
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 workspace(resolver = "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 Skills(14 个,导航见 docs/skills.md) |
docs/ |
持续维护的使用与开发文档(入口 docs/README.md) |
模块职责
crates/wecom(lib)
| 模块 | 职责 |
|---|---|
client/ |
Client/ClientBuilder(builder.rs);run.rs 的 CliRun 负责 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-run;doc.rs --doc;alias.rs path_alias 隐藏别名;service_handle.rs/method_handle.rs 程序化句柄 |
registry/ |
discovery 服务目录、schema 拉取与缓存(<config_dir>/cache,TTL 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 层统一错误(错误码段 893000–893099);后台 errcode 经 transport 透传 |
telemetry/ |
lib 侧 telemetry 事件 |
ClientBuilder 主要配置点:transport、endpoint_catalog(整体/逐 key 覆写端点目录)、command(扩展顶层命令,优先于同名服务)、helper、bin_name、cwd/home_dir/tmp_dir、readable_dirs/writable_dirs(沙箱)、path_resolver。
crates/wecom-cli(bin)
| 模块 | 职责 |
|---|---|
main.rs |
装配入口:加载 .env 与 config.json → 初始化日志与 telemetry → 构建 transport 与 Client → client.run(argv);命令未找到时在 stderr 追加 skill 更新提示 |
auth/ |
鉴权体系:credentials.rs 单一凭据总账 credentials.enc(bot + token,AES-256-GCM,0600);crypto/ 密钥管理(系统 keyring,回退 .encryption_key 文件);qrcode.rs 扫码会话(终端/Unicode/PNG 渲染,轮询 3s、5 分钟超时);bootstrap.rs botid+secret 签名换 token(sha256(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 网关扁平响应信封 NestedRes 与 FlatRes;capability.rs 鉴权能力标记 |
config.rs |
config.json 解析(全字段可选)与环境变量应用;env 优先级高于配置文件 |
env.rs |
WECOM_CLI_* 环境变量常量 |
logging.rs |
WECOM_CLI_LOG_LEVEL(stderr 文本日志)与 WECOM_CLI_LOG_DIR(JSON Lines 按天滚动,前缀 ww.log,UTC+8) |
telemetry.rs |
JSON 自动修复监听:修复成功时向 stderr 输出修复前后对照 |
error.rs |
bin 层统一错误(错误码段 893200–893299) |
crates/wecom-transport(传输层)
| 模块 | 职责 |
|---|---|
traits.rs / transport.rs / builder.rs |
TransportBackend 开放 trait、Transport 统一句柄、TransportBuilder |
http/ |
reqwest HTTP 后端;HttpEndpoint;信封双轴 trait RequestEnvelope/ResponseEnvelope 及默认实现 PassthroughReq/GatewayRes;polling.rs 长任务轮询;resumable.rs 断点续传下载 |
http_client/ |
reqwest 封装(请求/响应/流式 body) |
common/ |
Endpoint、EndpointCatalog<K>/CatalogKey 泛型端点目录、PollEndpoint、RequestOptions、Extensions 扩展袋、统一错误(段 893100–893199) |
dispatch.rs |
TransportRequest(IntoFuture 驱动)、轮询事件 PollEvent/PollCallback |
telemetry/ |
CaptureScope 捕获域,供 bin 侧挂载事件监听 |
关键机制
- 服务发现:
/service/discovery下发服务目录与 schema;结果缓存于<config_dir>/cache(TTL 60 秒),cache status/cache clear管理。 - 信封双轴:请求侧
RequestEnvelope::wrap与响应侧ResponseEnvelope::parse为正交 trait,挂在HttpEndpoint上。transport 仅含默认实现;网关扁平协议(请求{"payload": "<stringified-json>"}、响应{errcode, errmsg, results_json})由产品层注入:PayloadStringReq在wecom/src/client/catalog.rs,NestedRes/FlatRes在wecom-cli/src/transport/envelope.rs。 - 端点目录:非 schema 驱动的 endpoint(服务发现、媒体上传/下载、轮询、schema 方法默认信封)统一登记在
EndpointCatalog;EndpointKey::builtin_default提供内建默认,wecom-cli经transport::endpoint_catalog()覆写(附鉴权能力与扁平信封)。 - 鉴权注入:
WecomBackend按 endpoint 的need_auth动态注入 Bearer token(need_auth=false不注入);token 失效(853004)用 bot 凭据静默换 token 并重放一次。 - 长任务轮询:响应含
taskid时按long_task_poll配置轮询(PollClawLongTask,polling_interval_ms/task_timeout),超时返回错误。 - 指令:schema 中的
x-wecom-*指令在请求前(媒体上传、multipart)与响应后(file-save、octet-stream 落盘)由directive/处理。 - 输出路由:默认 compact JSON 到 stdout;
--output/-o写文件、--output-dir写目录(返回DownloadResultJSON);--page-count自动分页并输出 NDJSON。 - JSON 修复:
--json/--set中的非法 JSON 经 jsonrepair 自动修复,bin 侧监听在 stderr 输出修复前后对照。 - 错误模型:三层嵌套
wecom_cli::Error::Wecom(wecom::Error::Transport(wecom_transport::Error));错误码段 893000–893099 / 893100–893199 / 893200–893299,共享兜底 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 / eslint,commit-msg 跑 commitlint(Conventional Commits),pre-push 跑 pnpm test + pnpm check。
测试约定
- 单元测试随源码
#[cfg(test)]模块组织。 - e2e 分两层:library-level(
crates/wecom/test-e2e/,wiremock)与 process-level(crates/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。