@sumeai/sumeclaw 1.2.1 → 1.2.3

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.
@@ -50,6 +50,13 @@ function appendPendingReplyText(accountId, userId, text) {
50
50
  }
51
51
  return ctx.accumulatedText;
52
52
  }
53
+ function formatErrorDetail(err) {
54
+ const anyErr = err;
55
+ const name = String(anyErr?.name || "Error");
56
+ const message = String(anyErr?.message || err || "\u672A\u77E5\u9519\u8BEF");
57
+ const stack = typeof anyErr?.stack === "string" ? anyErr.stack.split("\n").slice(0, 6).join("\n") : "";
58
+ return { name, message, stack };
59
+ }
53
60
  function connectGateway(opts) {
54
61
  const { accountId, botToken, api } = opts;
55
62
  const platformUrl = opts.platformUrl || DEFAULT_PLATFORM_URL;
@@ -83,7 +90,7 @@ function connectGateway(opts) {
83
90
  type: "register_info",
84
91
  token: botToken,
85
92
  agentId: defaultAgentId,
86
- version: "1.2.0"
93
+ version: "1.2.3"
87
94
  })
88
95
  );
89
96
  heartbeatTimer = setInterval(() => {
@@ -195,7 +202,9 @@ function connectGateway(opts) {
195
202
  sessionKey: input.sessionKey,
196
203
  text: input.text,
197
204
  messageId: input.messageId ?? `sumeclaw-${Date.now()}`,
198
- ok: input.ok ?? true
205
+ ok: input.ok ?? true,
206
+ errorCode: input.errorCode,
207
+ errorDetail: input.errorDetail
199
208
  })
200
209
  );
201
210
  console.log("[sumeclaw] \u{1F4E4} agent_reply sent", {
@@ -252,7 +261,9 @@ function connectGateway(opts) {
252
261
  sessionKey: input.sessionKey,
253
262
  text: input.text,
254
263
  messageId: input.messageId ?? `sumeclaw-${Date.now()}`,
255
- ok: input.ok ?? true
264
+ ok: input.ok ?? true,
265
+ errorCode: input.errorCode,
266
+ errorDetail: input.errorDetail
256
267
  })
257
268
  );
258
269
  console.log("[sumeclaw] \u{1F4E4} agent_done sent", {
@@ -311,18 +322,21 @@ function connectGateway(opts) {
311
322
  console.error(
312
323
  "[sumeclaw] \u274C \u5F53\u524D OpenClaw runtime \u4E0D\u63D0\u4F9B\u53EF\u7528\u7684 channel \u5165\u7AD9\u5206\u53D1\u80FD\u529B"
313
324
  );
314
- console.error("[sumeclaw] runtime debug:", {
325
+ const runtimeDebug = {
315
326
  hasStoredRuntime: Boolean(tryGetSumeclawRuntime()),
316
327
  apiKeys: api ? Object.keys(api) : [],
317
328
  runtimeKeys: runtime ? Object.keys(runtime) : [],
318
329
  channelKeys: runtime?.channel ? Object.keys(runtime.channel) : []
319
- });
330
+ };
331
+ console.error("[sumeclaw] runtime debug:", runtimeDebug);
320
332
  sendAgentReply({
321
333
  requestId: input.requestId,
322
334
  userId: input.userId,
323
335
  sessionKey: input.sessionKey,
324
336
  text: "OpenClaw \u63D2\u4EF6\u672A\u83B7\u5F97\u8FD0\u884C\u65F6\u5206\u53D1\u80FD\u529B\uFF0C\u8BF7\u5347\u7EA7\u63D2\u4EF6\u5165\u53E3\u540E\u91CD\u542F OpenClaw Gateway\u3002",
325
- ok: false
337
+ ok: false,
338
+ errorCode: "OPENCLAW_RUNTIME_UNAVAILABLE",
339
+ errorDetail: runtimeDebug
326
340
  });
327
341
  return;
328
342
  }
@@ -442,18 +456,41 @@ function connectGateway(opts) {
442
456
  });
443
457
  console.log("[sumeclaw] \u2705 OpenClaw turn dispatched", result?.admission ?? "");
444
458
  if (input.stream) {
445
- finishStreamReply(input);
459
+ if (!finishStreamReply(input)) {
460
+ sendAgentDone({
461
+ requestId: input.requestId,
462
+ userId: input.userId,
463
+ sessionKey: input.sessionKey,
464
+ text: "OpenClaw \u672C\u5730\u5904\u7406\u5B8C\u6210\u4F46\u672A\u4EA7\u751F\u56DE\u590D\uFF0C\u8BF7\u68C0\u67E5\u672C\u5730 Agent \u662F\u5426\u5B58\u5728\u3001\u662F\u5426\u542F\u7528\uFF0C\u4EE5\u53CA\u6A21\u578B/\u5DE5\u5177\u914D\u7F6E\u662F\u5426\u53EF\u7528\u3002",
465
+ ok: false,
466
+ errorCode: "OPENCLAW_EMPTY_REPLY",
467
+ errorDetail: { agentId: input.agentId, accountId, sessionKey: input.sessionKey }
468
+ });
469
+ }
446
470
  } else {
447
- finishBufferedReply(input);
471
+ if (!finishBufferedReply(input)) {
472
+ sendAgentReply({
473
+ requestId: input.requestId,
474
+ userId: input.userId,
475
+ sessionKey: input.sessionKey,
476
+ text: "OpenClaw \u672C\u5730\u5904\u7406\u5B8C\u6210\u4F46\u672A\u4EA7\u751F\u56DE\u590D\uFF0C\u8BF7\u68C0\u67E5\u672C\u5730 Agent \u662F\u5426\u5B58\u5728\u3001\u662F\u5426\u542F\u7528\uFF0C\u4EE5\u53CA\u6A21\u578B/\u5DE5\u5177\u914D\u7F6E\u662F\u5426\u53EF\u7528\u3002",
477
+ ok: false,
478
+ errorCode: "OPENCLAW_EMPTY_REPLY",
479
+ errorDetail: { agentId: input.agentId, accountId, sessionKey: input.sessionKey }
480
+ });
481
+ }
448
482
  }
449
483
  } catch (err) {
450
- console.error("[sumeclaw] \u274C OpenClaw turn dispatch failed", err);
484
+ const detail = formatErrorDetail(err);
485
+ console.error("[sumeclaw] \u274C OpenClaw turn dispatch failed", detail);
451
486
  sendAgentReply({
452
487
  requestId: input.requestId,
453
488
  userId: input.userId,
454
489
  sessionKey: input.sessionKey,
455
- text: "OpenClaw \u672C\u5730\u5904\u7406\u6D88\u606F\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5\u3002",
456
- ok: false
490
+ text: `OpenClaw \u672C\u5730\u5904\u7406\u6D88\u606F\u5931\u8D25\uFF1A${detail.message}`,
491
+ ok: false,
492
+ errorCode: "OPENCLAW_TURN_DISPATCH_FAILED",
493
+ errorDetail: { ...detail, agentId: input.agentId, accountId, sessionKey: input.sessionKey }
457
494
  });
458
495
  }
459
496
  }
@@ -546,18 +583,41 @@ function connectGateway(opts) {
546
583
  });
547
584
  console.log("[sumeclaw] \u2705 OpenClaw Direct DM dispatched");
548
585
  if (input.stream) {
549
- finishStreamReply(input);
586
+ if (!finishStreamReply(input)) {
587
+ sendAgentDone({
588
+ requestId: input.requestId,
589
+ userId: input.userId,
590
+ sessionKey: input.sessionKey,
591
+ text: "OpenClaw Direct DM \u5904\u7406\u5B8C\u6210\u4F46\u672A\u4EA7\u751F\u56DE\u590D\uFF0C\u8BF7\u68C0\u67E5\u672C\u5730 Agent \u662F\u5426\u5B58\u5728\u3001\u662F\u5426\u542F\u7528\uFF0C\u4EE5\u53CA\u6A21\u578B/\u5DE5\u5177\u914D\u7F6E\u662F\u5426\u53EF\u7528\u3002",
592
+ ok: false,
593
+ errorCode: "OPENCLAW_EMPTY_REPLY",
594
+ errorDetail: { agentId: input.agentId, accountId, sessionKey: input.sessionKey }
595
+ });
596
+ }
550
597
  } else {
551
- finishBufferedReply(input);
598
+ if (!finishBufferedReply(input)) {
599
+ sendAgentReply({
600
+ requestId: input.requestId,
601
+ userId: input.userId,
602
+ sessionKey: input.sessionKey,
603
+ text: "OpenClaw Direct DM \u5904\u7406\u5B8C\u6210\u4F46\u672A\u4EA7\u751F\u56DE\u590D\uFF0C\u8BF7\u68C0\u67E5\u672C\u5730 Agent \u662F\u5426\u5B58\u5728\u3001\u662F\u5426\u542F\u7528\uFF0C\u4EE5\u53CA\u6A21\u578B/\u5DE5\u5177\u914D\u7F6E\u662F\u5426\u53EF\u7528\u3002",
604
+ ok: false,
605
+ errorCode: "OPENCLAW_EMPTY_REPLY",
606
+ errorDetail: { agentId: input.agentId, accountId, sessionKey: input.sessionKey }
607
+ });
608
+ }
552
609
  }
553
610
  } catch (err) {
554
- console.error("[sumeclaw] \u274C Direct DM dispatch failed", err);
611
+ const detail = formatErrorDetail(err);
612
+ console.error("[sumeclaw] \u274C Direct DM dispatch failed", detail);
555
613
  sendAgentReply({
556
614
  requestId: input.requestId,
557
615
  userId: input.userId,
558
616
  sessionKey: input.sessionKey,
559
- text: "OpenClaw \u672C\u5730\u5904\u7406\u6D88\u606F\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5\u3002",
560
- ok: false
617
+ text: `OpenClaw Direct DM \u5904\u7406\u5931\u8D25\uFF1A${detail.message}`,
618
+ ok: false,
619
+ errorCode: "OPENCLAW_DIRECT_DM_FAILED",
620
+ errorDetail: { ...detail, agentId: input.agentId, accountId, sessionKey: input.sessionKey }
561
621
  });
562
622
  }
563
623
  }
@@ -625,6 +685,21 @@ var setupWizard = {
625
685
  hasConfiguredValue: Boolean(token)
626
686
  };
627
687
  }
688
+ },
689
+ {
690
+ inputKey: "replenishmentCode",
691
+ credentialLabel: "\u53CB\u867E\u8865\u8D27\u7801",
692
+ preferredEnvVar: "SUMECLAW_REPLENISH_CODE",
693
+ envPrompt: "\u662F\u5426\u4F7F\u7528\u73AF\u5883\u53D8\u91CF SUMECLAW_REPLENISH_CODE\uFF1F",
694
+ keepPrompt: "\u4FDD\u7559\u5F53\u524D\u8865\u8D27\u7801\uFF1F",
695
+ inputPrompt: "\u5982\u9700\u8865\u5145\u53EF\u96C7\u4F63\u667A\u80FD\u4F53\u5E93\u5B58\uFF0C\u8BF7\u8F93\u5165\u53CB\u867E\u540E\u53F0\u751F\u6210\u7684\u8865\u8D27\u7801\uFF1B\u4E0D\u8865\u8D27\u53EF\u7559\u7A7A\uFF1A",
696
+ inspect: ({ cfg }) => {
697
+ const code = cfg.channels?.[channelKey]?.replenishmentCode;
698
+ return {
699
+ accountConfigured: Boolean(code),
700
+ hasConfiguredValue: Boolean(code)
701
+ };
702
+ }
628
703
  }
629
704
  ]
630
705
  };
@@ -743,4 +818,4 @@ export {
743
818
  connectGateway,
744
819
  sumeclawPlugin
745
820
  };
746
- //# sourceMappingURL=chunk-RIUKFLMY.js.map
821
+ //# sourceMappingURL=chunk-ZMTWCTB4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime.ts","../src/gateway.ts","../src/channel.ts"],"sourcesContent":["let runtimeRef: any = null;\n\nexport function setSumeclawRuntime(runtime: any) {\n runtimeRef = runtime;\n}\n\nexport function tryGetSumeclawRuntime() {\n return runtimeRef;\n}\n","\n/**\n * 友虾名片 OpenClaw Channel 插件 — Gateway 层\n *\n * WebSocket 连接管理:\n * - 出站连接到 wss://api.gixin.cc/api/channel/{botToken}\n * - 心跳保活(30s 间隔)\n * - 断线自动重连(指数退避,最大 60s)\n * - 平台下发的消息注入 OpenClaw Agent\n * - Agent 回复通过 WS 推回平台\n */\n\nimport WebSocket from \"ws\";\nimport { dispatchInboundDirectDmWithRuntime } from \"openclaw/plugin-sdk/direct-dm\";\nimport { tryGetSumeclawRuntime } from \"./runtime.js\";\n\n/**\n * 全局 WS 管理\n */\nconst wsMap: Record<string, WebSocket> = {};\n\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport { readFileSync } from \"fs\";\nimport { fileURLToPath } from \"url\";\nimport { dirname, join } from \"path\";\n\n// const __filename = fileURLToPath(import.meta.url);\n// const __dirname = dirname(__filename);\n// const pkg = JSON.parse(readFileSync(join(__dirname, \"..\", \"..\", \"package.json\"), \"utf-8\"));\n\n// ─── 配置常量 ────────────────────────────────────────────────────────────────\n\nconst DEFAULT_PLATFORM_URL = \"wss://api.gixin.cc\";\nconst HEARTBEAT_MS = 30_000;\nconst MAX_RECONNECT_MS = 60_000;\nconst BASE_BACKOFF_MS = 1_000;\n\n// ─── 连接池 ──────────────────────────────────────────────────────────────────\n\n/** key: accountId → WebSocket */\nconst connections = new Map<string, WebSocket>();\nconst connectingAccounts = new Set<string>();\nconst pendingReplyContexts = new Map<\n string,\n {\n requestId?: string;\n sessionKey: string;\n stream?: boolean;\n accumulatedText: string;\n }\n>();\n\nfunction replyContextKey(accountId: string, userId: string): string {\n return `${accountId}:${userId}`;\n}\n\nexport function getWebSocket(accountId: string): WebSocket | undefined {\n return connections.get(accountId);\n}\n\nexport function rememberPendingReplyContext(params: {\n accountId: string;\n userId: string;\n requestId?: string;\n sessionKey: string;\n stream?: boolean;\n}) {\n const key = replyContextKey(params.accountId, params.userId);\n pendingReplyContexts.set(replyContextKey(params.accountId, params.userId), {\n requestId: params.requestId,\n sessionKey: params.sessionKey,\n stream: params.stream,\n accumulatedText: \"\",\n });\n}\n\nexport function getPendingReplyContext(accountId: string, userId: string) {\n return pendingReplyContexts.get(replyContextKey(accountId, userId));\n}\n\nexport function consumePendingReplyContext(accountId: string, userId: string) {\n const key = replyContextKey(accountId, userId);\n const ctx = pendingReplyContexts.get(key);\n pendingReplyContexts.delete(key);\n return ctx;\n}\n\nexport function appendPendingReplyText(accountId: string, userId: string, text: string) {\n const ctx = getPendingReplyContext(accountId, userId);\n if (!ctx) return \"\";\n\n if (!ctx.accumulatedText) {\n ctx.accumulatedText = text;\n } else if (text.startsWith(ctx.accumulatedText)) {\n ctx.accumulatedText = text;\n } else if (!ctx.accumulatedText.endsWith(text)) {\n ctx.accumulatedText += text;\n }\n\n return ctx.accumulatedText;\n}\n\nfunction formatErrorDetail(err: unknown) {\n const anyErr = err as any;\n const name = String(anyErr?.name || \"Error\");\n const message = String(anyErr?.message || err || \"未知错误\");\n const stack = typeof anyErr?.stack === \"string\"\n ? anyErr.stack.split(\"\\n\").slice(0, 6).join(\"\\n\")\n : \"\";\n return { name, message, stack };\n}\n\n// ─── 连接逻辑 ────────────────────────────────────────────────────────────────\n\nexport interface MinicardAccount {\n botToken?: string;\n platformUrl?: string;\n enabled?: boolean;\n}\n\n\n\n\ntype ConnectOptions = {\n accountId: string;\n platformUrl?: string;\n botToken: string;\n defaultAgentId?: string;\n api: any;\n};\n\nexport function connectGateway(opts: ConnectOptions) {\n const { accountId, botToken, api } = opts;\n const platformUrl = opts.platformUrl || DEFAULT_PLATFORM_URL;\n const defaultAgentId = opts.defaultAgentId || \"main\";\n\n const existing = connections.get(accountId);\n if (\n existing &&\n (existing.readyState === WebSocket.OPEN ||\n existing.readyState === WebSocket.CONNECTING)\n ) {\n console.log(`[sumeclaw] ♻️ reuse existing connection: ${accountId}`);\n return;\n }\n\n if (connectingAccounts.has(accountId)) {\n console.log(`[sumeclaw] ♻️ connection already starting: ${accountId}`);\n return;\n }\n\n let ws: WebSocket | null = null;\n let heartbeatTimer: NodeJS.Timeout | null = null;\n let reconnectTimer: NodeJS.Timeout | null = null;\n\n const HEARTBEAT_INTERVAL = 30_000;\n const RECONNECT_DELAY = 5_000;\n\n function start() {\n \n const url = `${platformUrl.replace(/\\/$/, \"\")}/api/channel/${botToken}`;\n console.log(`[sumeclaw] 🌐 connecting -> ${url} (${accountId})`);\n\n connectingAccounts.add(accountId);\n ws = new WebSocket(url);\n connections.set(accountId, ws);\n \n\n ws.on(\"open\", () => {\n console.log(`[sumeclaw] ✅ connected: ${accountId}`);\n connectingAccounts.delete(accountId);\n connections.set(accountId, ws as WebSocket);\n\n // 🔐 上报本地插件/Agent 信息。平台端会据此刷新在线状态。\n ws?.send(\n JSON.stringify({\n type: \"register_info\",\n token: botToken,\n agentId: defaultAgentId,\n version: \"1.2.3\",\n })\n );\n\n // ❤️ 心跳\n heartbeatTimer = setInterval(() => {\n if (ws?.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify({ type: \"heartbeat\" }));\n }\n }, HEARTBEAT_INTERVAL);\n });\n\n ws.on(\"message\", (data) => {\n try {\n const msg = JSON.parse(data.toString());\n\n // 🔍 调试\n console.log(\"[sumeclaw] 📩 message:\", msg);\n\n handleMessage(msg).catch((err) => {\n console.error(\"[sumeclaw] ❌ handle message error\", err);\n });\n } catch (err) {\n console.error(\"[sumeclaw] ❌ parse message error\", err);\n }\n });\n\n ws.on(\"close\", (code, reasonBuffer) => {\n const reason = reasonBuffer.toString();\n console.warn(`[sumeclaw] ⚠️ disconnected: ${accountId}`, { code, reason });\n cleanup();\n if (code === 4000 || reason.includes(\"replaced by a newer OpenClaw plugin connection\")) {\n console.warn(`[sumeclaw] 🛑 connection replaced, stop reconnecting: ${accountId}`);\n return;\n }\n scheduleReconnect();\n });\n\n ws.on(\"error\", (err) => {\n console.error(`[sumeclaw] ❌ ws error: ${accountId}`, err);\n connectingAccounts.delete(accountId);\n ws?.close();\n });\n }\n\n async function handleMessage(msg: any) {\n switch (msg.type) {\n case \"heartbeat_ack\":\n // 心跳回应\n break;\n\n case \"hooks_agent\":\n await handleHooksAgent(msg.payload ?? msg);\n break;\n\n case \"message\":\n // 👉 这里接入 OpenClaw\n console.log(\"[sumeclaw] 💬 收到消息:\", msg);\n\n await dispatchToOpenClaw({\n agentId: msg.agentId || \"main\",\n message: msg.text || msg.message || \"\",\n messageId: msg.id || msg.messageId,\n sessionKey:\n msg.sessionKey ||\n `agent:${msg.agentId || \"main\"}:user:${msg.from || msg.userId || \"unknown\"}`,\n userId: msg.from || msg.userId || msg.senderId || \"unknown\",\n raw: msg,\n requestId: msg.requestId,\n stream: Boolean(msg.stream),\n });\n\n break;\n\n case \"registered\":\n console.log(`[sumeclaw] 🔐 注册成功: ${accountId}`);\n break;\n\n default:\n console.log(\"[sumeclaw] ❓ 未处理消息:\", msg);\n }\n }\n\n async function handleHooksAgent(payload: any) {\n const meta = payload?.meta ?? {};\n const userId = String(meta.user_id || payload.userId || payload.from || \"unknown\");\n const agentId = String(payload.agentId || meta.agent_id || \"main\");\n const text = String(payload.message || payload.text || \"\");\n const sessionKey =\n payload.sessionKey || `agent:${agentId}:user:${userId}`;\n\n console.log(\"[sumeclaw] 🧠 hooks_agent -> OpenClaw\", {\n accountId,\n agentId,\n sessionKey,\n userId,\n text: text.slice(0, 100),\n });\n\n rememberPendingReplyContext({\n accountId,\n userId,\n requestId: payload.requestId,\n sessionKey,\n stream: Boolean(payload.stream),\n });\n\n await dispatchToOpenClaw({\n agentId,\n message: text,\n messageId: payload.messageId || `${sessionKey}:${Date.now()}`,\n sessionKey,\n userId,\n raw: payload,\n requestId: payload.requestId,\n stream: Boolean(payload.stream),\n });\n }\n\n function sendAgentReply(input: {\n requestId?: string;\n userId: string;\n sessionKey: string;\n text: string;\n ok?: boolean;\n messageId?: string;\n errorCode?: string;\n errorDetail?: any;\n }) {\n const activeWs = connections.get(accountId) ?? ws;\n if (!activeWs || activeWs.readyState !== WebSocket.OPEN) {\n console.error(\"[sumeclaw] ❌ cannot send agent_reply, websocket is not open\", {\n accountId,\n requestId: input.requestId,\n readyState: activeWs?.readyState,\n });\n return false;\n }\n\n activeWs.send(\n JSON.stringify({\n type: \"agent_reply\",\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text: input.text,\n messageId: input.messageId ?? `sumeclaw-${Date.now()}`,\n ok: input.ok ?? true,\n errorCode: input.errorCode,\n errorDetail: input.errorDetail,\n }),\n );\n console.log(\"[sumeclaw] 📤 agent_reply sent\", {\n accountId,\n requestId: input.requestId,\n userId: input.userId,\n textLength: input.text.length,\n });\n return true;\n }\n\n function sendAgentDelta(input: {\n requestId?: string;\n userId: string;\n sessionKey: string;\n text: string;\n messageId?: string;\n }) {\n const activeWs = connections.get(accountId) ?? ws;\n if (!activeWs || activeWs.readyState !== WebSocket.OPEN) {\n console.error(\"[sumeclaw] ❌ cannot send agent_delta, websocket is not open\", {\n accountId,\n requestId: input.requestId,\n readyState: activeWs?.readyState,\n });\n return false;\n }\n\n activeWs.send(\n JSON.stringify({\n type: \"agent_delta\",\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text: input.text,\n messageId: input.messageId ?? `sumeclaw-${Date.now()}`,\n }),\n );\n console.log(\"[sumeclaw] 📤 agent_delta sent\", {\n accountId,\n requestId: input.requestId,\n userId: input.userId,\n textLength: input.text.length,\n });\n return true;\n }\n\n function sendAgentDone(input: {\n requestId?: string;\n userId: string;\n sessionKey: string;\n text: string;\n ok?: boolean;\n messageId?: string;\n errorCode?: string;\n errorDetail?: any;\n }) {\n const activeWs = connections.get(accountId) ?? ws;\n if (!activeWs || activeWs.readyState !== WebSocket.OPEN) {\n console.error(\"[sumeclaw] ❌ cannot send agent_done, websocket is not open\", {\n accountId,\n requestId: input.requestId,\n readyState: activeWs?.readyState,\n });\n return false;\n }\n\n activeWs.send(\n JSON.stringify({\n type: \"agent_done\",\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text: input.text,\n messageId: input.messageId ?? `sumeclaw-${Date.now()}`,\n ok: input.ok ?? true,\n errorCode: input.errorCode,\n errorDetail: input.errorDetail,\n }),\n );\n console.log(\"[sumeclaw] 📤 agent_done sent\", {\n accountId,\n requestId: input.requestId,\n userId: input.userId,\n textLength: input.text.length,\n });\n return true;\n }\n\n function finishStreamReply(input: {\n requestId?: string;\n userId: string;\n sessionKey: string;\n ok?: boolean;\n }) {\n const latest = consumePendingReplyContext(accountId, input.userId);\n if (!latest) {\n console.warn(\"[sumeclaw] ⚠️ no pending stream context to finish\", {\n accountId,\n requestId: input.requestId,\n userId: input.userId,\n });\n return false;\n }\n\n return sendAgentDone({\n requestId: latest.requestId ?? input.requestId,\n userId: input.userId,\n sessionKey: latest.sessionKey ?? input.sessionKey,\n text: latest.accumulatedText,\n ok: input.ok,\n });\n }\n\n function finishBufferedReply(input: {\n requestId?: string;\n userId: string;\n sessionKey: string;\n ok?: boolean;\n }) {\n const latest = consumePendingReplyContext(accountId, input.userId);\n if (!latest) {\n console.warn(\"[sumeclaw] ⚠️ no pending reply context to finish\", {\n accountId,\n requestId: input.requestId,\n userId: input.userId,\n });\n return false;\n }\n\n return sendAgentReply({\n requestId: latest.requestId ?? input.requestId,\n userId: input.userId,\n sessionKey: latest.sessionKey ?? input.sessionKey,\n text: latest.accumulatedText,\n ok: input.ok,\n });\n }\n\n async function dispatchToOpenClaw(input: {\n agentId: string;\n message: string;\n messageId?: string;\n sessionKey: string;\n userId: string;\n raw: any;\n requestId?: string;\n stream?: boolean;\n }) {\n const runtime = tryGetSumeclawRuntime() ?? api?.runtime;\n const turn = runtime?.channel?.turn;\n\n if (!turn?.run) {\n const directReplyDispatcher = runtime?.channel?.reply?.dispatchReplyWithBufferedBlockDispatcher;\n if (directReplyDispatcher) {\n await dispatchViaDirectDmRuntime(runtime, input);\n return;\n }\n\n console.error(\n \"[sumeclaw] ❌ 当前 OpenClaw runtime 不提供可用的 channel 入站分发能力\",\n );\n const runtimeDebug = {\n hasStoredRuntime: Boolean(tryGetSumeclawRuntime()),\n apiKeys: api ? Object.keys(api) : [],\n runtimeKeys: runtime ? Object.keys(runtime) : [],\n channelKeys: runtime?.channel ? Object.keys(runtime.channel) : [],\n };\n console.error(\"[sumeclaw] runtime debug:\", runtimeDebug);\n sendAgentReply({\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text: \"OpenClaw 插件未获得运行时分发能力,请升级插件入口后重启 OpenClaw Gateway。\",\n ok: false,\n errorCode: \"OPENCLAW_RUNTIME_UNAVAILABLE\",\n errorDetail: runtimeDebug,\n });\n return;\n }\n\n const now = Date.now();\n const messageId = String(input.messageId || `${input.sessionKey}:${now}`);\n const senderLabel = `友虾用户 ${input.userId}`;\n\n try {\n const result = await turn.run({\n channel: \"sumeclaw\",\n accountId,\n raw: input.raw,\n adapter: {\n ingest() {\n return {\n id: messageId,\n timestamp: now,\n rawText: input.message,\n textForAgent: input.message,\n textForCommands: input.message,\n raw: input.raw,\n };\n },\n classify(turnInput: any) {\n return {\n kind: \"message\",\n canStartAgentTurn: Boolean(turnInput.rawText),\n };\n },\n resolveTurn(turnInput: any) {\n return {\n sender: {\n id: input.userId,\n name: senderLabel,\n displayLabel: senderLabel,\n isBot: false,\n isSelf: false,\n },\n conversation: {\n kind: \"direct\",\n id: input.userId,\n label: senderLabel,\n routePeer: input.userId,\n },\n route: {\n agentId: input.agentId,\n accountId,\n routeSessionKey: input.sessionKey,\n dispatchSessionKey: input.sessionKey,\n persistedSessionKey: input.sessionKey,\n mainSessionKey: input.sessionKey,\n createIfMissing: true,\n },\n reply: {\n to: input.userId,\n originatingTo: input.userId,\n replyTarget: input.userId,\n sourceReplyDeliveryMode: \"direct\",\n },\n access: {\n dm: {\n policy: \"open\",\n allowed: true,\n allowFrom: [],\n },\n group: {\n isGroup: false,\n routeAllowed: true,\n senderAllowed: true,\n requireMention: false,\n },\n commands: {\n authorized: true,\n },\n mentions: {\n canDetectMention: false,\n wasMentioned: true,\n },\n },\n message: {\n body: turnInput.rawText,\n rawBody: turnInput.rawText,\n bodyForAgent: turnInput.textForAgent,\n commandBody: turnInput.textForCommands,\n envelopeFrom: senderLabel,\n senderLabel,\n preview: turnInput.rawText.slice(0, 120),\n },\n delivery: {\n deliver: async (payload: any) => {\n const text = String(payload?.text || payload?.body || \"\");\n if (!text) return { visibleReplySent: false };\n const replyId = `sumeclaw-${Date.now()}`;\n if (input.stream) {\n appendPendingReplyText(accountId, input.userId, text);\n sendAgentDelta({\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text,\n messageId: replyId,\n });\n } else {\n appendPendingReplyText(accountId, input.userId, text);\n }\n return {\n messageIds: [replyId],\n visibleReplySent: true,\n };\n },\n onError(err: unknown) {\n console.error(\"[sumeclaw] ❌ deliver error\", err);\n },\n },\n };\n },\n },\n });\n\n console.log(\"[sumeclaw] ✅ OpenClaw turn dispatched\", result?.admission ?? \"\");\n if (input.stream) {\n if (!finishStreamReply(input)) {\n sendAgentDone({\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text: \"OpenClaw 本地处理完成但未产生回复,请检查本地 Agent 是否存在、是否启用,以及模型/工具配置是否可用。\",\n ok: false,\n errorCode: \"OPENCLAW_EMPTY_REPLY\",\n errorDetail: { agentId: input.agentId, accountId, sessionKey: input.sessionKey },\n });\n }\n } else {\n if (!finishBufferedReply(input)) {\n sendAgentReply({\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text: \"OpenClaw 本地处理完成但未产生回复,请检查本地 Agent 是否存在、是否启用,以及模型/工具配置是否可用。\",\n ok: false,\n errorCode: \"OPENCLAW_EMPTY_REPLY\",\n errorDetail: { agentId: input.agentId, accountId, sessionKey: input.sessionKey },\n });\n }\n }\n } catch (err) {\n const detail = formatErrorDetail(err);\n console.error(\"[sumeclaw] ❌ OpenClaw turn dispatch failed\", detail);\n sendAgentReply({\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text: `OpenClaw 本地处理消息失败:${detail.message}`,\n ok: false,\n errorCode: \"OPENCLAW_TURN_DISPATCH_FAILED\",\n errorDetail: { ...detail, agentId: input.agentId, accountId, sessionKey: input.sessionKey },\n });\n }\n }\n\n async function dispatchViaDirectDmRuntime(runtime: any, input: {\n agentId: string;\n message: string;\n messageId?: string;\n sessionKey: string;\n userId: string;\n raw: any;\n requestId?: string;\n stream?: boolean;\n }) {\n const now = Date.now();\n const messageId = String(input.messageId || `${input.sessionKey}:${now}`);\n const senderLabel = `友虾用户 ${input.userId}`;\n const baseCfg = api?.getConfig?.() ?? api?.config ?? runtime?.config ?? {};\n const cfg = input.stream\n ? {\n ...baseCfg,\n agents: {\n ...(baseCfg.agents ?? {}),\n defaults: {\n ...(baseCfg.agents?.defaults ?? {}),\n blockStreamingDefault: \"on\",\n blockStreamingBreak: \"text_end\",\n blockStreamingChunk: {\n minChars: 12,\n maxChars: 80,\n breakPreference: \"sentence\",\n ...(baseCfg.agents?.defaults?.blockStreamingChunk ?? {}),\n },\n },\n },\n channels: {\n ...(baseCfg.channels ?? {}),\n sumeclaw: {\n ...(baseCfg.channels?.sumeclaw ?? {}),\n blockStreaming: true,\n },\n },\n }\n : baseCfg;\n\n try {\n await dispatchInboundDirectDmWithRuntime({\n cfg,\n runtime,\n channel: \"sumeclaw\",\n channelLabel: \"友虾名片\",\n accountId,\n peer: {\n kind: \"direct\",\n id: input.userId,\n },\n senderId: input.userId,\n senderAddress: input.userId,\n recipientAddress: \"sumeclaw\",\n conversationLabel: senderLabel,\n rawBody: input.message,\n messageId,\n timestamp: now,\n bodyForAgent: input.message,\n commandBody: input.message,\n commandAuthorized: true,\n provider: \"sumeclaw\",\n surface: \"sumeclaw\",\n originatingChannel: \"sumeclaw\",\n originatingTo: input.userId,\n extraContext: {\n AccountId: accountId,\n RouteAgentId: input.agentId,\n RequestId: input.requestId,\n },\n deliver: async (payload: any) => {\n const text = String(payload?.text || payload?.body || \"\");\n if (!text) return { visibleReplySent: false };\n\n const replyId = `sumeclaw-${Date.now()}`;\n if (input.stream) {\n appendPendingReplyText(accountId, input.userId, text);\n sendAgentDelta({\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text,\n messageId: replyId,\n });\n } else {\n appendPendingReplyText(accountId, input.userId, text);\n }\n\n return {\n messageIds: [replyId],\n visibleReplySent: true,\n };\n },\n onDispatchError: (err: unknown) => {\n console.error(\"[sumeclaw] ❌ Direct DM dispatch error\", err);\n },\n onRecordError: (err: unknown) => {\n console.error(\"[sumeclaw] ❌ Direct DM record error\", err);\n },\n });\n\n console.log(\"[sumeclaw] ✅ OpenClaw Direct DM dispatched\");\n if (input.stream) {\n if (!finishStreamReply(input)) {\n sendAgentDone({\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text: \"OpenClaw Direct DM 处理完成但未产生回复,请检查本地 Agent 是否存在、是否启用,以及模型/工具配置是否可用。\",\n ok: false,\n errorCode: \"OPENCLAW_EMPTY_REPLY\",\n errorDetail: { agentId: input.agentId, accountId, sessionKey: input.sessionKey },\n });\n }\n } else {\n if (!finishBufferedReply(input)) {\n sendAgentReply({\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text: \"OpenClaw Direct DM 处理完成但未产生回复,请检查本地 Agent 是否存在、是否启用,以及模型/工具配置是否可用。\",\n ok: false,\n errorCode: \"OPENCLAW_EMPTY_REPLY\",\n errorDetail: { agentId: input.agentId, accountId, sessionKey: input.sessionKey },\n });\n }\n }\n } catch (err) {\n const detail = formatErrorDetail(err);\n console.error(\"[sumeclaw] ❌ Direct DM dispatch failed\", detail);\n sendAgentReply({\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text: `OpenClaw Direct DM 处理失败:${detail.message}`,\n ok: false,\n errorCode: \"OPENCLAW_DIRECT_DM_FAILED\",\n errorDetail: { ...detail, agentId: input.agentId, accountId, sessionKey: input.sessionKey },\n });\n }\n }\n\n function cleanup() {\n connectingAccounts.delete(accountId);\n if (heartbeatTimer) {\n clearInterval(heartbeatTimer);\n heartbeatTimer = null;\n }\n if (connections.get(accountId) === ws) {\n connections.delete(accountId);\n }\n }\n\n function scheduleReconnect() {\n if (reconnectTimer) return;\n\n console.log(`[sumeclaw] 🔁 reconnecting in ${RECONNECT_DELAY / 1000}s`);\n\n reconnectTimer = setTimeout(() => {\n reconnectTimer = null;\n start();\n }, RECONNECT_DELAY);\n }\n\n start();\n}\n","// @ts-nocheck\n/**\n * 友虾名片 ChannelPlugin 核心定义\n *\n * 基于新版 plugin-sdk(2026.3.22+)的 createChatChannelPlugin API。\n */\nimport {\n createChatChannelPlugin,\n createChannelPluginBase,\n} from \"openclaw/plugin-sdk/channel-core\";\nimport type { ChannelSetupWizard } from \"openclaw/plugin-sdk/channel-setup\";\nimport {\n appendPendingReplyText,\n consumePendingReplyContext,\n getPendingReplyContext,\n getWebSocket,\n} from \"./gateway.js\";\n\nexport interface SumelawAccount {\n botToken?: string;\n platformUrl?: string;\n enabled?: boolean;\n}\n\n/**\n * 安装/配置向导 — 交互式提示用户输入 botToken\n */\nconst channelKey = \"sumeclaw\";\n\nconst channelConfigAdapter = {\n listAccountIds(cfg: any) {\n const accounts = (cfg.channels as any)?.[channelKey]?.accounts ?? {};\n return Object.keys(accounts);\n },\n\n resolveAccount(cfg: any, accountId?: string) {\n const accounts = (cfg.channels as any)?.[channelKey]?.accounts ?? {};\n return (accounts[accountId ?? \"default\"] ?? {}) as SumelawAccount;\n },\n};\n\nconst setupWizard: ChannelSetupWizard = {\n channel: channelKey,\n\n /** 根据当前配置显示连接状态 */\n status: {\n configuredLabel: \"已连接友虾名片\",\n unconfiguredLabel: \"尚未配置\",\n resolveConfigured: ({ cfg }) => {\n const accounts = (cfg.channels as any)?.[channelKey]?.accounts ?? {};\n return Object.values(accounts).some((acct: any) => acct?.botToken);\n },\n },\n\n /** 交互式凭据收集 — 引导用户输入 botToken */\n credentials: [\n {\n inputKey: \"botToken\",\n credentialLabel: \"友虾连接码\",\n preferredEnvVar: \"SUMECLAW_BOT_TOKEN\",\n envPrompt: \"是否使用环境变量 SUMECLAW_BOT_TOKEN?\",\n keepPrompt: \"保留当前 botToken?\",\n inputPrompt: \"请输入从友虾小程序获取的 botToken:\",\n inspect: ({ cfg, accountId }) => {\n const token = (cfg.channels as any)?.[channelKey]?.accounts?.[\n accountId ?? \"default\"\n ]?.botToken;\n return {\n accountConfigured: Boolean(token),\n hasConfiguredValue: Boolean(token),\n };\n },\n },\n {\n inputKey: \"replenishmentCode\",\n credentialLabel: \"友虾补货码\",\n preferredEnvVar: \"SUMECLAW_REPLENISH_CODE\",\n envPrompt: \"是否使用环境变量 SUMECLAW_REPLENISH_CODE?\",\n keepPrompt: \"保留当前补货码?\",\n inputPrompt: \"如需补充可雇佣智能体库存,请输入友虾后台生成的补货码;不补货可留空:\",\n inspect: ({ cfg }) => {\n const code = (cfg.channels as any)?.[channelKey]?.replenishmentCode;\n return {\n accountConfigured: Boolean(code),\n hasConfiguredValue: Boolean(code),\n };\n },\n },\n ],\n};\n\nexport const sumeclawPlugin = createChatChannelPlugin<SumelawAccount>({\n base: createChannelPluginBase({\n id: channelKey,\n setupWizard,\n setup: {\n /**\n * 从用户配置中解析账户信息\n */\n resolveAccount(cfg, accountId) {\n const accounts = (cfg.channels as any)?.[channelKey]?.accounts ?? {};\n return (accounts[accountId ?? \"default\"] ?? {}) as SumelawAccount;\n },\n\n /**\n * 检查账户配置状态\n */\n inspectAccount(cfg, accountId) {\n const account = (cfg.channels as any)?.[channelKey]?.accounts?.[\n accountId ?? \"default\"\n ];\n return {\n enabled: !!account?.botToken,\n configured: !!account?.botToken,\n };\n },\n },\n }),\n\n /**\n * 渠道配置适配器 (ChannelConfigAdapter)\n */\n config: channelConfigAdapter,\n\n /**\n * DM 安全策略\n *\n * 友虾名片场景下,所有通过名片访问的用户都允许对话。\n * 名片主可在小程序端管理黑名单(后续扩展)。\n */\n security: {\n dm: {\n channelKey: \"sumeclaw\",\n resolvePolicy: () => \"open\",\n defaultPolicy: \"open\",\n },\n },\n\n /**\n * 出站消息处理\n *\n * 当 OpenClaw Agent 生成回复后,通过 WebSocket 推回友虾名片平台。\n */\n outbound: {\n attachedResults: {\n sendText: async ({ text, to, accountId }) => {\n const resolvedAccountId = accountId ?? \"default\";\n const ws = getWebSocket(resolvedAccountId);\n if (!ws || ws.readyState !== 1) {\n throw new Error(\"WebSocket 未连接到友虾名片平台\");\n }\n\n const pending = getPendingReplyContext(resolvedAccountId, to);\n const messageId = `sumeclaw-${Date.now()}`;\n if (pending?.stream) {\n appendPendingReplyText(resolvedAccountId, to, text);\n ws.send(\n JSON.stringify({\n type: \"agent_delta\",\n requestId: pending.requestId,\n userId: to,\n sessionKey: pending.sessionKey,\n text,\n messageId,\n }),\n );\n console.log(\"[sumeclaw] 📤 outbound agent_delta sent\", {\n accountId: resolvedAccountId,\n requestId: pending.requestId,\n userId: to,\n textLength: text.length,\n });\n return { messageId };\n }\n\n if (pending && !pending.stream) {\n appendPendingReplyText(resolvedAccountId, to, text);\n console.log(\"[sumeclaw] 📥 outbound reply buffered\", {\n accountId: resolvedAccountId,\n requestId: pending.requestId,\n userId: to,\n textLength: text.length,\n });\n return { messageId };\n }\n\n const finalPending = consumePendingReplyContext(resolvedAccountId, to);\n ws.send(\n JSON.stringify({\n type: \"agent_reply\",\n requestId: finalPending?.requestId,\n userId: to,\n sessionKey: finalPending?.sessionKey,\n text,\n messageId,\n }),\n );\n console.log(\"[sumeclaw] 📤 outbound agent_reply sent\", {\n accountId: resolvedAccountId,\n requestId: finalPending?.requestId,\n userId: to,\n textLength: text.length,\n });\n\n return { messageId };\n },\n },\n },\n});\n\n// Some OpenClaw gateway health paths read plugin.config directly after the\n// SDK wrapper is created. Keep this explicit for compatibility across builds.\n(sumeclawPlugin as any).config ??= channelConfigAdapter;\n"],"mappings":"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","names":[]}
package/dist/index.js CHANGED
@@ -2,10 +2,178 @@ import {
2
2
  connectGateway,
3
3
  setSumeclawRuntime,
4
4
  sumeclawPlugin
5
- } from "./chunk-RIUKFLMY.js";
5
+ } from "./chunk-ZMTWCTB4.js";
6
6
 
7
7
  // index.ts
8
8
  import { defineChannelPluginEntry } from "openclaw/plugin-sdk/channel-core";
9
+
10
+ // src/replenishment.ts
11
+ var DEFAULT_PLATFORM_URL = "wss://api.gixin.cc";
12
+ function httpBaseFromWs(platformUrl) {
13
+ return platformUrl.replace(/^wss:\/\//, "https://").replace(/^ws:\/\//, "http://").replace(/\/$/, "");
14
+ }
15
+ function resolveChannelConfig(api) {
16
+ const cfg = api?.getConfig?.() ?? api?.config ?? {};
17
+ return cfg?.channels?.sumeclaw ?? {};
18
+ }
19
+ function resolveReplenishmentConfig(api) {
20
+ const channelConfig = resolveChannelConfig(api);
21
+ const code = process.env.SUMECLAW_REPLENISH_CODE || channelConfig.replenishmentCode || channelConfig.replenishCode;
22
+ if (!code) return null;
23
+ return {
24
+ code,
25
+ auto: process.env.SUMECLAW_REPLENISH_AUTO === "true" || channelConfig.replenishmentAuto !== false || channelConfig.replenishAuto === true,
26
+ platformUrl: process.env.SUMECLAW_PLATFORM_URL || channelConfig.platformUrl || channelConfig.wsUrl || DEFAULT_PLATFORM_URL,
27
+ instanceId: process.env.SUMECLAW_INSTANCE_ID || channelConfig.instanceId || channelConfig.openclawInstanceId,
28
+ desiredAgentId: process.env.SUMECLAW_AGENT_ID || channelConfig.defaultAgentId || channelConfig.desiredAgentId
29
+ };
30
+ }
31
+ async function postJson(url, body) {
32
+ const res = await fetch(url, {
33
+ method: "POST",
34
+ headers: { "Content-Type": "application/json" },
35
+ body: JSON.stringify(body)
36
+ });
37
+ const data = await res.json().catch(() => ({}));
38
+ if (!res.ok) {
39
+ throw new Error(data?.detail || data?.message || `HTTP ${res.status}`);
40
+ }
41
+ return data;
42
+ }
43
+ async function tryCreateOpenClawAgent(api, claim) {
44
+ const template = claim.agent_template ?? {};
45
+ const agentId = String(template.agent_id || claim.default_agent_id || "main");
46
+ const payload = {
47
+ id: agentId,
48
+ name: template.name || claim.display_name || "\u53CB\u867E\u5E93\u5B58\u667A\u80FD\u4F53",
49
+ description: template.description,
50
+ systemPrompt: template.system_prompt,
51
+ system_prompt: template.system_prompt
52
+ };
53
+ const runtime = api?.runtime;
54
+ const candidates = [
55
+ api?.agents?.create,
56
+ api?.agent?.create,
57
+ runtime?.agents?.create,
58
+ runtime?.agent?.create,
59
+ api?.createAgent
60
+ ].filter(Boolean);
61
+ if (candidates.length === 0) {
62
+ console.warn(
63
+ "[sumeclaw] \u26A0\uFE0F \u5F53\u524D OpenClaw \u63D2\u4EF6 API \u672A\u66B4\u9732\u521B\u5EFA Agent \u80FD\u529B\uFF0C\u4F7F\u7528\u540E\u53F0\u8FD4\u56DE\u7684 defaultAgentId \u7EE7\u7EED\u767B\u8BB0\u3002"
64
+ );
65
+ return agentId;
66
+ }
67
+ for (const create of candidates) {
68
+ try {
69
+ const result = await create.call(api?.agents ?? api?.agent ?? runtime?.agents ?? runtime?.agent ?? api, payload);
70
+ return String(result?.id || result?.agentId || agentId);
71
+ } catch (err) {
72
+ console.warn("[sumeclaw] \u26A0\uFE0F \u521B\u5EFA OpenClaw Agent \u5C1D\u8BD5\u5931\u8D25\uFF0C\u7EE7\u7EED\u5C1D\u8BD5\u5176\u4ED6 API", err);
73
+ }
74
+ }
75
+ throw new Error("OpenClaw Agent \u521B\u5EFA\u5931\u8D25");
76
+ }
77
+ async function persistAccountConfig(api, account) {
78
+ const cfg = api?.getConfig?.() ?? api?.config ?? {};
79
+ const existingSumeclaw = cfg.channels?.sumeclaw ?? {};
80
+ const {
81
+ replenishmentCode: _replenishmentCode,
82
+ replenishCode: _replenishCode,
83
+ ...sumeclawWithoutOneTimeCode
84
+ } = existingSumeclaw;
85
+ const nextCfg = {
86
+ ...cfg,
87
+ channels: {
88
+ ...cfg.channels ?? {},
89
+ sumeclaw: {
90
+ ...sumeclawWithoutOneTimeCode,
91
+ accounts: {
92
+ ...cfg.channels?.sumeclaw?.accounts ?? {},
93
+ [account.accountId]: {
94
+ botToken: account.botToken,
95
+ platformUrl: account.platformUrl,
96
+ defaultAgentId: account.defaultAgentId,
97
+ enabled: true
98
+ }
99
+ }
100
+ }
101
+ }
102
+ };
103
+ const writers = [
104
+ api?.setConfig,
105
+ api?.updateConfig,
106
+ api?.config?.set,
107
+ api?.runtime?.setConfig
108
+ ].filter(Boolean);
109
+ for (const writer of writers) {
110
+ try {
111
+ await writer.call(api, nextCfg);
112
+ console.log("[sumeclaw] \u2705 \u5DF2\u5199\u5165 OpenClaw sumeclaw account \u914D\u7F6E");
113
+ return true;
114
+ } catch (err) {
115
+ console.warn("[sumeclaw] \u26A0\uFE0F \u5199\u5165\u914D\u7F6E\u5C1D\u8BD5\u5931\u8D25\uFF0C\u7EE7\u7EED\u5C1D\u8BD5\u5176\u4ED6 API", err);
116
+ }
117
+ }
118
+ try {
119
+ if (api && typeof api === "object") {
120
+ api.config = nextCfg;
121
+ console.warn("[sumeclaw] \u26A0\uFE0F \u672A\u627E\u5230\u6301\u4E45\u5316\u914D\u7F6E API\uFF0C\u4EC5\u66F4\u65B0\u8FD0\u884C\u65F6\u5185\u5B58\u914D\u7F6E");
122
+ return false;
123
+ }
124
+ } catch {
125
+ }
126
+ console.warn("[sumeclaw] \u26A0\uFE0F \u672A\u80FD\u5199\u5165 OpenClaw \u914D\u7F6E\uFF1B\u8BF7\u624B\u52A8\u4FDD\u5B58 claim \u8FD4\u56DE\u7684 botToken");
127
+ return false;
128
+ }
129
+ async function runReplenishment(api) {
130
+ const cfg = resolveReplenishmentConfig(api);
131
+ if (!cfg) return null;
132
+ if (!cfg.auto) {
133
+ console.log("[sumeclaw] \u{1F4E6} \u68C0\u6D4B\u5230\u8865\u8D27\u7801\uFF0C\u4F46 replenishmentAuto=false\uFF0C\u8DF3\u8FC7\u81EA\u52A8\u8865\u8D27");
134
+ return null;
135
+ }
136
+ console.log("[sumeclaw] \u{1F4E6} \u68C0\u6D4B\u5230\u8865\u8D27\u7801\uFF0C\u5F00\u59CB\u5411\u53CB\u867E\u540E\u53F0\u9886\u53D6\u8865\u8D27\u4EFB\u52A1");
137
+ const httpBase = httpBaseFromWs(cfg.platformUrl);
138
+ const claim = await postJson(`${httpBase}/api/hired-agents/replenish/claim`, {
139
+ code: cfg.code,
140
+ instance_id: cfg.instanceId,
141
+ plugin_version: "1.2.3",
142
+ desired_agent_id: cfg.desiredAgentId
143
+ });
144
+ if (!claim.bot_token) {
145
+ throw new Error("\u540E\u53F0\u672A\u8FD4\u56DE botToken\uFF0C\u5F53\u524D sumeclaw \u4EC5\u652F\u6301 OpenClaw \u8865\u8D27");
146
+ }
147
+ let openclawAgentId = claim.default_agent_id;
148
+ try {
149
+ openclawAgentId = await tryCreateOpenClawAgent(api, claim);
150
+ } catch (err) {
151
+ await postJson(`${httpBase}/api/hired-agents/replenish/confirm`, {
152
+ inventory_id: claim.inventory_id,
153
+ openclaw_agent_id: claim.default_agent_id || "main",
154
+ ok: false,
155
+ error_message: String(err?.message || err)
156
+ });
157
+ throw err;
158
+ }
159
+ const account = {
160
+ accountId: claim.account_id || claim.inventory_id,
161
+ botToken: claim.bot_token,
162
+ platformUrl: claim.platform_url || cfg.platformUrl,
163
+ defaultAgentId: openclawAgentId,
164
+ enabled: true
165
+ };
166
+ await persistAccountConfig(api, account);
167
+ const confirm = await postJson(`${httpBase}/api/hired-agents/replenish/confirm`, {
168
+ inventory_id: claim.inventory_id,
169
+ openclaw_agent_id: openclawAgentId,
170
+ ok: true
171
+ });
172
+ console.log("[sumeclaw] \u2705 \u8865\u8D27\u786E\u8BA4\u5B8C\u6210", confirm);
173
+ return account;
174
+ }
175
+
176
+ // index.ts
9
177
  function isPluginManagementCommand() {
10
178
  const argv = process.argv.slice(2);
11
179
  const pluginIndex = argv.findIndex((arg) => arg === "plugin" || arg === "plugins");
@@ -40,13 +208,21 @@ function resolveAccounts(api) {
40
208
  }
41
209
  return {};
42
210
  }
43
- function startGatewayConnections(api) {
211
+ async function startGatewayConnections(api) {
44
212
  console.log("[sumeclaw] \u{1F680} registerFull() called");
45
213
  if (isPluginManagementCommand()) {
46
214
  console.log("[sumeclaw] \u{1F4A4} plugin management command detected, skip gateway connection");
47
215
  return;
48
216
  }
49
217
  const accounts = resolveAccounts(api);
218
+ try {
219
+ const replenishedAccount = await runReplenishment(api);
220
+ if (replenishedAccount) {
221
+ accounts[replenishedAccount.accountId] = replenishedAccount;
222
+ }
223
+ } catch (err) {
224
+ console.error("[sumeclaw] \u274C \u81EA\u52A8\u8865\u8D27\u5931\u8D25:", err);
225
+ }
50
226
  if (Object.keys(accounts).length === 0) {
51
227
  console.warn("[sumeclaw] \u26A0\uFE0F \u6CA1\u6709\u914D\u7F6E accounts \u6216 botToken\uFF0C\u63D2\u4EF6\u7A7A\u8F6C");
52
228
  return;
@@ -84,7 +260,7 @@ var entry = defineChannelPluginEntry({
84
260
  setSumeclawRuntime(runtime);
85
261
  },
86
262
  registerFull(api) {
87
- startGatewayConnections(api);
263
+ void startGatewayConnections(api);
88
264
  }
89
265
  });
90
266
  var index_default = entry;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../index.ts"],"sourcesContent":["/**\n * @sumeai/sumeclaw — OpenClaw Channel 插件入口\n */\n\nimport { defineChannelPluginEntry } from \"openclaw/plugin-sdk/channel-core\";\nimport { connectGateway } from \"./src/gateway.js\";\nimport { sumeclawPlugin } from \"./src/channel.js\";\nimport { setSumeclawRuntime } from \"./src/runtime.js\";\n\nfunction isPluginManagementCommand(): boolean {\n const argv = process.argv.slice(2);\n const pluginIndex = argv.findIndex((arg) => arg === \"plugin\" || arg === \"plugins\");\n if (pluginIndex === -1) return false;\n\n const subcommand = argv[pluginIndex + 1];\n return [\n \"add\",\n \"disable\",\n \"enable\",\n \"install\",\n \"list\",\n \"remove\",\n \"uninstall\",\n \"update\",\n ].includes(subcommand);\n}\n\nfunction resolveAccounts(api: any): Record<string, any> {\n const cfg = api.getConfig?.() ?? api.config ?? {};\n const channelConfig = cfg?.channels?.sumeclaw ?? {};\n\n if (channelConfig.accounts && Object.keys(channelConfig.accounts).length > 0) {\n return channelConfig.accounts;\n }\n\n if (channelConfig.botToken || channelConfig.token) {\n return {\n default: {\n botToken: channelConfig.botToken ?? channelConfig.token,\n platformUrl: channelConfig.platformUrl ?? channelConfig.wsUrl,\n enabled: channelConfig.enabled,\n defaultAgentId: channelConfig.defaultAgentId,\n },\n };\n }\n\n return {};\n}\n\nfunction startGatewayConnections(api: any) {\n console.log(\"[sumeclaw] 🚀 registerFull() called\");\n\n if (isPluginManagementCommand()) {\n console.log(\"[sumeclaw] 💤 plugin management command detected, skip gateway connection\");\n return;\n }\n\n const accounts = resolveAccounts(api);\n if (Object.keys(accounts).length === 0) {\n console.warn(\"[sumeclaw] ⚠️ 没有配置 accounts 或 botToken,插件空转\");\n return;\n }\n\n for (const [accountId, account] of Object.entries(accounts) as any) {\n if (account?.enabled === false) {\n console.log(`[sumeclaw] 💤 account disabled: ${accountId}`);\n continue;\n }\n\n const botToken = account?.botToken ?? account?.token;\n if (!botToken) {\n console.error(`[sumeclaw] ❌ account ${accountId} 缺少 botToken`);\n continue;\n }\n\n console.log(`[sumeclaw] 🔗 正在连接 account: ${accountId}`);\n\n try {\n connectGateway({\n accountId,\n platformUrl: account.platformUrl ?? account.wsUrl,\n botToken,\n defaultAgentId: account.defaultAgentId ?? account.agentId,\n api,\n });\n } catch (err) {\n console.error(\"[sumeclaw] ❌ 连接失败:\", err);\n }\n }\n}\n\nconst entry = defineChannelPluginEntry({\n id: \"sumeclaw\",\n name: \"友虾名片\",\n description: \"友虾名片 Channel\",\n plugin: sumeclawPlugin,\n setRuntime(runtime: any) {\n setSumeclawRuntime(runtime);\n },\n registerFull(api: any) {\n startGatewayConnections(api);\n },\n});\n\nexport default entry;\n"],"mappings":";;;;;;;AAIA,SAAS,gCAAgC;AAKzC,SAAS,4BAAqC;AAC5C,QAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,QAAM,cAAc,KAAK,UAAU,CAAC,QAAQ,QAAQ,YAAY,QAAQ,SAAS;AACjF,MAAI,gBAAgB,GAAI,QAAO;AAE/B,QAAM,aAAa,KAAK,cAAc,CAAC;AACvC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,SAAS,UAAU;AACvB;AAEA,SAAS,gBAAgB,KAA+B;AACtD,QAAM,MAAM,IAAI,YAAY,KAAK,IAAI,UAAU,CAAC;AAChD,QAAM,gBAAgB,KAAK,UAAU,YAAY,CAAC;AAElD,MAAI,cAAc,YAAY,OAAO,KAAK,cAAc,QAAQ,EAAE,SAAS,GAAG;AAC5E,WAAO,cAAc;AAAA,EACvB;AAEA,MAAI,cAAc,YAAY,cAAc,OAAO;AACjD,WAAO;AAAA,MACL,SAAS;AAAA,QACP,UAAU,cAAc,YAAY,cAAc;AAAA,QAClD,aAAa,cAAc,eAAe,cAAc;AAAA,QACxD,SAAS,cAAc;AAAA,QACvB,gBAAgB,cAAc;AAAA,MAChC;AAAA,IACF;AAAA,EACF;AAEA,SAAO,CAAC;AACV;AAEA,SAAS,wBAAwB,KAAU;AACzC,UAAQ,IAAI,4CAAqC;AAEjD,MAAI,0BAA0B,GAAG;AAC/B,YAAQ,IAAI,kFAA2E;AACvF;AAAA,EACF;AAEA,QAAM,WAAW,gBAAgB,GAAG;AACpC,MAAI,OAAO,KAAK,QAAQ,EAAE,WAAW,GAAG;AACtC,YAAQ,KAAK,yGAA6C;AAC1D;AAAA,EACF;AAEA,aAAW,CAAC,WAAW,OAAO,KAAK,OAAO,QAAQ,QAAQ,GAAU;AAClE,QAAI,SAAS,YAAY,OAAO;AAC9B,cAAQ,IAAI,0CAAmC,SAAS,EAAE;AAC1D;AAAA,IACF;AAEA,UAAM,WAAW,SAAS,YAAY,SAAS;AAC/C,QAAI,CAAC,UAAU;AACb,cAAQ,MAAM,6BAAwB,SAAS,wBAAc;AAC7D;AAAA,IACF;AAEA,YAAQ,IAAI,0DAA+B,SAAS,EAAE;AAEtD,QAAI;AACF,qBAAe;AAAA,QACb;AAAA,QACA,aAAa,QAAQ,eAAe,QAAQ;AAAA,QAC5C;AAAA,QACA,gBAAgB,QAAQ,kBAAkB,QAAQ;AAAA,QAClD;AAAA,MACF,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,cAAQ,MAAM,+CAAsB,GAAG;AAAA,IACzC;AAAA,EACF;AACF;AAEA,IAAM,QAAQ,yBAAyB;AAAA,EACrC,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,QAAQ;AAAA,EACR,WAAW,SAAc;AACvB,uBAAmB,OAAO;AAAA,EAC5B;AAAA,EACA,aAAa,KAAU;AACrB,4BAAwB,GAAG;AAAA,EAC7B;AACF,CAAC;AAED,IAAO,gBAAQ;","names":[]}
1
+ {"version":3,"sources":["../index.ts","../src/replenishment.ts"],"sourcesContent":["/**\n * @sumeai/sumeclaw — OpenClaw Channel 插件入口\n */\n\nimport { defineChannelPluginEntry } from \"openclaw/plugin-sdk/channel-core\";\nimport { connectGateway } from \"./src/gateway.js\";\nimport { sumeclawPlugin } from \"./src/channel.js\";\nimport { setSumeclawRuntime } from \"./src/runtime.js\";\nimport { runReplenishment } from \"./src/replenishment.js\";\n\nfunction isPluginManagementCommand(): boolean {\n const argv = process.argv.slice(2);\n const pluginIndex = argv.findIndex((arg) => arg === \"plugin\" || arg === \"plugins\");\n if (pluginIndex === -1) return false;\n\n const subcommand = argv[pluginIndex + 1];\n return [\n \"add\",\n \"disable\",\n \"enable\",\n \"install\",\n \"list\",\n \"remove\",\n \"uninstall\",\n \"update\",\n ].includes(subcommand);\n}\n\nfunction resolveAccounts(api: any): Record<string, any> {\n const cfg = api.getConfig?.() ?? api.config ?? {};\n const channelConfig = cfg?.channels?.sumeclaw ?? {};\n\n if (channelConfig.accounts && Object.keys(channelConfig.accounts).length > 0) {\n return channelConfig.accounts;\n }\n\n if (channelConfig.botToken || channelConfig.token) {\n return {\n default: {\n botToken: channelConfig.botToken ?? channelConfig.token,\n platformUrl: channelConfig.platformUrl ?? channelConfig.wsUrl,\n enabled: channelConfig.enabled,\n defaultAgentId: channelConfig.defaultAgentId,\n },\n };\n }\n\n return {};\n}\n\nasync function startGatewayConnections(api: any) {\n console.log(\"[sumeclaw] 🚀 registerFull() called\");\n\n if (isPluginManagementCommand()) {\n console.log(\"[sumeclaw] 💤 plugin management command detected, skip gateway connection\");\n return;\n }\n\n const accounts = resolveAccounts(api);\n try {\n const replenishedAccount = await runReplenishment(api);\n if (replenishedAccount) {\n accounts[replenishedAccount.accountId] = replenishedAccount;\n }\n } catch (err) {\n console.error(\"[sumeclaw] ❌ 自动补货失败:\", err);\n }\n\n if (Object.keys(accounts).length === 0) {\n console.warn(\"[sumeclaw] ⚠️ 没有配置 accounts 或 botToken,插件空转\");\n return;\n }\n\n for (const [accountId, account] of Object.entries(accounts) as any) {\n if (account?.enabled === false) {\n console.log(`[sumeclaw] 💤 account disabled: ${accountId}`);\n continue;\n }\n\n const botToken = account?.botToken ?? account?.token;\n if (!botToken) {\n console.error(`[sumeclaw] ❌ account ${accountId} 缺少 botToken`);\n continue;\n }\n\n console.log(`[sumeclaw] 🔗 正在连接 account: ${accountId}`);\n\n try {\n connectGateway({\n accountId,\n platformUrl: account.platformUrl ?? account.wsUrl,\n botToken,\n defaultAgentId: account.defaultAgentId ?? account.agentId,\n api,\n });\n } catch (err) {\n console.error(\"[sumeclaw] ❌ 连接失败:\", err);\n }\n }\n}\n\nconst entry = defineChannelPluginEntry({\n id: \"sumeclaw\",\n name: \"友虾名片\",\n description: \"友虾名片 Channel\",\n plugin: sumeclawPlugin,\n setRuntime(runtime: any) {\n setSumeclawRuntime(runtime);\n },\n registerFull(api: any) {\n void startGatewayConnections(api);\n },\n});\n\nexport default entry;\n","// @ts-nocheck\n\ntype ReplenishAccount = {\n accountId: string;\n botToken: string;\n platformUrl?: string;\n defaultAgentId?: string;\n enabled: boolean;\n};\n\nconst DEFAULT_PLATFORM_URL = \"wss://api.gixin.cc\";\n\nfunction httpBaseFromWs(platformUrl: string) {\n return platformUrl\n .replace(/^wss:\\/\\//, \"https://\")\n .replace(/^ws:\\/\\//, \"http://\")\n .replace(/\\/$/, \"\");\n}\n\nfunction resolveChannelConfig(api: any) {\n const cfg = api?.getConfig?.() ?? api?.config ?? {};\n return cfg?.channels?.sumeclaw ?? {};\n}\n\nexport function resolveReplenishmentConfig(api: any) {\n const channelConfig = resolveChannelConfig(api);\n const code =\n process.env.SUMECLAW_REPLENISH_CODE ||\n channelConfig.replenishmentCode ||\n channelConfig.replenishCode;\n if (!code) return null;\n\n return {\n code,\n auto:\n process.env.SUMECLAW_REPLENISH_AUTO === \"true\" ||\n channelConfig.replenishmentAuto !== false ||\n channelConfig.replenishAuto === true,\n platformUrl:\n process.env.SUMECLAW_PLATFORM_URL ||\n channelConfig.platformUrl ||\n channelConfig.wsUrl ||\n DEFAULT_PLATFORM_URL,\n instanceId:\n process.env.SUMECLAW_INSTANCE_ID ||\n channelConfig.instanceId ||\n channelConfig.openclawInstanceId,\n desiredAgentId:\n process.env.SUMECLAW_AGENT_ID ||\n channelConfig.defaultAgentId ||\n channelConfig.desiredAgentId,\n };\n}\n\nasync function postJson(url: string, body: any) {\n const res = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n const data = await res.json().catch(() => ({}));\n if (!res.ok) {\n throw new Error(data?.detail || data?.message || `HTTP ${res.status}`);\n }\n return data;\n}\n\nasync function tryCreateOpenClawAgent(api: any, claim: any) {\n const template = claim.agent_template ?? {};\n const agentId = String(template.agent_id || claim.default_agent_id || \"main\");\n const payload = {\n id: agentId,\n name: template.name || claim.display_name || \"友虾库存智能体\",\n description: template.description,\n systemPrompt: template.system_prompt,\n system_prompt: template.system_prompt,\n };\n\n const runtime = api?.runtime;\n const candidates = [\n api?.agents?.create,\n api?.agent?.create,\n runtime?.agents?.create,\n runtime?.agent?.create,\n api?.createAgent,\n ].filter(Boolean);\n\n if (candidates.length === 0) {\n console.warn(\n \"[sumeclaw] ⚠️ 当前 OpenClaw 插件 API 未暴露创建 Agent 能力,使用后台返回的 defaultAgentId 继续登记。\",\n );\n return agentId;\n }\n\n for (const create of candidates) {\n try {\n const result = await create.call(api?.agents ?? api?.agent ?? runtime?.agents ?? runtime?.agent ?? api, payload);\n return String(result?.id || result?.agentId || agentId);\n } catch (err) {\n console.warn(\"[sumeclaw] ⚠️ 创建 OpenClaw Agent 尝试失败,继续尝试其他 API\", err);\n }\n }\n\n throw new Error(\"OpenClaw Agent 创建失败\");\n}\n\nasync function persistAccountConfig(api: any, account: ReplenishAccount) {\n const cfg = api?.getConfig?.() ?? api?.config ?? {};\n const existingSumeclaw = cfg.channels?.sumeclaw ?? {};\n const {\n replenishmentCode: _replenishmentCode,\n replenishCode: _replenishCode,\n ...sumeclawWithoutOneTimeCode\n } = existingSumeclaw;\n const nextCfg = {\n ...cfg,\n channels: {\n ...(cfg.channels ?? {}),\n sumeclaw: {\n ...sumeclawWithoutOneTimeCode,\n accounts: {\n ...(cfg.channels?.sumeclaw?.accounts ?? {}),\n [account.accountId]: {\n botToken: account.botToken,\n platformUrl: account.platformUrl,\n defaultAgentId: account.defaultAgentId,\n enabled: true,\n },\n },\n },\n },\n };\n\n const writers = [\n api?.setConfig,\n api?.updateConfig,\n api?.config?.set,\n api?.runtime?.setConfig,\n ].filter(Boolean);\n\n for (const writer of writers) {\n try {\n await writer.call(api, nextCfg);\n console.log(\"[sumeclaw] ✅ 已写入 OpenClaw sumeclaw account 配置\");\n return true;\n } catch (err) {\n console.warn(\"[sumeclaw] ⚠️ 写入配置尝试失败,继续尝试其他 API\", err);\n }\n }\n\n try {\n if (api && typeof api === \"object\") {\n api.config = nextCfg;\n console.warn(\"[sumeclaw] ⚠️ 未找到持久化配置 API,仅更新运行时内存配置\");\n return false;\n }\n } catch {}\n\n console.warn(\"[sumeclaw] ⚠️ 未能写入 OpenClaw 配置;请手动保存 claim 返回的 botToken\");\n return false;\n}\n\nexport async function runReplenishment(api: any): Promise<ReplenishAccount | null> {\n const cfg = resolveReplenishmentConfig(api);\n if (!cfg) return null;\n if (!cfg.auto) {\n console.log(\"[sumeclaw] 📦 检测到补货码,但 replenishmentAuto=false,跳过自动补货\");\n return null;\n }\n\n console.log(\"[sumeclaw] 📦 检测到补货码,开始向友虾后台领取补货任务\");\n\n const httpBase = httpBaseFromWs(cfg.platformUrl);\n const claim = await postJson(`${httpBase}/api/hired-agents/replenish/claim`, {\n code: cfg.code,\n instance_id: cfg.instanceId,\n plugin_version: \"1.2.3\",\n desired_agent_id: cfg.desiredAgentId,\n });\n\n if (!claim.bot_token) {\n throw new Error(\"后台未返回 botToken,当前 sumeclaw 仅支持 OpenClaw 补货\");\n }\n\n let openclawAgentId = claim.default_agent_id;\n try {\n openclawAgentId = await tryCreateOpenClawAgent(api, claim);\n } catch (err) {\n await postJson(`${httpBase}/api/hired-agents/replenish/confirm`, {\n inventory_id: claim.inventory_id,\n openclaw_agent_id: claim.default_agent_id || \"main\",\n ok: false,\n error_message: String(err?.message || err),\n });\n throw err;\n }\n\n const account: ReplenishAccount = {\n accountId: claim.account_id || claim.inventory_id,\n botToken: claim.bot_token,\n platformUrl: claim.platform_url || cfg.platformUrl,\n defaultAgentId: openclawAgentId,\n enabled: true,\n };\n\n await persistAccountConfig(api, account);\n\n const confirm = await postJson(`${httpBase}/api/hired-agents/replenish/confirm`, {\n inventory_id: claim.inventory_id,\n openclaw_agent_id: openclawAgentId,\n ok: true,\n });\n\n console.log(\"[sumeclaw] ✅ 补货确认完成\", confirm);\n return account;\n}\n"],"mappings":"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","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  sumeclawPlugin
3
- } from "./chunk-RIUKFLMY.js";
3
+ } from "./chunk-ZMTWCTB4.js";
4
4
 
5
5
  // setup-entry.ts
6
6
  import { defineSetupPluginEntry } from "openclaw/plugin-sdk/channel-core";
@@ -18,6 +18,8 @@
18
18
  "channelEnvVars": {
19
19
  "sumeclaw": [
20
20
  "SUMECLAW_BOT_TOKEN"
21
+ ,"SUMECLAW_REPLENISH_CODE"
22
+ ,"SUMECLAW_REPLENISH_AUTO"
21
23
  ]
22
24
  },
23
25
  "configSchema": {
@@ -41,6 +43,15 @@
41
43
  "type": "string",
42
44
  "description": "插件注册时上报的默认 OpenClaw 智能体 ID,实际对话以友虾后台 payload 中的 agentId 为准",
43
45
  "default": "main"
46
+ },
47
+ "replenishmentCode": {
48
+ "type": "string",
49
+ "description": "友虾后台生成的补货码,用于自动补充可雇佣智能体库存"
50
+ },
51
+ "replenishmentAuto": {
52
+ "type": "boolean",
53
+ "description": "启动时是否自动使用补货码领取库存任务",
54
+ "default": true
44
55
  }
45
56
  }
46
57
  },
@@ -89,6 +100,14 @@
89
100
  "defaultAgentId": {
90
101
  "type": "string",
91
102
  "default": "main"
103
+ },
104
+ "replenishmentCode": {
105
+ "type": "string",
106
+ "description": "友虾后台生成的补货码,用于自动补充可雇佣智能体库存"
107
+ },
108
+ "replenishmentAuto": {
109
+ "type": "boolean",
110
+ "default": true
92
111
  }
93
112
  }
94
113
  },
@@ -108,6 +127,11 @@
108
127
  "label": "默认 OpenClaw 智能体 ID",
109
128
  "placeholder": "main",
110
129
  "advanced": true
130
+ },
131
+ "replenishmentCode": {
132
+ "label": "友虾补货码",
133
+ "placeholder": "在友虾轻后台生成的补货码",
134
+ "sensitive": true
111
135
  }
112
136
  },
113
137
  "commands": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sumeai/sumeclaw",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "description": "友虾名片 OpenClaw Channel 插件 — 将 OpenClaw 连接到友虾名片平台,通过 AI 名片为客户提供服务",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -38,12 +38,12 @@
38
38
  "blurb": "将 OpenClaw 连接到友虾名片平台,通过 AI 名片为客户提供服务"
39
39
  },
40
40
  "compat": {
41
- "pluginApi": ">=2026.6.8",
42
- "minGatewayVersion": ">=2026.6.8"
41
+ "pluginApi": ">=2026.5.8",
42
+ "minGatewayVersion": ">=2026.5.8"
43
43
  },
44
44
  "install": {
45
45
  "npmSpec": "@sumeai/sumeclaw",
46
- "minHostVersion": ">=2026.6.8"
46
+ "minHostVersion": ">=2026.5.8"
47
47
  },
48
48
  "startup": {
49
49
  "deferConfiguredChannelFullLoadUntilAfterListen": true
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/runtime.ts","../src/gateway.ts","../src/channel.ts"],"sourcesContent":["let runtimeRef: any = null;\n\nexport function setSumeclawRuntime(runtime: any) {\n runtimeRef = runtime;\n}\n\nexport function tryGetSumeclawRuntime() {\n return runtimeRef;\n}\n","\n/**\n * 友虾名片 OpenClaw Channel 插件 — Gateway 层\n *\n * WebSocket 连接管理:\n * - 出站连接到 wss://api.gixin.cc/api/channel/{botToken}\n * - 心跳保活(30s 间隔)\n * - 断线自动重连(指数退避,最大 60s)\n * - 平台下发的消息注入 OpenClaw Agent\n * - Agent 回复通过 WS 推回平台\n */\n\nimport WebSocket from \"ws\";\nimport { dispatchInboundDirectDmWithRuntime } from \"openclaw/plugin-sdk/direct-dm\";\nimport { tryGetSumeclawRuntime } from \"./runtime.js\";\n\n/**\n * 全局 WS 管理\n */\nconst wsMap: Record<string, WebSocket> = {};\n\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport { readFileSync } from \"fs\";\nimport { fileURLToPath } from \"url\";\nimport { dirname, join } from \"path\";\n\n// const __filename = fileURLToPath(import.meta.url);\n// const __dirname = dirname(__filename);\n// const pkg = JSON.parse(readFileSync(join(__dirname, \"..\", \"..\", \"package.json\"), \"utf-8\"));\n\n// ─── 配置常量 ────────────────────────────────────────────────────────────────\n\nconst DEFAULT_PLATFORM_URL = \"wss://api.gixin.cc\";\nconst HEARTBEAT_MS = 30_000;\nconst MAX_RECONNECT_MS = 60_000;\nconst BASE_BACKOFF_MS = 1_000;\n\n// ─── 连接池 ──────────────────────────────────────────────────────────────────\n\n/** key: accountId → WebSocket */\nconst connections = new Map<string, WebSocket>();\nconst connectingAccounts = new Set<string>();\nconst pendingReplyContexts = new Map<\n string,\n {\n requestId?: string;\n sessionKey: string;\n stream?: boolean;\n accumulatedText: string;\n }\n>();\n\nfunction replyContextKey(accountId: string, userId: string): string {\n return `${accountId}:${userId}`;\n}\n\nexport function getWebSocket(accountId: string): WebSocket | undefined {\n return connections.get(accountId);\n}\n\nexport function rememberPendingReplyContext(params: {\n accountId: string;\n userId: string;\n requestId?: string;\n sessionKey: string;\n stream?: boolean;\n}) {\n const key = replyContextKey(params.accountId, params.userId);\n pendingReplyContexts.set(replyContextKey(params.accountId, params.userId), {\n requestId: params.requestId,\n sessionKey: params.sessionKey,\n stream: params.stream,\n accumulatedText: \"\",\n });\n}\n\nexport function getPendingReplyContext(accountId: string, userId: string) {\n return pendingReplyContexts.get(replyContextKey(accountId, userId));\n}\n\nexport function consumePendingReplyContext(accountId: string, userId: string) {\n const key = replyContextKey(accountId, userId);\n const ctx = pendingReplyContexts.get(key);\n pendingReplyContexts.delete(key);\n return ctx;\n}\n\nexport function appendPendingReplyText(accountId: string, userId: string, text: string) {\n const ctx = getPendingReplyContext(accountId, userId);\n if (!ctx) return \"\";\n\n if (!ctx.accumulatedText) {\n ctx.accumulatedText = text;\n } else if (text.startsWith(ctx.accumulatedText)) {\n ctx.accumulatedText = text;\n } else if (!ctx.accumulatedText.endsWith(text)) {\n ctx.accumulatedText += text;\n }\n\n return ctx.accumulatedText;\n}\n\n// ─── 连接逻辑 ────────────────────────────────────────────────────────────────\n\nexport interface MinicardAccount {\n botToken?: string;\n platformUrl?: string;\n enabled?: boolean;\n}\n\n\n\n\ntype ConnectOptions = {\n accountId: string;\n platformUrl?: string;\n botToken: string;\n defaultAgentId?: string;\n api: any;\n};\n\nexport function connectGateway(opts: ConnectOptions) {\n const { accountId, botToken, api } = opts;\n const platformUrl = opts.platformUrl || DEFAULT_PLATFORM_URL;\n const defaultAgentId = opts.defaultAgentId || \"main\";\n\n const existing = connections.get(accountId);\n if (\n existing &&\n (existing.readyState === WebSocket.OPEN ||\n existing.readyState === WebSocket.CONNECTING)\n ) {\n console.log(`[sumeclaw] ♻️ reuse existing connection: ${accountId}`);\n return;\n }\n\n if (connectingAccounts.has(accountId)) {\n console.log(`[sumeclaw] ♻️ connection already starting: ${accountId}`);\n return;\n }\n\n let ws: WebSocket | null = null;\n let heartbeatTimer: NodeJS.Timeout | null = null;\n let reconnectTimer: NodeJS.Timeout | null = null;\n\n const HEARTBEAT_INTERVAL = 30_000;\n const RECONNECT_DELAY = 5_000;\n\n function start() {\n \n const url = `${platformUrl.replace(/\\/$/, \"\")}/api/channel/${botToken}`;\n console.log(`[sumeclaw] 🌐 connecting -> ${url} (${accountId})`);\n\n connectingAccounts.add(accountId);\n ws = new WebSocket(url);\n connections.set(accountId, ws);\n \n\n ws.on(\"open\", () => {\n console.log(`[sumeclaw] ✅ connected: ${accountId}`);\n connectingAccounts.delete(accountId);\n connections.set(accountId, ws as WebSocket);\n\n // 🔐 上报本地插件/Agent 信息。平台端会据此刷新在线状态。\n ws?.send(\n JSON.stringify({\n type: \"register_info\",\n token: botToken,\n agentId: defaultAgentId,\n version: \"1.2.0\",\n })\n );\n\n // ❤️ 心跳\n heartbeatTimer = setInterval(() => {\n if (ws?.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify({ type: \"heartbeat\" }));\n }\n }, HEARTBEAT_INTERVAL);\n });\n\n ws.on(\"message\", (data) => {\n try {\n const msg = JSON.parse(data.toString());\n\n // 🔍 调试\n console.log(\"[sumeclaw] 📩 message:\", msg);\n\n handleMessage(msg).catch((err) => {\n console.error(\"[sumeclaw] ❌ handle message error\", err);\n });\n } catch (err) {\n console.error(\"[sumeclaw] ❌ parse message error\", err);\n }\n });\n\n ws.on(\"close\", (code, reasonBuffer) => {\n const reason = reasonBuffer.toString();\n console.warn(`[sumeclaw] ⚠️ disconnected: ${accountId}`, { code, reason });\n cleanup();\n if (code === 4000 || reason.includes(\"replaced by a newer OpenClaw plugin connection\")) {\n console.warn(`[sumeclaw] 🛑 connection replaced, stop reconnecting: ${accountId}`);\n return;\n }\n scheduleReconnect();\n });\n\n ws.on(\"error\", (err) => {\n console.error(`[sumeclaw] ❌ ws error: ${accountId}`, err);\n connectingAccounts.delete(accountId);\n ws?.close();\n });\n }\n\n async function handleMessage(msg: any) {\n switch (msg.type) {\n case \"heartbeat_ack\":\n // 心跳回应\n break;\n\n case \"hooks_agent\":\n await handleHooksAgent(msg.payload ?? msg);\n break;\n\n case \"message\":\n // 👉 这里接入 OpenClaw\n console.log(\"[sumeclaw] 💬 收到消息:\", msg);\n\n await dispatchToOpenClaw({\n agentId: msg.agentId || \"main\",\n message: msg.text || msg.message || \"\",\n messageId: msg.id || msg.messageId,\n sessionKey:\n msg.sessionKey ||\n `agent:${msg.agentId || \"main\"}:user:${msg.from || msg.userId || \"unknown\"}`,\n userId: msg.from || msg.userId || msg.senderId || \"unknown\",\n raw: msg,\n requestId: msg.requestId,\n stream: Boolean(msg.stream),\n });\n\n break;\n\n case \"registered\":\n console.log(`[sumeclaw] 🔐 注册成功: ${accountId}`);\n break;\n\n default:\n console.log(\"[sumeclaw] ❓ 未处理消息:\", msg);\n }\n }\n\n async function handleHooksAgent(payload: any) {\n const meta = payload?.meta ?? {};\n const userId = String(meta.user_id || payload.userId || payload.from || \"unknown\");\n const agentId = String(payload.agentId || meta.agent_id || \"main\");\n const text = String(payload.message || payload.text || \"\");\n const sessionKey =\n payload.sessionKey || `agent:${agentId}:user:${userId}`;\n\n console.log(\"[sumeclaw] 🧠 hooks_agent -> OpenClaw\", {\n accountId,\n agentId,\n sessionKey,\n userId,\n text: text.slice(0, 100),\n });\n\n rememberPendingReplyContext({\n accountId,\n userId,\n requestId: payload.requestId,\n sessionKey,\n stream: Boolean(payload.stream),\n });\n\n await dispatchToOpenClaw({\n agentId,\n message: text,\n messageId: payload.messageId || `${sessionKey}:${Date.now()}`,\n sessionKey,\n userId,\n raw: payload,\n requestId: payload.requestId,\n stream: Boolean(payload.stream),\n });\n }\n\n function sendAgentReply(input: {\n requestId?: string;\n userId: string;\n sessionKey: string;\n text: string;\n ok?: boolean;\n messageId?: string;\n }) {\n const activeWs = connections.get(accountId) ?? ws;\n if (!activeWs || activeWs.readyState !== WebSocket.OPEN) {\n console.error(\"[sumeclaw] ❌ cannot send agent_reply, websocket is not open\", {\n accountId,\n requestId: input.requestId,\n readyState: activeWs?.readyState,\n });\n return false;\n }\n\n activeWs.send(\n JSON.stringify({\n type: \"agent_reply\",\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text: input.text,\n messageId: input.messageId ?? `sumeclaw-${Date.now()}`,\n ok: input.ok ?? true,\n }),\n );\n console.log(\"[sumeclaw] 📤 agent_reply sent\", {\n accountId,\n requestId: input.requestId,\n userId: input.userId,\n textLength: input.text.length,\n });\n return true;\n }\n\n function sendAgentDelta(input: {\n requestId?: string;\n userId: string;\n sessionKey: string;\n text: string;\n messageId?: string;\n }) {\n const activeWs = connections.get(accountId) ?? ws;\n if (!activeWs || activeWs.readyState !== WebSocket.OPEN) {\n console.error(\"[sumeclaw] ❌ cannot send agent_delta, websocket is not open\", {\n accountId,\n requestId: input.requestId,\n readyState: activeWs?.readyState,\n });\n return false;\n }\n\n activeWs.send(\n JSON.stringify({\n type: \"agent_delta\",\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text: input.text,\n messageId: input.messageId ?? `sumeclaw-${Date.now()}`,\n }),\n );\n console.log(\"[sumeclaw] 📤 agent_delta sent\", {\n accountId,\n requestId: input.requestId,\n userId: input.userId,\n textLength: input.text.length,\n });\n return true;\n }\n\n function sendAgentDone(input: {\n requestId?: string;\n userId: string;\n sessionKey: string;\n text: string;\n ok?: boolean;\n messageId?: string;\n }) {\n const activeWs = connections.get(accountId) ?? ws;\n if (!activeWs || activeWs.readyState !== WebSocket.OPEN) {\n console.error(\"[sumeclaw] ❌ cannot send agent_done, websocket is not open\", {\n accountId,\n requestId: input.requestId,\n readyState: activeWs?.readyState,\n });\n return false;\n }\n\n activeWs.send(\n JSON.stringify({\n type: \"agent_done\",\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text: input.text,\n messageId: input.messageId ?? `sumeclaw-${Date.now()}`,\n ok: input.ok ?? true,\n }),\n );\n console.log(\"[sumeclaw] 📤 agent_done sent\", {\n accountId,\n requestId: input.requestId,\n userId: input.userId,\n textLength: input.text.length,\n });\n return true;\n }\n\n function finishStreamReply(input: {\n requestId?: string;\n userId: string;\n sessionKey: string;\n ok?: boolean;\n }) {\n const latest = consumePendingReplyContext(accountId, input.userId);\n if (!latest) {\n console.warn(\"[sumeclaw] ⚠️ no pending stream context to finish\", {\n accountId,\n requestId: input.requestId,\n userId: input.userId,\n });\n return false;\n }\n\n return sendAgentDone({\n requestId: latest.requestId ?? input.requestId,\n userId: input.userId,\n sessionKey: latest.sessionKey ?? input.sessionKey,\n text: latest.accumulatedText,\n ok: input.ok,\n });\n }\n\n function finishBufferedReply(input: {\n requestId?: string;\n userId: string;\n sessionKey: string;\n ok?: boolean;\n }) {\n const latest = consumePendingReplyContext(accountId, input.userId);\n if (!latest) {\n console.warn(\"[sumeclaw] ⚠️ no pending reply context to finish\", {\n accountId,\n requestId: input.requestId,\n userId: input.userId,\n });\n return false;\n }\n\n return sendAgentReply({\n requestId: latest.requestId ?? input.requestId,\n userId: input.userId,\n sessionKey: latest.sessionKey ?? input.sessionKey,\n text: latest.accumulatedText,\n ok: input.ok,\n });\n }\n\n async function dispatchToOpenClaw(input: {\n agentId: string;\n message: string;\n messageId?: string;\n sessionKey: string;\n userId: string;\n raw: any;\n requestId?: string;\n stream?: boolean;\n }) {\n const runtime = tryGetSumeclawRuntime() ?? api?.runtime;\n const turn = runtime?.channel?.turn;\n\n if (!turn?.run) {\n const directReplyDispatcher = runtime?.channel?.reply?.dispatchReplyWithBufferedBlockDispatcher;\n if (directReplyDispatcher) {\n await dispatchViaDirectDmRuntime(runtime, input);\n return;\n }\n\n console.error(\n \"[sumeclaw] ❌ 当前 OpenClaw runtime 不提供可用的 channel 入站分发能力\",\n );\n console.error(\"[sumeclaw] runtime debug:\", {\n hasStoredRuntime: Boolean(tryGetSumeclawRuntime()),\n apiKeys: api ? Object.keys(api) : [],\n runtimeKeys: runtime ? Object.keys(runtime) : [],\n channelKeys: runtime?.channel ? Object.keys(runtime.channel) : [],\n });\n sendAgentReply({\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text: \"OpenClaw 插件未获得运行时分发能力,请升级插件入口后重启 OpenClaw Gateway。\",\n ok: false,\n });\n return;\n }\n\n const now = Date.now();\n const messageId = String(input.messageId || `${input.sessionKey}:${now}`);\n const senderLabel = `友虾用户 ${input.userId}`;\n\n try {\n const result = await turn.run({\n channel: \"sumeclaw\",\n accountId,\n raw: input.raw,\n adapter: {\n ingest() {\n return {\n id: messageId,\n timestamp: now,\n rawText: input.message,\n textForAgent: input.message,\n textForCommands: input.message,\n raw: input.raw,\n };\n },\n classify(turnInput: any) {\n return {\n kind: \"message\",\n canStartAgentTurn: Boolean(turnInput.rawText),\n };\n },\n resolveTurn(turnInput: any) {\n return {\n sender: {\n id: input.userId,\n name: senderLabel,\n displayLabel: senderLabel,\n isBot: false,\n isSelf: false,\n },\n conversation: {\n kind: \"direct\",\n id: input.userId,\n label: senderLabel,\n routePeer: input.userId,\n },\n route: {\n agentId: input.agentId,\n accountId,\n routeSessionKey: input.sessionKey,\n dispatchSessionKey: input.sessionKey,\n persistedSessionKey: input.sessionKey,\n mainSessionKey: input.sessionKey,\n createIfMissing: true,\n },\n reply: {\n to: input.userId,\n originatingTo: input.userId,\n replyTarget: input.userId,\n sourceReplyDeliveryMode: \"direct\",\n },\n access: {\n dm: {\n policy: \"open\",\n allowed: true,\n allowFrom: [],\n },\n group: {\n isGroup: false,\n routeAllowed: true,\n senderAllowed: true,\n requireMention: false,\n },\n commands: {\n authorized: true,\n },\n mentions: {\n canDetectMention: false,\n wasMentioned: true,\n },\n },\n message: {\n body: turnInput.rawText,\n rawBody: turnInput.rawText,\n bodyForAgent: turnInput.textForAgent,\n commandBody: turnInput.textForCommands,\n envelopeFrom: senderLabel,\n senderLabel,\n preview: turnInput.rawText.slice(0, 120),\n },\n delivery: {\n deliver: async (payload: any) => {\n const text = String(payload?.text || payload?.body || \"\");\n if (!text) return { visibleReplySent: false };\n const replyId = `sumeclaw-${Date.now()}`;\n if (input.stream) {\n appendPendingReplyText(accountId, input.userId, text);\n sendAgentDelta({\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text,\n messageId: replyId,\n });\n } else {\n appendPendingReplyText(accountId, input.userId, text);\n }\n return {\n messageIds: [replyId],\n visibleReplySent: true,\n };\n },\n onError(err: unknown) {\n console.error(\"[sumeclaw] ❌ deliver error\", err);\n },\n },\n };\n },\n },\n });\n\n console.log(\"[sumeclaw] ✅ OpenClaw turn dispatched\", result?.admission ?? \"\");\n if (input.stream) {\n finishStreamReply(input);\n } else {\n finishBufferedReply(input);\n }\n } catch (err) {\n console.error(\"[sumeclaw] ❌ OpenClaw turn dispatch failed\", err);\n sendAgentReply({\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text: \"OpenClaw 本地处理消息失败,请稍后再试。\",\n ok: false,\n });\n }\n }\n\n async function dispatchViaDirectDmRuntime(runtime: any, input: {\n agentId: string;\n message: string;\n messageId?: string;\n sessionKey: string;\n userId: string;\n raw: any;\n requestId?: string;\n stream?: boolean;\n }) {\n const now = Date.now();\n const messageId = String(input.messageId || `${input.sessionKey}:${now}`);\n const senderLabel = `友虾用户 ${input.userId}`;\n const baseCfg = api?.getConfig?.() ?? api?.config ?? runtime?.config ?? {};\n const cfg = input.stream\n ? {\n ...baseCfg,\n agents: {\n ...(baseCfg.agents ?? {}),\n defaults: {\n ...(baseCfg.agents?.defaults ?? {}),\n blockStreamingDefault: \"on\",\n blockStreamingBreak: \"text_end\",\n blockStreamingChunk: {\n minChars: 12,\n maxChars: 80,\n breakPreference: \"sentence\",\n ...(baseCfg.agents?.defaults?.blockStreamingChunk ?? {}),\n },\n },\n },\n channels: {\n ...(baseCfg.channels ?? {}),\n sumeclaw: {\n ...(baseCfg.channels?.sumeclaw ?? {}),\n blockStreaming: true,\n },\n },\n }\n : baseCfg;\n\n try {\n await dispatchInboundDirectDmWithRuntime({\n cfg,\n runtime,\n channel: \"sumeclaw\",\n channelLabel: \"友虾名片\",\n accountId,\n peer: {\n kind: \"direct\",\n id: input.userId,\n },\n senderId: input.userId,\n senderAddress: input.userId,\n recipientAddress: \"sumeclaw\",\n conversationLabel: senderLabel,\n rawBody: input.message,\n messageId,\n timestamp: now,\n bodyForAgent: input.message,\n commandBody: input.message,\n commandAuthorized: true,\n provider: \"sumeclaw\",\n surface: \"sumeclaw\",\n originatingChannel: \"sumeclaw\",\n originatingTo: input.userId,\n extraContext: {\n AccountId: accountId,\n RouteAgentId: input.agentId,\n RequestId: input.requestId,\n },\n deliver: async (payload: any) => {\n const text = String(payload?.text || payload?.body || \"\");\n if (!text) return { visibleReplySent: false };\n\n const replyId = `sumeclaw-${Date.now()}`;\n if (input.stream) {\n appendPendingReplyText(accountId, input.userId, text);\n sendAgentDelta({\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text,\n messageId: replyId,\n });\n } else {\n appendPendingReplyText(accountId, input.userId, text);\n }\n\n return {\n messageIds: [replyId],\n visibleReplySent: true,\n };\n },\n onDispatchError: (err: unknown) => {\n console.error(\"[sumeclaw] ❌ Direct DM dispatch error\", err);\n },\n onRecordError: (err: unknown) => {\n console.error(\"[sumeclaw] ❌ Direct DM record error\", err);\n },\n });\n\n console.log(\"[sumeclaw] ✅ OpenClaw Direct DM dispatched\");\n if (input.stream) {\n finishStreamReply(input);\n } else {\n finishBufferedReply(input);\n }\n } catch (err) {\n console.error(\"[sumeclaw] ❌ Direct DM dispatch failed\", err);\n sendAgentReply({\n requestId: input.requestId,\n userId: input.userId,\n sessionKey: input.sessionKey,\n text: \"OpenClaw 本地处理消息失败,请稍后再试。\",\n ok: false,\n });\n }\n }\n\n function cleanup() {\n connectingAccounts.delete(accountId);\n if (heartbeatTimer) {\n clearInterval(heartbeatTimer);\n heartbeatTimer = null;\n }\n if (connections.get(accountId) === ws) {\n connections.delete(accountId);\n }\n }\n\n function scheduleReconnect() {\n if (reconnectTimer) return;\n\n console.log(`[sumeclaw] 🔁 reconnecting in ${RECONNECT_DELAY / 1000}s`);\n\n reconnectTimer = setTimeout(() => {\n reconnectTimer = null;\n start();\n }, RECONNECT_DELAY);\n }\n\n start();\n}\n","// @ts-nocheck\n/**\n * 友虾名片 ChannelPlugin 核心定义\n *\n * 基于新版 plugin-sdk(2026.3.22+)的 createChatChannelPlugin API。\n */\nimport {\n createChatChannelPlugin,\n createChannelPluginBase,\n} from \"openclaw/plugin-sdk/channel-core\";\nimport type { ChannelSetupWizard } from \"openclaw/plugin-sdk/channel-setup\";\nimport {\n appendPendingReplyText,\n consumePendingReplyContext,\n getPendingReplyContext,\n getWebSocket,\n} from \"./gateway.js\";\n\nexport interface SumelawAccount {\n botToken?: string;\n platformUrl?: string;\n enabled?: boolean;\n}\n\n/**\n * 安装/配置向导 — 交互式提示用户输入 botToken\n */\nconst channelKey = \"sumeclaw\";\n\nconst channelConfigAdapter = {\n listAccountIds(cfg: any) {\n const accounts = (cfg.channels as any)?.[channelKey]?.accounts ?? {};\n return Object.keys(accounts);\n },\n\n resolveAccount(cfg: any, accountId?: string) {\n const accounts = (cfg.channels as any)?.[channelKey]?.accounts ?? {};\n return (accounts[accountId ?? \"default\"] ?? {}) as SumelawAccount;\n },\n};\n\nconst setupWizard: ChannelSetupWizard = {\n channel: channelKey,\n\n /** 根据当前配置显示连接状态 */\n status: {\n configuredLabel: \"已连接友虾名片\",\n unconfiguredLabel: \"尚未配置\",\n resolveConfigured: ({ cfg }) => {\n const accounts = (cfg.channels as any)?.[channelKey]?.accounts ?? {};\n return Object.values(accounts).some((acct: any) => acct?.botToken);\n },\n },\n\n /** 交互式凭据收集 — 引导用户输入 botToken */\n credentials: [\n {\n inputKey: \"botToken\",\n credentialLabel: \"友虾连接码\",\n preferredEnvVar: \"SUMECLAW_BOT_TOKEN\",\n envPrompt: \"是否使用环境变量 SUMECLAW_BOT_TOKEN?\",\n keepPrompt: \"保留当前 botToken?\",\n inputPrompt: \"请输入从友虾小程序获取的 botToken:\",\n inspect: ({ cfg, accountId }) => {\n const token = (cfg.channels as any)?.[channelKey]?.accounts?.[\n accountId ?? \"default\"\n ]?.botToken;\n return {\n accountConfigured: Boolean(token),\n hasConfiguredValue: Boolean(token),\n };\n },\n },\n ],\n};\n\nexport const sumeclawPlugin = createChatChannelPlugin<SumelawAccount>({\n base: createChannelPluginBase({\n id: channelKey,\n setupWizard,\n setup: {\n /**\n * 从用户配置中解析账户信息\n */\n resolveAccount(cfg, accountId) {\n const accounts = (cfg.channels as any)?.[channelKey]?.accounts ?? {};\n return (accounts[accountId ?? \"default\"] ?? {}) as SumelawAccount;\n },\n\n /**\n * 检查账户配置状态\n */\n inspectAccount(cfg, accountId) {\n const account = (cfg.channels as any)?.[channelKey]?.accounts?.[\n accountId ?? \"default\"\n ];\n return {\n enabled: !!account?.botToken,\n configured: !!account?.botToken,\n };\n },\n },\n }),\n\n /**\n * 渠道配置适配器 (ChannelConfigAdapter)\n */\n config: channelConfigAdapter,\n\n /**\n * DM 安全策略\n *\n * 友虾名片场景下,所有通过名片访问的用户都允许对话。\n * 名片主可在小程序端管理黑名单(后续扩展)。\n */\n security: {\n dm: {\n channelKey: \"sumeclaw\",\n resolvePolicy: () => \"open\",\n defaultPolicy: \"open\",\n },\n },\n\n /**\n * 出站消息处理\n *\n * 当 OpenClaw Agent 生成回复后,通过 WebSocket 推回友虾名片平台。\n */\n outbound: {\n attachedResults: {\n sendText: async ({ text, to, accountId }) => {\n const resolvedAccountId = accountId ?? \"default\";\n const ws = getWebSocket(resolvedAccountId);\n if (!ws || ws.readyState !== 1) {\n throw new Error(\"WebSocket 未连接到友虾名片平台\");\n }\n\n const pending = getPendingReplyContext(resolvedAccountId, to);\n const messageId = `sumeclaw-${Date.now()}`;\n if (pending?.stream) {\n appendPendingReplyText(resolvedAccountId, to, text);\n ws.send(\n JSON.stringify({\n type: \"agent_delta\",\n requestId: pending.requestId,\n userId: to,\n sessionKey: pending.sessionKey,\n text,\n messageId,\n }),\n );\n console.log(\"[sumeclaw] 📤 outbound agent_delta sent\", {\n accountId: resolvedAccountId,\n requestId: pending.requestId,\n userId: to,\n textLength: text.length,\n });\n return { messageId };\n }\n\n if (pending && !pending.stream) {\n appendPendingReplyText(resolvedAccountId, to, text);\n console.log(\"[sumeclaw] 📥 outbound reply buffered\", {\n accountId: resolvedAccountId,\n requestId: pending.requestId,\n userId: to,\n textLength: text.length,\n });\n return { messageId };\n }\n\n const finalPending = consumePendingReplyContext(resolvedAccountId, to);\n ws.send(\n JSON.stringify({\n type: \"agent_reply\",\n requestId: finalPending?.requestId,\n userId: to,\n sessionKey: finalPending?.sessionKey,\n text,\n messageId,\n }),\n );\n console.log(\"[sumeclaw] 📤 outbound agent_reply sent\", {\n accountId: resolvedAccountId,\n requestId: finalPending?.requestId,\n userId: to,\n textLength: text.length,\n });\n\n return { messageId };\n },\n },\n },\n});\n\n// Some OpenClaw gateway health paths read plugin.config directly after the\n// SDK wrapper is created. Keep this explicit for compatibility across builds.\n(sumeclawPlugin as any).config ??= channelConfigAdapter;\n"],"mappings":"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","names":[]}