@junjiezhang/openclaw-wecom-plugin 1.0.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.
Files changed (97) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +227 -0
  3. package/dist/accounts.d.ts +19 -0
  4. package/dist/accounts.d.ts.map +1 -0
  5. package/dist/accounts.js +52 -0
  6. package/dist/accounts.js.map +1 -0
  7. package/dist/bot.d.ts +30 -0
  8. package/dist/bot.d.ts.map +1 -0
  9. package/dist/bot.js +290 -0
  10. package/dist/bot.js.map +1 -0
  11. package/dist/channel.d.ts +4 -0
  12. package/dist/channel.d.ts.map +1 -0
  13. package/dist/channel.js +254 -0
  14. package/dist/channel.js.map +1 -0
  15. package/dist/client.d.ts +7 -0
  16. package/dist/client.d.ts.map +1 -0
  17. package/dist/client.js +41 -0
  18. package/dist/client.js.map +1 -0
  19. package/dist/config-schema.d.ts +73 -0
  20. package/dist/config-schema.d.ts.map +1 -0
  21. package/dist/config-schema.js +79 -0
  22. package/dist/config-schema.js.map +1 -0
  23. package/dist/dedup.d.ts +3 -0
  24. package/dist/dedup.d.ts.map +1 -0
  25. package/dist/dedup.js +39 -0
  26. package/dist/dedup.js.map +1 -0
  27. package/dist/directory.d.ts +38 -0
  28. package/dist/directory.d.ts.map +1 -0
  29. package/dist/directory.js +66 -0
  30. package/dist/directory.js.map +1 -0
  31. package/dist/index.d.ts +11 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +16 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/media.d.ts +17 -0
  36. package/dist/media.d.ts.map +1 -0
  37. package/dist/media.js +64 -0
  38. package/dist/media.js.map +1 -0
  39. package/dist/monitor.d.ts +9 -0
  40. package/dist/monitor.d.ts.map +1 -0
  41. package/dist/monitor.js +233 -0
  42. package/dist/monitor.js.map +1 -0
  43. package/dist/outbound.d.ts +3 -0
  44. package/dist/outbound.d.ts.map +1 -0
  45. package/dist/outbound.js +24 -0
  46. package/dist/outbound.js.map +1 -0
  47. package/dist/policy.d.ts +29 -0
  48. package/dist/policy.d.ts.map +1 -0
  49. package/dist/policy.js +65 -0
  50. package/dist/policy.js.map +1 -0
  51. package/dist/probe.d.ts +6 -0
  52. package/dist/probe.d.ts.map +1 -0
  53. package/dist/probe.js +7 -0
  54. package/dist/probe.js.map +1 -0
  55. package/dist/reply-dispatcher.d.ts +16 -0
  56. package/dist/reply-dispatcher.d.ts.map +1 -0
  57. package/dist/reply-dispatcher.js +57 -0
  58. package/dist/reply-dispatcher.js.map +1 -0
  59. package/dist/runtime.d.ts +4 -0
  60. package/dist/runtime.d.ts.map +1 -0
  61. package/dist/runtime.js +11 -0
  62. package/dist/runtime.js.map +1 -0
  63. package/dist/send.d.ts +18 -0
  64. package/dist/send.d.ts.map +1 -0
  65. package/dist/send.js +61 -0
  66. package/dist/send.js.map +1 -0
  67. package/dist/targets.d.ts +4 -0
  68. package/dist/targets.d.ts.map +1 -0
  69. package/dist/targets.js +16 -0
  70. package/dist/targets.js.map +1 -0
  71. package/dist/types.d.ts +2 -0
  72. package/dist/types.d.ts.map +1 -0
  73. package/dist/types.js +2 -0
  74. package/dist/types.js.map +1 -0
  75. package/openclaw.plugin.json +12 -0
  76. package/package.json +64 -0
  77. package/src/accounts.ts +81 -0
  78. package/src/bot.ts +410 -0
  79. package/src/channel.ts +278 -0
  80. package/src/client.ts +55 -0
  81. package/src/config-schema.ts +102 -0
  82. package/src/dedup.ts +60 -0
  83. package/src/directory.ts +150 -0
  84. package/src/index.ts +20 -0
  85. package/src/media.ts +105 -0
  86. package/src/monitor.ts +344 -0
  87. package/src/outbound.ts +26 -0
  88. package/src/policy.ts +108 -0
  89. package/src/probe.ts +13 -0
  90. package/src/reply-dispatcher.ts +78 -0
  91. package/src/runtime.ts +14 -0
  92. package/src/send.ts +91 -0
  93. package/src/targets.ts +21 -0
  94. package/src/types.d.ts +17 -0
  95. package/src/types.ts +3 -0
  96. package/tsconfig.json +32 -0
  97. package/types.d.ts +43 -0
@@ -0,0 +1,16 @@
1
+ import { type ClawdbotConfig, type RuntimeEnv } from "openclaw/plugin-sdk";
2
+ export type CreateWeComReplyDispatcherParams = {
3
+ cfg: ClawdbotConfig;
4
+ agentId: string;
5
+ runtime: RuntimeEnv;
6
+ userId?: string;
7
+ chatId?: string;
8
+ isGroupChat: boolean;
9
+ accountId?: string;
10
+ };
11
+ export declare function createWeComReplyDispatcher(params: CreateWeComReplyDispatcherParams): {
12
+ dispatcher: any;
13
+ replyOptions: any;
14
+ markDispatchIdle: any;
15
+ };
16
+ //# sourceMappingURL=reply-dispatcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reply-dispatcher.d.ts","sourceRoot":"","sources":["../src/reply-dispatcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EAEnB,KAAK,UAAU,EAChB,MAAM,qBAAqB,CAAC;AAK7B,MAAM,MAAM,gCAAgC,GAAG;IAC7C,GAAG,EAAE,cAAc,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,UAAU,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,gCAAgC;;;;EAyDlF"}
@@ -0,0 +1,57 @@
1
+ import { createReplyPrefixContext, } from "openclaw/plugin-sdk";
2
+ import { resolveWeComAccount } from "./accounts.js";
3
+ import { getWeComRuntime } from "./runtime.js";
4
+ import { sendMessageWeCom, sendGroupMessageWeCom } from "./send.js";
5
+ export function createWeComReplyDispatcher(params) {
6
+ const core = getWeComRuntime();
7
+ const { cfg, agentId, userId, chatId, isGroupChat, accountId } = params;
8
+ const account = resolveWeComAccount({ cfg, accountId });
9
+ const prefixContext = createReplyPrefixContext({ cfg, agentId });
10
+ const textChunkLimit = core.channel.text.resolveTextChunkLimit(cfg, "wecom", accountId, {
11
+ fallbackLimit: 2000,
12
+ });
13
+ const chunkMode = core.channel.text.resolveChunkMode(cfg, "wecom");
14
+ const { dispatcher, replyOptions, markDispatchIdle } = core.channel.reply.createReplyDispatcherWithTyping({
15
+ responsePrefix: prefixContext.responsePrefix,
16
+ responsePrefixContextProvider: prefixContext.responsePrefixContextProvider,
17
+ humanDelay: core.channel.reply.resolveHumanDelayConfig(cfg, agentId),
18
+ deliver: async (payload) => {
19
+ const text = payload.text ?? "";
20
+ if (!text.trim()) {
21
+ return;
22
+ }
23
+ for (const chunk of core.channel.text.chunkTextWithMode(text, textChunkLimit, chunkMode)) {
24
+ if (isGroupChat && chatId) {
25
+ await sendGroupMessageWeCom({
26
+ cfg,
27
+ chatId,
28
+ text: chunk,
29
+ accountId,
30
+ });
31
+ }
32
+ else if (userId) {
33
+ await sendMessageWeCom({
34
+ cfg,
35
+ to: userId,
36
+ text: chunk,
37
+ accountId,
38
+ });
39
+ }
40
+ }
41
+ },
42
+ onError: async (error, info) => {
43
+ params.runtime.error?.(`wecom[${account.accountId}] ${info.kind} reply failed: ${String(error)}`);
44
+ },
45
+ onIdle: async () => { },
46
+ onCleanup: () => { },
47
+ });
48
+ return {
49
+ dispatcher,
50
+ replyOptions: {
51
+ ...replyOptions,
52
+ onModelSelected: prefixContext.onModelSelected,
53
+ },
54
+ markDispatchIdle,
55
+ };
56
+ }
57
+ //# sourceMappingURL=reply-dispatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reply-dispatcher.js","sourceRoot":"","sources":["../src/reply-dispatcher.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,GAIzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAYpE,MAAM,UAAU,0BAA0B,CAAC,MAAwC;IACjF,MAAM,IAAI,GAAG,eAAe,EAAE,CAAC;IAC/B,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC;IACxE,MAAM,OAAO,GAAG,mBAAmB,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC;IACxD,MAAM,aAAa,GAAG,wBAAwB,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;IAEjE,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE;QACtF,aAAa,EAAE,IAAI;KACpB,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAEnE,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,gBAAgB,EAAE,GAClD,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,+BAA+B,CAAC;QACjD,cAAc,EAAE,aAAa,CAAC,cAAc;QAC5C,6BAA6B,EAAE,aAAa,CAAC,6BAA6B;QAC1E,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,uBAAuB,CAAC,GAAG,EAAE,OAAO,CAAC;QACpE,OAAO,EAAE,KAAK,EAAE,OAAqB,EAAE,EAAE;YACvC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;YAChC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;gBACjB,OAAO;YACT,CAAC;YAED,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,cAAc,EAAE,SAAS,CAAC,EAAE,CAAC;gBACzF,IAAI,WAAW,IAAI,MAAM,EAAE,CAAC;oBAC1B,MAAM,qBAAqB,CAAC;wBAC1B,GAAG;wBACH,MAAM;wBACN,IAAI,EAAE,KAAK;wBACX,SAAS;qBACV,CAAC,CAAC;gBACL,CAAC;qBAAM,IAAI,MAAM,EAAE,CAAC;oBAClB,MAAM,gBAAgB,CAAC;wBACrB,GAAG;wBACH,EAAE,EAAE,MAAM;wBACV,IAAI,EAAE,KAAK;wBACX,SAAS;qBACV,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;YAC7B,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,CACpB,SAAS,OAAO,CAAC,SAAS,KAAK,IAAI,CAAC,IAAI,kBAAkB,MAAM,CAAC,KAAK,CAAC,EAAE,CAC1E,CAAC;QACJ,CAAC;QACD,MAAM,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;QACtB,SAAS,EAAE,GAAG,EAAE,GAAE,CAAC;KACpB,CAAC,CAAC;IAEL,OAAO;QACL,UAAU;QACV,YAAY,EAAE;YACZ,GAAG,YAAY;YACf,eAAe,EAAE,aAAa,CAAC,eAAe;SAC/C;QACD,gBAAgB;KACjB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { PluginRuntime } from "openclaw/plugin-sdk";
2
+ export declare function setWeComRuntime(next: PluginRuntime): void;
3
+ export declare function getWeComRuntime(): PluginRuntime;
4
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIzD,wBAAgB,eAAe,CAAC,IAAI,EAAE,aAAa,QAElD;AAED,wBAAgB,eAAe,IAAI,aAAa,CAK/C"}
@@ -0,0 +1,11 @@
1
+ let runtime = null;
2
+ export function setWeComRuntime(next) {
3
+ runtime = next;
4
+ }
5
+ export function getWeComRuntime() {
6
+ if (!runtime) {
7
+ throw new Error("WeCom runtime not initialized");
8
+ }
9
+ return runtime;
10
+ }
11
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAEA,IAAI,OAAO,GAAyB,IAAI,CAAC;AAEzC,MAAM,UAAU,eAAe,CAAC,IAAmB;IACjD,OAAO,GAAG,IAAI,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
package/dist/send.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ import type { ClawdbotConfig } from "openclaw/plugin-sdk";
2
+ export declare function sendMessageWeCom({ cfg, to, text, accountId, }: {
3
+ cfg: ClawdbotConfig;
4
+ to: string;
5
+ text: string;
6
+ accountId?: string;
7
+ }): Promise<{
8
+ messageId: string;
9
+ }>;
10
+ export declare function sendGroupMessageWeCom({ cfg, chatId, text, accountId, }: {
11
+ cfg: ClawdbotConfig;
12
+ chatId: string;
13
+ text: string;
14
+ accountId?: string;
15
+ }): Promise<{
16
+ messageId: string;
17
+ }>;
18
+ //# sourceMappingURL=send.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"send.d.ts","sourceRoot":"","sources":["../src/send.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAO1D,wBAAsB,gBAAgB,CAAC,EACrC,GAAG,EACH,EAAE,EACF,IAAI,EACJ,SAAS,GACV,EAAE;IACD,GAAG,EAAE,cAAc,CAAC;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAgCjC;AAKD,wBAAsB,qBAAqB,CAAC,EAC1C,GAAG,EACH,MAAM,EACN,IAAI,EACJ,SAAS,GACV,EAAE;IACD,GAAG,EAAE,cAAc,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CA0BjC"}
package/dist/send.js ADDED
@@ -0,0 +1,61 @@
1
+ import { fetchWithSsrFGuard } from "openclaw/plugin-sdk";
2
+ import { resolveWeComCredentials } from "./accounts.js";
3
+ import { getWeComAccessToken } from "./client.js";
4
+ const WECOM_API_POLICY = { allowedHostnames: ["qyapi.weixin.qq.com"] };
5
+ export async function sendMessageWeCom({ cfg, to, text, accountId, }) {
6
+ const accessToken = await getWeComAccessToken({ cfg, accountId });
7
+ const { agentId } = resolveWeComCredentials({ cfg, accountId });
8
+ const url = `https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=${accessToken}`;
9
+ const { response, release } = await fetchWithSsrFGuard({
10
+ url,
11
+ init: {
12
+ method: "POST",
13
+ headers: { "Content-Type": "application/json" },
14
+ body: JSON.stringify({
15
+ touser: to,
16
+ msgtype: "text",
17
+ agentid: agentId,
18
+ text: { content: text },
19
+ }),
20
+ },
21
+ policy: WECOM_API_POLICY,
22
+ auditContext: "wecom-send-message",
23
+ });
24
+ let data;
25
+ try {
26
+ data = await response.json();
27
+ }
28
+ finally {
29
+ await release();
30
+ }
31
+ if (data.errcode !== 0) {
32
+ throw new Error(`WeCom send error ${data.errcode}: ${data.errmsg}`);
33
+ }
34
+ return { messageId: data.msgid ?? "" };
35
+ }
36
+ export async function sendGroupMessageWeCom({ cfg, chatId, text, accountId, }) {
37
+ const accessToken = await getWeComAccessToken({ cfg, accountId });
38
+ const url = `https://qyapi.weixin.qq.com/cgi-bin/appchat/send?access_token=${accessToken}`;
39
+ const { response, release } = await fetchWithSsrFGuard({
40
+ url,
41
+ init: {
42
+ method: "POST",
43
+ headers: { "Content-Type": "application/json" },
44
+ body: JSON.stringify({ chatid: chatId, msgtype: "text", text: { content: text } }),
45
+ },
46
+ policy: WECOM_API_POLICY,
47
+ auditContext: "wecom-send-group-message",
48
+ });
49
+ let data;
50
+ try {
51
+ data = await response.json();
52
+ }
53
+ finally {
54
+ await release();
55
+ }
56
+ if (data.errcode !== 0) {
57
+ throw new Error(`WeCom group send error ${data.errcode}: ${data.errmsg}`);
58
+ }
59
+ return { messageId: data.msgid ?? "" };
60
+ }
61
+ //# sourceMappingURL=send.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"send.js","sourceRoot":"","sources":["../src/send.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function normalizeWeComTarget(raw: string): string | null;
2
+ export declare function looksLikeWeComId(raw: string): boolean;
3
+ export declare function formatWeComTarget(userId: string): string;
4
+ //# sourceMappingURL=targets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"targets.d.ts","sourceRoot":"","sources":["../src/targets.ts"],"names":[],"mappings":"AAAA,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAY/D;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAErD;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAExD"}
@@ -0,0 +1,16 @@
1
+ export function normalizeWeComTarget(raw) {
2
+ if (!raw)
3
+ return null;
4
+ const cleaned = raw.replace(/^(wecom|user):/i, "");
5
+ if (/^[a-zA-Z0-9_-]+$/.test(cleaned)) {
6
+ return cleaned;
7
+ }
8
+ return null;
9
+ }
10
+ export function looksLikeWeComId(raw) {
11
+ return /^[a-zA-Z0-9_-]+$/.test(raw);
12
+ }
13
+ export function formatWeComTarget(userId) {
14
+ return `user:${userId}`;
15
+ }
16
+ //# sourceMappingURL=targets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"targets.js","sourceRoot":"","sources":["../src/targets.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC9C,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IAGtB,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC;IAGnD,IAAI,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACrC,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,OAAO,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,OAAO,QAAQ,MAAM,EAAE,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export type { WeComConfig, WeComGroupConfig, ResolvedWeComAccount } from "./config-schema.js";
2
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,12 @@
1
+ {
2
+ "id": "wecom",
3
+ "name": "WeCom",
4
+ "description": "WeCom (企业微信) channel plugin for OpenClaw",
5
+ "version": "1.0.0",
6
+ "channels": ["wecom"],
7
+ "configSchema": {
8
+ "type": "object",
9
+ "additionalProperties": false,
10
+ "properties": {}
11
+ }
12
+ }
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@junjiezhang/openclaw-wecom-plugin",
3
+ "version": "1.0.0",
4
+ "description": "OpenClaw WeCom (企业微信) channel plugin - Send and receive messages via WeCom",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "keywords": [
9
+ "openclaw",
10
+ "plugin",
11
+ "channel",
12
+ "wecom",
13
+ "企业微信"
14
+ ],
15
+ "author": "张俊杰",
16
+ "license": "MIT",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/pk19876824/openclaw-wecom-plugin.git"
20
+ },
21
+ "scripts": {
22
+ "build": "tsc",
23
+ "prepublishOnly": "npm run build",
24
+ "test": "echo \"Error: no test specified\" && exit 1"
25
+ },
26
+ "dependencies": {
27
+ "@sinclair/typebox": "0.34.48",
28
+ "zod": "^4.3.6",
29
+ "axios": "^1.6.0",
30
+ "crypto-js": "^4.2.0",
31
+ "xml2js": "^0.6.2"
32
+ },
33
+ "peerDependencies": {
34
+ "openclaw": ">=2025.1.0"
35
+ },
36
+ "devDependencies": {
37
+ "typescript": "^5.3.0",
38
+ "@types/node": "^20.0.0",
39
+ "@types/crypto-js": "^4.2.0",
40
+ "@types/xml2js": "^0.4.14"
41
+ },
42
+ "openclaw": {
43
+ "extensions": [
44
+ "./dist/index.js"
45
+ ],
46
+ "channel": {
47
+ "id": "wecom",
48
+ "label": "WeCom",
49
+ "selectionLabel": "WeCom (企业微信)",
50
+ "docsPath": "/channels/wecom",
51
+ "docsLabel": "wecom",
52
+ "blurb": "企业微信消息通道,支持私聊和群聊",
53
+ "aliases": ["wecom"],
54
+ "order": 40,
55
+ "quickstartAllowFrom": true
56
+ },
57
+ "install": {
58
+ "npmSpec": "@junjiezhang/openclaw-wecom-plugin",
59
+ "localPath": "openclaw-wecom-plugin",
60
+ "defaultChoice": "npm",
61
+ "gitUrl": "git+https://github.com/pk19876824/openclaw-wecom-plugin.git"
62
+ }
63
+ }
64
+ }
@@ -0,0 +1,81 @@
1
+ import type { ClawdbotConfig } from "openclaw/plugin-sdk";
2
+ import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk";
3
+ import type { WeComConfig, ResolvedWeComAccount } from "./types.js";
4
+
5
+ export function listWeComAccountIds(cfg: ClawdbotConfig): string[] {
6
+ const wecomCfg = cfg.channels?.wecom as WeComConfig | undefined;
7
+ if (!wecomCfg) return [];
8
+ return [DEFAULT_ACCOUNT_ID];
9
+ }
10
+
11
+ export function resolveDefaultWeComAccountId(cfg: ClawdbotConfig): string {
12
+ return DEFAULT_ACCOUNT_ID;
13
+ }
14
+
15
+ export function resolveWeComAccount({
16
+ cfg,
17
+ accountId,
18
+ }: {
19
+ cfg: ClawdbotConfig;
20
+ accountId?: string;
21
+ }): ResolvedWeComAccount {
22
+ const id = accountId ?? DEFAULT_ACCOUNT_ID;
23
+ const wecomCfg = cfg.channels?.wecom as WeComConfig | undefined;
24
+
25
+ if (!wecomCfg) {
26
+ return {
27
+ accountId: id,
28
+ enabled: false,
29
+ configured: false,
30
+ name: "default",
31
+ };
32
+ }
33
+
34
+ const enabled = wecomCfg.enabled ?? false;
35
+ const configured = !!(
36
+ wecomCfg.corpId &&
37
+ wecomCfg.agentId &&
38
+ wecomCfg.secret &&
39
+ wecomCfg.token &&
40
+ wecomCfg.encodingAESKey
41
+ );
42
+
43
+ return {
44
+ accountId: id,
45
+ enabled,
46
+ configured,
47
+ name: "default",
48
+ corpId: wecomCfg.corpId,
49
+ agentId: wecomCfg.agentId,
50
+ config: wecomCfg,
51
+ };
52
+ }
53
+
54
+ export function resolveWeComCredentials({
55
+ cfg,
56
+ accountId,
57
+ }: {
58
+ cfg: ClawdbotConfig;
59
+ accountId?: string;
60
+ }): {
61
+ corpId: string;
62
+ agentId: string;
63
+ secret: string;
64
+ token?: string;
65
+ encodingAESKey?: string;
66
+ } {
67
+ const account = resolveWeComAccount({ cfg, accountId });
68
+ const wecomCfg = account.config;
69
+
70
+ if (!wecomCfg?.corpId || !wecomCfg?.agentId || !wecomCfg?.secret) {
71
+ throw new Error("WeCom credentials not configured");
72
+ }
73
+
74
+ return {
75
+ corpId: wecomCfg.corpId,
76
+ agentId: wecomCfg.agentId,
77
+ secret: wecomCfg.secret,
78
+ token: wecomCfg.token,
79
+ encodingAESKey: wecomCfg.encodingAESKey,
80
+ };
81
+ }