@tencent-weixin/openclaw-weixin 2.3.1 → 2.4.2
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/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/src/api/api.js +374 -0
- package/dist/src/api/api.js.map +1 -0
- package/dist/src/api/config-cache.js +64 -0
- package/dist/src/api/config-cache.js.map +1 -0
- package/dist/src/api/session-guard.js +49 -0
- package/dist/src/api/session-guard.js.map +1 -0
- package/dist/src/api/types.js +35 -0
- package/dist/src/api/types.js.map +1 -0
- package/dist/src/auth/accounts.js +326 -0
- package/dist/src/auth/accounts.js.map +1 -0
- package/dist/src/auth/login-qr.js +332 -0
- package/dist/src/auth/login-qr.js.map +1 -0
- package/dist/src/auth/pairing.js +104 -0
- package/dist/src/auth/pairing.js.map +1 -0
- package/dist/src/cdn/aes-ecb.js +19 -0
- package/dist/src/cdn/aes-ecb.js.map +1 -0
- package/dist/src/cdn/cdn-upload.js +73 -0
- package/dist/src/cdn/cdn-upload.js.map +1 -0
- package/dist/src/cdn/cdn-url.js +14 -0
- package/dist/src/cdn/cdn-url.js.map +1 -0
- package/dist/src/cdn/pic-decrypt.js +89 -0
- package/dist/src/cdn/pic-decrypt.js.map +1 -0
- package/dist/src/cdn/upload.js +106 -0
- package/dist/src/cdn/upload.js.map +1 -0
- package/dist/src/channel.js +460 -0
- package/dist/src/channel.js.map +1 -0
- package/dist/src/compat.js +67 -0
- package/dist/src/compat.js.map +1 -0
- package/dist/src/config/config-schema.js +19 -0
- package/dist/src/config/config-schema.js.map +1 -0
- package/dist/src/media/media-download.js +95 -0
- package/dist/src/media/media-download.js.map +1 -0
- package/dist/src/media/mime.js +73 -0
- package/dist/src/media/mime.js.map +1 -0
- package/dist/src/media/silk-transcode.js +64 -0
- package/dist/src/media/silk-transcode.js.map +1 -0
- package/dist/src/media/voice-outbound.js +177 -0
- package/dist/src/media/voice-outbound.js.map +1 -0
- package/dist/src/messaging/abort-fence.js +70 -0
- package/dist/src/messaging/abort-fence.js.map +1 -0
- package/dist/src/messaging/buttons.js +117 -0
- package/dist/src/messaging/buttons.js.map +1 -0
- package/dist/src/messaging/debug-mode.js +63 -0
- package/dist/src/messaging/debug-mode.js.map +1 -0
- package/dist/src/messaging/error-notice.js +24 -0
- package/dist/src/messaging/error-notice.js.map +1 -0
- package/dist/src/messaging/inbound.js +201 -0
- package/dist/src/messaging/inbound.js.map +1 -0
- package/dist/src/messaging/lane-key.js +66 -0
- package/dist/src/messaging/lane-key.js.map +1 -0
- package/dist/src/messaging/markdown-filter.js +368 -0
- package/dist/src/messaging/markdown-filter.js.map +1 -0
- package/dist/src/messaging/merged-record.js +149 -0
- package/dist/src/messaging/merged-record.js.map +1 -0
- package/dist/src/messaging/model-buttons.js +182 -0
- package/dist/src/messaging/model-buttons.js.map +1 -0
- package/dist/src/messaging/model-callback-handler.js +133 -0
- package/dist/src/messaging/model-callback-handler.js.map +1 -0
- package/dist/src/messaging/outbound-hooks.js +56 -0
- package/dist/src/messaging/outbound-hooks.js.map +1 -0
- package/dist/src/messaging/process-message.js +381 -0
- package/dist/src/messaging/process-message.js.map +1 -0
- package/dist/src/messaging/send-media.js +54 -0
- package/dist/src/messaging/send-media.js.map +1 -0
- package/dist/src/messaging/send.js +182 -0
- package/dist/src/messaging/send.js.map +1 -0
- package/dist/src/messaging/slash-commands.js +70 -0
- package/dist/src/messaging/slash-commands.js.map +1 -0
- package/dist/src/monitor/lane-scheduler.js +46 -0
- package/dist/src/monitor/lane-scheduler.js.map +1 -0
- package/dist/src/monitor/monitor.js +143 -0
- package/dist/src/monitor/monitor.js.map +1 -0
- package/dist/src/runtime.js +54 -0
- package/dist/src/runtime.js.map +1 -0
- package/dist/src/storage/state-dir.js +9 -0
- package/dist/src/storage/state-dir.js.map +1 -0
- package/dist/src/storage/sync-buf.js +64 -0
- package/dist/src/storage/sync-buf.js.map +1 -0
- package/dist/src/streaming/stream-pipeline.js +431 -0
- package/dist/src/streaming/stream-pipeline.js.map +1 -0
- package/dist/src/streaming/stream-session.js +260 -0
- package/dist/src/streaming/stream-session.js.map +1 -0
- package/dist/src/streaming/stream.js +239 -0
- package/dist/src/streaming/stream.js.map +1 -0
- package/dist/src/util/logger.js +120 -0
- package/dist/src/util/logger.js.map +1 -0
- package/dist/src/util/markdown-fences.js +54 -0
- package/dist/src/util/markdown-fences.js.map +1 -0
- package/dist/src/util/random.js +16 -0
- package/dist/src/util/random.js.map +1 -0
- package/dist/src/util/redact.js +54 -0
- package/dist/src/util/redact.js.map +1 -0
- package/index.ts +0 -5
- package/openclaw.plugin.json +11 -1
- package/package.json +9 -2
- package/src/api/api.ts +2 -3
- package/src/auth/accounts.ts +0 -1
- package/src/channel.ts +13 -1
- package/src/monitor/monitor.ts +11 -10
- package/src/runtime.ts +0 -70
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { normalizeAccountId } from "openclaw/plugin-sdk/account-id";
|
|
3
|
+
import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/infra-runtime";
|
|
4
|
+
import { registerWeixinAccountId, loadWeixinAccount, saveWeixinAccount, listWeixinAccountIds, resolveWeixinAccount, triggerWeixinChannelReload, clearStaleAccountsForUserId, DEFAULT_BASE_URL, } from "./auth/accounts.js";
|
|
5
|
+
import { notifyStop, notifyStart } from "./api/api.js";
|
|
6
|
+
import { assertSessionActive } from "./api/session-guard.js";
|
|
7
|
+
import { getContextToken, findAccountIdsByContextToken, restoreContextTokens, clearContextTokensForAccount } from "./messaging/inbound.js";
|
|
8
|
+
import { logger } from "./util/logger.js";
|
|
9
|
+
import { DEFAULT_ILINK_BOT_TYPE, startWeixinLoginWithQr, waitForWeixinLogin, displayQRCode, } from "./auth/login-qr.js";
|
|
10
|
+
// Lazy-imported inside startAccount to avoid pulling in the monitor -> process-message ->
|
|
11
|
+
// command-auth chain during plugin registration, which can re-enter plugin/provider registry
|
|
12
|
+
// resolution before the account actually starts.
|
|
13
|
+
import { applyWeixinMessageSendingHook, emitWeixinMessageSent } from "./messaging/outbound-hooks.js";
|
|
14
|
+
import { sendWeixinMediaFile } from "./messaging/send-media.js";
|
|
15
|
+
import { sendMessageWeixin, StreamingMarkdownFilter } from "./messaging/send.js";
|
|
16
|
+
import { downloadRemoteImageToTemp } from "./cdn/upload.js";
|
|
17
|
+
/** Returns true when mediaUrl refers to a local filesystem path (absolute or relative). */
|
|
18
|
+
function isLocalFilePath(mediaUrl) {
|
|
19
|
+
// Treat anything without a URL scheme (no "://") as a local path.
|
|
20
|
+
return !mediaUrl.includes("://");
|
|
21
|
+
}
|
|
22
|
+
function isRemoteUrl(mediaUrl) {
|
|
23
|
+
return mediaUrl.startsWith("http://") || mediaUrl.startsWith("https://");
|
|
24
|
+
}
|
|
25
|
+
const MEDIA_OUTBOUND_TEMP_DIR = path.join(resolvePreferredOpenClawTmpDir(), "weixin/media/outbound-temp");
|
|
26
|
+
/** Resolve any local path scheme to an absolute filesystem path. */
|
|
27
|
+
function resolveLocalPath(mediaUrl) {
|
|
28
|
+
if (mediaUrl.startsWith("file://"))
|
|
29
|
+
return new URL(mediaUrl).pathname;
|
|
30
|
+
// Resolve any relative path (./foo, ../foo, .openclaw/foo, foo/bar) against cwd
|
|
31
|
+
if (!path.isAbsolute(mediaUrl))
|
|
32
|
+
return path.resolve(mediaUrl);
|
|
33
|
+
return mediaUrl;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Resolve the effective accountId for an outbound message when the caller
|
|
37
|
+
* did not provide one (e.g. cron delivery without explicit accountId).
|
|
38
|
+
*
|
|
39
|
+
* Priority:
|
|
40
|
+
* 1. Multiple accounts → match via contextToken for the `to` recipient
|
|
41
|
+
* 2. Single account → use it directly
|
|
42
|
+
* 3. No match → throw a descriptive error
|
|
43
|
+
*/
|
|
44
|
+
function resolveOutboundAccountId(cfg, to) {
|
|
45
|
+
const allIds = listWeixinAccountIds(cfg);
|
|
46
|
+
if (allIds.length === 0) {
|
|
47
|
+
throw new Error(`weixin: no accounts registered — run \`openclaw channels login --channel openclaw-weixin\``);
|
|
48
|
+
}
|
|
49
|
+
if (allIds.length === 1) {
|
|
50
|
+
logger.info(`resolveOutboundAccountId: single account, using ${allIds[0]}`);
|
|
51
|
+
return allIds[0];
|
|
52
|
+
}
|
|
53
|
+
// Multiple accounts: find which ones have a contextToken for the recipient.
|
|
54
|
+
const matched = findAccountIdsByContextToken(allIds, to);
|
|
55
|
+
if (matched.length === 1) {
|
|
56
|
+
logger.info(`resolveOutboundAccountId: matched accountId=${matched[0]} for to=${to}`);
|
|
57
|
+
return matched[0];
|
|
58
|
+
}
|
|
59
|
+
if (matched.length > 1) {
|
|
60
|
+
logger.warn(`resolveOutboundAccountId: ambiguous — ${matched.length} accounts matched for to=${to}: ${matched.join(", ")}`);
|
|
61
|
+
throw new Error(`weixin: ambiguous account for to=${to} ` +
|
|
62
|
+
`(${matched.length} accounts have active sessions with this recipient: ${matched.join(", ")}). ` +
|
|
63
|
+
`Specify accountId in the delivery config to disambiguate.`);
|
|
64
|
+
}
|
|
65
|
+
throw new Error(`weixin: cannot determine which account to use for to=${to} ` +
|
|
66
|
+
`(${allIds.length} accounts registered, none has an active session with this recipient). ` +
|
|
67
|
+
`Specify accountId in the delivery config, or ensure the recipient has recently messaged the bot.`);
|
|
68
|
+
}
|
|
69
|
+
async function sendWeixinOutbound(params) {
|
|
70
|
+
const account = resolveWeixinAccount(params.cfg, params.accountId);
|
|
71
|
+
const aLog = logger.withAccount(account.accountId);
|
|
72
|
+
assertSessionActive(account.accountId);
|
|
73
|
+
if (!account.configured) {
|
|
74
|
+
aLog.error(`sendWeixinOutbound: account not configured`);
|
|
75
|
+
throw new Error("weixin not configured: please run `openclaw channels login --channel openclaw-weixin`");
|
|
76
|
+
}
|
|
77
|
+
if (!params.contextToken) {
|
|
78
|
+
aLog.warn(`sendWeixinOutbound: contextToken missing for to=${params.to}, sending without context`);
|
|
79
|
+
}
|
|
80
|
+
const f = new StreamingMarkdownFilter();
|
|
81
|
+
const rawText = params.text ?? "";
|
|
82
|
+
let filteredText = f.feed(rawText) + f.flush();
|
|
83
|
+
const sendingResult = await applyWeixinMessageSendingHook({
|
|
84
|
+
to: params.to,
|
|
85
|
+
text: filteredText,
|
|
86
|
+
accountId: account.accountId,
|
|
87
|
+
});
|
|
88
|
+
if (sendingResult.cancelled) {
|
|
89
|
+
aLog.info(`sendWeixinOutbound: cancelled by message_sending hook to=${params.to}`);
|
|
90
|
+
return { channel: "openclaw-weixin", messageId: "" };
|
|
91
|
+
}
|
|
92
|
+
filteredText = sendingResult.text;
|
|
93
|
+
try {
|
|
94
|
+
const result = await sendMessageWeixin({ to: params.to, text: filteredText, opts: {
|
|
95
|
+
baseUrl: account.baseUrl,
|
|
96
|
+
token: account.token,
|
|
97
|
+
contextToken: params.contextToken,
|
|
98
|
+
} });
|
|
99
|
+
emitWeixinMessageSent({ to: params.to, content: filteredText, success: true, accountId: account.accountId });
|
|
100
|
+
return { channel: "openclaw-weixin", messageId: result.messageId };
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
emitWeixinMessageSent({ to: params.to, content: filteredText, success: false, error: String(err), accountId: account.accountId });
|
|
104
|
+
throw err;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
export const weixinPlugin = {
|
|
108
|
+
id: "openclaw-weixin",
|
|
109
|
+
meta: {
|
|
110
|
+
id: "openclaw-weixin",
|
|
111
|
+
label: "openclaw-weixin",
|
|
112
|
+
selectionLabel: "openclaw-weixin (long-poll)",
|
|
113
|
+
docsPath: "/channels/openclaw-weixin",
|
|
114
|
+
docsLabel: "openclaw-weixin",
|
|
115
|
+
blurb: "getUpdates long-poll upstream, sendMessage downstream; token auth.",
|
|
116
|
+
order: 75,
|
|
117
|
+
},
|
|
118
|
+
configSchema: {
|
|
119
|
+
schema: {
|
|
120
|
+
type: "object",
|
|
121
|
+
additionalProperties: false,
|
|
122
|
+
properties: {},
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
capabilities: {
|
|
126
|
+
chatTypes: ["direct"],
|
|
127
|
+
media: true,
|
|
128
|
+
blockStreaming: true,
|
|
129
|
+
},
|
|
130
|
+
streaming: {
|
|
131
|
+
blockStreamingCoalesceDefaults: {
|
|
132
|
+
minChars: 200,
|
|
133
|
+
idleMs: 3000,
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
messaging: {
|
|
137
|
+
targetResolver: {
|
|
138
|
+
// Weixin user IDs always end with @im.wechat; treat as direct IDs, skip directory lookup.
|
|
139
|
+
looksLikeId: (raw) => raw.endsWith("@im.wechat"),
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
agentPrompt: {
|
|
143
|
+
messageToolHints: () => [
|
|
144
|
+
"To send an image or file to the current user, use the message tool with action='send' and set 'media' to a local file path or a remote URL. You do not need to specify 'to' — the current conversation recipient is used automatically.",
|
|
145
|
+
"When the user asks you to find an image from the web, use a web search or browser tool to find a suitable image URL, then send it using the message tool with 'media' set to that HTTPS image URL — do NOT download the image first.",
|
|
146
|
+
"IMPORTANT: When generating or saving a file to send, always use an absolute path (e.g. /tmp/photo.png), never a relative path like ./photo.png. Relative paths cannot be resolved and the file will not be delivered.",
|
|
147
|
+
"IMPORTANT: When creating a cron job (scheduled task) for the current Weixin user, you MUST set delivery.to to the user's Weixin ID (the xxx@im.wechat address from the current conversation) AND set delivery.accountId to the current AccountId. Without an explicit 'to', the cron delivery will fail with 'requires target'. Without an explicit 'accountId', the message may be sent from the wrong bot account. Example: delivery: { mode: 'announce', channel: 'openclaw-weixin', to: '<current_user_id@im.wechat>', accountId: '<current_AccountId>' }.",
|
|
148
|
+
"IMPORTANT: When outputting a MEDIA: directive to send a file, the MEDIA: tag MUST be on its own line — never inline with other text. Correct:\nSome text here\nMEDIA:/path/to/file.mp4\nIncorrect: Some text here MEDIA:/path/to/file.mp4",
|
|
149
|
+
],
|
|
150
|
+
},
|
|
151
|
+
reload: { configPrefixes: ["channels.openclaw-weixin"] },
|
|
152
|
+
config: {
|
|
153
|
+
listAccountIds: (cfg) => listWeixinAccountIds(cfg),
|
|
154
|
+
resolveAccount: (cfg, accountId) => resolveWeixinAccount(cfg, accountId),
|
|
155
|
+
isConfigured: (account) => account.configured,
|
|
156
|
+
describeAccount: (account) => ({
|
|
157
|
+
accountId: account.accountId,
|
|
158
|
+
name: account.name,
|
|
159
|
+
enabled: account.enabled,
|
|
160
|
+
configured: account.configured,
|
|
161
|
+
}),
|
|
162
|
+
},
|
|
163
|
+
outbound: {
|
|
164
|
+
deliveryMode: "direct",
|
|
165
|
+
textChunkLimit: 4000,
|
|
166
|
+
sendText: async (ctx) => {
|
|
167
|
+
const accountId = ctx.accountId || resolveOutboundAccountId(ctx.cfg, ctx.to);
|
|
168
|
+
const result = await sendWeixinOutbound({
|
|
169
|
+
cfg: ctx.cfg,
|
|
170
|
+
to: ctx.to,
|
|
171
|
+
text: ctx.text,
|
|
172
|
+
accountId,
|
|
173
|
+
contextToken: getContextToken(accountId, ctx.to),
|
|
174
|
+
});
|
|
175
|
+
return result;
|
|
176
|
+
},
|
|
177
|
+
sendMedia: async (ctx) => {
|
|
178
|
+
const accountId = ctx.accountId || resolveOutboundAccountId(ctx.cfg, ctx.to);
|
|
179
|
+
const account = resolveWeixinAccount(ctx.cfg, accountId);
|
|
180
|
+
const aLog = logger.withAccount(account.accountId);
|
|
181
|
+
assertSessionActive(account.accountId);
|
|
182
|
+
if (!account.configured) {
|
|
183
|
+
aLog.error(`sendMedia: account not configured`);
|
|
184
|
+
throw new Error("weixin not configured: please run `openclaw channels login --channel openclaw-weixin`");
|
|
185
|
+
}
|
|
186
|
+
const mediaUrl = ctx.mediaUrl;
|
|
187
|
+
let text = ctx.text ?? "";
|
|
188
|
+
const sendingResult = await applyWeixinMessageSendingHook({
|
|
189
|
+
to: ctx.to,
|
|
190
|
+
text,
|
|
191
|
+
accountId: account.accountId,
|
|
192
|
+
mediaUrl,
|
|
193
|
+
});
|
|
194
|
+
if (sendingResult.cancelled) {
|
|
195
|
+
aLog.info(`sendMedia: cancelled by message_sending hook to=${ctx.to}`);
|
|
196
|
+
return { channel: "openclaw-weixin", messageId: "" };
|
|
197
|
+
}
|
|
198
|
+
text = sendingResult.text;
|
|
199
|
+
if (mediaUrl && (isLocalFilePath(mediaUrl) || isRemoteUrl(mediaUrl))) {
|
|
200
|
+
let filePath;
|
|
201
|
+
if (isLocalFilePath(mediaUrl)) {
|
|
202
|
+
filePath = resolveLocalPath(mediaUrl);
|
|
203
|
+
aLog.debug(`sendMedia: uploading local file ${filePath}`);
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
aLog.debug(`sendMedia: downloading remote mediaUrl=${mediaUrl.slice(0, 80)}...`);
|
|
207
|
+
filePath = await downloadRemoteImageToTemp(mediaUrl, MEDIA_OUTBOUND_TEMP_DIR);
|
|
208
|
+
aLog.debug(`sendMedia: remote image downloaded to ${filePath}`);
|
|
209
|
+
}
|
|
210
|
+
const contextToken = getContextToken(account.accountId, ctx.to);
|
|
211
|
+
try {
|
|
212
|
+
const result = await sendWeixinMediaFile({
|
|
213
|
+
filePath,
|
|
214
|
+
to: ctx.to,
|
|
215
|
+
text,
|
|
216
|
+
opts: { baseUrl: account.baseUrl, token: account.token, contextToken },
|
|
217
|
+
cdnBaseUrl: account.cdnBaseUrl,
|
|
218
|
+
});
|
|
219
|
+
emitWeixinMessageSent({ to: ctx.to, content: text, success: true, accountId: account.accountId });
|
|
220
|
+
return { channel: "openclaw-weixin", messageId: result.messageId };
|
|
221
|
+
}
|
|
222
|
+
catch (err) {
|
|
223
|
+
emitWeixinMessageSent({ to: ctx.to, content: text, success: false, error: String(err), accountId: account.accountId });
|
|
224
|
+
throw err;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
const contextToken = getContextToken(account.accountId, ctx.to);
|
|
228
|
+
try {
|
|
229
|
+
const result = await sendMessageWeixin({ to: ctx.to, text, opts: {
|
|
230
|
+
baseUrl: account.baseUrl,
|
|
231
|
+
token: account.token,
|
|
232
|
+
contextToken,
|
|
233
|
+
} });
|
|
234
|
+
emitWeixinMessageSent({ to: ctx.to, content: text, success: true, accountId: account.accountId });
|
|
235
|
+
return { channel: "openclaw-weixin", messageId: result.messageId };
|
|
236
|
+
}
|
|
237
|
+
catch (err) {
|
|
238
|
+
emitWeixinMessageSent({ to: ctx.to, content: text, success: false, error: String(err), accountId: account.accountId });
|
|
239
|
+
throw err;
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
status: {
|
|
244
|
+
defaultRuntime: {
|
|
245
|
+
accountId: "",
|
|
246
|
+
lastError: null,
|
|
247
|
+
lastInboundAt: null,
|
|
248
|
+
lastOutboundAt: null,
|
|
249
|
+
},
|
|
250
|
+
collectStatusIssues: () => [],
|
|
251
|
+
buildChannelSummary: ({ snapshot }) => ({
|
|
252
|
+
configured: snapshot.configured ?? false,
|
|
253
|
+
lastError: snapshot.lastError ?? null,
|
|
254
|
+
lastInboundAt: snapshot.lastInboundAt ?? null,
|
|
255
|
+
lastOutboundAt: snapshot.lastOutboundAt ?? null,
|
|
256
|
+
}),
|
|
257
|
+
buildAccountSnapshot: ({ account, runtime }) => ({
|
|
258
|
+
...runtime,
|
|
259
|
+
accountId: account.accountId,
|
|
260
|
+
name: account.name,
|
|
261
|
+
enabled: account.enabled,
|
|
262
|
+
configured: account.configured,
|
|
263
|
+
}),
|
|
264
|
+
},
|
|
265
|
+
auth: {
|
|
266
|
+
login: async ({ cfg, accountId, verbose, runtime }) => {
|
|
267
|
+
const account = resolveWeixinAccount(cfg, accountId);
|
|
268
|
+
const log = (msg) => {
|
|
269
|
+
runtime?.log?.(msg);
|
|
270
|
+
};
|
|
271
|
+
log(`正在启动...`);
|
|
272
|
+
const startResult = await startWeixinLoginWithQr({
|
|
273
|
+
accountId: account.accountId,
|
|
274
|
+
apiBaseUrl: account.baseUrl,
|
|
275
|
+
botType: DEFAULT_ILINK_BOT_TYPE,
|
|
276
|
+
verbose: Boolean(verbose),
|
|
277
|
+
});
|
|
278
|
+
if (!startResult.qrcodeUrl) {
|
|
279
|
+
logger.warn(`auth.login: failed to get QR code accountId=${account.accountId} message=${startResult.message}`);
|
|
280
|
+
log(startResult.message);
|
|
281
|
+
throw new Error(startResult.message);
|
|
282
|
+
}
|
|
283
|
+
log(`\n用手机微信扫描以下二维码,以继续连接:\n`);
|
|
284
|
+
await displayQRCode(startResult.qrcodeUrl);
|
|
285
|
+
const loginTimeoutMs = 480_000;
|
|
286
|
+
log(`\n正在等待操作...\n`);
|
|
287
|
+
const waitResult = await waitForWeixinLogin({
|
|
288
|
+
sessionKey: startResult.sessionKey,
|
|
289
|
+
apiBaseUrl: account.baseUrl,
|
|
290
|
+
timeoutMs: loginTimeoutMs,
|
|
291
|
+
verbose: Boolean(verbose),
|
|
292
|
+
botType: DEFAULT_ILINK_BOT_TYPE,
|
|
293
|
+
});
|
|
294
|
+
if (waitResult.connected && waitResult.botToken && waitResult.accountId) {
|
|
295
|
+
try {
|
|
296
|
+
// Normalize the raw ilink_bot_id (e.g. "hex@im.bot") to a filesystem-safe
|
|
297
|
+
// key (e.g. "hex-im-bot") so account files have no special chars.
|
|
298
|
+
const normalizedId = normalizeAccountId(waitResult.accountId);
|
|
299
|
+
saveWeixinAccount(normalizedId, {
|
|
300
|
+
token: waitResult.botToken,
|
|
301
|
+
baseUrl: waitResult.baseUrl,
|
|
302
|
+
userId: waitResult.userId,
|
|
303
|
+
});
|
|
304
|
+
registerWeixinAccountId(normalizedId);
|
|
305
|
+
if (waitResult.userId) {
|
|
306
|
+
clearStaleAccountsForUserId(normalizedId, waitResult.userId, clearContextTokensForAccount);
|
|
307
|
+
}
|
|
308
|
+
void triggerWeixinChannelReload();
|
|
309
|
+
log(`\n已将此 OpenClaw 连接到微信。`);
|
|
310
|
+
}
|
|
311
|
+
catch (err) {
|
|
312
|
+
logger.error(`auth.login: failed to save account data accountId=${waitResult.accountId} err=${String(err)}`);
|
|
313
|
+
log(`⚠️ 保存账号数据失败: ${String(err)}`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
logger.warn(`auth.login: login did not complete accountId=${account.accountId} message=${waitResult.message}`);
|
|
318
|
+
// log(waitResult.message);
|
|
319
|
+
throw new Error(waitResult.message);
|
|
320
|
+
}
|
|
321
|
+
},
|
|
322
|
+
},
|
|
323
|
+
gateway: {
|
|
324
|
+
startAccount: async (ctx) => {
|
|
325
|
+
logger.debug(`startAccount entry`);
|
|
326
|
+
if (!ctx) {
|
|
327
|
+
logger.warn(`gateway.startAccount: called with undefined ctx, skipping`);
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
const account = ctx.account;
|
|
331
|
+
const aLog = logger.withAccount(account.accountId);
|
|
332
|
+
aLog.debug(`about to call monitorWeixinProvider`);
|
|
333
|
+
restoreContextTokens(account.accountId);
|
|
334
|
+
aLog.info(`starting weixin webhook`);
|
|
335
|
+
ctx.setStatus?.({
|
|
336
|
+
accountId: account.accountId,
|
|
337
|
+
running: true,
|
|
338
|
+
lastStartAt: Date.now(),
|
|
339
|
+
lastEventAt: Date.now(),
|
|
340
|
+
});
|
|
341
|
+
if (!account.configured) {
|
|
342
|
+
aLog.error(`account not configured`);
|
|
343
|
+
ctx.log?.error?.(`[${account.accountId}] weixin not logged in — run: openclaw channels login --channel openclaw-weixin`);
|
|
344
|
+
ctx.setStatus?.({ accountId: account.accountId, running: false });
|
|
345
|
+
throw new Error("weixin not configured: missing token");
|
|
346
|
+
}
|
|
347
|
+
ctx.log?.info?.(`[${account.accountId}] starting weixin provider (${DEFAULT_BASE_URL})`);
|
|
348
|
+
try {
|
|
349
|
+
const resp = await notifyStart({
|
|
350
|
+
baseUrl: account.baseUrl,
|
|
351
|
+
token: account.token,
|
|
352
|
+
});
|
|
353
|
+
if (resp.ret !== undefined && resp.ret !== 0) {
|
|
354
|
+
aLog.warn(`notifyStart: ret=${resp.ret} errmsg=${resp.errmsg ?? ""}`);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
catch (err) {
|
|
358
|
+
aLog.warn(`notifyStart failed during startup (ignored): ${String(err)}`);
|
|
359
|
+
}
|
|
360
|
+
const logPath = aLog.getLogFilePath();
|
|
361
|
+
ctx.log?.info?.(`[${account.accountId}] weixin logs: ${logPath}`);
|
|
362
|
+
// The gateway injects the channel runtime surface per-call (task-scoped). We require it:
|
|
363
|
+
// it carries reply/routing/session/media/commands helpers used by processOneMessage.
|
|
364
|
+
// Available on hosts >= 2026.2.19 (our peerDependency is >= 2026.3.22).
|
|
365
|
+
if (!ctx.channelRuntime) {
|
|
366
|
+
const msg = `ctx.channelRuntime missing — host too old or plugin SDK contract violated`;
|
|
367
|
+
aLog.error(msg);
|
|
368
|
+
ctx.log?.error?.(`[${account.accountId}] ${msg}`);
|
|
369
|
+
ctx.setStatus?.({ accountId: account.accountId, running: false });
|
|
370
|
+
throw new Error(msg);
|
|
371
|
+
}
|
|
372
|
+
const { monitorWeixinProvider } = await import("./monitor/monitor.js");
|
|
373
|
+
return monitorWeixinProvider({
|
|
374
|
+
baseUrl: account.baseUrl,
|
|
375
|
+
cdnBaseUrl: account.cdnBaseUrl,
|
|
376
|
+
token: account.token,
|
|
377
|
+
accountId: account.accountId,
|
|
378
|
+
config: ctx.cfg,
|
|
379
|
+
runtime: ctx.runtime,
|
|
380
|
+
channelRuntime: ctx.channelRuntime,
|
|
381
|
+
abortSignal: ctx.abortSignal,
|
|
382
|
+
setStatus: ctx.setStatus,
|
|
383
|
+
});
|
|
384
|
+
},
|
|
385
|
+
stopAccount: async (ctx) => {
|
|
386
|
+
const account = ctx.account;
|
|
387
|
+
const aLog = logger.withAccount(account.accountId);
|
|
388
|
+
if (!account.configured || !account.token?.trim()) {
|
|
389
|
+
aLog.debug(`gateway.stopAccount: skip notifyStop (not configured or no token)`);
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
try {
|
|
393
|
+
const resp = await notifyStop({
|
|
394
|
+
baseUrl: account.baseUrl,
|
|
395
|
+
token: account.token,
|
|
396
|
+
});
|
|
397
|
+
if (resp.ret !== undefined && resp.ret !== 0) {
|
|
398
|
+
aLog.warn(`notifyStop: ret=${resp.ret} errmsg=${resp.errmsg ?? ""}`);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
catch (err) {
|
|
402
|
+
aLog.warn(`notifyStop failed during shutdown (ignored): ${String(err)}`);
|
|
403
|
+
}
|
|
404
|
+
},
|
|
405
|
+
loginWithQrStart: async ({ accountId, force, verbose }) => {
|
|
406
|
+
// For re-login: use saved baseUrl from account data; fall back to default for new accounts.
|
|
407
|
+
const savedBaseUrl = accountId ? loadWeixinAccount(accountId)?.baseUrl?.trim() : "";
|
|
408
|
+
const result = await startWeixinLoginWithQr({
|
|
409
|
+
accountId: accountId ?? undefined,
|
|
410
|
+
apiBaseUrl: savedBaseUrl || DEFAULT_BASE_URL,
|
|
411
|
+
botType: DEFAULT_ILINK_BOT_TYPE,
|
|
412
|
+
force,
|
|
413
|
+
verbose,
|
|
414
|
+
});
|
|
415
|
+
// Return sessionKey so the client can pass it back in loginWithQrWait.
|
|
416
|
+
return {
|
|
417
|
+
qrDataUrl: result.qrcodeUrl,
|
|
418
|
+
message: result.message,
|
|
419
|
+
sessionKey: result.sessionKey,
|
|
420
|
+
};
|
|
421
|
+
},
|
|
422
|
+
loginWithQrWait: async (params) => {
|
|
423
|
+
// sessionKey is forwarded by the client after loginWithQrStart (runtime param extension).
|
|
424
|
+
const sessionKey = params.sessionKey || params.accountId || "";
|
|
425
|
+
const savedBaseUrl = params.accountId
|
|
426
|
+
? loadWeixinAccount(params.accountId)?.baseUrl?.trim()
|
|
427
|
+
: "";
|
|
428
|
+
const result = await waitForWeixinLogin({
|
|
429
|
+
sessionKey,
|
|
430
|
+
apiBaseUrl: savedBaseUrl || DEFAULT_BASE_URL,
|
|
431
|
+
timeoutMs: params.timeoutMs,
|
|
432
|
+
});
|
|
433
|
+
if (result.connected && result.botToken && result.accountId) {
|
|
434
|
+
try {
|
|
435
|
+
const normalizedId = normalizeAccountId(result.accountId);
|
|
436
|
+
saveWeixinAccount(normalizedId, {
|
|
437
|
+
token: result.botToken,
|
|
438
|
+
baseUrl: result.baseUrl,
|
|
439
|
+
userId: result.userId,
|
|
440
|
+
});
|
|
441
|
+
registerWeixinAccountId(normalizedId);
|
|
442
|
+
if (result.userId) {
|
|
443
|
+
clearStaleAccountsForUserId(normalizedId, result.userId, clearContextTokensForAccount);
|
|
444
|
+
}
|
|
445
|
+
triggerWeixinChannelReload();
|
|
446
|
+
logger.info(`loginWithQrWait: saved account data for accountId=${normalizedId}`);
|
|
447
|
+
}
|
|
448
|
+
catch (err) {
|
|
449
|
+
logger.error(`loginWithQrWait: failed to save account data err=${String(err)}`);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return {
|
|
453
|
+
connected: result.connected,
|
|
454
|
+
message: result.message,
|
|
455
|
+
accountId: result.accountId,
|
|
456
|
+
};
|
|
457
|
+
},
|
|
458
|
+
},
|
|
459
|
+
};
|
|
460
|
+
//# sourceMappingURL=channel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel.js","sourceRoot":"","sources":["../../src/channel.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,8BAA8B,EAAE,MAAM,mCAAmC,CAAC;AAEnF,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,0BAA0B,EAC1B,2BAA2B,EAC3B,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,4BAA4B,EAAE,oBAAoB,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AAC3I,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,kBAAkB,EAClB,aAAa,GACd,MAAM,oBAAoB,CAAC;AAE5B,0FAA0F;AAC1F,6FAA6F;AAC7F,iDAAiD;AACjD,OAAO,EAAE,6BAA6B,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACrG,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AACjF,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAE5D,2FAA2F;AAC3F,SAAS,eAAe,CAAC,QAAgB;IACvC,kEAAkE;IAClE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,WAAW,CAAC,QAAgB;IACnC,OAAO,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,uBAAuB,GAAG,IAAI,CAAC,IAAI,CAAC,8BAA8B,EAAE,EAAE,4BAA4B,CAAC,CAAC;AAE1G,oEAAoE;AACpE,SAAS,gBAAgB,CAAC,QAAgB;IACxC,IAAI,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC;IACtE,gFAAgF;IAChF,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC9D,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,wBAAwB,CAC/B,GAAmB,EACnB,EAAU;IAEV,MAAM,MAAM,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;IAEzC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,4FAA4F,CAC7F,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,CAAC,IAAI,CAAC,mDAAmD,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC5E,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;IACnB,CAAC;IAED,4EAA4E;IAC5E,MAAM,OAAO,GAAG,4BAA4B,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAEzD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,CAAC,+CAA+C,OAAO,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QACtF,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,CAAC,IAAI,CACT,yCAAyC,OAAO,CAAC,MAAM,4BAA4B,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC/G,CAAC;QACF,MAAM,IAAI,KAAK,CACb,oCAAoC,EAAE,GAAG;YACzC,IAAI,OAAO,CAAC,MAAM,uDAAuD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK;YAChG,2DAA2D,CAC5D,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,KAAK,CACb,wDAAwD,EAAE,GAAG;QAC7D,IAAI,MAAM,CAAC,MAAM,yEAAyE;QAC1F,kGAAkG,CACnG,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAC,MAMjC;IACC,MAAM,OAAO,GAAG,oBAAoB,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IACnE,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACnD,mBAAmB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACvC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;QACxB,IAAI,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;QACzD,MAAM,IAAI,KAAK,CAAC,uFAAuF,CAAC,CAAC;IAC3G,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,mDAAmD,MAAM,CAAC,EAAE,2BAA2B,CAAC,CAAC;IACrG,CAAC;IACD,MAAM,CAAC,GAAG,IAAI,uBAAuB,EAAE,CAAC;IACxC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;IAClC,IAAI,YAAY,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC;IAE/C,MAAM,aAAa,GAAG,MAAM,6BAA6B,CAAC;QACxD,EAAE,EAAE,MAAM,CAAC,EAAE;QACb,IAAI,EAAE,YAAY;QAClB,SAAS,EAAE,OAAO,CAAC,SAAS;KAC7B,CAAC,CAAC;IACH,IAAI,aAAa,CAAC,SAAS,EAAE,CAAC;QAC5B,IAAI,CAAC,IAAI,CAAC,4DAA4D,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;QACnF,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IACvD,CAAC;IACD,YAAY,GAAG,aAAa,CAAC,IAAI,CAAC;IAElC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE;gBAChF,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,YAAY,EAAE,MAAM,CAAC,YAAY;aAClC,EAAC,CAAC,CAAC;QACJ,qBAAqB,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;QAC7G,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC;IACrE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,qBAAqB,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;QAClI,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAyC;IAChE,EAAE,EAAE,iBAAiB;IACrB,IAAI,EAAE;QACJ,EAAE,EAAE,iBAAiB;QACrB,KAAK,EAAE,iBAAiB;QACxB,cAAc,EAAE,6BAA6B;QAC7C,QAAQ,EAAE,2BAA2B;QACrC,SAAS,EAAE,iBAAiB;QAC5B,KAAK,EAAE,oEAAoE;QAC3E,KAAK,EAAE,EAAE;KACV;IACD,YAAY,EAAE;QACZ,MAAM,EAAE;YACN,IAAI,EAAE,QAAQ;YACd,oBAAoB,EAAE,KAAK;YAC3B,UAAU,EAAE,EAAE;SACf;KACF;IACD,YAAY,EAAE;QACZ,SAAS,EAAE,CAAC,QAAQ,CAAC;QACrB,KAAK,EAAE,IAAI;QACX,cAAc,EAAE,IAAI;KACrB;IACD,SAAS,EAAE;QACT,8BAA8B,EAAE;YAC9B,QAAQ,EAAE,GAAG;YACb,MAAM,EAAE,IAAI;SACb;KACF;IACD,SAAS,EAAE;QACT,cAAc,EAAE;YACd,0FAA0F;YAC1F,WAAW,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAC;SACjD;KACF;IACD,WAAW,EAAE;QACX,gBAAgB,EAAE,GAAG,EAAE,CAAC;YACtB,yOAAyO;YACzO,sOAAsO;YACtO,uNAAuN;YACvN,giBAAgiB;YAChiB,2OAA2O;SAC5O;KACF;IACD,MAAM,EAAE,EAAE,cAAc,EAAE,CAAC,0BAA0B,CAAC,EAAE;IACxD,MAAM,EAAE;QACN,cAAc,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,oBAAoB,CAAC,GAAG,CAAC;QAClD,cAAc,EAAE,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC,oBAAoB,CAAC,GAAG,EAAE,SAAS,CAAC;QACxE,YAAY,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,UAAU;QAC7C,eAAe,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YAC7B,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,UAAU,EAAE,OAAO,CAAC,UAAU;SAC/B,CAAC;KACH;IACD,QAAQ,EAAE;QACR,YAAY,EAAE,QAAQ;QACtB,cAAc,EAAE,IAAI;QACpB,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YACtB,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,IAAI,wBAAwB,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;YAC7E,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC;gBACtC,GAAG,EAAE,GAAG,CAAC,GAAG;gBACZ,EAAE,EAAE,GAAG,CAAC,EAAE;gBACV,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,SAAS;gBACT,YAAY,EAAE,eAAe,CAAC,SAAU,EAAE,GAAG,CAAC,EAAE,CAAC;aAClD,CAAC,CAAC;YACH,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YACvB,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,IAAI,wBAAwB,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;YAC7E,MAAM,OAAO,GAAG,oBAAoB,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YACzD,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YACnD,mBAAmB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YACvC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;gBACxB,IAAI,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;gBAChD,MAAM,IAAI,KAAK,CACb,uFAAuF,CACxF,CAAC;YACJ,CAAC;YAED,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;YAC9B,IAAI,IAAI,GAAG,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;YAE1B,MAAM,aAAa,GAAG,MAAM,6BAA6B,CAAC;gBACxD,EAAE,EAAE,GAAG,CAAC,EAAE;gBACV,IAAI;gBACJ,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,QAAQ;aACT,CAAC,CAAC;YACH,IAAI,aAAa,CAAC,SAAS,EAAE,CAAC;gBAC5B,IAAI,CAAC,IAAI,CAAC,mDAAmD,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;gBACvE,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;YACvD,CAAC;YACD,IAAI,GAAG,aAAa,CAAC,IAAI,CAAC;YAE1B,IAAI,QAAQ,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,IAAI,WAAW,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;gBACrE,IAAI,QAAgB,CAAC;gBACrB,IAAI,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAC9B,QAAQ,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;oBACtC,IAAI,CAAC,KAAK,CAAC,mCAAmC,QAAQ,EAAE,CAAC,CAAC;gBAC5D,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,KAAK,CAAC,0CAA0C,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;oBACjF,QAAQ,GAAG,MAAM,yBAAyB,CAAC,QAAQ,EAAE,uBAAuB,CAAC,CAAC;oBAC9E,IAAI,CAAC,KAAK,CAAC,yCAAyC,QAAQ,EAAE,CAAC,CAAC;gBAClE,CAAC;gBACD,MAAM,YAAY,GAAG,eAAe,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;gBAChE,IAAI,CAAC;oBACH,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC;wBACvC,QAAQ;wBACR,EAAE,EAAE,GAAG,CAAC,EAAE;wBACV,IAAI;wBACJ,IAAI,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,YAAY,EAAE;wBACtE,UAAU,EAAE,OAAO,CAAC,UAAU;qBAC/B,CAAC,CAAC;oBACH,qBAAqB,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;oBAClG,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC;gBACrE,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,qBAAqB,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;oBACvH,MAAM,GAAG,CAAC;gBACZ,CAAC;YACH,CAAC;YAED,MAAM,YAAY,GAAG,eAAe,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;YAChE,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;wBAC/D,OAAO,EAAE,OAAO,CAAC,OAAO;wBACxB,KAAK,EAAE,OAAO,CAAC,KAAK;wBACpB,YAAY;qBACb,EAAC,CAAC,CAAC;gBACJ,qBAAqB,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;gBAClG,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC;YACrE,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,qBAAqB,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;gBACvH,MAAM,GAAG,CAAC;YACZ,CAAC;QACH,CAAC;KACF;IACD,MAAM,EAAE;QACN,cAAc,EAAE;YACd,SAAS,EAAE,EAAE;YACb,SAAS,EAAE,IAAI;YACf,aAAa,EAAE,IAAI;YACnB,cAAc,EAAE,IAAI;SACrB;QACD,mBAAmB,EAAE,GAAG,EAAE,CAAC,EAAE;QAC7B,mBAAmB,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;YACtC,UAAU,EAAE,QAAQ,CAAC,UAAU,IAAI,KAAK;YACxC,SAAS,EAAE,QAAQ,CAAC,SAAS,IAAI,IAAI;YACrC,aAAa,EAAE,QAAQ,CAAC,aAAa,IAAI,IAAI;YAC7C,cAAc,EAAE,QAAQ,CAAC,cAAc,IAAI,IAAI;SAChD,CAAC;QACF,oBAAoB,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;YAC/C,GAAG,OAAO;YACV,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,UAAU,EAAE,OAAO,CAAC,UAAU;SAC/B,CAAC;KACH;IACD,IAAI,EAAE;QACJ,KAAK,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE;YACpD,MAAM,OAAO,GAAG,oBAAoB,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YAErD,MAAM,GAAG,GAAG,CAAC,GAAW,EAAE,EAAE;gBAC1B,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;YACtB,CAAC,CAAC;YAEF,GAAG,CAAC,SAAS,CAAC,CAAC;YACf,MAAM,WAAW,GAAwB,MAAM,sBAAsB,CAAC;gBACpE,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,UAAU,EAAE,OAAO,CAAC,OAAO;gBAC3B,OAAO,EAAE,sBAAsB;gBAC/B,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC;aAC1B,CAAC,CAAC;YAEH,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,CAAC;gBAC3B,MAAM,CAAC,IAAI,CACT,+CAA+C,OAAO,CAAC,SAAS,YAAY,WAAW,CAAC,OAAO,EAAE,CAClG,CAAC;gBACF,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;gBACzB,MAAM,IAAI,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;YACvC,CAAC;YAED,GAAG,CAAC,yBAAyB,CAAC,CAAC;YAC/B,MAAM,aAAa,CAAC,WAAW,CAAC,SAAU,CAAC,CAAC;YAE5C,MAAM,cAAc,GAAG,OAAO,CAAC;YAC/B,GAAG,CAAC,eAAe,CAAC,CAAC;YAErB,MAAM,UAAU,GAAuB,MAAM,kBAAkB,CAAC;gBAC9D,UAAU,EAAE,WAAW,CAAC,UAAU;gBAClC,UAAU,EAAE,OAAO,CAAC,OAAO;gBAC3B,SAAS,EAAE,cAAc;gBACzB,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC;gBACzB,OAAO,EAAE,sBAAsB;aAChC,CAAC,CAAC;YAEH,IAAI,UAAU,CAAC,SAAS,IAAI,UAAU,CAAC,QAAQ,IAAI,UAAU,CAAC,SAAS,EAAE,CAAC;gBACxE,IAAI,CAAC;oBACH,0EAA0E;oBAC1E,kEAAkE;oBAClE,MAAM,YAAY,GAAG,kBAAkB,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;oBAC9D,iBAAiB,CAAC,YAAY,EAAE;wBAC9B,KAAK,EAAE,UAAU,CAAC,QAAQ;wBAC1B,OAAO,EAAE,UAAU,CAAC,OAAO;wBAC3B,MAAM,EAAE,UAAU,CAAC,MAAM;qBAC1B,CAAC,CAAC;oBACH,uBAAuB,CAAC,YAAY,CAAC,CAAC;oBACtC,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;wBACtB,2BAA2B,CAAC,YAAY,EAAE,UAAU,CAAC,MAAM,EAAE,4BAA4B,CAAC,CAAC;oBAC7F,CAAC;oBACD,KAAK,0BAA0B,EAAE,CAAC;oBAClC,GAAG,CAAC,uBAAuB,CAAC,CAAC;gBAC/B,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,MAAM,CAAC,KAAK,CACV,qDAAqD,UAAU,CAAC,SAAS,QAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,CAC/F,CAAC;oBACF,GAAG,CAAC,iBAAiB,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACtC,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,CACT,gDAAgD,OAAO,CAAC,SAAS,YAAY,UAAU,CAAC,OAAO,EAAE,CAClG,CAAC;gBACF,2BAA2B;gBAC3B,MAAM,IAAI,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YACtC,CAAC;QACH,CAAC;KACF;IACD,OAAO,EAAE;QACP,YAAY,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YAC1B,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;YACnC,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,MAAM,CAAC,IAAI,CAAC,2DAA2D,CAAC,CAAC;gBACzE,OAAO;YACT,CAAC;YACD,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;YAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YACnD,IAAI,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;YAClD,oBAAoB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YACxC,IAAI,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;YAErC,GAAG,CAAC,SAAS,EAAE,CAAC;gBACd,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,OAAO,EAAE,IAAI;gBACb,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE;gBACvB,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE;aACxB,CAAC,CAAC;YAEH,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;gBACxB,IAAI,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;gBACrC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,CACd,IAAI,OAAO,CAAC,SAAS,iFAAiF,CACvG,CAAC;gBACF,GAAG,CAAC,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;gBAClE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;YAC1D,CAAC;YAED,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,IAAI,OAAO,CAAC,SAAS,+BAA+B,gBAAgB,GAAG,CAAC,CAAC;YAEzF,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC;oBAC7B,OAAO,EAAE,OAAO,CAAC,OAAO;oBACxB,KAAK,EAAE,OAAO,CAAC,KAAK;iBACrB,CAAC,CAAC;gBACH,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS,IAAI,IAAI,CAAC,GAAG,KAAK,CAAC,EAAE,CAAC;oBAC7C,IAAI,CAAC,IAAI,CAAC,oBAAoB,IAAI,CAAC,GAAG,WAAW,IAAI,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC;gBACxE,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,CAAC,IAAI,CAAC,gDAAgD,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC3E,CAAC;YAED,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;YACtC,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,IAAI,OAAO,CAAC,SAAS,kBAAkB,OAAO,EAAE,CAAC,CAAC;YAElE,yFAAyF;YACzF,qFAAqF;YACrF,wEAAwE;YACxE,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC;gBACxB,MAAM,GAAG,GAAG,2EAA2E,CAAC;gBACxF,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAChB,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,IAAI,OAAO,CAAC,SAAS,KAAK,GAAG,EAAE,CAAC,CAAC;gBAClD,GAAG,CAAC,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;gBAClE,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;YACvB,CAAC;YAED,MAAM,EAAE,qBAAqB,EAAE,GAAG,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAC;YACvE,OAAO,qBAAqB,CAAC;gBAC3B,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,UAAU,EAAE,OAAO,CAAC,UAAU;gBAC9B,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,MAAM,EAAE,GAAG,CAAC,GAAG;gBACf,OAAO,EAAE,GAAG,CAAC,OAAO;gBACpB,cAAc,EAAE,GAAG,CAAC,cAAqD;gBACzE,WAAW,EAAE,GAAG,CAAC,WAAW;gBAC5B,SAAS,EAAE,GAAG,CAAC,SAAS;aACzB,CAAC,CAAC;QACL,CAAC;QACD,WAAW,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YACzB,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;YAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YACnD,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC;gBAClD,IAAI,CAAC,KAAK,CAAC,mEAAmE,CAAC,CAAC;gBAChF,OAAO;YACT,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC;oBAC5B,OAAO,EAAE,OAAO,CAAC,OAAO;oBACxB,KAAK,EAAE,OAAO,CAAC,KAAK;iBACrB,CAAC,CAAC;gBACH,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS,IAAI,IAAI,CAAC,GAAG,KAAK,CAAC,EAAE,CAAC;oBAC7C,IAAI,CAAC,IAAI,CAAC,mBAAmB,IAAI,CAAC,GAAG,WAAW,IAAI,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC;gBACvE,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,CAAC,IAAI,CAAC,gDAAgD,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC3E,CAAC;QACH,CAAC;QACD,gBAAgB,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE;YACxD,4FAA4F;YAC5F,MAAM,YAAY,GAAG,SAAS,CAAC,CAAC,CAAC,iBAAiB,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACpF,MAAM,MAAM,GAAwB,MAAM,sBAAsB,CAAC;gBAC/D,SAAS,EAAE,SAAS,IAAI,SAAS;gBACjC,UAAU,EAAE,YAAY,IAAI,gBAAgB;gBAC5C,OAAO,EAAE,sBAAsB;gBAC/B,KAAK;gBACL,OAAO;aACR,CAAC,CAAC;YACH,uEAAuE;YACvE,OAAO;gBACL,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,UAAU,EAAE,MAAM,CAAC,UAAU;aACa,CAAC;QAC/C,CAAC;QACD,eAAe,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;YAChC,0FAA0F;YAC1F,MAAM,UAAU,GAAI,MAAkC,CAAC,UAAU,IAAI,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC;YAC5F,MAAM,YAAY,GAAG,MAAM,CAAC,SAAS;gBACnC,CAAC,CAAC,iBAAiB,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE;gBACtD,CAAC,CAAC,EAAE,CAAC;YACP,MAAM,MAAM,GAAuB,MAAM,kBAAkB,CAAC;gBAC1D,UAAU;gBACV,UAAU,EAAE,YAAY,IAAI,gBAAgB;gBAC5C,SAAS,EAAE,MAAM,CAAC,SAAS;aAC5B,CAAC,CAAC;YAEH,IAAI,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;gBAC5D,IAAI,CAAC;oBACH,MAAM,YAAY,GAAG,kBAAkB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;oBAC1D,iBAAiB,CAAC,YAAY,EAAE;wBAC9B,KAAK,EAAE,MAAM,CAAC,QAAQ;wBACtB,OAAO,EAAE,MAAM,CAAC,OAAO;wBACvB,MAAM,EAAE,MAAM,CAAC,MAAM;qBACtB,CAAC,CAAC;oBACH,uBAAuB,CAAC,YAAY,CAAC,CAAC;oBACtC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;wBAClB,2BAA2B,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,4BAA4B,CAAC,CAAC;oBACzF,CAAC;oBACD,0BAA0B,EAAE,CAAC;oBAC7B,MAAM,CAAC,IAAI,CAAC,qDAAqD,YAAY,EAAE,CAAC,CAAC;gBACnF,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,MAAM,CAAC,KAAK,CAAC,oDAAoD,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAClF,CAAC;YACH,CAAC;YAED,OAAO;gBACL,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,SAAS,EAAE,MAAM,CAAC,SAAS;aACe,CAAC;QAC/C,CAAC;KACF;CACF,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime host-version compatibility check for openclaw-weixin.
|
|
3
|
+
*
|
|
4
|
+
* OpenClaw uses a date-based version format: YYYY.M.DD (e.g. 2026.3.22).
|
|
5
|
+
* This module parses that format and validates the running host is within
|
|
6
|
+
* the supported range for this plugin version.
|
|
7
|
+
*/
|
|
8
|
+
import { logger } from "./util/logger.js";
|
|
9
|
+
export const SUPPORTED_HOST_MIN = "2026.3.22";
|
|
10
|
+
/**
|
|
11
|
+
* Parse an OpenClaw date version string (e.g. "2026.3.22") into components.
|
|
12
|
+
* Returns null for unparseable strings.
|
|
13
|
+
*/
|
|
14
|
+
export function parseOpenClawVersion(version) {
|
|
15
|
+
// Strip any pre-release suffix (e.g. "2026.3.22-beta.1" -> "2026.3.22")
|
|
16
|
+
const base = version.trim().split("-")[0];
|
|
17
|
+
const parts = base.split(".");
|
|
18
|
+
if (parts.length !== 3)
|
|
19
|
+
return null;
|
|
20
|
+
const [year, month, day] = parts.map(Number);
|
|
21
|
+
if (Number.isNaN(year) || Number.isNaN(month) || Number.isNaN(day))
|
|
22
|
+
return null;
|
|
23
|
+
return { year, month, day };
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Compare two parsed versions. Returns -1 | 0 | 1.
|
|
27
|
+
*/
|
|
28
|
+
export function compareVersions(a, b) {
|
|
29
|
+
for (const key of ["year", "month", "day"]) {
|
|
30
|
+
if (a[key] < b[key])
|
|
31
|
+
return -1;
|
|
32
|
+
if (a[key] > b[key])
|
|
33
|
+
return 1;
|
|
34
|
+
}
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Check whether a host version string is >= SUPPORTED_HOST_MIN.
|
|
39
|
+
*/
|
|
40
|
+
export function isHostVersionSupported(hostVersion) {
|
|
41
|
+
const host = parseOpenClawVersion(hostVersion);
|
|
42
|
+
if (!host)
|
|
43
|
+
return false;
|
|
44
|
+
const min = parseOpenClawVersion(SUPPORTED_HOST_MIN);
|
|
45
|
+
return compareVersions(host, min) >= 0;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Fail-fast guard. Call at the very start of `register()` to prevent the
|
|
49
|
+
* plugin from loading on an incompatible host.
|
|
50
|
+
*
|
|
51
|
+
* @throws {Error} with a human-readable message when the host is out of range.
|
|
52
|
+
*/
|
|
53
|
+
export function assertHostCompatibility(hostVersion) {
|
|
54
|
+
if (!hostVersion || hostVersion === "unknown") {
|
|
55
|
+
logger.warn(`[compat] Could not determine host OpenClaw version; skipping compatibility check.`);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (isHostVersionSupported(hostVersion)) {
|
|
59
|
+
logger.info(`[compat] Host OpenClaw ${hostVersion} >= ${SUPPORTED_HOST_MIN}, OK.`);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
throw new Error(`This version of openclaw-weixin requires OpenClaw >=${SUPPORTED_HOST_MIN}, ` +
|
|
63
|
+
`but found ${hostVersion}. ` +
|
|
64
|
+
`Please upgrade OpenClaw, or install the compatible track for older hosts:\n` +
|
|
65
|
+
` npx @tencent-weixin/openclaw-weixin-cli install`);
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=compat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compat.js","sourceRoot":"","sources":["../../src/compat.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,MAAM,CAAC,MAAM,kBAAkB,GAAG,WAAW,CAAC;AAQ9C;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAe;IAClD,wEAAwE;IACxE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACpC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7C,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAChF,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;AAC9B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,CAAkB,EAAE,CAAkB;IACpE,KAAK,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAU,EAAE,CAAC;QACpD,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC;YAAE,OAAO,CAAC,CAAC,CAAC;QAC/B,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC;YAAE,OAAO,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,sBAAsB,CAAC,WAAmB;IACxD,MAAM,IAAI,GAAG,oBAAoB,CAAC,WAAW,CAAC,CAAC;IAC/C,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACxB,MAAM,GAAG,GAAG,oBAAoB,CAAC,kBAAkB,CAAE,CAAC;IACtD,OAAO,eAAe,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,WAA+B;IACrE,IAAI,CAAC,WAAW,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC9C,MAAM,CAAC,IAAI,CACT,mFAAmF,CACpF,CAAC;QACF,OAAO;IACT,CAAC;IACD,IAAI,sBAAsB,CAAC,WAAW,CAAC,EAAE,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,0BAA0B,WAAW,OAAO,kBAAkB,OAAO,CAAC,CAAC;QACnF,OAAO;IACT,CAAC;IACD,MAAM,IAAI,KAAK,CACb,uDAAuD,kBAAkB,IAAI;QAC7E,aAAa,WAAW,IAAI;QAC5B,6EAA6E;QAC7E,mDAAmD,CACpD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { CDN_BASE_URL, DEFAULT_BASE_URL } from "../auth/accounts.js";
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Zod config schema
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
const weixinAccountSchema = z.object({
|
|
7
|
+
name: z.string().optional(),
|
|
8
|
+
enabled: z.boolean().optional(),
|
|
9
|
+
baseUrl: z.string().default(DEFAULT_BASE_URL),
|
|
10
|
+
cdnBaseUrl: z.string().default(CDN_BASE_URL),
|
|
11
|
+
routeTag: z.number().optional(),
|
|
12
|
+
});
|
|
13
|
+
/** Top-level weixin config schema (token is stored in credentials file, not config). */
|
|
14
|
+
export const WeixinConfigSchema = weixinAccountSchema.extend({
|
|
15
|
+
accounts: z.record(z.string(), weixinAccountSchema).optional(),
|
|
16
|
+
/** ISO 8601; bumped on each successful login to refresh gateway config from disk. */
|
|
17
|
+
channelConfigUpdatedAt: z.string().optional(),
|
|
18
|
+
});
|
|
19
|
+
//# sourceMappingURL=config-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-schema.js","sourceRoot":"","sources":["../../../src/config/config-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAErE,8EAA8E;AAC9E,oBAAoB;AACpB,8EAA8E;AAE9E,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC/B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,gBAAgB,CAAC;IAC7C,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC;IAC5C,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAChC,CAAC,CAAC;AAEH,wFAAwF;AACxF,MAAM,CAAC,MAAM,kBAAkB,GAAG,mBAAmB,CAAC,MAAM,CAAC;IAC3D,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,mBAAmB,CAAC,CAAC,QAAQ,EAAE;IAC9D,qFAAqF;IACrF,sBAAsB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC9C,CAAC,CAAC"}
|