- 人工智能
- AI 应用
- 桌面应用
- 交互助手
【免费下载链接】ClawX
ClawX is a desktop app that provides a graphical interface for OpenClaw AI agents. It turns CLI-based AI orchestration into a desktop experience without using the terminal. China website is https://clawx.com.cn.
本篇技术指南以 upgrade-dingtalk-official-connector.md 任务规范为核心骨架,结合 ClawX 仓库的 dingtalk-plugin-compat.ts、dingtalk-dws.ts、plugin-install.ts、config-sync.ts 等源码,系统讲解在 OpenClaw 2026.7.1-2 运行时下,如何把钉钉通道从社区连接器迁移到官方连接器,同时保持 ClawX 的dingtalk通道身份、既有凭据、绑定与会话键完全不变。读完本文,你将掌握:身份重映射机制、soimy 专属配置字段的清洗与映射规则、__default__账户归一化原理、dws 工作区 CLI 的预启动供给与桌面回环 OAuth 授权流程,以及这套迁移在单元测试与 E2E 测试中的验收口径。
迁移背景:为什么要把钉钉通道从社区插件换到官方连接器
ClawX 桌面端为 OpenClaw AI Agent 提供图形化界面,钉钉(DingTalk)是其渠道目录中一个核心通道类型。早期 ClawX 通过社区维护的@soimy/dingtalk插件接入钉钉,而 OpenClaw 2026.7.1-2 运行时已经转向钉钉官方的@dingtalk-real-ai/dingtalk-connector@0.8.25连接器。任务规范中明确了本次迁移的核心意图(intent):
用官方
@dingtalk-real-ai/dingtalk-connector@0.8.25替换社区@soimy/dingtalk,同时保持 ClawX 的dingtalk通道身份、既有凭据和单一 Stream client(single Stream client)不变。
在 package.json 的 devDependencies 中可以看到本次迁移相关的版本事实:"@dingtalk-real-ai/dingtalk-connector": "0.8.25"、"dingtalk-workspace-cli": "1.0.30"、"openclaw": "2026.7.1-2",且不再依赖@soimy/dingtalk。
迁移涉及的主干文件(touchedAreas)覆盖三端:Electron 主进程(plugin-install.ts、dingtalk-plugin-compat.ts、dingtalk-dws.ts、channel-config.ts、openclaw-auth.ts、config-sync.ts、channels-api.ts、plugin-channel-activation.ts)、共享层(shared/types/channel.ts、shared/host-api/contract.ts、四语 i18n 的 channels.json)、渲染层(src/pages/Channels/index.tsx、ChannelConfigModal.tsx),以及打包脚本(after-pack.cjs、bundle-openclaw-plugins.mjs)。
核心策略:单一身份重映射,dingtalk-connector永不暴露为目录类型
迁移的第一原则是:ClawX 的通道目录身份永远是dingtalk。官方连接器的插件/通道 id 是dingtalk-connector,但 ClawX 不允许它出现在 Channels 页面作为可配置类型;channel-plugin-migration-guards.md 明确规定:
- ClawX 的目录身份保持
dingtalk,不要将dingtalk-connector作为 Channels 页面类型暴露; - 同一时刻只允许一个钉钉插件身份激活:官方
@dingtalk-real-ai/dingtalk-connector被重映射到dingtalk名下,社区@soimy/dingtalk与官方连接器绝不允许同时启用; channels.dingtalk是唯一事实来源(source of truth)。如果channels.dingtalk-connector同时存在,必须折叠到dingtalk并删除官方键,防止两个 Stream client 共享同一个clientId。
在 dingtalk-plugin-compat.ts 中,四个身份常量被明确定义:
export const DINGTALK_PLUGIN_ID = 'dingtalk'; export const DINGTALK_OFFICIAL_PLUGIN_ID = 'dingtalk-connector'; export const DINGTALK_OFFICIAL_NPM = '@dingtalk-real-ai/dingtalk-connector'; export const DINGTALK_COMMUNITY_NPM = '@soimy/dingtalk';围绕这四个常量,兼容层提供了三类重映射函数:
- Manifest 重映射
remapDingTalkOfficialManifest:官方插件的openclaw.plugin.json中id为dingtalk-connector,函数将其改写为dingtalk,同时把channels声明数组里的dingtalk-connector元素逐一替换为dingtalk,并把channelConfigs键从官方 id 重映射到dingtalk; - package.json 重映射
remapDingTalkOfficialPackageJson:npm 元数据保持原样(仍是@dingtalk-real-ai/dingtalk-connector),只改写openclaw.channels与openclaw.channel.id中的身份标识——这是为了让 OpenClaw 的 repair planner 仍能识别真实 npm 来源; - 编译产物 JS 补丁
patchDingTalkChannelIdsInJs(dingtalk-plugin-compat.ts):对dist/下所有 JS 文件做精确字符串替换——只改写被引号包裹的"dingtalk-connector"身份字面量,保留 Gateway RPC 名如dingtalk-connector.docs.create原封不动(注释明确说明"Rewrite exact quoted dingtalk-connector identities, but leave Gateway RPC names such as dingtalk-connector.docs.create untouched")。
这一步非常关键:RPC 名称是官方连接器暴露给 Gateway 的接口名,如果一并改写会导致网关调用失败;而身份字面量不改写则会被 Gateway 以 "plugin id mismatch" 拒绝。这也是为何迁移必须采用"精准字符串替换"而非全局文本替换。
配置清洗:soimy 专属字段剔除与兼容字段映射
社区插件与官方连接器的配置 schema 并不一致。迁移规范要求在写入前对配置做清洗(sanitization),原则是:soimy 专属字段一律剔除;可以兼容的语义做字段映射;无法映射的用户配置必须保留而不是静默丢弃。
soimy 专属字段黑名单
dingtalk-plugin-compat.ts 定义了SOIMY_ONLY_KEYS集合,涵盖:
- 卡片消息类:
messageType、cardTemplateId、cardTemplateKey、cardStreamingMode、cardStreamInterval、cardRealTimeStream、aicardDegradeMs、cardAtSender、cardStatusLine、showThinkingStream; - 学习类:
learningEnabled、learningAutoApply、learningNoteTtlMs; - 连接管理类:
useConnectionManager、maxConnectionAttempts、initialReconnectDelay、maxReconnectDelay、reconnectJitter、maxReconnectCycles、reconnectDeadlineMs、keepAlive、bypassProxyForSend; - 其他:
convertMarkdownTables、proactivePermissionHint、journalTTLDays、displayNameResolution、contextVisibility、mediaUrlAllowlist、ackReaction、robotCode、corpId、agentId。
sanitizeDingTalkChannelConfig会同时清洗通道级(scope'channel')与账户级(scope'account')配置,其中通道级还会额外删除name字段(scope === 'channel' && key === 'name'时删除)。
关键语义映射表
| 社区插件(soimy) | 官方连接器(dingtalk-connector 0.8.25) | 说明 |
|---|---|---|
messageType: 'card' | groupReplyMode: 'aicard' | 消息类型映射为群回复模式,见mapSoimyMessageType |
messageType: 'markdown' | groupReplyMode: 'markdown' | 同上 |
messageType: 'text' | groupReplyMode: 'text' | 同上 |
群内嵌套groupAllowFrom | 群配置allowFrom | 迁移时若allowFrom为空且groupAllowFrom是数组,则原样搬移,避免丢失用户配置 |
defaultAccount | defaultAccount(保留) | 官方 0.8.25 schema 允许该字段,ClawX 保留多账户默认行为 |
群配置白名单
官方 schema 下的群级配置只保留以下键(OFFICIAL_GROUP_KEYS):requireMention、tools、enabled、allowFrom、systemPrompt、groupSessionScope。sanitizeDingTalkGroups会遍历groups与每个accounts.<id>.groups,先完成groupAllowFrom → allowFrom映射,再删除白名单之外的键。
被提及(mention)默认行为的双轨保留
社区插件与官方连接器在"开放群组是否必须 @ 才响应"上默认值不同,迁移必须分别保留各自语义:
- 存量 ClawX 配置:社区连接器允许开放群(
groupPolicy: open)下未提及消息也能响应。清洗时若requireMention未设置且groupPolicy为空或open,则写入requireMention: false(preserveCommunityDefaults = true),保持既有行为; - 从
dingtalk-connector导入的配置:官方默认requireMention: true。在 migrateDingTalkChannelSection 中,当只存在channels.dingtalk-connector且requireMention未设置时,会显式写入true,然后整体折叠为channels.dingtalk;当两个键同时存在时,以channels.dingtalk为准并删除官方键。
双通道配置折叠
migrateDingTalkChannelSection的完整逻辑为:
- 存在
channels.dingtalk-connector且不存在channels.dingtalk→ 官方配置补上requireMention: true默认后复制到channels.dingtalk,删除官方键; - 两个键都存在 → 直接删除
channels.dingtalk-connector(channels.dingtalk优先); - 对折叠后的
channels.dingtalk执行sanitizeDingTalkChannelConfig(config, 'channel', ...),其中preserveCommunityDefaults参数取决于原配置是否本就用channels.dingtalk(即存量 ClawX 配置保留社区默认,官方导入配置保留官方默认)。
这套清洗在 channel-config.ts 的两处被调用:saveChannelConfig保存通道时对表单输入做账户级清洗(sanitizeDingTalkChannelConfig(transformedConfig, 'account')),以及sanitizeChannelSectionsBeforeWrite在每次配置提交前执行migrateDingTalkChannelSection+migrateDingTalkPluginRegistrations,确保磁盘上的配置永远保持单一dingtalk身份。
插件注册收敛:plugins.allow/plugins.entries只保留一个dingtalk
migrateDingTalkPluginRegistrations负责收敛插件注册表:
plugins.allow数组:过滤掉dingtalk-connector,若dingtalk不在其中则追加;plugins.entries:若存在dingtalk-connector条目,复制到dingtalk(若尚无)后删除官方键;ensureDingTalkPluginActivation:兜底保证plugins.enabled = true、plugins.allow包含dingtalk、plugins.entries.dingtalk = { enabled: true },并删除任何dingtalk-connector残留条目。
同时,channel-config.ts 中对插件条目做了账户字段约束:plugins.entries.<id>只承载激活元数据,ensurePluginRegistration会删除pluginEntry.accounts与pluginEntry.defaultAccount,因为 OpenClaw 2026.7.1 会拒绝这种"激活条目里混入账户配置"的非法形状——通道凭据必须只存在于channels.<id>下。钉钉的clientId被注册为唯一凭据键(CHANNEL_UNIQUE_CREDENTIAL_KEY中的dingtalk: 'clientId'),保存时若两个账户复用同一clientId会被拒绝。
账户身份归一化:官方内部__default__映射回 ClawX 的default
官方连接器内部使用__default__作为默认账户 id,而 ClawX 存量配置、通道绑定与按账户划分的会话键全部使用default。若不做处理,升级后运行时会把账户解析到主 Agent 或全新的会话命名空间,导致既有的会话历史"失联"。
dingtalk-plugin-compat.ts 的patchDingTalkChannelIdsInJs在补丁编译产物时同步执行:
.replace(/(["'])dingtalk-connector\1/g, `$1${DINGTALK_PLUGIN_ID}$1`) .replace(/(["'])__default__\1/g, '$1default$1');即把 JS 中所有被引号包裹的"__default__"字面量改写为"default",让官方连接器运行时解析到与 ClawX 相同的账户身份,保证升级后凭据、绑定和会话键全部原位复用,无需用户重新配对。这是expectedUserBehavior中"Existing DingTalk users keepchannels.dingtalkcredentials, bindings, and session keys without re-pairing"的实现基础。
安装与升级流水线:自动把社区镜像替换为官方镜像
plugin-install.ts 是插件安装/升级的核心:
已知清单 ID 修正
MANIFEST_ID_FIXES表把上游 npm 包声明的 manifest id 修正为 ClawX 有效 id:'dingtalk-connector': 'dingtalk'(另一条是 WeCom 的wecom-openclaw-plugin → wecom)。fixupPluginManifest在插件被复制到~/.openclaw/extensions/<dir>后依次执行:修正openclaw.plugin.json的id、调用remapDingTalkOfficialManifest、修正package.json的 npm 元数据(保留真实上游名@dingtalk-real-ai/dingtalk-connector,避免 OpenClaw repair planner 因包名不存在而启动失败)、patchPluginEntryIds修正编译入口中硬编码的插件 id、patchDingTalkCompiledChannelIds对官方包执行前述的 JS 身份字面量替换。
社区 → 官方升级判定
ensurePluginInstalled中有一个专门判定:当pluginDirName === 'dingtalk'且已安装包名是@soimy/dingtalk而源包名是@dingtalk-real-ai/dingtalk-connector时,即使版本字符串相同也强制覆盖安装(communityDingTalkMirror分支)。配合 config-sync.ts 的packageOwnerChanged判定(源包名 ≠ 已安装包名即视为升级),确保升级安装不必等待官方连接器发新版本。
安装记录与 peer 链接
TRUSTED_OFFICIAL_EXTENSION_PLUGINS中钉钉的条目为:npmName: '@dingtalk-real-ai/dingtalk-connector'、pluginId: 'dingtalk'、recordSource: 'path'、legacyPluginIds: ['dingtalk-connector']。ClawX 会把安装记录写入 OpenClaw 的 SQLite 索引(syncTrustedOfficialPluginInstallRecord),同时删除plugins.installs中的遗留元数据;repairPluginOpenClawPeerLink会在镜像目录的node_modules/openclaw建立指向运行时包目录的符号链接——OpenClaw 2026.7.1 在报告 Gateway ready 前会审计这条链接。开发模式下copyPluginFromNodeModules还会从 pnpm 虚拟存储收集传递依赖并展平复制到镜像的node_modules/。
遗留扩展目录清理
removeLegacyOfficialDingTalkExtension删除~/.openclaw/extensions/dingtalk-connector遗留目录,但只有先确认规范化镜像(extensions/dingtalk/package.json的包名是官方 npm 名)就绪后才删除(requireCanonicalMirror: true),避免在镜像尚未就绪时删掉唯一可用插件。plugin-install.ts 的日志明确:"Keeping dingtalk-connector extension until the canonical official mirror is installed"。
ensureDingTalkPluginInstalled将上述步骤串成一条链路:安装/升级dingtalk镜像 →ensureDingTalkDwsInstalled()→ 删除遗留官方扩展目录;它与其他通道插件一起在启动时由ensureAllBundledPluginsInstalled以 fire-and-forget 方式批量执行。
dws 工作区 CLI:预启动供给与桌面 OAuth 授权
官方连接器的 skills(如dws-cli)需要钉钉工作区 CLI(dws)才能执行日历/文档类命令,这是本次迁移引入的全新能力。dingtalk-dws.ts 完整实现了供给与授权:
二进制供给与平台归档
- 常量:
DINGTALK_DWS_NPM = 'dingtalk-workspace-cli'、DINGTALK_DWS_VERSION = '1.0.30'; - 安装目录固定在
~/.openclaw/tools/dingtalk-workspace-cli; DWS_PLATFORM_ARCHIVES维护六个平台的归档名:darwin-x64/darwin-arm64对应dws-darwin-*.tar.gz,linux-x64/linux-arm64对应dws-linux-*.tar.gz,win32-x64/win32-arm64对应dws-windows-*.zip;- 官方 npm 包的 postinstall 本会从
assets/提取vendor/dws,但 pnpm 可能跳过该脚本,因此 ClawX 自行提取:extractDingTalkDwsVendor用tar/powershell Expand-Archive/unzip解包后定位dws/dws.exe二进制,复制到vendor/并chmod 0o755(Windows 除外),随后删除assets/以节省磁盘; - 打包模式下从
process.resourcesPath的dingtalk-dws/app.asar.unpacked/node_modules/dingtalk-workspace-cli等候选源解析包目录,开发模式从node_modules解析; resolveDingTalkDwsBinDir返回vendor目录(而非bin/),因为 Windows 上bin/dws.jswrapper 没有node_modules/.bin/dws.cmdshim,直接暴露vendor/dws.exe才能被正常命令查找;ensureDingTalkDwsInstalled具备幂等性:已安装且版本为 1.0.30 且 wrapper/vendor 二进制齐备时直接返回,否则从源复制并提取。
预启动供给:不依赖插件维护缓存、不阻塞基础聊天
config-sync.ts 的provisionConfiguredDingTalkDws是预启动(prelaunch)供给入口:只要configuredChannels包含dingtalk就调用ensureDingTalkDwsInstalled({ probeAuth: false })——注意probeAuth: false意味着供给阶段不探测授权状态,设备登录是交互式的,绝不能阻塞通道保存或 Gateway 启动。它独立于插件维护缓存(plugin-maintenance cache)运行,对旧版本升级(未经过通道保存)同样生效,且 dws 不可用时只记录告警日志,绝不阻断基础聊天。供给的 dwsvendor目录会被加入 PATH,供官方钉钉 skills(dws-cli)执行。
桌面回环 OAuth 与设备码双流程
startDingTalkDwsOAuth是授权核心,支持两种流程:
- 桌面回环 OAuth(loopback):优先启动
dws auth login --format json。注释说明这是刻意选择——当组织尚未开启 CLI 数据访问权限时,DWS 可重定向到本地审批页,让用户直接向主管理员申请审批,而不必退回终端; - 设备码流程(device flow):
parseDingTalkDwsDeviceOutput从输出中提取verificationUri(登录页)、verificationUriComplete(含user_code的完成链接)与显示授权码,默认有效期 900 秒(DEVICE_AUTH_FALLBACK_EXPIRES_SECONDS);回环流程兜底有效期 600 秒。
运行时通过环境变量注入凭据:DWS_CLIENT_ID、DWS_CLIENT_SECRET(来自 ClawX 保存的通道凭据)以及DINGTALK_AGENT: 'DING_DWS_CLAW'。probeDingTalkDwsAuth以dws auth status --format json探测授权状态(authorized/needs_auth/unavailable)。错误分类classifyDingTalkDwsOAuthError覆盖常见失败:用户不在允许范围、拒绝授权、client secret 无效、组织未开启 CLI 数据访问、权限不足、网络错误、授权码过期等,中文/英文错误文本均有匹配规则。
安全与 UI 状态
- 状态快照
DingTalkDwsOAuthSnapshot携带verificationUri、userCode、expiresAt等字段,由渲染层在通道配置弹窗中展示; - 失败日志不打印原始 CLI 输出(可能包含一次性授权码),只记录退出码与归类原因(dingtalk-dws.ts);
getDingTalkDwsStatusNote提供 30 秒缓存的状态提示(dingtalk_dws_missing/dingtalk_dws_auth_required),供健康诊断与 UI 展示。
用户可见行为:升级后不需要重新配对
任务规范expectedUserBehavior给出四条升级后的行为承诺,均可与上述实现一一对应:
- 零重配对:存量用户保留
channels.dingtalk凭据、绑定与会话键——由__default__ → default归一化与配置折叠保证; - 自愈式供给:已配置钉钉通道的升级会在 Gateway 启动前自动供给/修复 dws CLI,无需用户编辑并重新保存凭据;未认证的安装会暴露工作区授权动作——由
provisionConfiguredDingTalkDws与ensureDingTalkPluginInstalled保证; - UI 身份不变:Channels 页面只显示
dingtalk,dingtalk-connector永不出现在目录类型中——由目录收敛与 i18n 文案(shared/i18n/locales/zh/channels.json 等四语)保证; - 永不双开:社区 soimy 与官方连接器绝不在同一个
clientId上同时运行——由插件注册收敛、遗留目录延迟删除与镜像替换保证。
此外,即使 dws 工作区授权被跳过或仍在待处理状态,保存后聊天也能正常工作;新配置可以在 ClawX 通道弹窗内完成可选的桌面回环 OAuth,且clientSecret不会暴露给 Renderer 进程。
验收标准与测试覆盖
迁移任务在acceptance中列出了可验证的验收清单,仓库中的实现与测试均可逐条核对:
- 官方连接器固定为
0.8.25并重映射到dingtalk插件/通道 id;npm 元数据保持@dingtalk-real-ai/dingtalk-connector;Gateway RPC 名dingtalk-connector.*保持完整; channels.dingtalk+channels.dingtalk-connector双键折叠为dingtalk;从官方导入且无plugins对象的配置会在插件恢复前完成迁移并获得规范的dingtalk激活元数据;- soimy 专属字段被剔除;
messageType: card → groupReplyMode: aicard;嵌套groupAllowFrom → allowFrom;defaultAccount保留; - 存量 ClawX 配置保留开放群提及行为,官方导入配置保留官方默认;
plugins.allow/plugins.entries只保留单一dingtalk身份;启动时仅在规范化镜像就绪后删除遗留extensions/dingtalk-connector;- 锁文件不保留
@soimy/dingtalk@3.6.10(见 pnpm-lock.yaml); - 新钉钉配置在通道配置持久化保存后可选用 dws 桌面回环 OAuth,
clientSecret不暴露给 Renderer; - 预启动供给可修复存量已配置通道的 dws,独立于插件维护缓存、对当前捆绑版本幂等、安装不可用时绝不阻塞基础聊天。
测试证据集中在:
- dingtalk-plugin-compat.test.ts:覆盖
sanitizeDingTalkChannelConfig(card/markdown 映射与嵌套账户清洗)、migrateDingTalkChannelSection(官方配置复制、双键优先)、migrateDingTalkPluginRegistrations(注册折叠)、ensureDingTalkPluginActivation、remapDingTalkOfficialManifest/remapDingTalkOfficialPackageJson(保留 npm 名、改写通道 id、不影响无关 manifest)、patchDingTalkChannelIdsInJs(改写通道与默认账户 id、不触碰 Gateway RPC); - dingtalk-dws.test.ts:dws 供给、授权探测与输出解析;
- plugin-install.test.ts、config-sync.test.ts、channel-config.test.ts、openclaw-bundle-config.test.ts:镜像替换、预启动供给、配置折叠链路;
- channels-dingtalk-workspace-auth.spec.ts 与 channels-health-diagnostics.spec.ts:E2E 层面验证工作区授权入口与通道健康诊断。
排查与运维建议
遇到迁移相关问题时,可以按以下线索定位:
- 插件加载失败(plugin id mismatch):检查
~/.openclaw/extensions/dingtalk/openclaw.plugin.json的id是否为dingtalk、入口 JS 中id:字面量是否被patchPluginEntryIds修正;确认node_modules/openclawpeer 链接指向运行时包目录; - 双 Stream / 重复 clientId:检查
~/.openclaw/config.json(或等效配置路径)中是否存在channels.dingtalk-connector与plugins.entries.dingtalk-connector残留,正常情况下它们会被migrateDingTalkChannelSection/migrateDingTalkPluginRegistrations清除; - 会话历史"消失":确认 JS 补丁是否把
__default__改写为default,否则会话键会落入新命名空间; - dws 状态提示
dingtalk_dws_missing:说明~/.openclaw/tools/dingtalk-workspace-cli缺失或版本非 1.0.30,可触发一次通道保存或重启让预启动供给重建;dingtalk_dws_auth_required则说明二进制就绪但尚未授权,走通道弹窗的 OAuth 流程即可; - 授权失败归类:对照 classifyDingTalkDwsOAuthError 的中英文错误匹配模式,确认是组织权限(未开启 CLI 数据访问)、凭据无效还是网络问题。
整体而言,这次迁移的技术内核是"身份归一化 + 配置折叠 + 运行时补丁"三位一体:对外保持dingtalk单一目录身份,对内把官方连接器的 npm 元数据、RPC 接口原样保留,只改写身份字面量,配合预启动的 dws 供给与桌面 OAuth,让存量用户在升级后几乎无感地完成从社区插件到官方连接器的过渡。
- 人工智能
- AI 应用
- 桌面应用
- 交互助手
【免费下载链接】ClawX
ClawX is a desktop app that provides a graphical interface for OpenClaw AI agents. It turns CLI-based AI orchestration into a desktop experience without using the terminal. China website is https://clawx.com.cn.
相关推荐
Apache APISIX 集成钉钉 OAuth 2.0 登录:dingtalk-auth 插件实战指南
Apache APISIX 集成钉钉 OAuth 2.0 登录:dingtalk auth 插件实战指南 本指南以 Apache APISIX 的 dingta
API网关后端云原生微服务AtlasOS 显卡性能优化怎么做:新手 4 步实操指南
AtlasOS 显卡性能优化怎么做:新手 4 步实操指南 AtlasOS 是一个开源的 Windows 轻量改造项目,本文围绕它的显卡性能优化能力展开:通过清理
操作系统隐私合规从0到1精通ChatGPT-DingTalk:企业级钉钉AI机器人部署与实战指南
从0到1精通ChatGPT DingTalk:企业级钉钉AI机器人部署与实战指南 引言:为什么选择ChatGPT DingTalk? 你是否还在为团队沟通中的信
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考