dsh-dingtalk 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.en.md +129 -0
- package/README.md +29 -1
- package/lib/index.js +33 -0
- package/package.json +6 -6
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 stardustlc
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.en.md
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# dsh-dingtalk
|
|
2
|
+
|
|
3
|
+
[](https://awesome-dsh-plugin.com)
|
|
4
|
+
|
|
5
|
+
DeepSeek Harness DingTalk group robot notification plugin: lets the agent **push Markdown / plain-text messages to a DingTalk group one-way**. Pure plugin implementation, zero core changes, works out of the box.
|
|
6
|
+
|
|
7
|
+
Pure Node implementation, **cross-platform** (one codebase for Windows / macOS / Linux), depends only on `node:crypto` and the built-in `fetch` — no runtime dependencies, no native binaries.
|
|
8
|
+
|
|
9
|
+
## Tools
|
|
10
|
+
|
|
11
|
+
| Tool | Purpose |
|
|
12
|
+
|---|---|
|
|
13
|
+
| `dingtalk_notify` | Send a **Markdown** message to the configured DingTalk group (`title` heading + `text` Markdown body) |
|
|
14
|
+
| `dingtalk_text` | Send a **plain-text** message to the configured DingTalk group (`content`) |
|
|
15
|
+
|
|
16
|
+
Example:
|
|
17
|
+
|
|
18
|
+
> Send a message to the DingTalk group: title "Build complete", body "Pipeline #123 passed ✅".
|
|
19
|
+
|
|
20
|
+
## Compatibility
|
|
21
|
+
|
|
22
|
+
Verified against `@deepseek-ai/dsh@0.1.1-rc.2` on 2026-08-26. Built for the cordis patch-bundle plugin model (`cordis.patch.yml` + `dsh.bundle.patch`). No runtime imports of `@deepseek-ai/*` internals.
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
dsh plugin --profile web add dsh-dingtalk
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
After installing, restart `dsh web`. The plugin ships with an empty config and **won't crash startup**; calling any `dingtalk_*` tool before configuration returns a clear Chinese configuration hint.
|
|
31
|
+
|
|
32
|
+
## Uninstall
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
dsh plugin --profile web remove dsh-dingtalk
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Then restart the web service. To clean up fully, also remove the plugin entry from your profile `cordis.patch.yml` if you overrode it.
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
## Step 1: Get the webhook and signing secret
|
|
42
|
+
|
|
43
|
+
Use DingTalk's **custom robot** method — **no enterprise app or admin permission needed**:
|
|
44
|
+
|
|
45
|
+
1. Open the target DingTalk group → **Group settings** → **Smart group assistant** → **Add robot** → **Custom (connect a custom service via Webhook)**
|
|
46
|
+
2. The robot name is arbitrary; under **Security settings, check "Sign" (加签)**, then finish
|
|
47
|
+
3. Copy two things:
|
|
48
|
+
- **Webhook URL**: like `https://oapi.dingtalk.com/robot/send?access_token=xxxx`
|
|
49
|
+
- **Signing secret (secret)**: like `SECxxxx` (only appears after checking "Sign")
|
|
50
|
+
|
|
51
|
+
> For security settings it's recommended to check only "Sign". If you also check "Custom keywords", the robot validates whether the message contains the keyword — that's DingTalk server-side behavior, not handled by this plugin (see "Known limitations").
|
|
52
|
+
|
|
53
|
+
## Configuration
|
|
54
|
+
|
|
55
|
+
In your profile's `cordis.patch.yml` (under `$DSH_HOME/profiles/<name>/`), override the `tool-dingtalk` line, then restart:
|
|
56
|
+
|
|
57
|
+
```yaml
|
|
58
|
+
- id: tool-dingtalk
|
|
59
|
+
config:
|
|
60
|
+
webhook: https://oapi.dingtalk.com/robot/send?access_token=你的token
|
|
61
|
+
secret: SEC你的加签密钥 # 可选,但强烈建议;也可用环境变量 DSH_DINGTALK_SECRET
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Full configuration
|
|
65
|
+
|
|
66
|
+
| Field | Default | Description |
|
|
67
|
+
|---|---|---|
|
|
68
|
+
| `webhook` | required | Full webhook URL of the robot (`?access_token=...`) |
|
|
69
|
+
| `secret` | empty | Signing secret; when omitted, falls back to the `DSH_DINGTALK_SECRET` env var. Empty = no signing |
|
|
70
|
+
| `timeoutMs` | `10000` | Request timeout in milliseconds (1000–60000) |
|
|
71
|
+
|
|
72
|
+
### Store the secret in an environment variable
|
|
73
|
+
|
|
74
|
+
If you don't want to write the secret into YAML, write only `webhook` and set an environment variable:
|
|
75
|
+
|
|
76
|
+
```sh
|
|
77
|
+
# Windows PowerShell
|
|
78
|
+
$env:DSH_DINGTALK_SECRET = "SEC你的加签密钥"
|
|
79
|
+
# 或系统环境变量里加一条 DSH_DINGTALK_SECRET
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
An explicit `secret` in YAML takes precedence over the environment variable.
|
|
83
|
+
|
|
84
|
+
## Security notes
|
|
85
|
+
|
|
86
|
+
- **The webhook is the key to group notifications**: anyone who knows it can post to the group. Don't commit `cordis.patch.yml` to any Git repo; for the `secret`, prefer the `DSH_DINGTALK_SECRET` env var.
|
|
87
|
+
- This plugin is **one-way notification only** (agent → DingTalk group); it never reads messages from the group and has no two-way bot capability.
|
|
88
|
+
- This plugin performs no outbound telemetry; the `secret` is used in memory only to compute an HMAC signature, which is appended to the URL and sent to DingTalk's official endpoint.
|
|
89
|
+
|
|
90
|
+
## Signing algorithm (matches the official one)
|
|
91
|
+
|
|
92
|
+
When a `secret` is present, the request URL appends `timestamp` (millisecond timestamp) and `sign`:
|
|
93
|
+
|
|
94
|
+
```text
|
|
95
|
+
stringToSign = timestamp + "
|
|
96
|
+
" + secret
|
|
97
|
+
sign = urlencode(base64(HmacSHA256(secret, stringToSign)))
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Identical to this plugin's `computeDingTalkSign`, equivalent to `urllib.parse.quote_plus(base64(...))` in the official Python example.
|
|
101
|
+
|
|
102
|
+
## Known limitations
|
|
103
|
+
|
|
104
|
+
- **One-way notification only**: no support for enterprise self-built apps, no receiving group messages / two-way bots (@robot replies, etc.); these are v0.2+ directions.
|
|
105
|
+
- **No automatic workaround for custom keyword validation**: if the robot checks "Custom keywords" on DingTalk's side, messages must contain the keyword or DingTalk returns an error (errcode 310000 can also appear for this reason). This plugin attributes 310000 to signing; please also check the keyword setting.
|
|
106
|
+
- **No settings page**: v0.1 is a "node half-body"; configuration only via `cordis.patch.yml` (+ env var). A Web settings page is planned for v0.2+.
|
|
107
|
+
- **Message types**: currently only Markdown (`dingtalk_notify`) and plain text (`dingtalk_text`); image / Link / FeedCard / ActionCard etc. come later.
|
|
108
|
+
- **Markdown rendering**: DingTalk robot Markdown syntax differs slightly from standard Markdown (e.g., headings, links); write according to DingTalk's syntax.
|
|
109
|
+
|
|
110
|
+
## Error code reference
|
|
111
|
+
|
|
112
|
+
| errcode | Meaning | Suggestion |
|
|
113
|
+
|---|---|---|
|
|
114
|
+
| `0` | Success | — |
|
|
115
|
+
| `310000` | Signing validation failed (see the keyword note above) | Check that `secret` is correct and matches the robot's "Sign" setting |
|
|
116
|
+
| `120001` | `access_token` expired | Re-copy the webhook URL from the DingTalk group and overwrite `webhook` |
|
|
117
|
+
| other | Server error | Check the returned `errmsg` |
|
|
118
|
+
|
|
119
|
+
## Development
|
|
120
|
+
|
|
121
|
+
```sh
|
|
122
|
+
pnpm install
|
|
123
|
+
pnpm run build # tsc → lib/
|
|
124
|
+
pnpm test # 构建 + node --test(加签算法/配置解析/客户端封装/注册与中文报错)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## License
|
|
128
|
+
|
|
129
|
+
MIT. This is a community plugin, not affiliated with DeepSeek or DingTalk; `@deepseek-ai/*` is an officially reserved namespace.
|
package/README.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
|
+
[English](README.en.md)
|
|
2
|
+
|
|
1
3
|
# dsh-dingtalk
|
|
2
4
|
|
|
5
|
+
> **让 agent 在钉钉群里说话**:Markdown / 纯文本通知,加签安全,零依赖。
|
|
6
|
+
|
|
7
|
+
   
|
|
8
|
+
|
|
9
|
+
[](https://awesome-dsh-plugin.com)
|
|
10
|
+
|
|
11
|
+
|
|
3
12
|
DeepSeek Harness 钉钉群机器人通知插件:让 agent 能**单向推送 Markdown / 纯文本消息到钉钉群**。纯插件实现,零核心改动,安装即可用。
|
|
4
13
|
|
|
5
14
|
纯 Node 实现,**全平台通用**(Windows / macOS / Linux 同一份代码),只依赖 `node:crypto` 与内置 `fetch`,无运行时依赖、无原生二进制。
|
|
@@ -15,6 +24,10 @@ DeepSeek Harness 钉钉群机器人通知插件:让 agent 能**单向推送 Ma
|
|
|
15
24
|
|
|
16
25
|
> 帮我给钉钉群发一条消息:标题「构建完成」,正文「流水线 #123 已通过 ✅」。
|
|
17
26
|
|
|
27
|
+
## 兼容性
|
|
28
|
+
|
|
29
|
+
在 `@deepseek-ai/dsh@0.1.1-rc.2` 上验证(2026-08-26)。遵循 cordis 组合包补丁模型(`cordis.patch.yml` + `dsh.bundle.patch`),运行时不 import 任何 `@deepseek-ai/*` 内部模块。
|
|
30
|
+
|
|
18
31
|
## 安装
|
|
19
32
|
|
|
20
33
|
```sh
|
|
@@ -23,6 +36,15 @@ dsh plugin --profile web add dsh-dingtalk
|
|
|
23
36
|
|
|
24
37
|
装好后重启 `dsh web`。插件自带空配置,**不会弄崩启动**;配置前调用任何 `dingtalk_*` 工具都会返回明确的中文配置提示。
|
|
25
38
|
|
|
39
|
+
## 卸载
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
dsh plugin --profile web remove dsh-dingtalk
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
卸载后重启 Web 服务。如需彻底清理,可再手动删除自己 profile `cordis.patch.yml` 中覆盖的插件行。
|
|
46
|
+
|
|
47
|
+
|
|
26
48
|
## 第一步:拿到 webhook 与加签密钥
|
|
27
49
|
|
|
28
50
|
用钉钉【自定义机器人】方式,**不需要企业应用、不需要管理员权限**:
|
|
@@ -84,7 +106,7 @@ sign = urlencode(base64(HmacSHA256(secret, stringToSign)))
|
|
|
84
106
|
|
|
85
107
|
与本插件 `computeDingTalkSign` 一致,等价于官方 Python 示例的 `urllib.parse.quote_plus(base64(...))`。
|
|
86
108
|
|
|
87
|
-
##
|
|
109
|
+
## 已知限制
|
|
88
110
|
|
|
89
111
|
- **仅单向通知**:不支持企业自建应用、不支持接收群消息 / 双向机器人(@机器人 回复等),这些是 v0.2+ 的方向。
|
|
90
112
|
- **不支持自定义关键词校验的自动规避**:如果机器人在钉钉侧勾选了「自定义关键词」,消息必须包含关键词,否则钉钉返回错误(errcode 310000 也可能因此出现)。本插件把 310000 归因于加签,请同时检查关键词设置。
|
|
@@ -112,3 +134,9 @@ pnpm test # 构建 + node --test(加签算法/配置解析/客户端封
|
|
|
112
134
|
## 协议
|
|
113
135
|
|
|
114
136
|
MIT。这是一个社区插件,与 DeepSeek 官方及钉钉官方无关;`@deepseek-ai/*` 为官方保留命名空间。
|
|
137
|
+
|
|
138
|
+
## 相关插件
|
|
139
|
+
|
|
140
|
+
- [dsh-calendar](https://github.com/STARDUSTLC666/dsh-calendar) — CalDAV 日历五件套
|
|
141
|
+
- [dsh-dingtalk](https://github.com/STARDUSTLC666/dsh-dingtalk) — 钉钉群通知(零依赖)
|
|
142
|
+
- [dsh-email](https://github.com/STARDUSTLC666/dsh-email) — 邮件六件套 + Web 设置页
|
package/lib/index.js
CHANGED
|
@@ -100,6 +100,39 @@ export function apply(ctx, config = {}) {
|
|
|
100
100
|
return { ok: true, msgtype: 'text', title: '', errcode: result.errcode, errmsg: result.errmsg };
|
|
101
101
|
},
|
|
102
102
|
});
|
|
103
|
+
ctx.tools.register({
|
|
104
|
+
name: 'dingtalk_health',
|
|
105
|
+
description: 'dsh-dingtalk 自检:检查钉钉机器人 webhook 与加签密钥(secret)配置是否就绪(不发送任何消息)。遇到问题时先运行本工具定位。',
|
|
106
|
+
parameters: compileParameters({}),
|
|
107
|
+
output: {
|
|
108
|
+
schema: { type: 'object', additionalProperties: true },
|
|
109
|
+
render: (_args, value) => {
|
|
110
|
+
const rec = (value ?? {});
|
|
111
|
+
const rawChecks = Array.isArray(rec.checks) ? rec.checks : [];
|
|
112
|
+
const lines = ['dsh-dingtalk 自检' + (rec.ok === true ? ':正常。' : ':发现问题。')];
|
|
113
|
+
for (const item of rawChecks) {
|
|
114
|
+
const c = (item ?? {});
|
|
115
|
+
lines.push('- ' + String(c.name) + ':' + (c.ok === true ? '✅ ' + String(c.detail ?? '') : '❌ ' + String(c.detail ?? '')));
|
|
116
|
+
}
|
|
117
|
+
return oneText(lines.join('\n'));
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
async execute() {
|
|
121
|
+
const checks = [];
|
|
122
|
+
let ok = true;
|
|
123
|
+
try {
|
|
124
|
+
const resolved = resolveDingTalkConfig(config);
|
|
125
|
+
checks.push({ name: 'webhook', ok: true, detail: '已配置' });
|
|
126
|
+
const secret = resolved.secret;
|
|
127
|
+
checks.push({ name: '加签密钥', ok: true, detail: typeof secret === 'string' && secret !== '' ? '已配置(加签模式)' : '未配置(关键词/白名单模式)' });
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
ok = false;
|
|
131
|
+
checks.push({ name: 'webhook', ok: false, detail: error instanceof Error ? error.message : String(error) });
|
|
132
|
+
}
|
|
133
|
+
return { ok, plugin: 'dsh-dingtalk', checks };
|
|
134
|
+
},
|
|
135
|
+
});
|
|
103
136
|
}
|
|
104
137
|
export { resolveDingTalkConfig, DINGTALK_SECRET_ENV, DEFAULT_TIMEOUT_MS, clampInt } from './config.js';
|
|
105
138
|
export { DingTalkClient, DingTalkError, dingTalkErrorMessage } from './client.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-dingtalk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "钉钉群机器人单向通知工具(DeepSeek Harness 插件):agent 推送 Markdown / 纯文本消息到钉钉群,支持加签安全模式。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -17,11 +17,11 @@
|
|
|
17
17
|
"files": [
|
|
18
18
|
"lib",
|
|
19
19
|
"cordis.patch.yml",
|
|
20
|
-
"README.md"
|
|
20
|
+
"README.md",
|
|
21
|
+
"README.en.md"
|
|
21
22
|
],
|
|
22
23
|
"scripts": {
|
|
23
24
|
"build": "tsc",
|
|
24
|
-
"prepare": "tsc",
|
|
25
25
|
"prepublishOnly": "pnpm run build",
|
|
26
26
|
"test": "pnpm run build && node --test \"test/*.test.mjs\""
|
|
27
27
|
},
|
|
@@ -33,11 +33,11 @@
|
|
|
33
33
|
"dingtalk-robot",
|
|
34
34
|
"webhook"
|
|
35
35
|
],
|
|
36
|
-
"author": "
|
|
36
|
+
"author": "stardustlc",
|
|
37
37
|
"license": "MIT",
|
|
38
38
|
"packageManager": "pnpm@11.7.0",
|
|
39
39
|
"engines": {
|
|
40
|
-
"node": ">=
|
|
40
|
+
"node": ">=22"
|
|
41
41
|
},
|
|
42
42
|
"dsh": {
|
|
43
43
|
"bundle": {
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"typescript": "^5.7.3"
|
|
50
50
|
},
|
|
51
51
|
"repository": {
|
|
52
|
-
"url": "https://github.com/STARDUSTLC666/dsh-dingtalk",
|
|
52
|
+
"url": "git+https://github.com/STARDUSTLC666/dsh-dingtalk.git",
|
|
53
53
|
"type": "git"
|
|
54
54
|
},
|
|
55
55
|
"bugs": {
|