gewe-openclaw 2026.1.30 → 2026.2.1
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 +24 -10
- package/openclaw.plugin.json +1 -1
- package/package.json +7 -6
- package/src/accounts.ts +6 -6
- package/src/channel.ts +50 -29
- package/src/config-schema.ts +10 -2
- package/src/constants.ts +10 -0
- package/src/delivery.ts +43 -20
- package/src/download.ts +1 -1
- package/src/inbound.ts +32 -12
- package/src/monitor.ts +2 -2
- package/src/normalize.ts +3 -4
- package/src/onboarding.ts +265 -0
- package/src/policy.ts +6 -5
- package/src/send.ts +1 -1
- package/src/silk.ts +465 -0
- package/src/types.ts +7 -1
package/src/inbound.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type { GeweDownloadQueue } from "./download-queue.js";
|
|
|
9
9
|
import { downloadGeweFile, downloadGeweImage, downloadGeweVideo, downloadGeweVoice } from "./download.js";
|
|
10
10
|
import { deliverGewePayload } from "./delivery.js";
|
|
11
11
|
import { getGeweRuntime } from "./runtime.js";
|
|
12
|
+
import { ensureRustSilkBinary } from "./silk.js";
|
|
12
13
|
import {
|
|
13
14
|
normalizeGeweAllowlist,
|
|
14
15
|
resolveGeweAllowlistMatch,
|
|
@@ -19,8 +20,7 @@ import {
|
|
|
19
20
|
} from "./policy.js";
|
|
20
21
|
import type { CoreConfig, GeweInboundMessage, ResolvedGeweAccount } from "./types.js";
|
|
21
22
|
import { extractAppMsgType, extractFileName, extractLinkDetails } from "./xml.js";
|
|
22
|
-
|
|
23
|
-
const CHANNEL_ID = "gewe" as const;
|
|
23
|
+
import { CHANNEL_ID } from "./constants.js";
|
|
24
24
|
|
|
25
25
|
type PreparedInbound = {
|
|
26
26
|
rawBody: string;
|
|
@@ -103,7 +103,7 @@ async function decodeSilkVoice(params: {
|
|
|
103
103
|
fileName?: string | null;
|
|
104
104
|
}): Promise<DecodedVoice | null> {
|
|
105
105
|
const core = getGeweRuntime();
|
|
106
|
-
const logger = core.logging.getChildLogger({ channel:
|
|
106
|
+
const logger = core.logging.getChildLogger({ channel: CHANNEL_ID, module: "voice" });
|
|
107
107
|
const decodeOutput = params.account.config.voiceDecodeOutput ?? "pcm";
|
|
108
108
|
const sampleRate = resolveVoiceDecodeSampleRate(params.account);
|
|
109
109
|
const ffmpegPath = params.account.config.voiceFfmpegPath?.trim() || "ffmpeg";
|
|
@@ -117,10 +117,28 @@ async function decodeSilkVoice(params: {
|
|
|
117
117
|
["{input}", "-o", "{output}"],
|
|
118
118
|
["-i", "{input}", "{output}"],
|
|
119
119
|
];
|
|
120
|
-
const
|
|
120
|
+
const rustArgs = [
|
|
121
|
+
"decode",
|
|
122
|
+
"-i",
|
|
123
|
+
"{input}",
|
|
124
|
+
"-o",
|
|
125
|
+
"{output}",
|
|
126
|
+
"--sample-rate",
|
|
127
|
+
"{sampleRate}",
|
|
128
|
+
"--quiet",
|
|
129
|
+
];
|
|
130
|
+
if (decodeOutput === "wav") rustArgs.push("--wav");
|
|
131
|
+
const rustSilk = customPath ? null : await ensureRustSilkBinary(params.account);
|
|
132
|
+
const argTemplates = customArgs.length
|
|
133
|
+
? customArgs
|
|
134
|
+
: rustSilk
|
|
135
|
+
? [rustArgs]
|
|
136
|
+
: fallbackArgs;
|
|
121
137
|
const candidates = customPath
|
|
122
138
|
? [customPath]
|
|
123
|
-
:
|
|
139
|
+
: rustSilk
|
|
140
|
+
? [rustSilk]
|
|
141
|
+
: ["silk-decoder", "silk-v3-decoder", "decoder"];
|
|
124
142
|
|
|
125
143
|
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gewe-voice-in-"));
|
|
126
144
|
const silkPath = path.join(tmpDir, "voice.silk");
|
|
@@ -261,8 +279,10 @@ async function dispatchGeweInbound(params: {
|
|
|
261
279
|
Body: body,
|
|
262
280
|
RawBody: prepared.rawBody,
|
|
263
281
|
CommandBody: prepared.rawBody,
|
|
264
|
-
From: prepared.groupId
|
|
265
|
-
|
|
282
|
+
From: prepared.groupId
|
|
283
|
+
? `${CHANNEL_ID}:group:${prepared.groupId}`
|
|
284
|
+
: `${CHANNEL_ID}:${prepared.senderId}`,
|
|
285
|
+
To: `${CHANNEL_ID}:${prepared.toWxid}`,
|
|
266
286
|
SessionKey: prepared.route.sessionKey,
|
|
267
287
|
AccountId: prepared.route.accountId,
|
|
268
288
|
ChatType: prepared.isGroup ? "group" : "direct",
|
|
@@ -272,16 +292,16 @@ async function dispatchGeweInbound(params: {
|
|
|
272
292
|
SenderName: prepared.senderName || undefined,
|
|
273
293
|
SenderId: prepared.senderId,
|
|
274
294
|
CommandAuthorized: prepared.commandAuthorized,
|
|
275
|
-
Provider:
|
|
276
|
-
Surface:
|
|
295
|
+
Provider: CHANNEL_ID,
|
|
296
|
+
Surface: CHANNEL_ID,
|
|
277
297
|
MessageSid: prepared.messageSid,
|
|
278
298
|
MessageSidFull: prepared.messageSid,
|
|
279
299
|
MediaPath: media?.path,
|
|
280
300
|
MediaType: media?.contentType,
|
|
281
301
|
MediaUrl: media?.path,
|
|
282
302
|
GroupSystemPrompt: prepared.groupSystemPrompt,
|
|
283
|
-
OriginatingChannel:
|
|
284
|
-
OriginatingTo:
|
|
303
|
+
OriginatingChannel: CHANNEL_ID,
|
|
304
|
+
OriginatingTo: `${CHANNEL_ID}:${prepared.toWxid}`,
|
|
285
305
|
});
|
|
286
306
|
|
|
287
307
|
await core.channel.session.recordInboundSession({
|
|
@@ -523,7 +543,7 @@ export async function handleGeweInbound(params: {
|
|
|
523
543
|
};
|
|
524
544
|
|
|
525
545
|
core.channel.activity.record({
|
|
526
|
-
channel:
|
|
546
|
+
channel: CHANNEL_ID,
|
|
527
547
|
accountId: account.accountId,
|
|
528
548
|
direction: "inbound",
|
|
529
549
|
});
|
package/src/monitor.ts
CHANGED
|
@@ -15,9 +15,9 @@ import type {
|
|
|
15
15
|
ResolvedGeweAccount,
|
|
16
16
|
} from "./types.js";
|
|
17
17
|
|
|
18
|
-
const DEFAULT_WEBHOOK_PORT =
|
|
18
|
+
const DEFAULT_WEBHOOK_PORT = 4399;
|
|
19
19
|
const DEFAULT_WEBHOOK_HOST = "0.0.0.0";
|
|
20
|
-
const DEFAULT_WEBHOOK_PATH = "/
|
|
20
|
+
const DEFAULT_WEBHOOK_PATH = "/webhook";
|
|
21
21
|
const HEALTH_PATH = "/healthz";
|
|
22
22
|
const DEDUPE_TTL_MS = 12 * 60 * 60 * 1000;
|
|
23
23
|
|
package/src/normalize.ts
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
export function normalizeGeweMessagingTarget(target: string): string | null {
|
|
2
2
|
const trimmed = target.trim();
|
|
3
3
|
if (!trimmed) return null;
|
|
4
|
+
const prefix = /^(gewe-openclaw|gewe|wechat|wx):(group:|user:)?/i;
|
|
4
5
|
return trimmed
|
|
5
|
-
.replace(
|
|
6
|
-
.replace(/^wechat:(group:|user:)?/i, "")
|
|
7
|
-
.replace(/^wx:/i, "")
|
|
6
|
+
.replace(prefix, "")
|
|
8
7
|
.trim();
|
|
9
8
|
}
|
|
10
9
|
|
|
11
10
|
export function looksLikeGeweTargetId(id: string): boolean {
|
|
12
11
|
const trimmed = id?.trim();
|
|
13
12
|
if (!trimmed) return false;
|
|
14
|
-
if (/^gewe:/i.test(trimmed)) return true;
|
|
13
|
+
if (/^(gewe-openclaw|gewe):/i.test(trimmed)) return true;
|
|
15
14
|
if (/@chatroom$/i.test(trimmed)) return true;
|
|
16
15
|
if (/^wxid_/i.test(trimmed)) return true;
|
|
17
16
|
if (/^gh_/i.test(trimmed)) return true;
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import type { ChannelPlugin, OpenClawConfig, WizardPrompter } from "openclaw/plugin-sdk";
|
|
2
|
+
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk";
|
|
3
|
+
|
|
4
|
+
import type { CoreConfig, GeweAccountConfig, ResolvedGeweAccount } from "./types.js";
|
|
5
|
+
import { resolveGeweAccount, resolveDefaultGeweAccountId, listGeweAccountIds } from "./accounts.js";
|
|
6
|
+
import { CHANNEL_CONFIG_KEY, CHANNEL_ID, stripChannelPrefix } from "./constants.js";
|
|
7
|
+
|
|
8
|
+
const DEFAULT_WEBHOOK_HOST = "0.0.0.0";
|
|
9
|
+
const DEFAULT_WEBHOOK_PORT = 4399;
|
|
10
|
+
const DEFAULT_WEBHOOK_PATH = "/webhook";
|
|
11
|
+
const DEFAULT_MEDIA_HOST = "0.0.0.0";
|
|
12
|
+
const DEFAULT_MEDIA_PORT = 4400;
|
|
13
|
+
const DEFAULT_MEDIA_PATH = "/gewe-media";
|
|
14
|
+
const DEFAULT_API_BASE_URL = "https://www.geweapi.com";
|
|
15
|
+
|
|
16
|
+
type GeweOnboardingAdapter = NonNullable<
|
|
17
|
+
ChannelPlugin<ResolvedGeweAccount>["onboarding"]
|
|
18
|
+
>;
|
|
19
|
+
|
|
20
|
+
type AccountSelection = {
|
|
21
|
+
accountId: string;
|
|
22
|
+
label: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
function listAccountChoices(cfg: OpenClawConfig): AccountSelection[] {
|
|
26
|
+
const ids = listGeweAccountIds(cfg as CoreConfig);
|
|
27
|
+
return ids.map((accountId) => ({
|
|
28
|
+
accountId,
|
|
29
|
+
label: accountId === DEFAULT_ACCOUNT_ID ? "default (primary)" : accountId,
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function promptAccountId(params: {
|
|
34
|
+
cfg: OpenClawConfig;
|
|
35
|
+
prompter: WizardPrompter;
|
|
36
|
+
currentId?: string;
|
|
37
|
+
}): Promise<string> {
|
|
38
|
+
const choices = listAccountChoices(params.cfg);
|
|
39
|
+
const defaultId = resolveDefaultGeweAccountId(params.cfg as CoreConfig);
|
|
40
|
+
const initial = params.currentId?.trim() || defaultId || DEFAULT_ACCOUNT_ID;
|
|
41
|
+
const selection = await params.prompter.select({
|
|
42
|
+
message: "GeWe account",
|
|
43
|
+
options: [
|
|
44
|
+
...choices.map((item) => ({ value: item.accountId, label: item.label })),
|
|
45
|
+
{ value: "__new__", label: "Add a new account" },
|
|
46
|
+
],
|
|
47
|
+
initialValue: initial,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
if (selection !== "__new__") {
|
|
51
|
+
return normalizeAccountId(selection) ?? DEFAULT_ACCOUNT_ID;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const entered = await params.prompter.text({
|
|
55
|
+
message: "New GeWe account id",
|
|
56
|
+
validate: (value) => (value?.trim() ? undefined : "Required"),
|
|
57
|
+
});
|
|
58
|
+
const normalized = normalizeAccountId(String(entered));
|
|
59
|
+
if (String(entered).trim() !== normalized) {
|
|
60
|
+
await params.prompter.note(`Normalized account id to "${normalized}".`, "GeWe account");
|
|
61
|
+
}
|
|
62
|
+
return normalized;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function parseAllowFrom(raw: string): string[] {
|
|
66
|
+
return raw
|
|
67
|
+
.split(/[\n,;]+/g)
|
|
68
|
+
.map((entry) => stripChannelPrefix(entry.trim()))
|
|
69
|
+
.filter(Boolean);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function promptAllowFrom(params: {
|
|
73
|
+
prompter: WizardPrompter;
|
|
74
|
+
existing?: Array<string | number>;
|
|
75
|
+
required?: boolean;
|
|
76
|
+
}): Promise<string[]> {
|
|
77
|
+
const initial = (params.existing ?? []).map((entry) => String(entry)).join(", ");
|
|
78
|
+
const value = await params.prompter.text({
|
|
79
|
+
message: "Allowlist wxid (comma or newline separated)",
|
|
80
|
+
placeholder: "wxid_xxx, wxid_yyy",
|
|
81
|
+
initialValue: initial || undefined,
|
|
82
|
+
validate: params.required
|
|
83
|
+
? (input) => (parseAllowFrom(input).length > 0 ? undefined : "Required")
|
|
84
|
+
: undefined,
|
|
85
|
+
});
|
|
86
|
+
return parseAllowFrom(String(value));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function applyAccountPatch(
|
|
90
|
+
cfg: OpenClawConfig,
|
|
91
|
+
accountId: string,
|
|
92
|
+
patch: GeweAccountConfig,
|
|
93
|
+
): OpenClawConfig {
|
|
94
|
+
const existing = (cfg.channels?.[CHANNEL_CONFIG_KEY] ?? {}) as GeweAccountConfig & {
|
|
95
|
+
accounts?: Record<string, GeweAccountConfig>;
|
|
96
|
+
};
|
|
97
|
+
if (accountId === DEFAULT_ACCOUNT_ID) {
|
|
98
|
+
return {
|
|
99
|
+
...cfg,
|
|
100
|
+
channels: {
|
|
101
|
+
...cfg.channels,
|
|
102
|
+
[CHANNEL_CONFIG_KEY]: {
|
|
103
|
+
...existing,
|
|
104
|
+
...patch,
|
|
105
|
+
enabled: patch.enabled ?? existing.enabled ?? true,
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
...cfg,
|
|
113
|
+
channels: {
|
|
114
|
+
...cfg.channels,
|
|
115
|
+
[CHANNEL_CONFIG_KEY]: {
|
|
116
|
+
...existing,
|
|
117
|
+
accounts: {
|
|
118
|
+
...(existing.accounts ?? {}),
|
|
119
|
+
[accountId]: {
|
|
120
|
+
...(existing.accounts?.[accountId] ?? {}),
|
|
121
|
+
...patch,
|
|
122
|
+
enabled:
|
|
123
|
+
patch.enabled ??
|
|
124
|
+
existing.accounts?.[accountId]?.enabled ??
|
|
125
|
+
existing.enabled ??
|
|
126
|
+
true,
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function readAccountConfig(cfg: OpenClawConfig, accountId: string): GeweAccountConfig {
|
|
135
|
+
const channelCfg = (cfg.channels?.[CHANNEL_CONFIG_KEY] ?? {}) as GeweAccountConfig & {
|
|
136
|
+
accounts?: Record<string, GeweAccountConfig>;
|
|
137
|
+
};
|
|
138
|
+
if (accountId === DEFAULT_ACCOUNT_ID) {
|
|
139
|
+
return channelCfg;
|
|
140
|
+
}
|
|
141
|
+
return channelCfg.accounts?.[accountId] ?? {};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export const geweOnboarding: GeweOnboardingAdapter = {
|
|
145
|
+
channel: CHANNEL_ID,
|
|
146
|
+
async getStatus(ctx) {
|
|
147
|
+
const accountId =
|
|
148
|
+
ctx.accountOverrides?.[CHANNEL_ID] ??
|
|
149
|
+
resolveDefaultGeweAccountId(ctx.cfg as CoreConfig);
|
|
150
|
+
const account = resolveGeweAccount({ cfg: ctx.cfg as CoreConfig, accountId });
|
|
151
|
+
const configured = Boolean(account.token?.trim() && account.appId?.trim());
|
|
152
|
+
const label = configured ? "configured" : "not configured";
|
|
153
|
+
const status = `GeWe (${accountId}): ${label}`;
|
|
154
|
+
return {
|
|
155
|
+
channel: CHANNEL_ID,
|
|
156
|
+
configured,
|
|
157
|
+
statusLines: [status],
|
|
158
|
+
selectionHint: label,
|
|
159
|
+
quickstartScore: configured ? 2 : 0,
|
|
160
|
+
};
|
|
161
|
+
},
|
|
162
|
+
async configure(ctx) {
|
|
163
|
+
const accountId = ctx.shouldPromptAccountIds
|
|
164
|
+
? await promptAccountId({ cfg: ctx.cfg, prompter: ctx.prompter })
|
|
165
|
+
: resolveDefaultGeweAccountId(ctx.cfg as CoreConfig);
|
|
166
|
+
const resolved = resolveGeweAccount({ cfg: ctx.cfg as CoreConfig, accountId });
|
|
167
|
+
const existing = readAccountConfig(ctx.cfg, accountId);
|
|
168
|
+
|
|
169
|
+
await ctx.prompter.note(
|
|
170
|
+
[
|
|
171
|
+
"You will need:",
|
|
172
|
+
"- GeWe token + appId",
|
|
173
|
+
"- Public webhook endpoint (FRP or reverse proxy)",
|
|
174
|
+
"- Public media base URL (for sending voice/media)",
|
|
175
|
+
].join("\n"),
|
|
176
|
+
"GeWe setup",
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
const token = await ctx.prompter.text({
|
|
180
|
+
message: "GeWe token",
|
|
181
|
+
initialValue: resolved.tokenSource !== "none" ? resolved.token : existing.token,
|
|
182
|
+
validate: (value) => (value.trim() ? undefined : "Required"),
|
|
183
|
+
});
|
|
184
|
+
const appId = await ctx.prompter.text({
|
|
185
|
+
message: "GeWe appId",
|
|
186
|
+
initialValue: resolved.appIdSource !== "none" ? resolved.appId : existing.appId,
|
|
187
|
+
validate: (value) => (value.trim() ? undefined : "Required"),
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
const apiBaseUrl = await ctx.prompter.text({
|
|
191
|
+
message: "GeWe API base URL",
|
|
192
|
+
initialValue: existing.apiBaseUrl ?? DEFAULT_API_BASE_URL,
|
|
193
|
+
validate: (value) => (value.trim() ? undefined : "Required"),
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
const webhookHost = await ctx.prompter.text({
|
|
197
|
+
message: "Webhook host",
|
|
198
|
+
initialValue: existing.webhookHost ?? DEFAULT_WEBHOOK_HOST,
|
|
199
|
+
validate: (value) => (value.trim() ? undefined : "Required"),
|
|
200
|
+
});
|
|
201
|
+
const webhookPortRaw = await ctx.prompter.text({
|
|
202
|
+
message: "Webhook port",
|
|
203
|
+
initialValue: String(existing.webhookPort ?? DEFAULT_WEBHOOK_PORT),
|
|
204
|
+
validate: (value) => {
|
|
205
|
+
const parsed = Number(value);
|
|
206
|
+
if (!Number.isInteger(parsed) || parsed <= 0) return "Must be a positive integer";
|
|
207
|
+
return undefined;
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
const webhookPath = await ctx.prompter.text({
|
|
211
|
+
message: "Webhook path",
|
|
212
|
+
initialValue: existing.webhookPath ?? DEFAULT_WEBHOOK_PATH,
|
|
213
|
+
validate: (value) => (value.trim() ? undefined : "Required"),
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
const mediaPublicUrl = await ctx.prompter.text({
|
|
217
|
+
message: "Media public URL (prefix)",
|
|
218
|
+
placeholder: "https://your-domain/gewe-media",
|
|
219
|
+
initialValue: existing.mediaPublicUrl,
|
|
220
|
+
validate: (value) => (value.trim() ? undefined : "Required"),
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
let allowFrom = existing.allowFrom;
|
|
224
|
+
let dmPolicy: GeweAccountConfig["dmPolicy"] | undefined;
|
|
225
|
+
if (ctx.forceAllowFrom) {
|
|
226
|
+
allowFrom = await promptAllowFrom({
|
|
227
|
+
prompter: ctx.prompter,
|
|
228
|
+
existing: existing.allowFrom,
|
|
229
|
+
required: true,
|
|
230
|
+
});
|
|
231
|
+
dmPolicy = "allowlist";
|
|
232
|
+
} else {
|
|
233
|
+
const wantsAllowlist = await ctx.prompter.confirm({
|
|
234
|
+
message: "Set a DM allowlist now? (optional)",
|
|
235
|
+
initialValue: false,
|
|
236
|
+
});
|
|
237
|
+
if (wantsAllowlist) {
|
|
238
|
+
allowFrom = await promptAllowFrom({
|
|
239
|
+
prompter: ctx.prompter,
|
|
240
|
+
existing: existing.allowFrom,
|
|
241
|
+
required: true,
|
|
242
|
+
});
|
|
243
|
+
dmPolicy = "allowlist";
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
let nextCfg = applyAccountPatch(ctx.cfg, accountId, {
|
|
248
|
+
enabled: true,
|
|
249
|
+
token: token.trim(),
|
|
250
|
+
appId: appId.trim(),
|
|
251
|
+
apiBaseUrl: apiBaseUrl.trim().replace(/\/$/, ""),
|
|
252
|
+
webhookHost: webhookHost.trim(),
|
|
253
|
+
webhookPort: Number(webhookPortRaw),
|
|
254
|
+
webhookPath: webhookPath.trim(),
|
|
255
|
+
mediaHost: existing.mediaHost ?? DEFAULT_MEDIA_HOST,
|
|
256
|
+
mediaPort: existing.mediaPort ?? DEFAULT_MEDIA_PORT,
|
|
257
|
+
mediaPath: existing.mediaPath ?? DEFAULT_MEDIA_PATH,
|
|
258
|
+
mediaPublicUrl: mediaPublicUrl.trim(),
|
|
259
|
+
...(allowFrom ? { allowFrom } : {}),
|
|
260
|
+
...(dmPolicy ? { dmPolicy } : {}),
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
return { cfg: nextCfg, accountId };
|
|
264
|
+
},
|
|
265
|
+
};
|
package/src/policy.ts
CHANGED
|
@@ -7,10 +7,11 @@ import {
|
|
|
7
7
|
resolveNestedAllowlistDecision,
|
|
8
8
|
} from "openclaw/plugin-sdk";
|
|
9
9
|
|
|
10
|
+
import { CHANNEL_CONFIG_KEY, CHANNEL_PREFIX_REGEX } from "./constants.js";
|
|
10
11
|
import type { GeweGroupConfig } from "./types.js";
|
|
11
12
|
|
|
12
13
|
function normalizeAllowEntry(raw: string): string {
|
|
13
|
-
return raw.trim().toLowerCase().replace(
|
|
14
|
+
return raw.trim().toLowerCase().replace(CHANNEL_PREFIX_REGEX, "");
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
export function normalizeGeweAllowlist(values: Array<string | number> | undefined): string[] {
|
|
@@ -89,7 +90,7 @@ export function resolveGeweGroupToolPolicy(
|
|
|
89
90
|
): GeweGroupConfig["tools"] | undefined {
|
|
90
91
|
const cfg = params.cfg as {
|
|
91
92
|
channels?: {
|
|
92
|
-
gewe?: {
|
|
93
|
+
"gewe-openclaw"?: {
|
|
93
94
|
groups?: Record<string, GeweGroupConfig>;
|
|
94
95
|
accounts?: Record<string, { groups?: Record<string, GeweGroupConfig> }>;
|
|
95
96
|
};
|
|
@@ -99,10 +100,10 @@ export function resolveGeweGroupToolPolicy(
|
|
|
99
100
|
if (!groupId) return undefined;
|
|
100
101
|
const groupName = params.groupChannel?.trim() || undefined;
|
|
101
102
|
const accountGroups =
|
|
102
|
-
params.accountId && cfg.channels?.
|
|
103
|
-
? cfg.channels?.
|
|
103
|
+
params.accountId && cfg.channels?.[CHANNEL_CONFIG_KEY]?.accounts?.[params.accountId]?.groups
|
|
104
|
+
? cfg.channels?.[CHANNEL_CONFIG_KEY]?.accounts?.[params.accountId]?.groups
|
|
104
105
|
: undefined;
|
|
105
|
-
const groups = accountGroups ?? cfg.channels?.
|
|
106
|
+
const groups = accountGroups ?? cfg.channels?.[CHANNEL_CONFIG_KEY]?.groups;
|
|
106
107
|
const match = resolveGeweGroupMatch({
|
|
107
108
|
groups,
|
|
108
109
|
groupId,
|
package/src/send.ts
CHANGED
|
@@ -8,7 +8,7 @@ type GeweSendContext = {
|
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
function buildContext(account: ResolvedGeweAccount): GeweSendContext {
|
|
11
|
-
const baseUrl = account.config.apiBaseUrl?.trim() || "
|
|
11
|
+
const baseUrl = account.config.apiBaseUrl?.trim() || "https://www.geweapi.com";
|
|
12
12
|
return { baseUrl, token: account.token, appId: account.appId };
|
|
13
13
|
}
|
|
14
14
|
|