Files
muling.cs 73c063a53e fix(auth): defer legacy ciphertext-mismatch repair until fresh login
Allow OAuth, device, auth-code, PAT, and --token reauthorization to start
when the legacy auth-token ciphertext has a confirmed DEK mismatch or a
missing DEK. The old ciphertext is preserved until fresh credentials are
available, then only the slots targeted by that login's persistence plan
are replaced. Transient and unclassified Keychain failures still fail
closed.
2026-09-21 18:09:33 +08:00

46 KiB
Raw Permalink Blame History

DingTalk Workspace CLI (dws)

dws — 钉钉工作台命令行工具,为人类和 AI Agent 而生。

DWS Product Overview

Go 1.25+ License Apache-2.0 Latest Release CI Coverage

中文版 · English · 参考手册 · 更新日志

Important

钉钉 DWS CLI 已全面开放,欢迎使用:本项目涉及钉钉企业数据访问,需企业管理员授权后方可使用。欢迎加入钉钉 DWS 共创群获取支持与最新动态。详见下方 开始使用。

dws 开源沟通群二维码
目录

为什么选择 dws?

  • 为人类而设计 — --help 查看用法,--dry-run 预览请求,-f table/json/raw 切换格式。
  • 为 AI Agent 而设计 — 结构化 JSON 响应 + 内置 Agent Skills,开箱即用。
  • 为企业管理员而设计 — 零信任架构:OAuth 设备流认证 + 域名白名单 + 权限最小化。没有一个字节能绕过安全鉴权和审计。

安装

macOS / Linux:

curl -fsSL https://raw.githubusercontent.com/DingTalk-Real-AI/dingtalk-workspace-cli/main/scripts/install.sh | sh

Linux 产物链接 glibc(基线 2.17)。不支持 musl 发行版(如 Alpine),安装脚本会识别并提前中止,而不是装上一个无法启动的二进制。

Windows(PowerShell):

irm https://raw.githubusercontent.com/DingTalk-Real-AI/dingtalk-workspace-cli/main/scripts/install.ps1 | iex
Skill 模式:mono 与 multi

安装时可以选择两种 skill 组织方式。两种模式下 CLI 命令完全一样(dws aitable ... / dws calendar ...),区别只在 Agent 那边读到的 skill 文档结构。

模式 安装内容 适合场景
multi(默认) 按产品拆分的独立 skill(dingtalk-aitable / dingtalk-calendar / dingtalk-chat ...) 单产品任务;每次召唤上下文更小
mono(legacy) 一个 dws skill,覆盖全部产品 跨产品组合操作;单一入口召唤

安装与升级默认均为 multi。mono 仍可通过 DWS_SKILL_MODE=mono 或 dws skill setup --mode mono 使用。问题请提 issue 反馈。

怎么选:

  • 快速安装(上方一行 curl):非交互,默认装 multi。
  • TTY 安装(先下载再执行):curl -O .../install.sh && bash install.sh,会弹出 1) multi 2) mono 选项(默认 1)。
  • 环境变量覆盖:DWS_SKILL_MODE=mono curl -fsSL ... | sh。
  • 装完之后再切换:dws skill setup --mode mono(或 --mode multi),核对列出的路径后交互确认。
其他安装方式

npm(需要 Node.js(npm/npx)):

npm install -g dingtalk-workspace-cli

安装最新 beta:

npm install -g dingtalk-workspace-cli@beta

Homebrew(macOS / Linux):

brew tap DingTalk-Real-AI/dingtalk-workspace-cli https://github.com/DingTalk-Real-AI/dingtalk-workspace-cli.git
brew install dingtalk-workspace-cli

Formula 与代码位于同一个仓库,因此首次 tap 需要显式指定仓库 URL。后续可直接使用 brew upgrade dingtalk-workspace-cli。

安装 Homebrew beta(keg-only,不覆盖稳定版):

brew install dingtalk-workspace-cli-beta
$(brew --prefix dingtalk-workspace-cli-beta)/bin/dws version

如需让 beta 的 dws 成为当前 shell 默认版本,将 $(brew --prefix dingtalk-workspace-cli-beta)/bin 放到 PATH 最前面。

预编译二进制文件:从 GitHub Releases 下载。

macOS 用户注意:如果提示“无法打开,因为 Apple 无法检查其是否包含恶意软件”,请执行:

xattr -d com.apple.quarantine /path/to/dws

从源码构建:

git clone https://github.com/DingTalk-Real-AI/dingtalk-workspace-cli.git
cd dingtalk-workspace-cli
go build -o dws ./cmd       # 编译到当前目录
cp dws ~/.local/bin/         # 安装到 PATH

需要 Go 1.25+。在支持的 macOS、Linux、Windows amd64/arm64 平台上,默认 CGO 构建无需 build tag 即包含 SafeChat 后端,因此本机构建需要可用的 C 编译器。 只有明确需要 stub 时才设置 CGO_ENABLED=0。使用 make package 和 Docker 可通过仓库固定的交叉编译工具链构建全部六个平台产物。 静态端点数据由悟空基线生成并提交在本仓库 internal/syncdata,源码构建不需要额外 checkout 数据仓库。

国内加速安装

国内用户可使用以下通道,避免 GitHub 网络问题。默认(不设置这些环境变量)走 GitHub。

1. 安装脚本 + 预编译二进制(Gitee 镜像):

仓库镜像地址:https://gitee.com/DingTalk-Real-AI/dingtalk-workspace-cli

DWS_GITEE_REPO=DingTalk-Real-AI/dingtalk-workspace-cli curl -fsSL https://gitee.com/DingTalk-Real-AI/dingtalk-workspace-cli/raw/main/scripts/install.sh | sh

设置 DWS_GITEE_REPO 后,安装脚本会改从 Gitee API 解析最新版本和各个 release 产物(二进制、校验和、skills 包),而不是走 GitHub。不设置时默认从 GitHub 安装。

2. npm 包(npmmirror 镜像):

npm install -g dingtalk-workspace-cli --registry=https://registry.npmmirror.com

npmmirror 会自动同步公网 npm 的公开包,国内可直接使用。

3. 单独安装 Skills(Gitee 镜像):

DWS_GITEE_REPO=DingTalk-Real-AI/dingtalk-workspace-cli curl -fsSL https://gitee.com/DingTalk-Real-AI/dingtalk-workspace-cli/raw/main/scripts/install-skills.sh | sh

同样设置 DWS_GITEE_REPO,install-skills.sh 会从 Gitee 解析版本和 skills 包;GitHub 不可达时也会自动回退到 Gitee 镜像。

升级

需要 v1.0.7 及以上版本。更早版本请重新执行安装脚本进行升级。

dws 内置自升级能力,直接从 GitHub Releases 拉取更新,支持 SHA256 完整性校验和自动备份。

dws upgrade                    # 交互式升级到最新版本
dws upgrade --check            # 仅检查是否有新版本
dws upgrade --list             # 列出正式 release 版本
dws upgrade --beta             # 升级到最新 beta 预发布版本
dws upgrade --check --beta     # 仅检查 beta 轨道是否有新版本
dws upgrade --list --beta      # 列出 beta 预发布版本
dws upgrade --version v1.0.7   # 升级到指定版本
dws upgrade --version v1.0.8-beta.1  # 升级到指定 beta 版本
dws upgrade --rollback         # 回滚到上一版本
dws upgrade -y                 # 跳过确认直接升级

默认情况下,dws upgrade 只跟随正式 release 轨道。只有显式传入 --beta 时,才会选择 GitHub pre-release 里的 beta 构建。

六渠道发布后验证

维护者和验证同学可按发版质量保障 SOP,对 curl、PowerShell、npm stable、npm beta、Homebrew、dws upgrade 执行安装与冒烟验证:

git clone https://github.com/DingTalk-Real-AI/dingtalk-workspace-cli.git /tmp/dws-verify
cd /tmp/dws-verify/verify
bash verify-all-channels.sh

脚本使用隔离目录,不会替换当前 PATH 中的 dws;输出 PASS、FAIL、SKIP 汇总。跨平台渠道必须由对应平台补测,SKIP 不计为通过。验证范围和平台矩阵见 verify/README.md。

工作原理

升级过程采用两阶段原子流程,确保一致性:

  1. 准备阶段 — 将平台对应的二进制文件和技能包下载到临时目录,校验 SHA256 校验和,解压并验证所有文件。任何步骤失败则立即中止,不会修改现有安装。
  2. 执行阶段 — 仅在所有准备工作成功后,替换二进制文件并将技能包平铺到已检测到的具体 Agent 目录(例如 ~/.codex/skills/dingtalk-chat、~/.claude/skills/dingtalk-chat)。只有未检测到具体 Agent 时才使用 ~/.agents/skills;检测到具体 Agent 后会备份迁走旧的 DWS 通用副本,避免同一 Skill 被重复发现。

每次升级前自动备份当前版本,可通过 dws upgrade --rollback 随时回滚。

Flag 说明
--check 仅检查更新,不安装
--list 列出正式 release 版本及更新日志
--beta 对 upgrade、--check、--list 使用 beta 预发布轨道
--version 升级到指定版本(如 v1.0.7 或 v1.0.8-beta.1)
--rollback 回滚到上一个备份版本
--force 强制重新安装,即使已是最新版本
--skip-skills 跳过技能包更新
-y 跳过确认提示

开始使用

dws auth login            # 自动唤起浏览器
dws auth login --device   # 无浏览器环境(Docker、SSH、CI)

选择组织并授权即可。

如果组织尚未开启 CLI 访问权限,系统会引导你向管理员发送申请。审批通过后重新执行 dws auth login 即可。

组织未开启 CLI 访问权限?
  1. 选择组织后,点击「立即申请」通知管理员
  2. 管理员收到申请卡片,一键审批
  3. 审批通过后,重新执行 dws auth login

申请权限

管理员:为组织开启 CLI 访问权限

进入 开发者平台 →「CLI 访问管理」→ 开启。

CLI访问管理

自建应用模式(CI/CD、ISV 集成)

企业自主管控场景,可创建自有钉钉应用:

  1. 开放平台应用开发后台 → 创建应用
  2. 安全设置 → 添加重定向 URL:http://127.0.0.1,https://login.dingtalk.com
  3. 发布应用
  4. 登录:
dws auth login --client-id <your-app-key> --client-secret <your-app-secret>

首次登录后凭证安全存储(Keychain),后续自动刷新 Token。

多组织(profile)

dws 可以同时登录多个钉钉账号,同一组织也能保留多个账号。一个 profile 由 corpId + userId 唯一确定。

业务命令会检查本地 OAuth token 并按需自动刷新,无需先执行认证状态查询。 dws auth status 保留刷新、迁移和修复能力,可能等待认证锁。 并发轮询请使用 dws auth status --readonly --format json(支持 --profile):只读本地快照,不获取认证锁、不刷新、不迁移或写入凭证;系统 Keychain 读取仍可能等待。 两种模式返回相同字段,但只读模式不会报告刷新成功,可能返回普通模式会刷新掉的过期 token 状态。 只读结果的 reason 非空时表示无法判断,不能仅凭 authenticated: false 当作已确认未登录;local_state_requires_repair 表示需要迁移或修复,local_state_unreadable 表示读取失败。 需要刷新或修复时使用相同 profile 运行 auth status(不加 --readonly)。 两种模式的 authenticated 判断一致:access token 或 refresh token 任一个有效即为已认证;token_valid 单独表示 access token 是否可用。 本地快照不验证服务端状态,并发更新时可能读到旧值或无法确定的结果。

dws auth login                              # 新增或刷新一个账号
dws profile list                            # 列出全部账号,profile 字段是稳定的 corpId:userId
dws profile switch <corpId:userId>          # 持久切换账号;用 - 切回上一个
dws profile switch "组织名:用户名"          # 名称输入要求唯一
dws --profile <corpId> contact user search --query "..."        # 使用该组织明确记录的当前账号
dws --profile <corpId:userId> contact user search --query "..." # 单次精确指定账号,不改默认账号

支持 corpId:userId、corpId:userName、corpName:userId、corpName:userName。名称只用于输入,自动化应使用 profile list 返回的稳定 profile。组织名或用户名重名时会列出候选并报错;同组织多账号但没有明确当前账号时,只传组织也会报错,不会选择第一项或最近使用账号。

currentProfile、previousProfile 和组织默认账号都保存精确身份。primaryProfile 只为 JSON 兼容保留,不再参与选择。profile list 直接读取各身份 Token 计算状态和到期时间,不触发刷新。auth logout --profile <corpId> 退出该组织全部账号;精确选择器或本地 profile 名只退出一个账号。

跨组织读取由 agent 编排,而非内置 --all-orgs:先 dws profile list,每个组织使用唯一的 isOrgCurrent=true 账号;若多账号组织没有默认账号,先让用户指定账号。写操作默认只在当前账号执行——跨组织写之前先确认目标组织和账号。

macOS 下,瞬态或未分类的 Keychain 读取失败仍会拒绝新的 OAuth 登录,避免把系统 Keychain 和 file-DEK 写成混合状态。已确认的 DEK 缺失或密文/DEK 不匹配会保留到授权完成,并且只替换本次新登录实际写入的 token slot。如果普通终端仍能读取登录态、只有设置 DWS_DISABLE_KEYCHAIN=1 的沙箱读不到,可在不暴露 token 的情况下迁移 legacy 与各 profile 的认证条目:

env -u DWS_DISABLE_KEYCHAIN dws auth migrate-keychain --to file-dek --dry-run --format json
env -u DWS_DISABLE_KEYCHAIN dws auth migrate-keychain --to file-dek --yes --format json
DWS_DISABLE_KEYCHAIN=1 dws auth status --format json

迁移会先验证全部认证密文再写入、忽略无关的应用密钥;提交中断后可安全重跑。如果预检确认是密文本身损坏,优先使用 dws auth logout --profile <corpId:userId> 只清理受影响账号;只有确认要丢弃全部本地 profile 时才用 dws auth reset。

沙箱间迁移登录态(Linux)

仅拷贝 ~/.dws/app.json 无法带走 refresh token;access token 约 2 小时后会失效。请使用官方导出/导入:

# A 沙箱(已登录)
dws auth export -o /tmp/dws-auth.tar.gz
# 或便于分片复制:dws auth export --base64 -o /tmp/dws-auth.b64

# B 沙箱
dws auth import -i /tmp/dws-auth.tar.gz
# 或:dws auth import -i /tmp/dws-auth.b64 --base64
dws auth status   # 确认 Refresh Token: 有效

包内包含 ~/.local/share/dws-cli 加密 keychain(含 auth-token.enc 与 dek)及 ~/.dws 必要配置。

快速开始

dws contact user search --query "悟空"             # 搜索联系人
dws calendar event list                            # 查看今天的日程
dws doc search --query "季度"                      # 搜索钉钉文档
dws whiteboard +query --node "<白板节点ID>" --view summary --format json  # 查询白板概况
dws minutes list mine                              # 列出我创建的 AI 听记
dws drive list                                     # 列出钉盘文件
dws todo task create --title "季度汇报" --executors "<your-userId>"   # 创建待办(请替换为真实 userId)
dws todo task list --dry-run                       # 预览操作但不执行

完整命令列表:docs/command-index.md — 全部命令,带描述和使用场景。

白板

使用 dws whiteboard 操作独立白板和文档内嵌白板:查询内容、通过 OpenNodes 创建/更新、使用 +diff 预览变更、生成本地 SVG 预览,以及管理个人/团队模板或使用公共模板。

dws whiteboard --help
dws whiteboard render --source @whiteboard.json --output ./whiteboard-preview.svg --format json
dws whiteboard +diff --help
dws whiteboard template personal list --format json
dws whiteboard template team list --template-workspace "<团队空间ID>" --page-all --format json
dws whiteboard template public list --query "复盘" --format json

whiteboard.json 为 OpenNodes 源文件。SVG 是本地预览,需要查看还原程度和警告,并确认当前预览后再创建白板;更新前使用 +diff 检查拟写入内容,再执行 +update。模板 save/create 命令的 --dry-run 是可选的服务端预检,不实际保存模板或创建白板。

详见白板参考、Diff 指南和 SVG 预渲染指南。

在 Agent 中使用

dws 是为 AI Agent 设计的 CLI 工具。请先完成安装和开始使用,然后安装 Agent Skills:

npx skills add DingTalk-Real-AI/dingtalk-workspace-cli -g

安装器会先展示计划——安装哪些 skill、写入哪些目标目录、如何处理已存在的同名 skill——并在写入前请求确认。dws skill setup 仍是进阶用户 / 国内 / 升级路径。详见 Agent Skills。

Agent 调用模式

# 使用 --yes 跳过确认提示(Agent 必须)
dws todo task create --title "Review PR" --executors "<your-userId>" --yes

# 使用 --dry-run 预览操作(安全执行)
dws contact user search --query "张三" --dry-run

# 使用 --jq 精确提取(节省 token)
dws contact user get-self --jq '.result[0].orgEmployeeModel | {name: .orgUserName, dept: .depts[0].deptName, userId}'

命令帮助与 Schema

命令帮助和 Schema 分别负责命令契约的不同部分:

  • dws <path> --help 是命令是否存在、当前二进制接受哪些 flags 的事实源。
  • dws schema "<path>" --compact 是 Agent 选命令、CLI 参数与约束、风险和确认语义的规范视图;映射或 provenance 审计使用 full leaf 配合 --jq 精确投影。
  • Help 与 Schema 冲突时视为契约漂移:执行只传 Cobra 接受的参数,安全语义取更保守值。
  • Schema 只描述命令,不读取或搜索钉钉业务数据;发现命令后仍需执行真实产品命令。
# 确认命令存在并查看当前接受的 flags
dws aitable record query --help

# 先在产品内发现命令,再查看选中 leaf 的契约
dws schema aitable --compact
dws schema "aitable record query" --compact

# 执行真实业务查询
dws aitable record query --base-id BASE_ID --table-id TABLE_ID --limit 10

dws schema --all 会完整导出命令契约,供工具、CI、审计和兼容性基线使用。Agent 应使用 --compact 渐进查询;该视图采用正向字段白名单,full 新增的审计字段不会自动进入 Agent 上下文。

Agent Skills

npx skills add DingTalk-Real-AI/dingtalk-workspace-cli -g

该命令发现 skills/multi/dingtalk-*/SKILL.md(skills/ 下三层的目录布局,正是 npx skills add 已支持的扫描深度),并把 dingtalk-calendar、dingtalk-chat 等安装到 vercel-labs/skills 已识别的 Agent 目录:默认是项目 .agents/skills/,加 -g 则装到用户全局 .agents/skills,并链接到 ~/.cursor/skills、~/.claude/skills 等已登记的 Agent home。

不带 -y 时,安装器会先列出要安装的 skill、目标目录以及对已存在同名内容的处理方式,经确认后才写入。交互式安装和首次全局安装请保留该确认。-y 仅用于自动化场景:只有在用户明确确认了安装目标与覆盖行为之后才应加上——该路径不维护 dws skill setup 的所有权、备份与 mono↔multi 互斥清理状态,跳过确认可能在未经用户同意的情况下替换用户文件。

一体式 mono skill(skills/mono,frontmatter 名为 dws)标了 metadata.internal: true,不是默认可安装 skill,因此 Agent 不会在 dws 与各产品 skill 之间双重路由。

dws skill setup 仍是进阶用户 / 国内 / 升级路径:负责 Gitee 回退、升级时刷新 skill、~/.dws/skills-state.json 所有权,以及 mono↔multi 互斥清理。

仓库仍保留两棵源树:

  • skills/multi/ — 每个产品一个独立 skill(dingtalk-aitable/ / dingtalk-calendar/ / dingtalk-chat/ ...),每个 skill 自带 SKILL.md。npx skills add 与 dws skill setup 的默认源。
  • skills/mono/ — 单 skill 布局(一个 SKILL.md + references/products/),legacy。对 npx skills add 隐藏;dws skill setup --mode mono 以及 curl / zip 安装器仍会安装它。

Schema 生成的叶子 safety/参数/选型文案由 Go 中的 ProductDecl / ContractFinal 声明驱动。原 internal/cli/schema_hints/ HintFile 目录已完全退役,不得重新引入。

安装之后,Claude Code / Cursor 等 AI 工具就能通过自然语言直接操作钉钉。

国内用户:npx skills add 从 GitHub clone。请优先用 dws skill setup,或给 install-skills.sh 加上 DWS_GITEE_REPO,见 国内加速安装。

进阶用户 / 国内 / 升级:dws skill setup

# 交互式:提示选模式 + 目标 Agent
dws skill setup

# 先预览 mono setup 将备份和替换的精确目录
dws skill setup --mode mono --target all --dry-run

# 交互执行并确认列出的目录
dws skill setup --mode mono --target all

# 先预览,再交互确认装到某一个 Agent home
dws skill setup --mode multi --target cursor --dry-run
dws skill setup --mode multi --target cursor

# 指定本地源目录(支持 dws-skills.zip 解压根目录、其 multi/ 目录或源码仓库根目录),先预览
DWS_SKILL_SOURCE=/绝对路径/dws-skills-解压目录 dws skill setup --mode multi --dry-run
DWS_SKILL_SOURCE=/绝对路径/dws-skills-解压目录 dws skill setup --mode multi
参数 取值 说明
--mode mono | multi skill 布局,不指定则交互式询问
--target all | claude | cursor | codex | zcode | opencode | qoder 安装目标;all 表示铺到检测到的具体 Agent home(ZCode 为 ~/.zcode/skills),仅在未检测到具体 Agent 时回退到 ~/.agents/skills
--source 路径 本地源目录(覆盖内置 skills);支持模式目录、dws-skills.zip 解压根目录或包含 skills/ 的源码仓库根目录
--yes — 仅供脚本使用:跳过确认提示。删除操作仍会先备份到 ~/.dws/skill-backups/

setup 命令可能移除对面模式残留(装 multi 删 dws/,装 mono 清理统一状态中登记或属于状态上线前精确官方名称集合的 multi Skill)以及不在 bundle 内的过期受管 Skill。DWS 在 ~/.dws/skills-state.json(或 $DWS_CONFIG_DIR/skills-state.json)集中记录所有权、安装版本、来源和内容摘要。仅有 dingtalk-* 前缀不能触发清理,因此其他同前缀市场/用户 Skill 会保留。所有删除都会先列入确认预览,并备份到 ~/.dws/skill-backups/<时间戳>/;备份失败的目录会保留原样、绝不删除。非交互环境应先用 --dry-run 核对输出,再由调用方显式决定是否使用仅供脚本的确认跳过参数。

multi setup 或 upgrade 后,DWS 会把官方 bundle 快照和统一所有权元数据写入 ~/.dws/skills-state.json(或 $DWS_CONFIG_DIR/skills-state.json)。每次 upgrade 都会安装并覆盖该版本的全部预制 Skill;手工删除或通过 setup 排除预制 Skill 不会永久保留,下次 upgrade 会恢复。dws upgrade --force 还允许在没有新版本时重装当前 CLI 版本。

环境变量:DWS_SKILL_MODE=mono|multi(install.sh / install.ps1 也认)、DWS_SKILL_SOURCE=<路径>。

包含内容(mono 布局):

组件 路径 说明
主 Skill skills/mono/SKILL.md 意图路由、决策树、安全规则、错误处理
产品参考 skills/mono/references/products/*.md 各产品命令详细参考(aitable、chat、calendar 等)
意图指南 skills/mono/references/intent-guide.md 易混淆场景消歧(如 report vs todo)
全局参考 skills/mono/references/global-reference.md 认证、输出格式、全局 flag
错误码 skills/mono/references/error-codes.md 错误码 + 调试流程
现成脚本 skills/mono/scripts/*.py 13 个批量操作脚本(见下方)
现成脚本 — 13 个 Python 脚本,覆盖常见多步工作流
脚本 说明
calendar_schedule_meeting.py 一键创建日程 + 添加参与者 + 搜索并预定空闲会议室
calendar_free_slot_finder.py 查询多人共同空闲时段,推荐最佳会议时间
calendar_today_agenda.py 查看今天/明天/本周的日程安排
import_records.py 从 CSV/JSON 批量导入记录到 AI 表格
bulk_add_fields.py 批量添加字段到 AI 表格数据表
upload_attachment.py 上传附件到 AI 表格 attachment 字段
todo_batch_create.py 从 JSON 文件批量创建待办(含优先级、截止时间、执行者)
todo_daily_summary.py 汇总今天/本周未完成的待办
todo_overdue_check.py 扫描已过截止时间但未完成的待办,输出逾期清单
contact_dept_members.py 按部门名称搜索并列出所有成员
attendance_my_record.py 查看我今天/本周/指定日期的考勤记录
attendance_team_shift.py 查询团队成员本周排班和出勤统计
report_inbox_today.py 查看今天收到的日志列表及详情

ISV 集成:编写您自己的 Agent Skill,与 dws 内置 Skill 搭配构建跨产品工作流:ISV Skill → dws Skill → 钉钉开放平台 API(强制鉴权 + 全链路审计)。

功能特性

个人事件订阅 — 实时接收钉钉消息,驱动事件触发的 Agent

dws event consume 使用当前 OAuth 登录用户建立托管的 Stream WebSocket 长连接,并把每条事件以 NDJSON 一行输出到 stdout。当前 28 个公开事件覆盖指定范围和全量单聊/群消息、指定发送人、已读/撤回/表情回应、群生命周期、七个 OA 审批任务/实例事件、一个 VoIP 通话邀请事件、三个待办生命周期事件,以及互动卡片回调事件。

默认 ndjson、json、pretty 输出保留兼容 transport envelope(type、event_type、字符串 data、headers),compact 继续沿用原 processor。Agent 或新脚本显式加 --flatten 后,输出稳定的顶层业务字段。--format 控制 JSON 序列化,--flatten 控制数据结构,且不能与 -f raw 或 --debug-raw-events 同时使用。

前置条件:先运行 dws auth login。个人身份从 OAuth token 解析,不允许通过命令行伪造。

只需要 event 能力时,可以使用官方便捷安装脚本:

curl -fsSL https://raw.githubusercontent.com/DingTalk-Real-AI/dingtalk-workspace-cli/main/scripts/install-event.sh | sh

# 或在已有 dws 环境中安装独立的 multi skill
dws skill setup --mode multi -s event
# 查看公开个人事件目录和 schema
dws event list
dws event schema user_im_message_receive_o2o --flatten
dws event list --category oa
dws event schema user_oa_approval_task_created --flatten
dws event list --category card
dws event schema user_card_action_triggered --flatten
dws event list --category todo
dws event schema user_todo_task_create --flatten

# 监听当前用户被 @ 的消息
dws event +listen-im --kind at-me -f ndjson

# 监听指定发送人的消息
dws event +listen-im --kind sender --user <userId> -f ndjson

# 使用 openDingtalkId 监听外部联系人、机器人或跨组织身份
dws event +listen-im --kind sender --open-dingtalk-id <openDingtalkId> -f ndjson

# 监听指定群的消息
dws event +listen-im --kind group --chat-id <openConversationId> -f ndjson

# 监听所有单聊或所有群消息
dws event +listen-im --kind all-direct -f ndjson
dws event +listen-im --kind all-group -f ndjson

# 监听指定群标题变更、成员进退群或群解散
dws event consume user_im_group_updated --group <openConversationId> --flatten -f ndjson
dws event consume user_im_group_member_added --group <openConversationId> --flatten -f ndjson
dws event consume user_im_group_member_exited --group <openConversationId> --flatten -f ndjson
dws event consume user_im_group_disbanded --group <openConversationId> --flatten -f ndjson

# 一个进程监听同一发送人的消息、已读和撤回
dws event +listen-im --kind sender --user <userId> \
  --events message,read,recall -f ndjson

# 一个进程监听全部七个公开 OA 审批事件
dws event consume \
  user_oa_approval_task_created \
  user_oa_approval_task_finished \
  user_oa_approval_task_redirected \
  user_oa_approval_instance_started \
  user_oa_approval_instance_cc \
  user_oa_approval_instance_terminated \
  user_oa_approval_instance_finished \
  --flatten -f ndjson

# 监听当前用户作为执行者的待办创建、更新和删除事件
dws event consume \
  user_todo_task_create \
  user_todo_task_update \
  user_todo_task_delete \
  --role-types executor \
  --flatten -f ndjson

# 监听互动卡片回调;Schema 描述已评审字段并保留未知扩展
dws event consume user_card_action_triggered --flatten -f ndjson

# 查看本地 consume,并取消指定订阅
dws event status
dws event stop <subscribe_id>

互动卡片的结构化操作上下文位于 payload.body.actionData.context。通过 questions[].id 关联 answers[question_id],再按同一问题的 options[].id 解析 selected 中的选项 ID;空 selected 是合法未选择状态。body.context 中的 JSON 字符串仅作兼容回退,所有 payload 层级仍保留未知字段。

单聊和指定发送人事件必须且只能选择一种目标身份:企业内部 userId 使用 --user,openDingtalkId 使用 --open-dingtalk-id。CLI 不会自动猜测或转换身份类型。

特性 说明
自动编排 consume 创建或复用个人订阅,stop 取消订阅并清理本地状态
共享连接 同一用户的多个 consumer 共享本地 bus 和云端长连接
多事件进程 同一目标的兼容事件可由一个 consume 进程监听,每个事件仍有独立订阅
订阅隔离 正常 consumer 同时按事件类型和 subscribe_id 匹配
Agent 友好输出 Stream 事件写入 stdout,连接状态和诊断信息写入 stderr
状态可观测 status 同时显示服务端订阅、personal bus 和本地 consumers
跨平台 macOS/Linux 使用 Unix Socket,Windows 使用 Named Pipe

Agent 工作流和事件参数详见 skills/multi/dingtalk-event/SKILL.md。

Raw API 调用 — 直接调用支持 App Token 的钉钉服务端 OpenAPI

dws api 让你直接调用支持企业内部应用 App Token 的钉钉服务端 OpenAPI,无需 SDK,Token 自动获取和刷新。

前置条件:必须提供一对完整的自有应用 Client ID/Client Secret,可来自本次 flags、环境变量或成功登录后保存的 app config(见自建应用模式)。仅通过 MCP 默认凭证登录不支持 Raw API 调用。

Client ID/Client Secret 必须来自同一完整凭证对,优先级为:完整 --client-id/--client-secret > 完整 DWS_CLIENT_ID/DWS_CLIENT_SECRET > 完整 app config。任一来源只提供一项都会明确失败,不会与其他来源拼接。直接用于 dws api 的 flags/env 仅对本次调用生效,不持久化 AppSecret;成功执行 dws auth login 时使用的 flags/env 则会按实际使用的完整 pair 持久化,供 OAuth 刷新和后续 Raw API 使用。获取到的 App Token 会按 app-token:<clientID> 缓存;隐藏 --token 仅临时使用调用方提供的 App Token,不持久化、不自动刷新。

Client Secret 统一使用 Keychain 槽位 appsecret:<clientID>,与 OAuth User Token、App Token 完全隔离。历史明文 app config 和 client-secret:<clientID> 会自动迁移;新旧槽位值不一致时 fail closed,要求重新登录,不猜测正确值。

# 登录(仅首次)
dws auth login --client-id <APP_KEY> --client-secret <APP_SECRET>

# 或使用一对环境变量,完整 env pair 会整体覆盖 app config
export DWS_CLIENT_ID=<APP_KEY>
export DWS_CLIENT_SECRET=<APP_SECRET>

# === api.dingtalk.com ===

# 获取企业所有应用列表
dws api GET /v1.0/microApp/allApps

# 搜索用户 (POST + JSON body)
dws api POST /v1.0/contact/users/search \
  --data '{"queryWord":"张三","offset":0,"size":10}'

# === oapi.dingtalk.com ===

# 获取用户详情(使用 --base-url 指定域名)
dws api POST /topapi/v2/user/get \
  --base-url https://oapi.dingtalk.com \
  --data '{"userid":"<USER_ID>"}'

# 也可以直接使用完整 URL
dws api POST https://oapi.dingtalk.com/topapi/v2/user/get \
  --data '{"userid":"<USER_ID>"}'

# === 通用功能 ===
dws api GET /v1.0/microApp/allApps --dry-run             # 预览请求
dws api GET /v1.0/microApp/allApps --jq '.appList | length'  # jq 过滤

# 从文件读取 JSON body(--params 也支持 @file;也可用 - 从 stdin 读取)
dws api POST https://oapi.dingtalk.com/topapi/v2/department/listsubid \
  --data @department-request.json --dry-run

# 单文件流式 multipart 上传;--data 顶层字段转为文本 form field;先 dry-run 核对
dws api POST https://oapi.dingtalk.com/media/upload \
  --data '{"type":"image"}' --file media=./demo.png --dry-run
特性 说明
双形态自动识别 根据 URL 自动选择 api.dingtalk.com(Header 认证)或 oapi.dingtalk.com(Query 参数认证)
Token 自动管理 首次调用自动获取应用级 accessToken,有效期内缓存,过期自动刷新
域名白名单 仅允许 api.dingtalk.com 和 oapi.dingtalk.com,防止 Token 泄露
自动分页 --page-all 自动遍历所有分页。--page-limit 控制翻页上限(默认 10,设为 0 不限制,硬上限 500 防止死循环)
安全传输 仅允许 HTTPS/443 和同源 HTTPS 重定向;JSON/错误响应有限读取,二进制流式原子下载
Agent 发现 现有产品命令未覆盖时,内置 misc/mono Skill 指导 Agent 从 https://open.dingtalk.com/llms.txt 分层定位官方接口;Raw api 本身不进入 Agent Schema

dws api 只自动使用企业内部应用的 App Token,不读取 OAuth User Token,也不提供 --as user / --user。优先使用已有 DWS 产品命令;只有未封装的企业内部应用服务端 OpenAPI 才使用 Raw 逃生舱。写、删、撤销等操作须在 dry-run 核对并确认后执行。

智能输入纠错 — 自动修正 AI 模型常见的参数错误

内置 Pipeline 纠错引擎,支持命名风格转换、粘连参数拆分、拼写模糊匹配:

# 命名风格自动转换 (camelCase / snake_case / UPPER → kebab-case)
dws aitable record query --baseId BASE_ID --tableId TABLE_ID         # 自动纠正为 --base-id --table-id

# 粘连参数自动拆分
dws contact user search --query "张三" --timeout30                  # 自动拆分为 --timeout 30

# 拼写错误模糊匹配
dws aitable record query --base-id BASE_ID --tabel-id TABLE_ID       # --tabel-id → --table-id

# 参数值归一化 (布尔 / 数字 / 日期 / 枚举)
# "yes" → true, "1,000" → 1000, "2024/03/29" → "2024-03-29", "ACTIVE" → "active"
Agent 输出 dws 自动纠正为
--userId --user-id
--limit100 --limit 100
--tabel-id --table-id
--USER-ID --user-id
--user_name --user-name
jq 过滤 & 字段筛选 — 精确控制输出,减少 token 消耗
# 内置 jq 表达式
dws aitable record query --base-id BASE_ID --table-id TABLE_ID --jq '.invocation.params'
dws schema "dev app create" --jq '.parameters'

# 只返回指定字段
dws aitable record query --base-id BASE_ID --table-id TABLE_ID --fields invocation,response
Schema 自省 — Agent 命令发现与执行契约
dws schema aitable --compact                            # 发现产品命令
dws schema "aitable record query" --compact             # 查看 Agent leaf 契约
dws schema "aitable record query" --jq '[.parameters | to_entries[] | select(.value.required)]' # 定向查看必填字段
dws schema --all                                        # CI/审计/基线的全量导出
管道 & 文件输入 — 从文件或 stdin 读取 flag 值
# 从文件读取消息内容
dws chat message send-by-bot --robot-code BOT_CODE --group GROUP_ID \
  --title "周报" --text @report.md

# 通过管道传入内容
cat report.md | dws chat message send-by-bot --robot-code BOT_CODE --group GROUP_ID \
  --title "周报"

# 显式从 stdin 读取
dws chat message send-by-bot --robot-code BOT_CODE --group GROUP_ID \
  --title "周报" --text @-

说明:@ 仅在其后是 ASCII 路径前缀字符(A-Z / a-z / 0-9 / . / / / ~ / _ / -)或 @-(stdin)时,才会被识别为 @<path> 文件注入语法。--text "@所有人 周报" / --text "@张三 看一下" 这类机器人消息中的字面 @ 提及会原样透传到 API。

钉钉机器人 —— 把机器人接到你本地的 AI

dws dev connect 把一个钉钉机器人接到本地 AI CLI(Claude Code / Codex / opencode / Qoder / Gemini,或用 --agent-cmd 接任意工具):群里 @ 机器人提问,它用你本地的 agent 回答,按会话保留多轮上下文。

dws dev connect --channel auto --robot-client-id <id> --robot-client-secret <secret>

聊天里的会话指令(整条消息就是指令时生效,不消耗一次 AI 调用):

指令 作用
/new(别名 /start、/reset) 开启新会话;旧会话保留(agent 支持的话仍可回溯)
/clear 清空当前会话 —— 调 agent 真实会话原语真删(opencode 走 DELETE /session/:id);驱动接口没有删除原语的渠道退化为重置

完整四步教程见 docs/robot-quickstart.md(装工具 → 建机器人 → 接上 AI → 拉进群)。

核心服务

服务 命令 能力
通讯录 contact 按姓名 / 手机号 / 工号查人,部门、角色标签、花名册与离职;创建企业、企业账号及邀请员工
群聊 chat(im) 发送 / 回复 / 搜索消息,群与成员管理,机器人与 Webhook 发消息,表情反应,撤回
日历 calendar 日程 CRUD、参与者、会议室、闲忙与时间建议
待办 todo 创建 / 列表 / 修改 / 完成待办及评论
审批 oa 同意 / 拒绝 / 撤销 / 转交,查待办 / 已发起 / 抄送及表单
考勤 attendance 打卡记录、排班、考勤摘要、考勤组规则(只读)
DING ding 发送 / 撤回 DING 消息
日志 report 创建 / 提交日志,收发件箱,模版,统计
AI 表格 aitable Base / 数据表 / 记录 / 字段 / 视图,权限与角色,自动化,图表与仪表盘,导入导出
文档 doc 搜索 / 读写文档,块级编辑,评论,权限,媒体,上传 / 下载
白板 whiteboard 独立/内嵌白板:查询、创建/更新、Diff、本地 SVG 预渲染、个人/团队模板
钉盘 drive 列表 / 搜索 / 下载,文件夹,上传,复制 / 移动 / 重命名,权限
AI 听记 minutes 听记列表、摘要 / 关键词 / 转写 / 待办、思维导图、发言人、标签
邮箱 mail 邮箱、KQL 搜索、读 / 发、草稿、文件夹、模版、联系人
在线电子表格 sheet 在线表格:工作表与区域读写、筛选、条件格式、图片、CSV
知识库 wiki 知识库:空间、成员、节点树、文档与文件
开发者文档 devdoc 搜索开放平台文档并排查 API 错误
AI 搜问 aisearch 企业人员搜索:按姓名 / 部门 / 角色 / 职责 / 上下级 / 手机号 / 工号
直播 live 查看我的直播列表
Raw API api 直接调用支持 App Token 的钉钉服务端 OpenAPI,自动管理应用级 Token

完整命令清单(带描述与使用场景):docs/command-index.md。运行 dws --help 查看顶层命令树,或 dws <service> --help 查看任一服务的子命令。

关于 chat bot:机器人能力(send-by-bot / recall-by-bot / add-bot / send-by-webhook / bot 搜索)已合并到对应的 chat 子树下(例如 dws chat message send-by-bot、dws chat group members add-bot),保持 agent 视角下的命令面扁平易发现。不再有独立的顶层 bot 产品。

即将推出
  • conference(视频会议)
  • 多 skill 模式(默认)— 每产品一个独立 skill,位于 skills/multi/,安装与升级默认启用;dws skill setup --mode mono 交互确认后可切回单 skill

安全设计

dws 从架构层面将安全作为一等公民,而非事后补丁。凭证不落盘、Token 不出域、权限不越界、操作不脱审 — 每一次 API 调用都必须经过钉钉开放平台的鉴权和审计链路,无例外。

开发者安全机制
机制 说明
Token 加密存储 PBKDF2(600,000 次迭代 + SHA-256)+ AES-256-GCM 加密,密钥绑定设备物理 MAC 地址;macOS 集成系统 Keychain、Windows 集成 DPAPI 提供额外保护,跨设备无法解密
输入安全防护 路径遍历防护(符号链接解析 + 工作目录约束)、CRLF 注入拦截、Unicode 视觉欺骗字符过滤,防止 AI Agent 被恶意指令诱导
域名白名单 DWS_TRUSTED_DOMAINS 默认仅信任 *.dingtalk.com,Bearer Token 不会发送到非白名单域
并发安全 双层锁机制(进程内 + 跨进程文件锁)保障 Token 刷新原子性,适配高并发 MCP Server 场景
数据完整性 所有配置写入采用原子操作(temp + fsync + rename),确保进程中断时数据不损坏
HTTPS 强制 除 loopback 开发调试外,所有请求强制 TLS
Dry-run 预览 --dry-run 展示调用参数但不执行,防止误操作生产数据
凭证零落盘 Client ID / Secret 仅在内存中使用,不写入配置文件或日志
企业管理员安全机制
机制 说明
OAuth 设备流认证 用户必须通过管理员授权的钉钉应用认证,未授权应用无法获取 Token
权限最小化 CLI 仅能调用管理员授予该应用的 API 权限范围,无法越权
白名单准入 共创阶段需管理员主动确认开通,后续支持自助审批
操作全链路审计 每一次数据读写都经过钉钉开放平台 API,企业管理员可在管理后台实时追溯完整调用日志,任何异常操作无处隐藏
ISV / 企业服务商安全机制
机制 说明
租户数据隔离 以已授权应用身份调用 API,不同租户数据严格隔离
Skill 沙箱 Agent Skills 是 Markdown 文档(SKILL.md),仅提供 prompt 描述,不执行任意代码
集成链路零盲区 ISV Skill 与 dws Skill 联调时,每一次 API 调用都强制经过钉钉开放平台鉴权,完整调用链路可追溯,不存在绕过审计的旁路

发现安全漏洞?请通过 GitHub Security Advisories 报告,详见 SECURITY.md。

参考与文档

贡献指南

参见 CONTRIBUTING.md 了解构建、测试和开发工作流。

许可证

Apache-2.0