# ADR-0001:从「手搓 REST」改为「包装官方 dws CLI」 - **状态**:已接受(Accepted) - **日期**:2026-09-14 - **决策者**:yiyunet - **影响范围**:本插件全部数据通路(鉴权 / 分页 / 错误码 / 命令面) - **取代**:v0.1 的手搓 REST 实现(已删除) --- ## 背景(Context) v0.1 的实现方式是**自己调用钉钉 AI 表格的 REST API**:自行拼端点、自行换 accessToken 并缓存刷新、自行实现分页与错误码映射。 在实测推进中发现三个问题: 1. **端点靠推断**。AI 表格的 REST 端点没有一份稳定的、面向第三方的公开契约,v0.1 的端点路径在代码里被标注为 `pending`——即"未确认"。 2. **数据模型理解错误**。v0.1 使用了 `sheetId` 这套命名,而 AI 表格的真实数据模型是 `base / table / field / record`,正确字段是 **`tableId`**。 3. **成本全在自己身上**。token 刷新、分页游标、错误码分类、限流退避全部要自己维护,且每次钉钉侧 API 变更都要跟。 **关键观察(实测,2026-09-14)**:钉钉官方的 OpenClaw connector (`DingTalk-Real-AI/dingtalk-openclaw-connector`)**自己也不直连 REST**—— 它是注入 `DWS_CLIENT_ID/SECRET` 后调用 `dws`(`dingtalk-workspace-cli`)。 即:**官方推荐的第三方接入路径就是包装 CLI,而不是直连 REST。** --- ## 决策(Decision) **废弃 v0.1 的手搓 REST 实现,改为包装钉钉官方 `dws` CLI,执行 `dws aitable ...`。** 同时纠正 v0.1 的三处硬错误(钉钉官方文档明确点名): 1. `sheetId` → 正确是 **`tableId`** 2. 记录写入时 `cells` 的 key 必须是 **`fieldId`(`fldXXX`)**,**不是字段名** 3. 更新记录必须带 **`recordId`** **发布形态同步对齐生态惯例**:源码在 `plugin-src/`,`lib/` 为构建产物; 引入 esbuild 构建客户端产物;新增 `scripts/verify-package.mjs` 把打包契约变成 CI 断言。 --- ## 后果(Consequences) ### 收益 | 维度 | v0.1 手搓 REST | v0.2+ 包装 dws | |---|---|---| | 端点来源 | 靠推断,标 `pending` | 官方 CLI 内置,已发布可用 | | 鉴权 | 自己换 token、缓存、刷新 | dws 自动管理(access 2h 自动刷新) | | 分页 / 错误码 | 自己实现 | dws 提供 `--format json` + 恢复闭环 | | 正确性风险 | **高**(路径与请求体都可能错) | **低**(命令面有官方文档与错误码参考) | | 维护成本 | 跟钉钉 API 变更 | 跟 dws 版本 | **消除了全部端点不确定性**,这是本次反转最大的收益。 ### 代价(明确记账,不掩饰) 1. **新增一个外部前置依赖**:使用者必须自己装 `dws`(`npm i -g dingtalk-workspace-cli`,≥ 1.0.6)。 详见 [安装与前置条件.md](./../安装与前置条件.md)。这是**把复杂度从插件内部转移到了使用者的环境准备**—— 我们买到了正确性,付出的是安装摩擦。 2. **引入子进程调用面**:需要处理参数注入、超时、shell 转义等问题。 **缓解**:凭证只走环境变量不进命令行;参数逐元素传递不拼 shell 字符串; Windows 上提供 `dwsEntry` 走 node 直 spawn 完全绕开 shell;无法绕开时硬拒绝并返回 `ARG_UNSAFE`。 3. **能力上限受 dws 命令面约束**:dws 没暴露的 AI 表格能力,本插件也拿不到。 ### 被否决的替代方案 | 方案 | 否决理由 | |---|---| | 继续手搓 REST,补全端点 | 端点仍无稳定公开契约,正确性风险不降 | | 直接调用钉钉开放平台 OpenAPI | 与官方 connector 的推荐路径背离;且要自行实现 AI 表格的数据模型适配 | | 包装官方 connector 而非 dws | 官方 connector 本身也包装 dws,多一层包装只增加耦合面 | --- ## 关联 - 术语与禁用说法:[../../CONTEXT.md](../../CONTEXT.md) - 安装与前置条件:[../安装与前置条件.md](../安装与前置条件.md) - 变更留痕(含架构反转记录):[../../CHANGELOG.md](../../CHANGELOG.md) - 实测记录:[../实测/](./../实测/)