@workclaw/openclaw-workclaw 1.0.342 → 1.0.343

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/{anthropic-BX4T2YIB.js → anthropic-C1jzp_Rc.js} +1 -1
  2. package/dist/api.js +379 -0
  3. package/dist/{azure-openai-responses-CRtsnQnD.js → azure-openai-responses-zym2wxMB.js} +2 -2
  4. package/dist/{index-ZWLWkJXc.js → channel-CWeiUgV5.js} +2162 -5548
  5. package/dist/channel-bootstrap.runtime-B0t3vnup-S_ZINco5.js +5 -0
  6. package/dist/channel-entry-api.d.ts +3 -0
  7. package/dist/channel-entry-api.d.ts.map +1 -0
  8. package/dist/channel-entry-api.js +719 -0
  9. package/dist/channel-entry-contract-BDMmGZzs-4ZlSsA7g.js +252 -0
  10. package/dist/channel-plugin-api.d.ts +2 -0
  11. package/dist/channel-plugin-api.d.ts.map +1 -0
  12. package/dist/channel-plugin-api.js +4 -0
  13. package/dist/{cleanup-i9QIMqva-CYcFSfZC.js → cleanup-i9QIMqva-DceifGSO.js} +2 -2
  14. package/dist/config-QB0JLJHX.js +94 -0
  15. package/dist/{cron-tasks-handler-BIpSoLIG.js → cron-tasks-handler-CIhnDbA3.js} +1 -1
  16. package/dist/{google-BhYq3yh7.js → google-DqQHu2NY.js} +2 -2
  17. package/dist/{google-shared-sAeUdThk.js → google-shared-BeRWP6yE.js} +1 -1
  18. package/dist/{google-vertex-CFbea9mm.js → google-vertex-Cs1hEe_j.js} +2 -2
  19. package/dist/{host-hook-cleanup-BNlJQu7G-DZh9GtcC.js → host-hook-cleanup-BNlJQu7G-NNZIzDgg.js} +3 -2
  20. package/dist/index-DLeHpawu.js +1351 -0
  21. package/dist/index-DvlDhBhd.js +524 -0
  22. package/dist/{index-CXEk4j12.js → index-mQv9vOMk.js} +1 -1
  23. package/dist/index.d.ts +1 -10
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +42 -11
  26. package/dist/{legacy-config-issues-Czu0_ffE-BUj03gnH.js → legacy-config-issues-Czu0_ffE-C-SKoHc6.js} +4 -2
  27. package/dist/{message-oTt1u1XX-BHxJ4z66.js → message-oTt1u1XX-NFsrpDss.js} +5 -4
  28. package/dist/message.config.runtime-DmvQNASl.js +4 -0
  29. package/dist/{message.gateway.runtime-Ch5zdrYr.js → message.gateway.runtime-BIIf6teh.js} +3 -2
  30. package/dist/{mistral-DgMDMo1J.js → mistral-B0v4IfAz.js} +1 -1
  31. package/dist/models-config.runtime-cY4XGOI0.js +4 -0
  32. package/dist/{openai-codex-responses-D6j-616z.js → openai-codex-responses-tC0hde6o.js} +2 -2
  33. package/dist/{openai-completions-BtT6C5eC.js → openai-completions-w3FtI3rd.js} +1 -1
  34. package/dist/{openai-responses-Dtuy4M7B.js → openai-responses-rRjf4OAK.js} +2 -2
  35. package/dist/{openai-responses-shared-DZBSlU2d.js → openai-responses-shared-ZlolmuqL.js} +1 -1
  36. package/dist/{openrouter-DbsgRqzU.js → openrouter-CXWxTM8p.js} +1 -1
  37. package/dist/{photon_rs-CbOi7Vp0.js → photon_rs-CGHeuAJ1.js} +1 -1
  38. package/dist/{plugin-load-profile-DOnG9jJ5-zOQuKNoi.js → plugin-load-profile-DOnG9jJ5-B0ymqOTX.js} +9936 -9990
  39. package/dist/plugins-C54ejDC8-qGQvFNWW.js +8 -0
  40. package/dist/provider-discovery.runtime-ZgcVwu5_.js +4 -0
  41. package/dist/runtime-api-DU-e2Pen.js +391 -0
  42. package/dist/runtime-api.d.ts +2 -0
  43. package/dist/runtime-api.d.ts.map +1 -0
  44. package/dist/runtime-api.js +4 -0
  45. package/dist/{session-archive.runtime-BAljnZWW.js → session-archive.runtime-SvY1eJq4.js} +2 -2
  46. package/dist/setup-entry.js +2 -194
  47. package/dist/src/runtime.js +37 -0
  48. package/dist/src/secret-contract-api.js +7 -0
  49. package/dist/string-coerce-DyL154ka-BEV0SzzS.js +61 -0
  50. package/dist/subsystem-W8wAQXn1-BIMucqMi.js +4 -0
  51. package/dist/tools-api.d.ts +2 -0
  52. package/dist/tools-api.d.ts.map +1 -0
  53. package/dist/tools-api.js +4 -0
  54. package/dist/transcript.runtime-Dchg_w3u.js +5 -0
  55. package/dist/workclaw-client-CMjcFjJx.js +538 -0
  56. package/package.json +9 -5
  57. package/dist/channel-bootstrap.runtime-B0t3vnup-vflkdVI8.js +0 -5
  58. package/dist/config-Cw8JPyMQ.js +0 -94
  59. package/dist/message.config.runtime-DuzEAWuz.js +0 -4
  60. package/dist/models-config.runtime-DLspRp8e.js +0 -4
  61. package/dist/plugins-C54ejDC8-Df48OaX-.js +0 -8
  62. package/dist/provider-discovery.runtime-Dps3xmj0.js +0 -4
  63. package/dist/subsystem-W8wAQXn1-Dh_4L9-w.js +0 -4
  64. package/dist/transcript.runtime-B6llle92.js +0 -5
@@ -0,0 +1,524 @@
1
+ import { readFile, mkdir, writeFile, rename, stat } from "node:fs/promises";
2
+ import { a as resolveWorkclawMessage, s as sendWorkclawReplyMessage, b as sendWorkclawMessage, c as resolveWorkclawAccountWithCache, e as resolveAccountByUserIdAndAgentId } from "./workclaw-client-CMjcFjJx.js";
3
+ import { execSync } from "node:child_process";
4
+ import { existsSync, readFileSync } from "node:fs";
5
+ import os__default, { homedir } from "node:os";
6
+ import path__default, { join } from "node:path";
7
+ import { l as logger, a as getWorkclawRuntime, s as setLastOutboundAt } from "./runtime-api-DU-e2Pen.js";
8
+ import { fileURLToPath } from "node:url";
9
+ import { Agent, fetch } from "undici";
10
+ const PLUGIN_ID = "openclaw-workclaw";
11
+ const DEFAULT_PROVIDER = "mingto";
12
+ const STATE_DIR = "workclaw/data";
13
+ function fixOwner(dir) {
14
+ if (process.platform === "win32")
15
+ return;
16
+ try {
17
+ execSync(`chown -R node:node "${dir}"`, { stdio: "ignore" });
18
+ } catch {
19
+ }
20
+ }
21
+ const SAVE_THROTTLE_MS = 1e3;
22
+ const lastSaveTimeMap = /* @__PURE__ */ new Map();
23
+ function findStateDir() {
24
+ const stateDir = join(homedir(), ".openclaw");
25
+ return join(stateDir, STATE_DIR);
26
+ }
27
+ function getStateFilePath() {
28
+ return join(findStateDir(), "conversations.json");
29
+ }
30
+ async function writeConfigFile(newConfig, cfg, log) {
31
+ try {
32
+ const runtime = getWorkclawRuntime();
33
+ const configApi = runtime.config;
34
+ const afterWrite = {
35
+ mode: "auto",
36
+ reason: "workclaw-full-config-write"
37
+ };
38
+ logger.info(`【智小途-配置】准备写入配置 (channels/openclaw-workclaw/accounts): ${JSON.stringify(newConfig?.channels?.["openclaw-workclaw"]?.accounts, null, 2)}`);
39
+ logger.info(`【智小途-配置】准备写入配置 (models): ${JSON.stringify(newConfig?.models, null, 2)}`);
40
+ if (configApi.mutateConfigFile) {
41
+ const result = await configApi.mutateConfigFile({
42
+ mutate: (draft) => {
43
+ replaceObjectContents(draft, newConfig);
44
+ },
45
+ afterWrite
46
+ });
47
+ logger.info("【智小途-配置】配置写入成功(使用 mutateConfigFile)");
48
+ logConfigWriteResult(result, log);
49
+ } else if (configApi.replaceConfigFile) {
50
+ const result = await configApi.replaceConfigFile(newConfig, afterWrite);
51
+ logger.info("【智小途-配置】配置写入成功(使用 replaceConfigFile)");
52
+ logConfigWriteResult(result, log);
53
+ } else if (configApi.writeConfigFile) {
54
+ await configApi.writeConfigFile(newConfig);
55
+ logger.info("【智小途-配置】配置写入成功(使用 writeConfigFile - 兼容模式)");
56
+ } else {
57
+ throw new Error("No config write API available");
58
+ }
59
+ replaceObjectContents(cfg, newConfig);
60
+ } catch (err) {
61
+ logger.error(`【智小途-配置】写入配置失败: ${String(err)}`);
62
+ throw err;
63
+ }
64
+ }
65
+ async function mutateConfigPatch(cfg, mutate, log, reason = "workclaw-config-patch") {
66
+ const runtime = getWorkclawRuntime();
67
+ const configApi = runtime.config;
68
+ const afterWrite = {
69
+ mode: "none",
70
+ reason
71
+ };
72
+ if (configApi.mutateConfigFile) {
73
+ const result = await configApi.mutateConfigFile({
74
+ mutate,
75
+ afterWrite
76
+ });
77
+ logConfigWriteResult(result, log);
78
+ } else {
79
+ const nextConfig = cloneConfig(cfg);
80
+ mutate(nextConfig);
81
+ if (configApi.replaceConfigFile) {
82
+ const result = await configApi.replaceConfigFile(nextConfig, afterWrite);
83
+ logConfigWriteResult(result, log);
84
+ } else if (configApi.writeConfigFile) {
85
+ await configApi.writeConfigFile(nextConfig);
86
+ } else {
87
+ throw new Error("No config write API available");
88
+ }
89
+ }
90
+ mutate(cfg);
91
+ }
92
+ function replaceObjectContents(target, source) {
93
+ if (target == null || typeof target !== "object")
94
+ return;
95
+ if (source == null || typeof source !== "object")
96
+ return;
97
+ for (const key of Object.keys(target)) {
98
+ if (!(key in source)) {
99
+ delete target[key];
100
+ }
101
+ }
102
+ const clonedSource = cloneConfig(source);
103
+ Object.assign(target, clonedSource);
104
+ }
105
+ function cloneConfig(value) {
106
+ return JSON.parse(JSON.stringify(value));
107
+ }
108
+ function logConfigWriteResult(result, log) {
109
+ if (!result)
110
+ return;
111
+ const serialized = JSON.stringify(result);
112
+ log?.info?.(`【智小途-配置】写入结果: ${serialized}`);
113
+ const mode = result.followUp?.mode ?? result.afterWrite?.mode;
114
+ if (mode === "restart") {
115
+ log?.info?.("【智小途-配置】框架要求重启后生效");
116
+ } else if (mode === "auto") {
117
+ log?.info?.("【智小途-配置】框架将按自动策略评估 reload/restart");
118
+ } else if (mode === "none") {
119
+ log?.info?.("【智小途-配置】配置按 none 策略写入,不请求自动重启");
120
+ }
121
+ }
122
+ function loadOpenConversationId(accountId, userId) {
123
+ const statePath = getStateFilePath();
124
+ const key = `${accountId}:${userId}`;
125
+ try {
126
+ if (!existsSync(statePath))
127
+ return null;
128
+ const content = readFileSync(statePath, "utf-8");
129
+ const state = JSON.parse(content);
130
+ return state[key]?.openConversationId ?? null;
131
+ } catch {
132
+ return null;
133
+ }
134
+ }
135
+ async function saveOpenConversationId(accountId, userId, openConversationId, cfg, log) {
136
+ const key = `${accountId}:${userId}`;
137
+ const workclawCfg = cfg?.channels?.[PLUGIN_ID];
138
+ if (workclawCfg?.accounts?.[accountId]) {
139
+ workclawCfg.accounts[accountId].openConversationId = openConversationId;
140
+ }
141
+ const lastSaveTime = lastSaveTimeMap.get(key) ?? 0;
142
+ const now = Date.now();
143
+ if (now - lastSaveTime < SAVE_THROTTLE_MS) {
144
+ return;
145
+ }
146
+ await doSaveOpenConversationId(key, openConversationId);
147
+ lastSaveTimeMap.set(key, now);
148
+ }
149
+ async function doSaveOpenConversationId(key, openConversationId, log) {
150
+ try {
151
+ const statePath = getStateFilePath();
152
+ let state = {};
153
+ if (existsSync(statePath)) {
154
+ try {
155
+ const content = await readFile(statePath, "utf-8");
156
+ state = JSON.parse(content);
157
+ } catch (parseErr) {
158
+ logger.error(`【智小途-会话】解析状态文件失败: ${String(parseErr)}`);
159
+ }
160
+ }
161
+ if (!state[key])
162
+ state[key] = {};
163
+ const existing = state[key].openConversationId;
164
+ if (existing === openConversationId && existing != null && existing !== "") {
165
+ return;
166
+ }
167
+ state[key].openConversationId = openConversationId;
168
+ const stateDir = findStateDir();
169
+ if (!existsSync(stateDir)) {
170
+ try {
171
+ await mkdir(stateDir, { recursive: true, mode: 493 });
172
+ } catch (mkdirErr) {
173
+ if (mkdirErr.code === "EACCES" || mkdirErr.code === "EPERM") {
174
+ await mkdir(stateDir, { recursive: true, mode: 511 });
175
+ } else {
176
+ throw mkdirErr;
177
+ }
178
+ }
179
+ fixOwner(stateDir);
180
+ }
181
+ const tmpPath = `${statePath}.tmp`;
182
+ await writeFile(tmpPath, JSON.stringify(state, null, 2), "utf-8");
183
+ await rename(tmpPath, statePath);
184
+ logger.info(`【智小途-会话】保存会话 ID,key=${key}`);
185
+ } catch (err) {
186
+ logger.error(`【智小途-会话】写入状态文件失败: ${String(err)}`);
187
+ }
188
+ }
189
+ async function initWorkclawAgent(params, cfg, log) {
190
+ try {
191
+ const workclawCfg = cfg?.channels?.[PLUGIN_ID];
192
+ if (!workclawCfg)
193
+ return;
194
+ const accountId = params.accountId || "default";
195
+ const existingApiKey = cfg.models?.providers?.[DEFAULT_PROVIDER]?.apiKey;
196
+ const shouldWriteApiKey = Boolean(
197
+ params.apiKey && !(existingApiKey && typeof existingApiKey === "object" && existingApiKey.type)
198
+ );
199
+ if (params.apiKey) {
200
+ if (existingApiKey && typeof existingApiKey === "object" && existingApiKey.type) {
201
+ logger.info(`【智小途-智能体】apiKey 是 SecretRef (type=${existingApiKey.type}),跳过覆盖`);
202
+ } else {
203
+ logger.info(`【智小途-智能体】apiKey 已设置(明文值)`);
204
+ }
205
+ }
206
+ if (params.agentId) {
207
+ logger.info(`【智小途-智能体】agentId=${params.agentId} 已设置 accountId=${accountId}`);
208
+ }
209
+ if (params.userId) {
210
+ logger.info(`【智小途-智能体】userId=${params.userId} 已设置`);
211
+ }
212
+ await mutateConfigPatch(
213
+ cfg,
214
+ (draft) => {
215
+ if (!draft.channels)
216
+ draft.channels = {};
217
+ if (!draft.channels[PLUGIN_ID])
218
+ draft.channels[PLUGIN_ID] = {};
219
+ const draftWorkclawCfg = draft.channels[PLUGIN_ID];
220
+ if (shouldWriteApiKey) {
221
+ if (!draft.models)
222
+ draft.models = {};
223
+ if (!draft.models.providers)
224
+ draft.models.providers = {};
225
+ if (!draft.models.providers[DEFAULT_PROVIDER])
226
+ draft.models.providers[DEFAULT_PROVIDER] = {};
227
+ draft.models.providers[DEFAULT_PROVIDER].apiKey = params.apiKey;
228
+ }
229
+ if (params.agentId) {
230
+ const accounts = draftWorkclawCfg.accounts ?? {};
231
+ draftWorkclawCfg.accounts = accounts;
232
+ if (!accounts[accountId])
233
+ accounts[accountId] = {};
234
+ accounts[accountId].agentId = params.agentId;
235
+ }
236
+ if (params.userId) {
237
+ draftWorkclawCfg.userId = params.userId;
238
+ }
239
+ },
240
+ log,
241
+ "workclaw-init-agent"
242
+ );
243
+ logger.info(`【智小途-智能体】所有配置已持久化`);
244
+ } catch (err) {
245
+ logger.error(`【智小途-智能体】初始化失败: ${String(err)}`);
246
+ throw err;
247
+ }
248
+ }
249
+ function isLocalMediaSource(value) {
250
+ const trimmed = value.trim();
251
+ return trimmed.startsWith("/") || trimmed.startsWith("./") || trimmed.startsWith("../") || trimmed.startsWith("~") || trimmed.startsWith("file://");
252
+ }
253
+ function resolveLocalPath(input) {
254
+ if (input.startsWith("file://")) {
255
+ return fileURLToPath(input);
256
+ }
257
+ if (input.startsWith("~")) {
258
+ return path__default.join(os__default.homedir(), input.slice(1));
259
+ }
260
+ return path__default.resolve(input);
261
+ }
262
+ function readResponseUrlPath(data, pathValue) {
263
+ if (!pathValue)
264
+ return void 0;
265
+ const parts = pathValue.split(".").filter(Boolean);
266
+ let current = data;
267
+ for (const part of parts) {
268
+ if (!current || typeof current !== "object")
269
+ return void 0;
270
+ current = current[part];
271
+ }
272
+ return typeof current === "string" ? current : void 0;
273
+ }
274
+ function extractUploadedUrl(responseText, responseData, pathValue) {
275
+ const fromPath = readResponseUrlPath(responseData, pathValue);
276
+ if (fromPath)
277
+ return fromPath;
278
+ const direct = responseData.url ?? responseData.mediaUrl;
279
+ if (typeof direct === "string" && direct.trim())
280
+ return direct;
281
+ const dataObj = responseData.data;
282
+ if (dataObj && typeof dataObj === "object") {
283
+ const dataUrl = dataObj.url;
284
+ const dataMedia = dataObj.mediaUrl;
285
+ if (typeof dataUrl === "string" && dataUrl.trim())
286
+ return dataUrl;
287
+ if (typeof dataMedia === "string" && dataMedia.trim())
288
+ return dataMedia;
289
+ }
290
+ const resultObj = responseData.result;
291
+ if (resultObj && typeof resultObj === "object") {
292
+ const resultUrl = resultObj.url;
293
+ const resultMedia = resultObj.mediaUrl;
294
+ if (typeof resultUrl === "string" && resultUrl.trim())
295
+ return resultUrl;
296
+ if (typeof resultMedia === "string" && resultMedia.trim())
297
+ return resultMedia;
298
+ }
299
+ if (responseText.trim() && /^https?:\/\//i.test(responseText.trim())) {
300
+ return responseText.trim();
301
+ }
302
+ return void 0;
303
+ }
304
+ async function uploadLocalMedia(params) {
305
+ const stats = await stat(params.filePath);
306
+ if (!stats.isFile()) {
307
+ throw new Error(`mediaUrl is not a file: ${params.filePath}`);
308
+ }
309
+ const content = await readFile(params.filePath);
310
+ const form = new FormData();
311
+ const fieldName = params.uploadFieldName?.trim() || "file";
312
+ const fileName = path__default.basename(params.filePath);
313
+ form.set(fieldName, new Blob([content], { type: "application/octet-stream" }), fileName);
314
+ if (params.uploadFormFields) {
315
+ for (const [key, value] of Object.entries(params.uploadFormFields)) {
316
+ form.set(key, String(value));
317
+ }
318
+ }
319
+ const controller = new AbortController();
320
+ const timeoutId = setTimeout(() => controller.abort(), params.requestTimeout);
321
+ let dispatcher;
322
+ let doFetch = globalThis.fetch.bind(globalThis);
323
+ if (params.allowInsecureTls) {
324
+ try {
325
+ dispatcher = new Agent({ connect: { rejectUnauthorized: false } });
326
+ doFetch = fetch;
327
+ } catch (error) {
328
+ const message = error instanceof Error ? error.message : String(error);
329
+ throw new Error(`allowInsecureTls requires undici. ${message}`);
330
+ }
331
+ }
332
+ try {
333
+ const response = await doFetch(params.uploadUrl, {
334
+ method: "POST",
335
+ headers: params.uploadHeaders ?? {},
336
+ body: form,
337
+ signal: controller.signal,
338
+ ...dispatcher ? { dispatcher } : {}
339
+ });
340
+ const responseText = await response.text().catch(() => "");
341
+ if (!response.ok) {
342
+ throw new Error(`Upload failed: ${response.status} ${responseText}`);
343
+ }
344
+ let data = {};
345
+ if (responseText) {
346
+ try {
347
+ data = JSON.parse(responseText);
348
+ } catch {
349
+ data = {};
350
+ }
351
+ }
352
+ const uploadedUrl = extractUploadedUrl(
353
+ responseText,
354
+ data,
355
+ params.uploadResponseUrlPath
356
+ );
357
+ if (!uploadedUrl) {
358
+ throw new Error("Upload response missing file URL");
359
+ }
360
+ return uploadedUrl;
361
+ } finally {
362
+ clearTimeout(timeoutId);
363
+ }
364
+ }
365
+ async function sendWorkclawOutboundMessage(params) {
366
+ const {
367
+ cacheKey,
368
+ to,
369
+ mediaUrl,
370
+ replyToMessageId,
371
+ openConversationId,
372
+ agentId,
373
+ config,
374
+ messageType = "reply",
375
+ last,
376
+ source
377
+ } = params;
378
+ let msgType = params.msgType;
379
+ let content = params.text;
380
+ const resolvedAgentId = agentId ?? config.agentId;
381
+ if (resolvedAgentId === void 0 || resolvedAgentId === null || String(resolvedAgentId).trim() === "") {
382
+ throw new Error(
383
+ "agentId is required for sending messages. Please create an account via cloud platform command or configure accounts in openclaw.json"
384
+ );
385
+ }
386
+ if (!msgType) {
387
+ ({ msgType, content } = resolveWorkclawMessage(content, mediaUrl));
388
+ }
389
+ const messageTypeCode = msgType === "text" ? "1" : msgType;
390
+ const workclawConfig = {
391
+ baseUrl: config.baseUrl ?? "",
392
+ appKey: config.appKey ?? "",
393
+ appSecret: config.appSecret ?? "",
394
+ localIp: config.localIp,
395
+ allowInsecureTls: config.allowInsecureTls,
396
+ requestTimeout: config.requestTimeout
397
+ };
398
+ const receiveId = config.userId ?? to;
399
+ const replyEndpoint = "/open-apis/im/v1/messages/{messageId}/reply";
400
+ const pushEndpoint = "/open-apis/im/v1/messages";
401
+ if (messageType === "reply") {
402
+ if (!replyToMessageId) {
403
+ throw new Error("replyToMessageId is required for reply message");
404
+ }
405
+ const resolvedOpenConversationId = openConversationId ?? config.openConversationId;
406
+ const msgId = await sendWorkclawReplyMessage({
407
+ cacheKey,
408
+ config: workclawConfig,
409
+ agentId: resolvedAgentId,
410
+ receiveId,
411
+ msgType: messageTypeCode,
412
+ content,
413
+ messageId: replyToMessageId,
414
+ openConversationId: resolvedOpenConversationId,
415
+ endpoint: replyEndpoint.replace("{messageId}", String(replyToMessageId)),
416
+ last,
417
+ source
418
+ });
419
+ return { messageId: msgId };
420
+ } else {
421
+ logger.info(`【智小途-发送】正在发送主动消息`);
422
+ const resolvedOpenConversationId = openConversationId ?? config.openConversationId;
423
+ logger.info(`【智小途-发送】已解析的 openConversationId: ${resolvedOpenConversationId}`);
424
+ logger.info(`【智小途-发送】配置中的 openConversationId: ${config.openConversationId}`);
425
+ const msgId = await sendWorkclawMessage({
426
+ cacheKey,
427
+ config: workclawConfig,
428
+ agentId: resolvedAgentId,
429
+ receiveId,
430
+ msgType: messageTypeCode,
431
+ content,
432
+ openConversationId: resolvedOpenConversationId,
433
+ endpoint: pushEndpoint,
434
+ last
435
+ });
436
+ return { messageId: msgId };
437
+ }
438
+ }
439
+ function findAccountIdByTarget(cfg, target, agentId) {
440
+ if (agentId !== void 0 && agentId !== null) {
441
+ return resolveAccountByUserIdAndAgentId(cfg, target, String(agentId)) ?? void 0;
442
+ }
443
+ return void 0;
444
+ }
445
+ async function resolveMediaUrl(mediaUrl, config) {
446
+ if (!mediaUrl)
447
+ return void 0;
448
+ if (!isLocalMediaSource(mediaUrl))
449
+ return mediaUrl;
450
+ const uploadUrl = config.uploadUrl;
451
+ if (!uploadUrl) {
452
+ throw new Error("uploadUrl not configured for local mediaUrl");
453
+ }
454
+ const filePath = resolveLocalPath(mediaUrl);
455
+ if (typeof config.mediaMaxMb === "number" && config.mediaMaxMb > 0) {
456
+ const stats = await stat(filePath);
457
+ const maxBytes = config.mediaMaxMb * 1024 * 1024;
458
+ if (stats.size > maxBytes) {
459
+ throw new Error(`mediaUrl exceeds limit (${config.mediaMaxMb} MB)`);
460
+ }
461
+ }
462
+ return uploadLocalMedia({
463
+ uploadUrl,
464
+ filePath,
465
+ uploadFieldName: config.uploadFieldName,
466
+ uploadHeaders: config.uploadHeaders,
467
+ uploadFormFields: config.uploadFormFields,
468
+ uploadResponseUrlPath: config.uploadResponseUrlPath,
469
+ requestTimeout: config.requestTimeout ?? 3e4,
470
+ allowInsecureTls: config.allowInsecureTls
471
+ });
472
+ }
473
+ async function sendMessageWorkclaw(params) {
474
+ const { cfg, to, text, mediaUrl, replyToMessageId, accountId, openConversationId, agentId, messageType, msgType, last } = params;
475
+ const resolvedMessageType = messageType ?? (replyToMessageId ? "reply" : "push");
476
+ let resolvedAccountId = accountId;
477
+ if (!resolvedAccountId) {
478
+ const foundAccountId = findAccountIdByTarget(cfg, to, agentId);
479
+ if (foundAccountId) {
480
+ resolvedAccountId = foundAccountId;
481
+ }
482
+ }
483
+ const account = resolveWorkclawAccountWithCache({ cfg, accountId: resolvedAccountId });
484
+ if (!account.configured) {
485
+ throw new Error(`Workclaw account "${account.accountId}" not configured`);
486
+ }
487
+ const resolvedMediaUrl = await resolveMediaUrl(mediaUrl, account.config);
488
+ const cfgChannel = cfg.channels?.["openclaw-workclaw"] ?? {};
489
+ const cfgAccounts = cfgChannel.accounts ?? {};
490
+ const cfgAccount = resolvedAccountId ? cfgAccounts[resolvedAccountId] ?? {} : {};
491
+ const cfgOpenConversationId = cfgAccount?.openConversationId ?? cfgChannel?.openConversationId;
492
+ const stateOpenConversationId = resolvedAccountId ? loadOpenConversationId(resolvedAccountId, to) : void 0;
493
+ const effectiveOpenConversationId = openConversationId ?? cfgOpenConversationId ?? stateOpenConversationId;
494
+ logger.info(`【智小途-发送】来源=${params.source || "?"} 类型=${resolvedMessageType} 会话=${effectiveOpenConversationId || "(无)"} 回复消息ID=${replyToMessageId}`);
495
+ const tokenCacheKey = account.config.appKey || account.accountId;
496
+ const result = await sendWorkclawOutboundMessage({
497
+ cacheKey: tokenCacheKey,
498
+ to,
499
+ text,
500
+ msgType,
501
+ mediaUrl: resolvedMediaUrl,
502
+ replyToMessageId,
503
+ openConversationId: effectiveOpenConversationId,
504
+ agentId,
505
+ config: account.config,
506
+ messageType: resolvedMessageType,
507
+ last,
508
+ source: params.source
509
+ });
510
+ if (resolvedAccountId) {
511
+ setLastOutboundAt(resolvedAccountId, Date.now());
512
+ }
513
+ return {
514
+ messageId: result.messageId,
515
+ chatId: to
516
+ };
517
+ }
518
+ export {
519
+ PLUGIN_ID as P,
520
+ saveOpenConversationId as a,
521
+ initWorkclawAgent as i,
522
+ sendMessageWorkclaw as s,
523
+ writeConfigFile as w
524
+ };
@@ -1,4 +1,4 @@
1
- import { aZ as getDefaultExportFromCjs } from "./index-ZWLWkJXc.js";
1
+ import { aZ as getDefaultExportFromCjs } from "./channel-CWeiUgV5.js";
2
2
  const WINDOWS_1252_EXTRA = {
3
3
  128: "€",
4
4
  130: "‚",
package/dist/index.d.ts CHANGED
@@ -1,12 +1,3 @@
1
- import { OpenClawPluginApi } from 'openclaw/plugin-sdk';
2
- declare const _default: {
3
- register(api: OpenClawPluginApi): void;
4
- id: string;
5
- name: string;
6
- description: string;
7
- configSchema: import('openclaw/plugin-sdk').ChannelConfigSchema;
8
- channelPlugin: import('openclaw/plugin-sdk').ChannelPlugin<import('./src/types/account.js').ResolvedWorkclawAccount>;
9
- setChannelRuntime?: (runtime: import('openclaw/plugin-sdk').PluginRuntime) => void;
10
- };
1
+ declare const _default: import('openclaw/plugin-sdk/channel-entry-contract').BundledChannelEntryContract<import('openclaw/plugin-sdk').ChannelPlugin>;
11
2
  export default _default;
12
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;;kBA2W5C,iBAAiB;;;;;;;;AAFjC,wBAOC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";AA8BA,wBAkBE"}
package/dist/index.js CHANGED
@@ -1,13 +1,44 @@
1
- import "node:fs/promises";
2
- import "node:path";
3
- import "node:process";
4
- import "node:url";
5
- import { cn } from "./index-ZWLWkJXc.js";
6
- import "./plugin-load-profile-DOnG9jJ5-zOQuKNoi.js";
7
- import "node:fs";
8
- import "node:os";
9
- import "node:net";
10
- import "node:crypto";
1
+ import { d as defineBundledChannelEntry, l as loadBundledEntryExportSync } from "./channel-entry-contract-BDMmGZzs-4ZlSsA7g.js";
2
+ function registerWorkclawFull(api) {
3
+ if (api.registrationMode === "tool-discovery") {
4
+ const registerTools = loadBundledEntryExportSync(
5
+ import.meta.url,
6
+ {
7
+ specifier: "./tools-api.js",
8
+ exportName: "registerWorkclawTools"
9
+ }
10
+ );
11
+ registerTools(api);
12
+ return;
13
+ }
14
+ const register = loadBundledEntryExportSync(
15
+ import.meta.url,
16
+ {
17
+ specifier: "./channel-entry-api.js",
18
+ exportName: "registerWorkclawFull"
19
+ }
20
+ );
21
+ register(api);
22
+ }
23
+ const index = defineBundledChannelEntry({
24
+ id: "openclaw-workclaw",
25
+ name: "智小途",
26
+ description: "智小途企业通讯平台 OpenClaw 渠道插件,支持消息收发、定时任务、工具调用等",
27
+ importMetaUrl: import.meta.url,
28
+ plugin: {
29
+ specifier: "./channel-plugin-api.js",
30
+ exportName: "workclawPlugin"
31
+ },
32
+ secrets: {
33
+ specifier: "./src/secret-contract-api.js",
34
+ exportName: "channelSecrets"
35
+ },
36
+ runtime: {
37
+ specifier: "./runtime-api.js",
38
+ exportName: "setWorkclawRuntime"
39
+ },
40
+ registerFull: registerWorkclawFull
41
+ });
11
42
  export {
12
- cn as default
43
+ index as default
13
44
  };
@@ -1,8 +1,10 @@
1
- import { a$ as asNullableRecord, b0 as loadPluginManifestRegistryForPluginRegistry, D as DEFAULT_GATEWAY_PORT, b1 as loadBundledPluginPublicArtifactModuleSync, b2 as isBlockedObjectKey, b3 as listLegacyRuntimeModelProviderAliases, b4 as getBootstrapChannelPlugin } from "./index-ZWLWkJXc.js";
2
- import { x as getCachedPluginModuleLoader, y as createPluginModuleLoaderCache, z as isRecord, A as normalizeOptionalLowercaseString, i as isModelThinkingFormat, B as isSafeExecutableValue, C as normalizeProviderId } from "./plugin-load-profile-DOnG9jJ5-zOQuKNoi.js";
1
+ import { a$ as asNullableRecord, b0 as loadPluginManifestRegistryForPluginRegistry, D as DEFAULT_GATEWAY_PORT, b1 as loadBundledPluginPublicArtifactModuleSync, b2 as listLegacyRuntimeModelProviderAliases, b3 as getBootstrapChannelPlugin } from "./channel-CWeiUgV5.js";
2
+ import { y as getCachedPluginModuleLoader, z as createPluginModuleLoaderCache, A as isRecord, i as isModelThinkingFormat, B as isSafeExecutableValue, C as normalizeProviderId } from "./plugin-load-profile-DOnG9jJ5-B0ymqOTX.js";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import fs__default from "node:fs";
5
5
  import path__default from "node:path";
6
+ import { a as normalizeOptionalLowercaseString } from "./string-coerce-DyL154ka-BEV0SzzS.js";
7
+ import { f as isBlockedObjectKey } from "./workclaw-client-CMjcFjJx.js";
6
8
  const CLI_MCP_TYPE_TO_OPENCLAW_TRANSPORT = {
7
9
  http: "streamable-http",
8
10
  "streamable-http": "streamable-http",
@@ -1,7 +1,8 @@
1
- import { b5 as resolveAgentWorkspaceDir, b6 as resolveDefaultAgentId, b7 as listExplicitlyDisabledChannelIdsForConfig, b8 as listPotentialConfiguredChannelPresenceSignals, b9 as createPluginActivationSource, b0 as loadPluginManifestRegistryForPluginRegistry, ba as normalizePluginsConfig, bb as isBundledManifestOwner, bc as hasExplicitManifestOwnerTrust, bd as isActivatedManifestOwner, be as resolveEffectivePluginActivationState, bf as isPluginEnabledByDefaultForPlatform, bg as hasMeaningfulChannelConfig, bh as passesManifestOwnerBasePolicy, bi as resolveManifestOwnerBasePolicyBlock, bj as resolveSessionAgentId, bk as getOfficialExternalPluginCatalogEntry, bl as resolveOfficialExternalPluginInstall, bm as getOfficialExternalPluginCatalogManifest, bn as resolveOfficialExternalPluginId, bo as resolveOfficialExternalPluginLabel, bp as normalizeMessageChannel, bq as resolveOutboundChannelPlugin, ak as listChannelPlugins, br as isDeliverableMessageChannel, bs as listDeliverableMessageChannels, bt as formatErrorMessage, bu as defaultRuntime, bv as formatCliCommand, bw as normalizeMessageChannel$1, bx as getActivePluginChannelRegistryFromState, by as createOutboundPayloadPlan, bz as projectOutboundPayloadPlanForDelivery, bA as projectOutboundPayloadPlanForMirror, bB as sendDurableMessageBatch, bC as resolveOutboundDurableFinalDeliverySupport, bD as GATEWAY_CLIENT_MODES, bE as GATEWAY_CLIENT_NAMES } from "./index-ZWLWkJXc.js";
2
- import { A as normalizeOptionalLowercaseString, F as normalizeOptionalString } from "./plugin-load-profile-DOnG9jJ5-zOQuKNoi.js";
1
+ import { b4 as resolveAgentWorkspaceDir, b5 as resolveDefaultAgentId, b6 as listExplicitlyDisabledChannelIdsForConfig, b7 as listPotentialConfiguredChannelPresenceSignals, b8 as createPluginActivationSource, b0 as loadPluginManifestRegistryForPluginRegistry, b9 as normalizePluginsConfig, ba as isBundledManifestOwner, bb as hasExplicitManifestOwnerTrust, bc as isActivatedManifestOwner, bd as resolveEffectivePluginActivationState, be as isPluginEnabledByDefaultForPlatform, bf as hasMeaningfulChannelConfig, bg as passesManifestOwnerBasePolicy, bh as resolveManifestOwnerBasePolicyBlock, bi as resolveSessionAgentId, bj as getOfficialExternalPluginCatalogEntry, bk as resolveOfficialExternalPluginInstall, bl as getOfficialExternalPluginCatalogManifest, bm as resolveOfficialExternalPluginId, bn as resolveOfficialExternalPluginLabel, bo as normalizeMessageChannel, bp as resolveOutboundChannelPlugin, al as listChannelPlugins, bq as isDeliverableMessageChannel, br as listDeliverableMessageChannels, bs as formatErrorMessage, bt as defaultRuntime, bu as formatCliCommand, bv as normalizeMessageChannel$1, bw as getActivePluginChannelRegistryFromState, bx as createOutboundPayloadPlan, by as projectOutboundPayloadPlanForDelivery, bz as projectOutboundPayloadPlanForMirror, bA as sendDurableMessageBatch, bB as resolveOutboundDurableFinalDeliverySupport, bC as GATEWAY_CLIENT_MODES, bD as GATEWAY_CLIENT_NAMES } from "./channel-CWeiUgV5.js";
2
+ import { a as normalizeOptionalLowercaseString, b as normalizeOptionalString } from "./string-coerce-DyL154ka-BEV0SzzS.js";
3
3
  import "node:fs";
4
4
  import "node:path";
5
+ import "./plugin-load-profile-DOnG9jJ5-B0ymqOTX.js";
5
6
  import "node:fs/promises";
6
7
  import "node:os";
7
8
  import "node:process";
@@ -624,11 +625,11 @@ function resolveOutboundTarget(params) {
624
625
  let messageConfigRuntimePromise = null;
625
626
  let messageGatewayRuntimePromise = null;
626
627
  function loadMessageConfigRuntime() {
627
- messageConfigRuntimePromise ??= import("./message.config.runtime-DuzEAWuz.js");
628
+ messageConfigRuntimePromise ??= import("./message.config.runtime-DmvQNASl.js");
628
629
  return messageConfigRuntimePromise;
629
630
  }
630
631
  function loadMessageGatewayRuntime() {
631
- messageGatewayRuntimePromise ??= import("./message.gateway.runtime-Ch5zdrYr.js");
632
+ messageGatewayRuntimePromise ??= import("./message.gateway.runtime-BIIf6teh.js");
632
633
  return messageGatewayRuntimePromise;
633
634
  }
634
635
  async function resolveRequiredChannel(params) {
@@ -0,0 +1,4 @@
1
+ import { i } from "./channel-CWeiUgV5.js";
2
+ export {
3
+ i as getRuntimeConfig
4
+ };
@@ -1,5 +1,6 @@
1
- import { F as normalizeOptionalString, r as resolveSecretInputRef, h as hasConfiguredSecretInput, G as secretRefKey, H as isValidExecSecretRefId, I as formatExecSecretRefIdValidationMessage, J as resolveDefaultSecretProviderAlias, S as SINGLE_VALUE_FILE_REF_ID, K as resolveUserPath, N as readSecureFile, z as isRecord, O as FsSafeError, o as isPathInside, P as inspectPathPermissions, Q as safeStat, g as normalizeSecretInputString } from "./plugin-load-profile-DOnG9jJ5-zOQuKNoi.js";
2
- import { bF as containsEnvVarReference, bG as resolveSafeTimeoutDelayMs, bH as resolveConnectChallengeTimeoutMs, O as resolveConfigPath, X as resolveGatewayPort, bI as redactSensitiveUrlLikeString, bJ as isSecureWebSocketUrl, bt as formatErrorMessage, bK as isDynamicOperatorGatewayMethod, bL as WRITE_SCOPE, bM as ADMIN_SCOPE, bN as READ_SCOPE, bO as APPROVALS_SCOPE, bP as PAIRING_SCOPE, bQ as TALK_SECRETS_SCOPE, bR as resolveCoreOperatorGatewayMethodScope, bS as resolveReservedGatewayMethodScope, bT as getPluginRegistryState, bU as resolvePreauthHandshakeTimeoutMs, bV as loadGatewayTlsRuntime, a4 as resolveStateDir, bW as loadOrCreateDeviceIdentity, i as getRuntimeConfig, bX as GatewayClient, bD as GATEWAY_CLIENT_MODES, bY as VERSION, bE as GATEWAY_CLIENT_NAMES, bZ as isGatewayConnectAssemblyError, b_ as isLoopbackIpAddress } from "./index-ZWLWkJXc.js";
1
+ import { b as normalizeOptionalString } from "./string-coerce-DyL154ka-BEV0SzzS.js";
2
+ import { bE as containsEnvVarReference, bF as resolveSafeTimeoutDelayMs, bG as resolveConnectChallengeTimeoutMs, P as resolveConfigPath, Y as resolveGatewayPort, bH as redactSensitiveUrlLikeString, bI as isSecureWebSocketUrl, bs as formatErrorMessage, bJ as isDynamicOperatorGatewayMethod, bK as WRITE_SCOPE, bL as ADMIN_SCOPE, bM as READ_SCOPE, bN as APPROVALS_SCOPE, bO as PAIRING_SCOPE, bP as TALK_SECRETS_SCOPE, bQ as resolveCoreOperatorGatewayMethodScope, bR as resolveReservedGatewayMethodScope, bS as getPluginRegistryState, bT as resolvePreauthHandshakeTimeoutMs, bU as loadGatewayTlsRuntime, a5 as resolveStateDir, bV as loadOrCreateDeviceIdentity, i as getRuntimeConfig, bW as GatewayClient, bC as GATEWAY_CLIENT_MODES, bX as VERSION, bD as GATEWAY_CLIENT_NAMES, bY as isGatewayConnectAssemblyError, bZ as isLoopbackIpAddress } from "./channel-CWeiUgV5.js";
3
+ import { r as resolveSecretInputRef, h as hasConfiguredSecretInput, F as secretRefKey, G as isValidExecSecretRefId, H as formatExecSecretRefIdValidationMessage, I as resolveDefaultSecretProviderAlias, S as SINGLE_VALUE_FILE_REF_ID, J as resolveUserPath, K as readSecureFile, A as isRecord, N as FsSafeError, x as isPathInside, O as inspectPathPermissions, P as safeStat, g as normalizeSecretInputString } from "./plugin-load-profile-DOnG9jJ5-B0ymqOTX.js";
3
4
  import "node:fs";
4
5
  import path__default from "node:path";
5
6
  import fs$1__default from "node:fs/promises";