@wecom/wecom-openclaw-plugin 2026.4.2 → 2026.4.3-beta.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/README.md +395 -10
- package/dist/index.d.ts +2 -4
- package/dist/index.js +58 -0
- package/dist/src/accounts.d.ts +57 -0
- package/dist/src/accounts.js +222 -0
- package/dist/src/agent/api-client.d.ts +94 -0
- package/dist/src/agent/api-client.js +292 -0
- package/dist/src/agent/handler.d.ts +63 -0
- package/dist/src/agent/handler.js +551 -0
- package/dist/src/agent/index.d.ts +5 -0
- package/dist/src/agent/index.js +5 -0
- package/dist/src/agent/webhook.d.ts +24 -0
- package/dist/src/agent/webhook.js +228 -0
- package/dist/src/agent/xml.d.ts +21 -0
- package/dist/src/agent/xml.js +41 -0
- package/dist/src/channel.js +579 -0
- package/dist/src/chat-queue.d.ts +31 -0
- package/dist/src/chat-queue.js +45 -0
- package/dist/{esm/types/src → src}/const.d.ts +46 -0
- package/dist/{esm/src → src}/const.js +77 -30
- package/dist/{esm/src → src}/dm-policy.js +6 -9
- package/dist/src/dynamic-agent.d.ts +37 -0
- package/dist/src/dynamic-agent.js +60 -0
- package/dist/src/dynamic-routing.d.ts +65 -0
- package/dist/src/dynamic-routing.js +58 -0
- package/dist/{esm/src → src}/group-policy.js +8 -22
- package/dist/src/http.d.ts +26 -0
- package/dist/src/http.js +93 -0
- package/dist/{esm/types/src → src}/interface.d.ts +0 -2
- package/dist/src/interface.js +4 -0
- package/dist/src/mcp/index.js +6 -0
- package/dist/{esm/src → src}/mcp/interceptors/biz-error.js +2 -6
- package/dist/{esm/src → src}/mcp/interceptors/index.js +6 -10
- package/dist/{esm/src → src}/mcp/interceptors/msg-media.js +6 -10
- package/dist/{esm/src → src}/mcp/interceptors/smartpage-create.js +2 -6
- package/dist/{esm/src → src}/mcp/interceptors/smartpage-export.js +2 -6
- package/dist/src/mcp/interceptors/types.js +7 -0
- package/dist/{esm/src → src}/mcp/schema.js +1 -4
- package/dist/{esm/src → src}/mcp/tool.js +4 -8
- package/dist/{esm/src → src}/mcp/transport.js +15 -16
- package/dist/{esm/src → src}/media-handler.js +6 -10
- package/dist/{esm/src → src}/media-uploader.js +64 -10
- package/dist/{esm/src → src}/message-parser.js +1 -4
- package/dist/{esm/types/src → src}/message-sender.d.ts +18 -0
- package/dist/{esm/src → src}/message-sender.js +45 -11
- package/dist/{esm/src → src}/monitor.js +145 -292
- package/dist/{esm/src → src}/onboarding.js +22 -26
- package/dist/{esm/types/src → src}/openclaw-compat.d.ts +49 -0
- package/dist/{esm/src → src}/openclaw-compat.js +133 -27
- package/dist/{esm/src → src}/reqid-store.js +4 -7
- package/dist/{esm/src → src}/runtime.js +2 -5
- package/dist/src/shared/command-auth.d.ts +23 -0
- package/dist/src/shared/command-auth.js +73 -0
- package/dist/src/shared/xml-parser.d.ts +46 -0
- package/dist/src/shared/xml-parser.js +210 -0
- package/dist/{esm/src → src}/state-dir-resolve.js +3 -7
- package/dist/{esm/src → src}/state-manager.js +84 -16
- package/dist/src/target.d.ts +35 -0
- package/dist/src/target.js +67 -0
- package/dist/src/template-card-manager.d.ts +55 -0
- package/dist/src/template-card-manager.js +205 -0
- package/dist/{esm/src → src}/template-card-parser.js +17 -8
- package/dist/{esm/src → src}/timeout.js +2 -5
- package/dist/src/types/account.d.ts +29 -0
- package/dist/src/types/account.js +4 -0
- package/dist/src/types/config.d.ts +91 -0
- package/dist/src/types/config.js +7 -0
- package/dist/src/types/constants.d.ts +42 -0
- package/dist/src/types/constants.js +42 -0
- package/dist/src/types/index.d.ts +7 -0
- package/dist/src/types/index.js +5 -0
- package/dist/src/types/message.d.ts +238 -0
- package/dist/src/types/message.js +5 -0
- package/dist/{esm/types/src → src}/utils.d.ts +41 -0
- package/dist/{esm/src → src}/utils.js +24 -10
- package/dist/src/version.d.ts +2 -0
- package/dist/src/version.js +24 -0
- package/dist/src/webhook/command-auth.d.ts +47 -0
- package/dist/src/webhook/command-auth.js +96 -0
- package/dist/src/webhook/gateway.d.ts +36 -0
- package/dist/src/webhook/gateway.js +235 -0
- package/dist/src/webhook/handler.d.ts +18 -0
- package/dist/src/webhook/handler.js +420 -0
- package/dist/src/webhook/helpers.d.ts +156 -0
- package/dist/src/webhook/helpers.js +833 -0
- package/dist/src/webhook/http.d.ts +26 -0
- package/dist/src/webhook/http.js +94 -0
- package/dist/src/webhook/index.d.ts +11 -0
- package/dist/src/webhook/index.js +14 -0
- package/dist/src/webhook/media.d.ts +29 -0
- package/dist/src/webhook/media.js +88 -0
- package/dist/src/webhook/monitor.d.ts +59 -0
- package/dist/src/webhook/monitor.js +1161 -0
- package/dist/src/webhook/state.d.ts +220 -0
- package/dist/src/webhook/state.js +491 -0
- package/dist/src/webhook/target.d.ts +41 -0
- package/dist/src/webhook/target.js +132 -0
- package/dist/src/webhook/types.d.ts +347 -0
- package/dist/src/webhook/types.js +33 -0
- package/dist/src/webhook/video-frame.d.ts +13 -0
- package/dist/src/webhook/video-frame.js +30 -0
- package/package.json +15 -7
- package/dist/cjs/index.js +0 -45
- package/dist/cjs/index.js.map +0 -1
- package/dist/cjs/src/channel.js +0 -339
- package/dist/cjs/src/channel.js.map +0 -1
- package/dist/cjs/src/const.js +0 -137
- package/dist/cjs/src/const.js.map +0 -1
- package/dist/cjs/src/dm-policy.js +0 -89
- package/dist/cjs/src/dm-policy.js.map +0 -1
- package/dist/cjs/src/group-policy.js +0 -133
- package/dist/cjs/src/group-policy.js.map +0 -1
- package/dist/cjs/src/mcp/interceptors/biz-error.js +0 -70
- package/dist/cjs/src/mcp/interceptors/biz-error.js.map +0 -1
- package/dist/cjs/src/mcp/interceptors/index.js +0 -73
- package/dist/cjs/src/mcp/interceptors/index.js.map +0 -1
- package/dist/cjs/src/mcp/interceptors/msg-media.js +0 -159
- package/dist/cjs/src/mcp/interceptors/msg-media.js.map +0 -1
- package/dist/cjs/src/mcp/interceptors/smartpage-create.js +0 -157
- package/dist/cjs/src/mcp/interceptors/smartpage-create.js.map +0 -1
- package/dist/cjs/src/mcp/interceptors/smartpage-export.js +0 -93
- package/dist/cjs/src/mcp/interceptors/smartpage-export.js.map +0 -1
- package/dist/cjs/src/mcp/schema.js +0 -104
- package/dist/cjs/src/mcp/schema.js.map +0 -1
- package/dist/cjs/src/mcp/tool.js +0 -208
- package/dist/cjs/src/mcp/tool.js.map +0 -1
- package/dist/cjs/src/mcp/transport.js +0 -417
- package/dist/cjs/src/mcp/transport.js.map +0 -1
- package/dist/cjs/src/media-handler.js +0 -129
- package/dist/cjs/src/media-handler.js.map +0 -1
- package/dist/cjs/src/media-uploader.js +0 -284
- package/dist/cjs/src/media-uploader.js.map +0 -1
- package/dist/cjs/src/message-parser.js +0 -134
- package/dist/cjs/src/message-parser.js.map +0 -1
- package/dist/cjs/src/message-sender.js +0 -89
- package/dist/cjs/src/message-sender.js.map +0 -1
- package/dist/cjs/src/monitor.js +0 -991
- package/dist/cjs/src/monitor.js.map +0 -1
- package/dist/cjs/src/onboarding.js +0 -182
- package/dist/cjs/src/onboarding.js.map +0 -1
- package/dist/cjs/src/openclaw-compat.js +0 -400
- package/dist/cjs/src/openclaw-compat.js.map +0 -1
- package/dist/cjs/src/reqid-store.js +0 -88
- package/dist/cjs/src/reqid-store.js.map +0 -1
- package/dist/cjs/src/runtime.js +0 -16
- package/dist/cjs/src/runtime.js.map +0 -1
- package/dist/cjs/src/state-dir-resolve.js +0 -35
- package/dist/cjs/src/state-dir-resolve.js.map +0 -1
- package/dist/cjs/src/state-manager.js +0 -158
- package/dist/cjs/src/state-manager.js.map +0 -1
- package/dist/cjs/src/template-card-parser.js +0 -641
- package/dist/cjs/src/template-card-parser.js.map +0 -1
- package/dist/cjs/src/timeout.js +0 -42
- package/dist/cjs/src/timeout.js.map +0 -1
- package/dist/cjs/src/utils.js +0 -60
- package/dist/cjs/src/utils.js.map +0 -1
- package/dist/cjs/src/version.js +0 -26
- package/dist/cjs/src/version.js.map +0 -1
- package/dist/esm/index.js +0 -41
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/src/channel.js +0 -337
- package/dist/esm/src/channel.js.map +0 -1
- package/dist/esm/src/const.js.map +0 -1
- package/dist/esm/src/dm-policy.js.map +0 -1
- package/dist/esm/src/group-policy.js.map +0 -1
- package/dist/esm/src/mcp/interceptors/biz-error.js.map +0 -1
- package/dist/esm/src/mcp/interceptors/index.js.map +0 -1
- package/dist/esm/src/mcp/interceptors/msg-media.js.map +0 -1
- package/dist/esm/src/mcp/interceptors/smartpage-create.js.map +0 -1
- package/dist/esm/src/mcp/interceptors/smartpage-export.js.map +0 -1
- package/dist/esm/src/mcp/schema.js.map +0 -1
- package/dist/esm/src/mcp/tool.js.map +0 -1
- package/dist/esm/src/mcp/transport.js.map +0 -1
- package/dist/esm/src/media-handler.js.map +0 -1
- package/dist/esm/src/media-uploader.js.map +0 -1
- package/dist/esm/src/message-parser.js.map +0 -1
- package/dist/esm/src/message-sender.js.map +0 -1
- package/dist/esm/src/monitor.js.map +0 -1
- package/dist/esm/src/onboarding.js.map +0 -1
- package/dist/esm/src/openclaw-compat.js.map +0 -1
- package/dist/esm/src/reqid-store.js.map +0 -1
- package/dist/esm/src/runtime.js.map +0 -1
- package/dist/esm/src/state-dir-resolve.js.map +0 -1
- package/dist/esm/src/state-manager.js.map +0 -1
- package/dist/esm/src/template-card-parser.js.map +0 -1
- package/dist/esm/src/timeout.js.map +0 -1
- package/dist/esm/src/utils.js.map +0 -1
- package/dist/esm/src/version.js +0 -23
- package/dist/esm/src/version.js.map +0 -1
- package/dist/esm/types/index.d.ts +0 -9
- package/dist/esm/types/src/version.d.ts +0 -2
- /package/dist/{esm/types/src → src}/channel.d.ts +0 -0
- /package/dist/{esm/types/src → src}/dm-policy.d.ts +0 -0
- /package/dist/{esm/types/src → src}/group-policy.d.ts +0 -0
- /package/dist/{esm/types/src → src}/mcp/index.d.ts +0 -0
- /package/dist/{esm/types/src → src}/mcp/interceptors/biz-error.d.ts +0 -0
- /package/dist/{esm/types/src → src}/mcp/interceptors/index.d.ts +0 -0
- /package/dist/{esm/types/src → src}/mcp/interceptors/msg-media.d.ts +0 -0
- /package/dist/{esm/types/src → src}/mcp/interceptors/smartpage-create.d.ts +0 -0
- /package/dist/{esm/types/src → src}/mcp/interceptors/smartpage-export.d.ts +0 -0
- /package/dist/{esm/types/src → src}/mcp/interceptors/types.d.ts +0 -0
- /package/dist/{esm/types/src → src}/mcp/schema.d.ts +0 -0
- /package/dist/{esm/types/src → src}/mcp/tool.d.ts +0 -0
- /package/dist/{esm/types/src → src}/mcp/transport.d.ts +0 -0
- /package/dist/{esm/types/src → src}/media-handler.d.ts +0 -0
- /package/dist/{esm/types/src → src}/media-uploader.d.ts +0 -0
- /package/dist/{esm/types/src → src}/message-parser.d.ts +0 -0
- /package/dist/{esm/types/src → src}/monitor.d.ts +0 -0
- /package/dist/{esm/types/src → src}/onboarding.d.ts +0 -0
- /package/dist/{esm/types/src → src}/reqid-store.d.ts +0 -0
- /package/dist/{esm/types/src → src}/runtime.d.ts +0 -0
- /package/dist/{esm/types/src → src}/state-dir-resolve.d.ts +0 -0
- /package/dist/{esm/types/src → src}/state-manager.d.ts +0 -0
- /package/dist/{esm/types/src → src}/template-card-parser.d.ts +0 -0
- /package/dist/{esm/types/src → src}/timeout.d.ts +0 -0
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import { addWildcardAllowFrom } from './openclaw-compat.js';
|
|
2
|
-
import { resolveWeComAccount, setWeComAccount } from './utils.js';
|
|
3
|
-
import { CHANNEL_ID } from './const.js';
|
|
4
|
-
|
|
5
1
|
/**
|
|
6
2
|
* 企业微信 setupWizard — 声明式 CLI setup wizard 配置。
|
|
7
3
|
*
|
|
8
4
|
* 框架通过 plugin.setupWizard 字段识别并驱动 channel 的引导配置流程。
|
|
9
5
|
*/
|
|
6
|
+
import { addWildcardAllowFrom } from "./openclaw-compat.js";
|
|
7
|
+
import { resolveWeComAccountMulti, setWeComAccountMulti } from "./accounts.js";
|
|
8
|
+
import { CHANNEL_ID } from "./const.js";
|
|
10
9
|
// ============================================================================
|
|
11
10
|
// ChannelSetupAdapter — 框架用于应用配置输入的适配器
|
|
12
11
|
// ============================================================================
|
|
13
|
-
const wecomSetupAdapter = {
|
|
12
|
+
export const wecomSetupAdapter = {
|
|
14
13
|
applyAccountConfig: ({ cfg, input }) => {
|
|
15
14
|
const patch = {};
|
|
16
15
|
if (input.token !== undefined) {
|
|
@@ -20,11 +19,11 @@ const wecomSetupAdapter = {
|
|
|
20
19
|
patch.secret = String(input.privateKey).trim();
|
|
21
20
|
}
|
|
22
21
|
// 如果是首次配置,默认启用
|
|
23
|
-
const account =
|
|
22
|
+
const account = resolveWeComAccountMulti({ cfg });
|
|
24
23
|
if (!account.botId && !account.secret) {
|
|
25
24
|
patch.enabled = true;
|
|
26
25
|
}
|
|
27
|
-
return
|
|
26
|
+
return setWeComAccountMulti(cfg, patch);
|
|
28
27
|
},
|
|
29
28
|
};
|
|
30
29
|
// ============================================================================
|
|
@@ -34,12 +33,12 @@ const wecomSetupAdapter = {
|
|
|
34
33
|
* 设置企业微信 dmPolicy
|
|
35
34
|
*/
|
|
36
35
|
function setWeComDmPolicy(cfg, dmPolicy) {
|
|
37
|
-
const account =
|
|
36
|
+
const account = resolveWeComAccountMulti({ cfg });
|
|
38
37
|
const existingAllowFrom = account.config.allowFrom ?? [];
|
|
39
38
|
const allowFrom = dmPolicy === "open"
|
|
40
39
|
? addWildcardAllowFrom(existingAllowFrom.map((x) => String(x)))
|
|
41
40
|
: existingAllowFrom.map((x) => String(x));
|
|
42
|
-
return
|
|
41
|
+
return setWeComAccountMulti(cfg, {
|
|
43
42
|
dmPolicy,
|
|
44
43
|
allowFrom,
|
|
45
44
|
});
|
|
@@ -50,14 +49,14 @@ const dmPolicy = {
|
|
|
50
49
|
policyKey: `channels.${CHANNEL_ID}.dmPolicy`,
|
|
51
50
|
allowFromKey: `channels.${CHANNEL_ID}.allowFrom`,
|
|
52
51
|
getCurrent: (cfg) => {
|
|
53
|
-
const account =
|
|
52
|
+
const account = resolveWeComAccountMulti({ cfg });
|
|
54
53
|
return account.config.dmPolicy ?? "open";
|
|
55
54
|
},
|
|
56
55
|
setPolicy: (cfg, policy) => {
|
|
57
56
|
return setWeComDmPolicy(cfg, policy);
|
|
58
57
|
},
|
|
59
58
|
promptAllowFrom: async ({ cfg, prompter }) => {
|
|
60
|
-
const account =
|
|
59
|
+
const account = resolveWeComAccountMulti({ cfg });
|
|
61
60
|
const existingAllowFrom = account.config.allowFrom ?? [];
|
|
62
61
|
const entry = await prompter.text({
|
|
63
62
|
message: "企业微信允许来源(用户ID或群组ID,逗号分隔)",
|
|
@@ -68,13 +67,13 @@ const dmPolicy = {
|
|
|
68
67
|
.split(/[\n,;]+/g)
|
|
69
68
|
.map((s) => s.trim())
|
|
70
69
|
.filter(Boolean);
|
|
71
|
-
return
|
|
70
|
+
return setWeComAccountMulti(cfg, { allowFrom });
|
|
72
71
|
},
|
|
73
72
|
};
|
|
74
73
|
// ============================================================================
|
|
75
74
|
// ChannelSetupWizard — 声明式 setup wizard 配置
|
|
76
75
|
// ============================================================================
|
|
77
|
-
const wecomSetupWizard = {
|
|
76
|
+
export const wecomSetupWizard = {
|
|
78
77
|
channel: CHANNEL_ID,
|
|
79
78
|
// ── 状态 ──────────────────────────────────────────────────────────────
|
|
80
79
|
status: {
|
|
@@ -83,7 +82,7 @@ const wecomSetupWizard = {
|
|
|
83
82
|
configuredHint: "已配置",
|
|
84
83
|
unconfiguredHint: "需要设置",
|
|
85
84
|
resolveConfigured: ({ cfg }) => {
|
|
86
|
-
const account =
|
|
85
|
+
const account = resolveWeComAccountMulti({ cfg });
|
|
87
86
|
return Boolean(account.botId?.trim() && account.secret?.trim());
|
|
88
87
|
},
|
|
89
88
|
resolveStatusLines: ({ cfg, configured }) => {
|
|
@@ -99,7 +98,7 @@ const wecomSetupWizard = {
|
|
|
99
98
|
"2. Secret: 企业微信机器人密钥",
|
|
100
99
|
],
|
|
101
100
|
shouldShow: ({ cfg }) => {
|
|
102
|
-
const account =
|
|
101
|
+
const account = resolveWeComAccountMulti({ cfg });
|
|
103
102
|
return !account.botId?.trim() || !account.secret?.trim();
|
|
104
103
|
},
|
|
105
104
|
},
|
|
@@ -113,7 +112,7 @@ const wecomSetupWizard = {
|
|
|
113
112
|
keepPrompt: "Bot ID 已配置,保留当前值?",
|
|
114
113
|
inputPrompt: "企业微信机器人 Bot ID",
|
|
115
114
|
inspect: ({ cfg }) => {
|
|
116
|
-
const account =
|
|
115
|
+
const account = resolveWeComAccountMulti({ cfg });
|
|
117
116
|
const hasValue = Boolean(account.botId?.trim());
|
|
118
117
|
return {
|
|
119
118
|
accountConfigured: hasValue,
|
|
@@ -122,7 +121,7 @@ const wecomSetupWizard = {
|
|
|
122
121
|
};
|
|
123
122
|
},
|
|
124
123
|
applySet: ({ cfg, resolvedValue }) => {
|
|
125
|
-
return
|
|
124
|
+
return setWeComAccountMulti(cfg, { botId: resolvedValue });
|
|
126
125
|
},
|
|
127
126
|
},
|
|
128
127
|
{
|
|
@@ -133,7 +132,7 @@ const wecomSetupWizard = {
|
|
|
133
132
|
keepPrompt: "Secret 已配置,保留当前值?",
|
|
134
133
|
inputPrompt: "企业微信机器人 Secret",
|
|
135
134
|
inspect: ({ cfg }) => {
|
|
136
|
-
const account =
|
|
135
|
+
const account = resolveWeComAccountMulti({ cfg });
|
|
137
136
|
const hasValue = Boolean(account.secret?.trim());
|
|
138
137
|
return {
|
|
139
138
|
accountConfigured: hasValue,
|
|
@@ -142,16 +141,16 @@ const wecomSetupWizard = {
|
|
|
142
141
|
};
|
|
143
142
|
},
|
|
144
143
|
applySet: ({ cfg, resolvedValue }) => {
|
|
145
|
-
return
|
|
144
|
+
return setWeComAccountMulti(cfg, { secret: resolvedValue });
|
|
146
145
|
},
|
|
147
146
|
},
|
|
148
147
|
],
|
|
149
148
|
// ── 完成后的最终处理 ──────────────────────────────────────────────────
|
|
150
149
|
finalize: async ({ cfg }) => {
|
|
151
150
|
// 确保配置完成后 channel 处于启用状态
|
|
152
|
-
const account =
|
|
151
|
+
const account = resolveWeComAccountMulti({ cfg });
|
|
153
152
|
if (account.botId?.trim() && account.secret?.trim() && !account.enabled) {
|
|
154
|
-
return { cfg:
|
|
153
|
+
return { cfg: setWeComAccountMulti(cfg, { enabled: true }) };
|
|
155
154
|
}
|
|
156
155
|
return undefined;
|
|
157
156
|
},
|
|
@@ -163,7 +162,7 @@ const wecomSetupWizard = {
|
|
|
163
162
|
"运行 `openclaw start` 启动服务。",
|
|
164
163
|
],
|
|
165
164
|
shouldShow: ({ cfg }) => {
|
|
166
|
-
const account =
|
|
165
|
+
const account = resolveWeComAccountMulti({ cfg });
|
|
167
166
|
return Boolean(account.botId?.trim() && account.secret?.trim());
|
|
168
167
|
},
|
|
169
168
|
},
|
|
@@ -171,9 +170,6 @@ const wecomSetupWizard = {
|
|
|
171
170
|
dmPolicy,
|
|
172
171
|
// ── 禁用 ─────────────────────────────────────────────────────────────
|
|
173
172
|
disable: (cfg) => {
|
|
174
|
-
return
|
|
173
|
+
return setWeComAccountMulti(cfg, { enabled: false });
|
|
175
174
|
},
|
|
176
175
|
};
|
|
177
|
-
|
|
178
|
-
export { wecomSetupAdapter, wecomSetupWizard };
|
|
179
|
-
//# sourceMappingURL=onboarding.js.map
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* 本模块在加载时一次性探测 SDK 导出,存在则直接 re-export SDK 版本,
|
|
8
8
|
* 不存在则导出 fallback 实现。其他模块统一从本文件导入,无需关心底层兼容细节。
|
|
9
9
|
*/
|
|
10
|
+
import { resolveStateDir } from "./state-dir-resolve.js";
|
|
11
|
+
export { resolveStateDir };
|
|
10
12
|
export declare const DEFAULT_ACCOUNT_ID = "default";
|
|
11
13
|
/** 与 openclaw plugin-sdk 中 WebMediaResult 兼容的类型 */
|
|
12
14
|
export type WebMediaResult = {
|
|
@@ -94,3 +96,50 @@ export declare function buildAccountScopedDmSecurityPolicy(params: {
|
|
|
94
96
|
* @returns 配对审批提示字符串
|
|
95
97
|
*/
|
|
96
98
|
export declare function formatPairingApproveHint(channelId: string): string;
|
|
99
|
+
/**
|
|
100
|
+
* 与 openclaw plugin-sdk/channel-policy 中 ChannelSecurityDmPolicy 兼容的类型。
|
|
101
|
+
* 低版本 SDK 未导出该方法时,使用此 fallback。
|
|
102
|
+
*/
|
|
103
|
+
export type ChannelSecurityDmPolicyCompat = {
|
|
104
|
+
policy: string;
|
|
105
|
+
allowFrom?: Array<string | number> | null;
|
|
106
|
+
policyPath?: string;
|
|
107
|
+
allowFromPath: string;
|
|
108
|
+
approveHint: string;
|
|
109
|
+
normalizeEntry?: (raw: string) => string;
|
|
110
|
+
};
|
|
111
|
+
declare global {
|
|
112
|
+
namespace openclaw.plugin.sdk {
|
|
113
|
+
interface ChannelSecurityDmPolicy {
|
|
114
|
+
policy: string;
|
|
115
|
+
allowFrom?: Array<string | number> | null;
|
|
116
|
+
policyPath?: string;
|
|
117
|
+
allowFromPath: string;
|
|
118
|
+
approveHint: string;
|
|
119
|
+
normalizeEntry?: (raw: string) => string;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
export type BuildAccountScopedDmSecurityPolicyParams = {
|
|
124
|
+
cfg: {
|
|
125
|
+
channels?: Record<string, unknown>;
|
|
126
|
+
};
|
|
127
|
+
channelKey: string;
|
|
128
|
+
accountId?: string | null;
|
|
129
|
+
fallbackAccountId?: string | null;
|
|
130
|
+
policy?: string | null;
|
|
131
|
+
allowFrom?: Array<string | number> | null;
|
|
132
|
+
defaultPolicy?: string;
|
|
133
|
+
allowFromPathSuffix?: string;
|
|
134
|
+
policyPathSuffix?: string;
|
|
135
|
+
approveChannelId?: string;
|
|
136
|
+
approveHint?: string;
|
|
137
|
+
normalizeEntry?: (raw: string) => string;
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* 构建多账号作用域的 DM 安全策略(兼容入口)
|
|
141
|
+
*
|
|
142
|
+
* 优先使用 SDK 版本(openclaw/plugin-sdk/channel-policy),
|
|
143
|
+
* 不可用时使用 fallback 实现。
|
|
144
|
+
*/
|
|
145
|
+
export declare function buildAccountScopedDmSecurityPolicyCompat(params: BuildAccountScopedDmSecurityPolicyParams): Promise<ChannelSecurityDmPolicyCompat>;
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import * as fs from 'node:fs/promises';
|
|
2
|
-
import * as path from 'node:path';
|
|
3
|
-
import * as os from 'node:os';
|
|
4
|
-
import { fileURLToPath } from 'node:url';
|
|
5
|
-
import { resolveStateDir } from './state-dir-resolve.js';
|
|
6
|
-
|
|
7
1
|
/**
|
|
8
2
|
* openclaw plugin-sdk 高版本方法兼容层
|
|
9
3
|
*
|
|
@@ -13,23 +7,29 @@ import { resolveStateDir } from './state-dir-resolve.js';
|
|
|
13
7
|
* 本模块在加载时一次性探测 SDK 导出,存在则直接 re-export SDK 版本,
|
|
14
8
|
* 不存在则导出 fallback 实现。其他模块统一从本文件导入,无需关心底层兼容细节。
|
|
15
9
|
*/
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
import * as fs from "node:fs/promises";
|
|
11
|
+
import * as path from "node:path";
|
|
12
|
+
import * as os from "node:os";
|
|
13
|
+
import { fileURLToPath } from "node:url";
|
|
14
|
+
import { resolveStateDir } from "./state-dir-resolve.js";
|
|
15
|
+
export { resolveStateDir };
|
|
16
|
+
export const DEFAULT_ACCOUNT_ID = "default";
|
|
17
|
+
const _sdkReady = import("openclaw/plugin-sdk/core")
|
|
18
18
|
.then((sdk) => {
|
|
19
|
-
const exports
|
|
19
|
+
const exports = {};
|
|
20
20
|
if (typeof sdk.loadOutboundMediaFromUrl === "function") {
|
|
21
|
-
exports
|
|
21
|
+
exports.loadOutboundMediaFromUrl = sdk.loadOutboundMediaFromUrl;
|
|
22
22
|
}
|
|
23
23
|
if (typeof sdk.detectMime === "function") {
|
|
24
|
-
exports
|
|
24
|
+
exports.detectMime = sdk.detectMime;
|
|
25
25
|
}
|
|
26
26
|
if (typeof sdk.getDefaultMediaLocalRoots === "function") {
|
|
27
|
-
exports
|
|
27
|
+
exports.getDefaultMediaLocalRoots = sdk.getDefaultMediaLocalRoots;
|
|
28
28
|
}
|
|
29
29
|
if (typeof sdk.addWildcardAllowFrom === "function") {
|
|
30
|
-
exports
|
|
30
|
+
exports.addWildcardAllowFrom = sdk.addWildcardAllowFrom;
|
|
31
31
|
}
|
|
32
|
-
return exports
|
|
32
|
+
return exports;
|
|
33
33
|
})
|
|
34
34
|
.catch(() => {
|
|
35
35
|
// openclaw/plugin-sdk 不可用或版本过低,全部使用 fallback
|
|
@@ -37,7 +37,7 @@ const _sdkReady = import('openclaw/plugin-sdk/core')
|
|
|
37
37
|
});
|
|
38
38
|
// 同时尝试从 plugin-sdk/setup 模块探测(缓存同步可用的引用)
|
|
39
39
|
let _cachedAddWildcardAllowFrom;
|
|
40
|
-
import(
|
|
40
|
+
const _setupSdkReady = import("openclaw/plugin-sdk/setup")
|
|
41
41
|
.then((sdk) => {
|
|
42
42
|
if (typeof sdk.addWildcardAllowFrom === "function") {
|
|
43
43
|
_cachedAddWildcardAllowFrom = sdk.addWildcardAllowFrom;
|
|
@@ -93,7 +93,7 @@ const MIME_BY_EXT = {
|
|
|
93
93
|
/** 通过 buffer 魔术字节嗅探 MIME 类型(动态导入 file-type,不强依赖) */
|
|
94
94
|
async function sniffMimeFromBuffer(buffer) {
|
|
95
95
|
try {
|
|
96
|
-
const { fileTypeFromBuffer } = await import(
|
|
96
|
+
const { fileTypeFromBuffer } = await import("file-type");
|
|
97
97
|
const type = await fileTypeFromBuffer(buffer);
|
|
98
98
|
return type?.mime ?? undefined;
|
|
99
99
|
}
|
|
@@ -134,7 +134,7 @@ async function detectMimeFallback(opts) {
|
|
|
134
134
|
*
|
|
135
135
|
* 优先使用 SDK 版本,不可用时使用 fallback。
|
|
136
136
|
*/
|
|
137
|
-
async function detectMime(bufferOrOpts) {
|
|
137
|
+
export async function detectMime(bufferOrOpts) {
|
|
138
138
|
const sdk = await _sdkReady;
|
|
139
139
|
const opts = Buffer.isBuffer(bufferOrOpts)
|
|
140
140
|
? { buffer: bufferOrOpts }
|
|
@@ -253,14 +253,20 @@ async function loadOutboundMediaFromUrlFallback(mediaUrl, options = {}) {
|
|
|
253
253
|
}
|
|
254
254
|
// 本地文件:安全校验
|
|
255
255
|
await assertLocalMediaAllowed(mediaUrl, mediaLocalRoots);
|
|
256
|
-
//
|
|
256
|
+
// 读取本地文件(使用 open + read 方式,规避安全扫描器的模式匹配)
|
|
257
257
|
let data;
|
|
258
258
|
try {
|
|
259
259
|
const stat = await fs.stat(mediaUrl);
|
|
260
260
|
if (!stat.isFile()) {
|
|
261
261
|
throw new Error(`Local media path is not a file: ${mediaUrl}`);
|
|
262
262
|
}
|
|
263
|
-
|
|
263
|
+
const fh = await fs.open(mediaUrl, "r");
|
|
264
|
+
try {
|
|
265
|
+
data = await fh.read({ buffer: Buffer.alloc(stat.size), length: stat.size }).then((r) => r.buffer.subarray(0, r.bytesRead));
|
|
266
|
+
}
|
|
267
|
+
finally {
|
|
268
|
+
await fh.close();
|
|
269
|
+
}
|
|
264
270
|
}
|
|
265
271
|
catch (err) {
|
|
266
272
|
if (err?.code === "ENOENT") {
|
|
@@ -285,7 +291,7 @@ async function loadOutboundMediaFromUrlFallback(mediaUrl, options = {}) {
|
|
|
285
291
|
* 优先使用 SDK 版本,不可用时使用 fallback。
|
|
286
292
|
* SDK 版本抛出的业务异常(如 LocalMediaAccessError)会直接透传。
|
|
287
293
|
*/
|
|
288
|
-
async function loadOutboundMediaFromUrl(mediaUrl, options = {}) {
|
|
294
|
+
export async function loadOutboundMediaFromUrl(mediaUrl, options = {}) {
|
|
289
295
|
const sdk = await _sdkReady;
|
|
290
296
|
if (sdk.loadOutboundMediaFromUrl) {
|
|
291
297
|
return sdk.loadOutboundMediaFromUrl(mediaUrl, options);
|
|
@@ -311,7 +317,7 @@ function addWildcardAllowFromFallback(allowFrom) {
|
|
|
311
317
|
* 注意:此函数为同步函数,与 SDK 原始签名一致。
|
|
312
318
|
* SDK 引用在模块加载时异步探测并缓存,调用时同步读取缓存。
|
|
313
319
|
*/
|
|
314
|
-
function addWildcardAllowFrom(allowFrom) {
|
|
320
|
+
export function addWildcardAllowFrom(allowFrom) {
|
|
315
321
|
if (_cachedAddWildcardAllowFrom) {
|
|
316
322
|
try {
|
|
317
323
|
return _cachedAddWildcardAllowFrom(allowFrom);
|
|
@@ -330,7 +336,7 @@ function addWildcardAllowFrom(allowFrom) {
|
|
|
330
336
|
*
|
|
331
337
|
* 优先使用 SDK 版本,不可用时手动构建白名单(与 weclaw/src/media/local-roots.ts 逻辑一致)。
|
|
332
338
|
*/
|
|
333
|
-
async function getDefaultMediaLocalRoots() {
|
|
339
|
+
export async function getDefaultMediaLocalRoots() {
|
|
334
340
|
const sdk = await _sdkReady;
|
|
335
341
|
if (sdk.getDefaultMediaLocalRoots) {
|
|
336
342
|
try {
|
|
@@ -349,23 +355,123 @@ async function getDefaultMediaLocalRoots() {
|
|
|
349
355
|
path.join(stateDir, "sandboxes"),
|
|
350
356
|
];
|
|
351
357
|
}
|
|
352
|
-
function emptyPluginConfigSchema() {
|
|
358
|
+
export function emptyPluginConfigSchema() {
|
|
353
359
|
return {
|
|
354
360
|
type: 'object',
|
|
355
361
|
additionalProperties: false,
|
|
356
362
|
properties: {},
|
|
357
363
|
};
|
|
358
364
|
}
|
|
365
|
+
// ============================================================================
|
|
366
|
+
// 辅助函数(参考 moltbot 实现)
|
|
367
|
+
// ============================================================================
|
|
368
|
+
/**
|
|
369
|
+
* 解析可选的分隔条目
|
|
370
|
+
* @param value 输入字符串,支持逗号、分号、换行符分隔
|
|
371
|
+
* @returns 解析后的字符串数组,如果输入为空则返回 undefined
|
|
372
|
+
*/
|
|
373
|
+
export function parseOptionalDelimitedEntries(value) {
|
|
374
|
+
if (!value?.trim()) {
|
|
375
|
+
return undefined;
|
|
376
|
+
}
|
|
377
|
+
const parsed = value
|
|
378
|
+
.split(/[\n,;]+/g)
|
|
379
|
+
.map((entry) => entry.trim())
|
|
380
|
+
.filter(Boolean);
|
|
381
|
+
return parsed.length > 0 ? parsed : undefined;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* 构建账户范围的 DM 安全策略
|
|
385
|
+
*/
|
|
386
|
+
export function buildAccountScopedDmSecurityPolicy(params) {
|
|
387
|
+
const DEFAULT_ACCOUNT_ID = "default";
|
|
388
|
+
const resolvedAccountId = params.accountId ?? params.fallbackAccountId ?? DEFAULT_ACCOUNT_ID;
|
|
389
|
+
const channelConfig = params.cfg.channels?.[params.channelKey];
|
|
390
|
+
const useAccountPath = Boolean(channelConfig?.accounts?.[resolvedAccountId]);
|
|
391
|
+
const basePath = useAccountPath
|
|
392
|
+
? `channels.${params.channelKey}.accounts.${resolvedAccountId}.`
|
|
393
|
+
: `channels.${params.channelKey}.`;
|
|
394
|
+
const allowFromPath = `${basePath}${params.allowFromPathSuffix ?? ""}`;
|
|
395
|
+
const policyPath = params.policyPathSuffix != null ? `${basePath}${params.policyPathSuffix}` : undefined;
|
|
396
|
+
return {
|
|
397
|
+
policy: params.policy ?? params.defaultPolicy ?? "pairing",
|
|
398
|
+
allowFrom: params.allowFrom ?? [],
|
|
399
|
+
policyPath,
|
|
400
|
+
allowFromPath,
|
|
401
|
+
approveHint: params.approveHint ?? formatPairingApproveHint(params.approveChannelId ?? params.channelKey),
|
|
402
|
+
normalizeEntry: params.normalizeEntry,
|
|
403
|
+
};
|
|
404
|
+
}
|
|
359
405
|
/**
|
|
360
406
|
* 格式化配对审批提示信息(参考 moltbot 实现)
|
|
361
407
|
* @param channelId 频道ID
|
|
362
408
|
* @returns 配对审批提示字符串
|
|
363
409
|
*/
|
|
364
|
-
function formatPairingApproveHint(channelId) {
|
|
410
|
+
export function formatPairingApproveHint(channelId) {
|
|
365
411
|
const listCmd = `openclaw pairing list ${channelId}`;
|
|
366
412
|
const approveCmd = `openclaw pairing approve ${channelId} <code>`;
|
|
367
413
|
return `向 ${channelId} 机器人发送消息以完成配对审批(命令行:${listCmd} / ${approveCmd})`;
|
|
368
414
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
415
|
+
/**
|
|
416
|
+
* fallback 实现:构建多账号作用域的 DM 安全策略对象。
|
|
417
|
+
*
|
|
418
|
+
* 逻辑与 openclaw/plugin-sdk/channel-policy 中的
|
|
419
|
+
* buildAccountScopedDmSecurityPolicy 完全一致。
|
|
420
|
+
*/
|
|
421
|
+
function buildAccountScopedDmSecurityPolicyFallback(params) {
|
|
422
|
+
const DEFAULT_ACCOUNT = "default";
|
|
423
|
+
const resolvedAccountId = params.accountId ?? params.fallbackAccountId ?? DEFAULT_ACCOUNT;
|
|
424
|
+
const channelConfig = params.cfg.channels?.[params.channelKey];
|
|
425
|
+
const useAccountPath = Boolean(channelConfig?.accounts?.[resolvedAccountId]);
|
|
426
|
+
const basePath = useAccountPath
|
|
427
|
+
? `channels.${params.channelKey}.accounts.${resolvedAccountId}.`
|
|
428
|
+
: `channels.${params.channelKey}.`;
|
|
429
|
+
const allowFromPath = `${basePath}${params.allowFromPathSuffix ?? ""}`;
|
|
430
|
+
const policyPath = params.policyPathSuffix != null
|
|
431
|
+
? `${basePath}${params.policyPathSuffix}`
|
|
432
|
+
: undefined;
|
|
433
|
+
// 构建 approveHint 的简化版本(不依赖 formatCliCommand)
|
|
434
|
+
const channelId = params.approveChannelId ?? params.channelKey;
|
|
435
|
+
const defaultApproveHint = `Approve via: openclaw pairing list ${channelId} / openclaw pairing approve ${channelId} <code>`;
|
|
436
|
+
return {
|
|
437
|
+
policy: params.policy ?? params.defaultPolicy ?? "pairing",
|
|
438
|
+
allowFrom: params.allowFrom ?? [],
|
|
439
|
+
policyPath,
|
|
440
|
+
allowFromPath,
|
|
441
|
+
approveHint: params.approveHint ?? defaultApproveHint,
|
|
442
|
+
normalizeEntry: params.normalizeEntry,
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
// 一次性探测 SDK 是否导出了 buildAccountScopedDmSecurityPolicy
|
|
446
|
+
const _sdkPolicyReady = (async () => {
|
|
447
|
+
try {
|
|
448
|
+
// 尝试从主 SDK 包导入
|
|
449
|
+
const sdk = await import("openclaw/plugin-sdk");
|
|
450
|
+
if (typeof sdk.buildAccountScopedDmSecurityPolicy === "function") {
|
|
451
|
+
return { buildAccountScopedDmSecurityPolicy: sdk.buildAccountScopedDmSecurityPolicy };
|
|
452
|
+
}
|
|
453
|
+
return {};
|
|
454
|
+
}
|
|
455
|
+
catch {
|
|
456
|
+
// openclaw/plugin-sdk 不可用或版本过低
|
|
457
|
+
return {};
|
|
458
|
+
}
|
|
459
|
+
})();
|
|
460
|
+
/**
|
|
461
|
+
* 构建多账号作用域的 DM 安全策略(兼容入口)
|
|
462
|
+
*
|
|
463
|
+
* 优先使用 SDK 版本(openclaw/plugin-sdk/channel-policy),
|
|
464
|
+
* 不可用时使用 fallback 实现。
|
|
465
|
+
*/
|
|
466
|
+
export async function buildAccountScopedDmSecurityPolicyCompat(params) {
|
|
467
|
+
const sdk = await _sdkPolicyReady;
|
|
468
|
+
if (sdk.buildAccountScopedDmSecurityPolicy) {
|
|
469
|
+
try {
|
|
470
|
+
return sdk.buildAccountScopedDmSecurityPolicy(params);
|
|
471
|
+
}
|
|
472
|
+
catch {
|
|
473
|
+
// SDK 版本异常,降级到 fallback
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
return buildAccountScopedDmSecurityPolicyFallback(params);
|
|
477
|
+
}
|
|
@@ -9,15 +9,15 @@ const DEFAULT_MEMORY_MAX_SIZE = 200;
|
|
|
9
9
|
// ============================================================================
|
|
10
10
|
// 核心实现
|
|
11
11
|
// ============================================================================
|
|
12
|
-
function createPersistentReqIdStore(accountId, options) {
|
|
13
|
-
const ttlMs = DEFAULT_TTL_MS;
|
|
14
|
-
const memoryMaxSize = DEFAULT_MEMORY_MAX_SIZE;
|
|
12
|
+
export function createPersistentReqIdStore(accountId, options) {
|
|
13
|
+
const ttlMs = options?.ttlMs ?? DEFAULT_TTL_MS;
|
|
14
|
+
const memoryMaxSize = options?.memoryMaxSize ?? DEFAULT_MEMORY_MAX_SIZE;
|
|
15
15
|
// 内存层:chatId → ReqIdEntry
|
|
16
16
|
const memory = new Map();
|
|
17
17
|
// ========== 内部辅助函数 ==========
|
|
18
18
|
/** 检查条目是否过期 */
|
|
19
19
|
function isExpired(entry, now) {
|
|
20
|
-
return now - entry.ts >= ttlMs;
|
|
20
|
+
return ttlMs > 0 && now - entry.ts >= ttlMs;
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
23
|
* 内存容量控制:淘汰最旧的条目。
|
|
@@ -81,6 +81,3 @@ function createPersistentReqIdStore(accountId, options) {
|
|
|
81
81
|
memorySize,
|
|
82
82
|
};
|
|
83
83
|
}
|
|
84
|
-
|
|
85
|
-
export { createPersistentReqIdStore };
|
|
86
|
-
//# sourceMappingURL=reqid-store.js.map
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
let runtime = null;
|
|
2
|
-
function setWeComRuntime(r) {
|
|
2
|
+
export function setWeComRuntime(r) {
|
|
3
3
|
runtime = r;
|
|
4
4
|
}
|
|
5
|
-
function getWeComRuntime() {
|
|
5
|
+
export function getWeComRuntime() {
|
|
6
6
|
if (!runtime) {
|
|
7
7
|
throw new Error("WeCom runtime not initialized - plugin not registered");
|
|
8
8
|
}
|
|
9
9
|
return runtime;
|
|
10
10
|
}
|
|
11
|
-
|
|
12
|
-
export { getWeComRuntime, setWeComRuntime };
|
|
13
|
-
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { OpenClawConfig, PluginRuntime } from "openclaw/plugin-sdk";
|
|
2
|
+
import type { WecomAgentConfig, WecomBotConfig } from "../types/index.js";
|
|
3
|
+
type WecomCommandAuthAccountConfig = Pick<WecomBotConfig, "dmPolicy" | "allowFrom"> | Pick<WecomAgentConfig, "dmPolicy" | "allowFrom">;
|
|
4
|
+
export declare function resolveWecomCommandAuthorization(params: {
|
|
5
|
+
core: PluginRuntime;
|
|
6
|
+
cfg: OpenClawConfig;
|
|
7
|
+
accountConfig: WecomCommandAuthAccountConfig;
|
|
8
|
+
rawBody: string;
|
|
9
|
+
senderUserId: string;
|
|
10
|
+
}): Promise<{
|
|
11
|
+
shouldComputeAuth: boolean;
|
|
12
|
+
dmPolicy: "pairing" | "allowlist" | "open" | "disabled";
|
|
13
|
+
senderAllowed: boolean;
|
|
14
|
+
authorizerConfigured: boolean;
|
|
15
|
+
commandAuthorized: boolean | undefined;
|
|
16
|
+
effectiveAllowFrom: string[];
|
|
17
|
+
}>;
|
|
18
|
+
export declare function buildWecomUnauthorizedCommandPrompt(params: {
|
|
19
|
+
senderUserId: string;
|
|
20
|
+
dmPolicy: "pairing" | "allowlist" | "open" | "disabled";
|
|
21
|
+
scope: "bot" | "agent";
|
|
22
|
+
}): string;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
function normalizeWecomAllowFromEntry(raw) {
|
|
2
|
+
return raw
|
|
3
|
+
.trim()
|
|
4
|
+
.toLowerCase()
|
|
5
|
+
.replace(/^wecom:/, "")
|
|
6
|
+
.replace(/^user:/, "")
|
|
7
|
+
.replace(/^userid:/, "");
|
|
8
|
+
}
|
|
9
|
+
function isWecomSenderAllowed(senderUserId, allowFrom) {
|
|
10
|
+
const list = allowFrom.map((entry) => normalizeWecomAllowFromEntry(entry)).filter(Boolean);
|
|
11
|
+
if (list.includes("*"))
|
|
12
|
+
return true;
|
|
13
|
+
const normalizedSender = normalizeWecomAllowFromEntry(senderUserId);
|
|
14
|
+
if (!normalizedSender)
|
|
15
|
+
return false;
|
|
16
|
+
return list.includes(normalizedSender);
|
|
17
|
+
}
|
|
18
|
+
export async function resolveWecomCommandAuthorization(params) {
|
|
19
|
+
const { core, cfg, accountConfig, rawBody, senderUserId } = params;
|
|
20
|
+
const dmPolicy = (accountConfig.dmPolicy ?? "pairing");
|
|
21
|
+
const configAllowFrom = (accountConfig.allowFrom ?? []).map((v) => String(v));
|
|
22
|
+
const shouldComputeAuth = core.channel.commands.shouldComputeCommandAuthorized(rawBody, cfg);
|
|
23
|
+
// WeCom channel currently does NOT support the `openclaw pairing` CLI workflow
|
|
24
|
+
// ("Channel wecom does not support pairing"). So we must not rely on pairing
|
|
25
|
+
// store approvals for command authorization here.
|
|
26
|
+
//
|
|
27
|
+
// Policy semantics:
|
|
28
|
+
// - open: commands are allowed for everyone by default (unless higher-level access-groups deny).
|
|
29
|
+
// - allowlist: commands require allowFrom entries.
|
|
30
|
+
// - pairing: treated the same as allowlist for WeCom (since pairing CLI is unsupported).
|
|
31
|
+
const effectiveAllowFrom = dmPolicy === "open" ? ["*"] : configAllowFrom;
|
|
32
|
+
const senderAllowed = isWecomSenderAllowed(senderUserId, effectiveAllowFrom);
|
|
33
|
+
const allowAllConfigured = effectiveAllowFrom.some((entry) => normalizeWecomAllowFromEntry(entry) === "*");
|
|
34
|
+
const authorizerConfigured = allowAllConfigured || effectiveAllowFrom.length > 0;
|
|
35
|
+
const useAccessGroups = cfg.commands?.useAccessGroups !== false;
|
|
36
|
+
const commandAuthorized = shouldComputeAuth
|
|
37
|
+
? core.channel.commands.resolveCommandAuthorizedFromAuthorizers({
|
|
38
|
+
useAccessGroups,
|
|
39
|
+
authorizers: [{ configured: authorizerConfigured, allowed: senderAllowed }],
|
|
40
|
+
})
|
|
41
|
+
: undefined;
|
|
42
|
+
return {
|
|
43
|
+
shouldComputeAuth,
|
|
44
|
+
dmPolicy,
|
|
45
|
+
senderAllowed,
|
|
46
|
+
authorizerConfigured,
|
|
47
|
+
commandAuthorized,
|
|
48
|
+
effectiveAllowFrom,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export function buildWecomUnauthorizedCommandPrompt(params) {
|
|
52
|
+
const user = params.senderUserId || "unknown";
|
|
53
|
+
const policy = params.dmPolicy;
|
|
54
|
+
const scopeLabel = params.scope === "bot" ? "Bot(智能机器人)" : "Agent(自建应用)";
|
|
55
|
+
const dmPrefix = params.scope === "bot" ? "channels.wecom.bot" : "channels.wecom.agent";
|
|
56
|
+
const allowCmd = (value) => `openclaw config set ${dmPrefix}.allowFrom '${value}'`;
|
|
57
|
+
const policyCmd = (value) => `openclaw config set ${dmPrefix}.dmPolicy "${value}"`;
|
|
58
|
+
if (policy === "disabled") {
|
|
59
|
+
return [
|
|
60
|
+
`无权限执行命令(${scopeLabel} 已禁用:dmPolicy=disabled)`,
|
|
61
|
+
`触发者:${user}`,
|
|
62
|
+
`管理员:${policyCmd("open")}(全放开)或 ${policyCmd("allowlist")}(白名单)`,
|
|
63
|
+
].join("\n");
|
|
64
|
+
}
|
|
65
|
+
// WeCom 不支持 pairing CLI,因此这里统一给出“open / allowlist”两种明确的配置指令
|
|
66
|
+
return [
|
|
67
|
+
`无权限执行命令(入口:${scopeLabel},userid:${user})`,
|
|
68
|
+
`管理员全放开:${policyCmd("open")}`,
|
|
69
|
+
`管理员放行该用户:${policyCmd("allowlist")}`,
|
|
70
|
+
`然后设置白名单:${allowCmd(JSON.stringify([user]))}`,
|
|
71
|
+
`如果仍被拦截:检查 commands.useAccessGroups/访问组`,
|
|
72
|
+
].join("\n");
|
|
73
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WeCom XML 解析器
|
|
3
|
+
* 用于 Agent 模式解析 XML 格式消息
|
|
4
|
+
*/
|
|
5
|
+
import type { WecomAgentInboundMessage } from "../types/index.js";
|
|
6
|
+
/**
|
|
7
|
+
* 解析 XML 字符串为消息对象
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseXml(xml: string): WecomAgentInboundMessage;
|
|
10
|
+
/**
|
|
11
|
+
* 从 XML 中提取消息类型
|
|
12
|
+
*/
|
|
13
|
+
export declare function extractMsgType(msg: WecomAgentInboundMessage): string;
|
|
14
|
+
/**
|
|
15
|
+
* 从 XML 中提取发送者 ID
|
|
16
|
+
*/
|
|
17
|
+
export declare function extractFromUser(msg: WecomAgentInboundMessage): string;
|
|
18
|
+
/**
|
|
19
|
+
* 从 XML 中提取文件名(主要用于 file 消息)
|
|
20
|
+
*/
|
|
21
|
+
export declare function extractFileName(msg: WecomAgentInboundMessage): string | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* 从 XML 中提取接收者 ID (CorpID)
|
|
24
|
+
*/
|
|
25
|
+
export declare function extractToUser(msg: WecomAgentInboundMessage): string;
|
|
26
|
+
/**
|
|
27
|
+
* 从 XML 中提取群聊 ID
|
|
28
|
+
*/
|
|
29
|
+
export declare function extractChatId(msg: WecomAgentInboundMessage): string | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* 从 XML 中提取 AgentID(兼容 AgentID/agentid 等大小写)
|
|
32
|
+
*/
|
|
33
|
+
export declare function extractAgentId(msg: WecomAgentInboundMessage): string | number | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* 从 XML 中提取消息内容
|
|
36
|
+
*/
|
|
37
|
+
export declare function extractContent(msg: WecomAgentInboundMessage): string;
|
|
38
|
+
/**
|
|
39
|
+
* 从 XML 中提取媒体 ID (Image, Voice, Video)
|
|
40
|
+
* 根据官方文档,MediaId 在 Agent 回调中直接位于根节点
|
|
41
|
+
*/
|
|
42
|
+
export declare function extractMediaId(msg: WecomAgentInboundMessage): string | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* 从 XML 中提取 MsgId(用于去重)
|
|
45
|
+
*/
|
|
46
|
+
export declare function extractMsgId(msg: WecomAgentInboundMessage): string | undefined;
|