# 钉钉进度通知参考

这里的脚本和配置只演示 Hub 如何向项目群发送辅助通知，不属于 Etunel 的任务通信主链路，也不能代替任务派发、负责人确认、阶段门禁或项目留档。成员 Agent 不调用本脚本。

当前布局刻意把工具和项目配置分开：

- `dingtalk-workspace-cli@1.0.60` 由 Bun 安装在用户级全局目录，项目不保存二进制或 `node_modules`。
- 官方 multi skills 保留在项目 `.agents/skills/dingtalk-*`，只对本项目生效。
- Client ID、群目标、`robotCode` 和汇报开关保存在项目 `.dingtalk/config.env`。
- Client Secret 从环境变量 `DING_SEC` 读取，未设置时回退到 macOS Keychain；脚本只临时注入给 `dws api`，App Token 由 DWS 自动获取和缓存。

项目统一通过稳定入口调用全局命令：

```sh
./scripts/dws version
```

Bun 默认阻止上游 `postinstall`；本机安装时已校验官方 SHA-256 并只释放 DWS 原生二进制，没有执行会发布全局 Skills 的安装脚本。升级 DWS 时也应保持这一边界。

## 应用身份（无需用户登录）

本项目不执行 `dws auth login`。进度脚本通过 `dws api` 调用企业内部应用 OpenAPI：

```text
POST https://api.dingtalk.com/v1.0/robot/groupMessages/send
```

管理员侧只需确保：

- Client ID/Secret 属于企业内部应用；
- 应用已有“企业内机器人发送消息”权限（`qyapi_robot_sendmsg`）；
- `robotCode` 属于同一个应用；
- 机器人已加入目标 `openConversationId` 对应的群。

当前使用 zsh 环境变量时，先确保它已导出（不要把真实值写进项目文件）：

```sh
export DING_SEC='<Client Secret>'
```

也可以不设置 `DING_SEC`，改用本项目专用的 macOS Keychain 项。`-w` 必须放在最后，它会在终端中隐藏输入：

```sh
/usr/bin/security add-generic-password \
  -U \
  -a '<Client ID>' \
  -s 'com.example.dingtalk.your-project' \
  -l 'Your project DingTalk bot Client Secret' \
  -w
```

`dws auth status` 显示未登录是正常状态，与 App Token 发送链路无关。

## 配置进度群

```sh
cp .dingtalk/config.env.example .dingtalk/config.env
chmod 600 .dingtalk/config.env
```

填写以下非密钥参数：

```dotenv
DINGTALK_PROGRESS_MODE=app-bot
DINGTALK_PROGRESS_CLIENT_ID=<Client ID>
DINGTALK_PROGRESS_TARGET=<openConversationId>
DINGTALK_PROGRESS_ROBOT_CODE=<robotCode>
```

先保持 `DINGTALK_PROGRESS_ENABLED=0`。凭据和参数就绪后改为 `1`，并保持 `DINGTALK_PROGRESS_DRY_RUN=1` 做无网络、无发送的请求预览：

```sh
./scripts/dingtalk-progress milestone "**已完成**

- 项目资料已经归档
- 本阶段成果已经负责人确认

**下一步**

- Hub 将安排下一阶段任务"
```

确认请求中的目标和正文正确后，再把 `DINGTALK_PROGRESS_DRY_RUN=0`。真实发送由 Hub 按根目录 `AGENTS.md` 的时机调用；响应中的 `processQueryKey` 才表示服务端已经接受该条机器人消息。摘要可以使用多行 Markdown，重点写已经确认的结果、下一步或阻塞原因，不要粘贴大段日志。
