@lumachat/lumachat 0.15.2 → 0.15.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.
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  该目录包含 LumaChat 的 OpenClaw 通道插件实现。
4
4
 
5
5
  ## 已实现功能
6
- - 完整配对流程(请求配对码+安全码、轮询状态、保存 token 到 `channels.clawdchat`)。
6
+ - 完整配对流程(请求配对码+安全码、轮询状态、保存 token 到 `channels.lumachat`,兼容读取 `channels.clawdchat`)。
7
7
  - 与 LumaChat 后端保持 WebSocket 长连接。
8
8
  - 入站消息接入(LumaChat -> OpenClaw),按 `request_id` 回传回复。
9
9
  - CLI 配对入口(`openclaw channels login --channel lumachat`)。
@@ -22,7 +22,7 @@ corepack prepare pnpm@latest --activate
22
22
 
23
23
  安装插件:
24
24
  ```
25
- openclaw plugins install @lumachat/lumachat@0.15.0
25
+ openclaw plugins install @lumachat/lumachat@0.15.2
26
26
  ```
27
27
 
28
28
  ## 更新
@@ -40,9 +40,17 @@ openclaw plugins install @lumachat/lumachat@0.15.0
40
40
  - 支持返回并展示 6 位安全码(pairing confirm code),与 App 双码配对流程保持一致。
41
41
  - 补齐 clawdchat 消息目标解析(`chat:<uuid>` / `clawdchat:<uuid>`),避免 `Unknown target` 导致回复丢失。
42
42
 
43
+ ### 0.15.1
44
+ - 修复 `openclaw plugins install @lumachat/lumachat` 后配置校验 `plugin not found: lumachat` 的问题。
45
+ - 插件 ID 迁移为 `lumachat`,并保持对旧 ID `clawdchat` 的兼容读取。
46
+ - 若本地历史配置里存在 `plugins.entries.clawdchat`,请删除该键并改为 `plugins.entries.lumachat`。
47
+
48
+ ### 0.15.2
49
+ - 发布 `@lumachat/lumachat@0.15.2`,作为当前稳定安装版本。
50
+
43
51
  升级:
44
52
  ```
45
- openclaw plugins install @lumachat/lumachat@0.15.0
53
+ openclaw plugins install @lumachat/lumachat@0.15.2
46
54
  ```
47
55
 
48
56
  ## 配对流程(当前)
@@ -52,6 +60,8 @@ openclaw plugins install @lumachat/lumachat@0.15.0
52
60
  4. 插件会保存通道 token 并自动连接后端。
53
61
 
54
62
  ## 可选配置
63
+ - `LUMACHAT_API_BASE_URL`:覆盖后端地址(默认:`https://api-love2.huaizuo2029.cn`;本地开发可设为 `http://127.0.0.1:8000`)。
64
+ - `LUMACHAT_CHANNEL_KEY` / `LUMACHAT_SHARED_KEY`:当后端要求 `X-Clawdchat-Channel-Key` 时使用。
55
65
  - `CLAWDCHAT_API_BASE_URL`:覆盖后端地址(默认:`https://api-love2.huaizuo2029.cn`;本地开发可设为 `http://127.0.0.1:8000`)。
56
66
  - `CLAWDCHAT_CHANNEL_KEY` / `CLAWDCHAT_SHARED_KEY`:当后端要求 `X-Clawdchat-Channel-Key` 时使用。
57
67
 
@@ -1,9 +1,10 @@
1
1
  {
2
- "id": "clawdchat",
2
+ "id": "lumachat",
3
3
  "name": "LumaChat Channel",
4
4
  "description": "LumaChat mobile channel for OpenClaw",
5
- "version": "0.15.2",
5
+ "version": "0.15.3",
6
6
  "channels": [
7
+ "lumachat",
7
8
  "clawdchat"
8
9
  ],
9
10
  "configSchema": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumachat/lumachat",
3
- "version": "0.15.2",
3
+ "version": "0.15.3",
4
4
  "description": "LumaChat channel plugin for OpenClaw",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -21,14 +21,14 @@
21
21
  "./src/index.ts"
22
22
  ],
23
23
  "channel": {
24
- "id": "clawdchat",
24
+ "id": "lumachat",
25
25
  "label": "LumaChat",
26
26
  "selectionLabel": "LumaChat (配对码)",
27
- "docsPath": "/channels/clawdchat",
27
+ "docsPath": "/channels/lumachat",
28
28
  "blurb": "通过配对码把 Clawdbot 接入 LumaChat。",
29
29
  "aliases": [
30
- "clawdchat",
31
- "lumachat"
30
+ "lumachat",
31
+ "clawdchat"
32
32
  ]
33
33
  },
34
34
  "install": {
package/src/index.ts CHANGED
@@ -17,6 +17,8 @@ const RECONNECT_BASE_MS = 2_000;
17
17
  const RECONNECT_MAX_MS = 20_000;
18
18
  const PAIRING_POLL_INTERVAL_MS = 2_000;
19
19
  const PAIRING_WAIT_TIMEOUT_MS = 10 * 60 * 1000;
20
+ const CHANNEL_ID = "lumachat";
21
+ const LEGACY_CHANNEL_ID = "clawdchat";
20
22
 
21
23
  const HEADER_CHANNEL_KEY = "X-Clawdchat-Channel-Key";
22
24
  const HEADER_PAIRING_SECRET = "X-Pairing-Secret";
@@ -83,15 +85,18 @@ const normalizeValue = (value?: string | null): string | undefined => {
83
85
  };
84
86
 
85
87
  const resolveClawdchatSection = (cfg: OpenClawConfig): ClawdchatConfigSection =>
86
- (cfg.channels?.clawdchat ?? {}) as ClawdchatConfigSection;
88
+ (cfg.channels?.lumachat ?? cfg.channels?.clawdchat ?? {}) as ClawdchatConfigSection;
87
89
 
88
90
  const resolveBaseUrl = (cfg: OpenClawConfig): string =>
89
91
  normalizeValue(resolveClawdchatSection(cfg).baseUrl) ??
92
+ normalizeValue(process.env.LUMACHAT_API_BASE_URL) ??
90
93
  normalizeValue(process.env.CLAWDCHAT_API_BASE_URL) ??
91
94
  DEFAULT_BASE_URL;
92
95
 
93
96
  const resolveSharedKey = (cfg: OpenClawConfig): string | undefined =>
94
97
  normalizeValue(resolveClawdchatSection(cfg).sharedKey) ??
98
+ normalizeValue(process.env.LUMACHAT_CHANNEL_KEY) ??
99
+ normalizeValue(process.env.LUMACHAT_SHARED_KEY) ??
95
100
  normalizeValue(process.env.CLAWDCHAT_CHANNEL_KEY) ??
96
101
  normalizeValue(process.env.CLAWDCHAT_SHARED_KEY);
97
102
 
@@ -101,7 +106,7 @@ const buildConfigPatch = (cfg: OpenClawConfig, patch: Partial<ClawdchatConfigSec
101
106
  ...cfg,
102
107
  channels: {
103
108
  ...cfg.channels,
104
- clawdchat: {
109
+ lumachat: {
105
110
  ...current,
106
111
  ...patch,
107
112
  },
@@ -111,14 +116,17 @@ const buildConfigPatch = (cfg: OpenClawConfig, patch: Partial<ClawdchatConfigSec
111
116
 
112
117
  const removeClawdchatFields = (cfg: OpenClawConfig, fields: Array<keyof ClawdchatConfigSection>) => {
113
118
  const current = { ...resolveClawdchatSection(cfg) } as Record<string, unknown>;
119
+ const legacy = { ...(cfg.channels?.clawdchat ?? {}) } as Record<string, unknown>;
114
120
  for (const field of fields) {
115
121
  delete current[field as string];
122
+ delete legacy[field as string];
116
123
  }
117
124
  return {
118
125
  ...cfg,
119
126
  channels: {
120
127
  ...cfg.channels,
121
- clawdchat: current,
128
+ lumachat: current,
129
+ clawdchat: legacy,
122
130
  },
123
131
  } as OpenClawConfig;
124
132
  };
@@ -204,7 +212,7 @@ const createClawdchatPlugin = (api: OpenClawPluginApi): ChannelPlugin<ResolvedCl
204
212
  const resolveAccount = (cfg: OpenClawConfig, accountId?: string | null): ResolvedClawdchatAccount => {
205
213
  const section = resolveClawdchatSection(cfg);
206
214
  const resolvedId = accountId ?? DEFAULT_ACCOUNT_ID;
207
- const name = section.name?.trim() || "Clawdchat";
215
+ const name = section.name?.trim() || "LumaChat";
208
216
  return {
209
217
  accountId: resolvedId,
210
218
  name,
@@ -299,18 +307,18 @@ const createClawdchatPlugin = (api: OpenClawPluginApi): ChannelPlugin<ResolvedCl
299
307
  };
300
308
 
301
309
  if (!requestId || !conversationId || !content) {
302
- await respondError("invalid_message", "Invalid clawdchat payload.");
310
+ await respondError("invalid_message", "Invalid lumachat payload.");
303
311
  return;
304
312
  }
305
313
 
306
314
  const timestampMs = payload.timestamp ? Date.parse(payload.timestamp) : Date.now();
307
315
  const route = api.runtime.channel.routing.resolveAgentRoute({
308
316
  cfg,
309
- channel: "clawdchat",
317
+ channel: CHANNEL_ID,
310
318
  peer: { kind: "dm", id: conversationId },
311
319
  });
312
320
 
313
- const senderLabel = `clawdchat:${conversationId}`;
321
+ const senderLabel = `${CHANNEL_ID}:${conversationId}`;
314
322
  const storePath = api.runtime.channel.session.resolveStorePath(cfg.session?.store, {
315
323
  agentId: route.agentId,
316
324
  });
@@ -320,7 +328,7 @@ const createClawdchatPlugin = (api: OpenClawPluginApi): ChannelPlugin<ResolvedCl
320
328
  });
321
329
  const envelopeOptions = api.runtime.channel.reply.resolveEnvelopeFormatOptions(cfg);
322
330
  const body = api.runtime.channel.reply.formatAgentEnvelope({
323
- channel: "Clawdchat",
331
+ channel: "LumaChat",
324
332
  from: senderLabel,
325
333
  timestamp: timestampMs,
326
334
  previousTimestamp,
@@ -340,13 +348,13 @@ const createClawdchatPlugin = (api: OpenClawPluginApi): ChannelPlugin<ResolvedCl
340
348
  ConversationLabel: senderLabel,
341
349
  SenderName: senderLabel,
342
350
  SenderId: conversationId,
343
- Provider: "clawdchat" as const,
344
- Surface: "clawdchat" as const,
351
+ Provider: CHANNEL_ID as const,
352
+ Surface: CHANNEL_ID as const,
345
353
  MessageSid: requestId,
346
354
  Timestamp: timestampMs,
347
355
  CommandAuthorized: true,
348
356
  CommandSource: "text" as const,
349
- OriginatingChannel: "clawdchat" as const,
357
+ OriginatingChannel: CHANNEL_ID as const,
350
358
  OriginatingTo: `chat:${conversationId}`,
351
359
  });
352
360
 
@@ -394,7 +402,7 @@ const createClawdchatPlugin = (api: OpenClawPluginApi): ChannelPlugin<ResolvedCl
394
402
  }
395
403
  },
396
404
  onError: (err) => {
397
- log?.warn?.(`clawdchat reply error: ${String(err)}`);
405
+ log?.warn?.(`lumachat reply error: ${String(err)}`);
398
406
  },
399
407
  });
400
408
 
@@ -420,7 +428,7 @@ const createClawdchatPlugin = (api: OpenClawPluginApi): ChannelPlugin<ResolvedCl
420
428
  }
421
429
  }
422
430
  } catch (err) {
423
- log?.error?.(`clawdchat dispatch failed: ${String(err)}`);
431
+ log?.error?.(`lumachat dispatch failed: ${String(err)}`);
424
432
  await respondError("assistant_unavailable", "Assistant unavailable.");
425
433
  }
426
434
  };
@@ -466,7 +474,7 @@ const createClawdchatPlugin = (api: OpenClawPluginApi): ChannelPlugin<ResolvedCl
466
474
  heartbeat = setInterval(() => {
467
475
  sendJson(socket, { type: "heartbeat" }).catch(() => undefined);
468
476
  }, HEARTBEAT_INTERVAL_MS);
469
- log?.info?.("clawdchat channel connected");
477
+ log?.info?.("lumachat channel connected");
470
478
  });
471
479
 
472
480
  socket.on("message", (data) => {
@@ -475,7 +483,7 @@ const createClawdchatPlugin = (api: OpenClawPluginApi): ChannelPlugin<ResolvedCl
475
483
  try {
476
484
  payload = JSON.parse(text) as InboundPayload;
477
485
  } catch (err) {
478
- log?.warn?.(`clawdchat payload parse error: ${String(err)}`);
486
+ log?.warn?.(`lumachat payload parse error: ${String(err)}`);
479
487
  return;
480
488
  }
481
489
  if (payload.type === "heartbeat") {
@@ -495,7 +503,7 @@ const createClawdchatPlugin = (api: OpenClawPluginApi): ChannelPlugin<ResolvedCl
495
503
  });
496
504
 
497
505
  socket.on("error", (err) => {
498
- log?.warn?.(`clawdchat socket error: ${String(err)}`);
506
+ log?.warn?.(`lumachat socket error: ${String(err)}`);
499
507
  });
500
508
 
501
509
  socket.on("close", (code, reason) => {
@@ -503,7 +511,7 @@ const createClawdchatPlugin = (api: OpenClawPluginApi): ChannelPlugin<ResolvedCl
503
511
  signal.removeEventListener("abort", abortHandler);
504
512
  update({ running: false, lastStopAt: new Date().toISOString() });
505
513
  const reasonText = reason?.toString?.() ?? "";
506
- log?.warn?.(`clawdchat channel closed (${code}) ${reasonText}`);
514
+ log?.warn?.(`lumachat channel closed (${code}) ${reasonText}`);
507
515
  resolve();
508
516
  });
509
517
 
@@ -557,14 +565,14 @@ const createClawdchatPlugin = (api: OpenClawPluginApi): ChannelPlugin<ResolvedCl
557
565
  };
558
566
 
559
567
  return {
560
- id: "clawdchat",
568
+ id: CHANNEL_ID,
561
569
  meta: {
562
- id: "clawdchat",
563
- label: "Clawdchat",
564
- selectionLabel: "Clawdchat (pair code)",
565
- docsPath: "/channels/clawdchat",
566
- blurb: "Pair Clawdchat with a 6-digit code.",
567
- aliases: ["clawdchat"],
570
+ id: CHANNEL_ID,
571
+ label: "LumaChat",
572
+ selectionLabel: "LumaChat (pair code)",
573
+ docsPath: "/channels/lumachat",
574
+ blurb: "Pair LumaChat with a 6-digit code.",
575
+ aliases: [CHANNEL_ID, LEGACY_CHANNEL_ID],
568
576
  },
569
577
  capabilities: {
570
578
  chatTypes: ["direct"],
@@ -580,7 +588,10 @@ const createClawdchatPlugin = (api: OpenClawPluginApi): ChannelPlugin<ResolvedCl
580
588
  if (!trimmed) return undefined;
581
589
  const lower = trimmed.toLowerCase();
582
590
  if (lower.startsWith("chat:")) return trimmed;
583
- if (lower.startsWith("clawdchat:")) return `chat:${trimmed.slice("clawdchat:".length)}`;
591
+ if (lower.startsWith(`${CHANNEL_ID}:`)) return `chat:${trimmed.slice(`${CHANNEL_ID}:`.length)}`;
592
+ if (lower.startsWith(`${LEGACY_CHANNEL_ID}:`)) {
593
+ return `chat:${trimmed.slice(`${LEGACY_CHANNEL_ID}:`.length)}`;
594
+ }
584
595
  if (UUID_REGEX.test(trimmed)) return `chat:${trimmed}`;
585
596
  return undefined;
586
597
  },
@@ -588,13 +599,20 @@ const createClawdchatPlugin = (api: OpenClawPluginApi): ChannelPlugin<ResolvedCl
588
599
  looksLikeId: (raw, normalized) => {
589
600
  const lower = raw.trim().toLowerCase();
590
601
  if (!lower) return false;
591
- if (lower.startsWith("chat:") || lower.startsWith("clawdchat:")) return true;
602
+ if (
603
+ lower.startsWith("chat:") ||
604
+ lower.startsWith(`${CHANNEL_ID}:`) ||
605
+ lower.startsWith(`${LEGACY_CHANNEL_ID}:`)
606
+ ) {
607
+ return true;
608
+ }
592
609
  if (UUID_REGEX.test(lower)) return true;
593
610
  return Boolean(normalized && normalized.toLowerCase().startsWith("chat:"));
594
611
  },
595
- hint: "使用 clawdchat 会话 ID(形如 chat:<uuid>)。",
612
+ hint: "使用 lumachat 会话 ID(形如 chat:<uuid>)。",
596
613
  },
597
- formatTargetDisplay: ({ target }) => target.replace(/^chat:/i, "").replace(/^clawdchat:/i, ""),
614
+ formatTargetDisplay: ({ target }) =>
615
+ target.replace(/^chat:/i, "").replace(/^lumachat:/i, "").replace(/^clawdchat:/i, ""),
598
616
  },
599
617
  config: {
600
618
  listAccountIds: () => [DEFAULT_ACCOUNT_ID],
@@ -616,7 +634,7 @@ const createClawdchatPlugin = (api: OpenClawPluginApi): ChannelPlugin<ResolvedCl
616
634
  outbound: {
617
635
  deliveryMode: "direct",
618
636
  sendText: async () => {
619
- throw new Error("Clawdchat outbound is only supported for inbound replies.");
637
+ throw new Error("LumaChat outbound is only supported for inbound replies.");
620
638
  },
621
639
  },
622
640
  status: {
@@ -632,10 +650,10 @@ const createClawdchatPlugin = (api: OpenClawPluginApi): ChannelPlugin<ResolvedCl
632
650
  for (const account of accounts) {
633
651
  if (!account.configured) {
634
652
  issues.push({
635
- channel: "clawdchat",
653
+ channel: CHANNEL_ID,
636
654
  accountId: account.accountId ?? DEFAULT_ACCOUNT_ID,
637
655
  kind: "config",
638
- message: "Clawdchat channel not paired",
656
+ message: "LumaChat channel not paired",
639
657
  });
640
658
  }
641
659
  }
@@ -673,7 +691,7 @@ const createClawdchatPlugin = (api: OpenClawPluginApi): ChannelPlugin<ResolvedCl
673
691
  const cfg = api.runtime.config.loadConfig();
674
692
  const account = resolveAccount(cfg, resolvedId);
675
693
  if (account.channelToken && !force) {
676
- return { message: "Clawdchat already paired." };
694
+ return { message: "LumaChat already paired." };
677
695
  }
678
696
  const baseUrl = account.baseUrl;
679
697
  const sharedKey = account.sharedKey;
@@ -718,7 +736,7 @@ const createClawdchatPlugin = (api: OpenClawPluginApi): ChannelPlugin<ResolvedCl
718
736
  });
719
737
  await api.runtime.config.writeConfigFile(nextCfg);
720
738
  pairingSessions.delete(resolvedId);
721
- return { connected: true, message: "Clawdchat paired." };
739
+ return { connected: true, message: "LumaChat paired." };
722
740
  }
723
741
  if (status.status === "expired") {
724
742
  pairingSessions.delete(resolvedId);
@@ -744,7 +762,7 @@ const createClawdchatPlugin = (api: OpenClawPluginApi): ChannelPlugin<ResolvedCl
744
762
  const warn = runtime.error ?? console.warn;
745
763
 
746
764
  if (account.channelToken) {
747
- log("Clawdchat 已配对。若需重新配对,请先执行 `openclaw channels logout --channel clawdchat`。");
765
+ log("LumaChat 已配对。若需重新配对,请先执行 `openclaw channels logout --channel lumachat`。");
748
766
  return;
749
767
  }
750
768
 
@@ -755,9 +773,9 @@ const createClawdchatPlugin = (api: OpenClawPluginApi): ChannelPlugin<ResolvedCl
755
773
  if (!pairing.pairingId || !pairing.pairingCode || !pairing.pairingConfirmCode || !pairing.pairingSecret) {
756
774
  throw new Error("Failed to request pairing code.");
757
775
  }
758
- log(`Clawdchat 配对码:${pairing.pairingCode}`);
759
- log(`Clawdchat 安全码:${pairing.pairingConfirmCode}`);
760
- log("请在 clawdchat App -> 设置 -> Clawdbot 配对 中输入配对码与安全码。");
776
+ log(`LumaChat 配对码:${pairing.pairingCode}`);
777
+ log(`LumaChat 安全码:${pairing.pairingConfirmCode}`);
778
+ log("请在 LumaChat App -> 设置 -> Clawdbot 配对 中输入配对码与安全码。");
761
779
 
762
780
  const session: PairingSession = {
763
781
  accountId: resolvedId,
@@ -787,7 +805,7 @@ const createClawdchatPlugin = (api: OpenClawPluginApi): ChannelPlugin<ResolvedCl
787
805
  pairedAt: new Date().toISOString(),
788
806
  });
789
807
  await api.runtime.config.writeConfigFile(nextCfg);
790
- log("Clawdchat 配对成功。");
808
+ log("LumaChat 配对成功。");
791
809
  return;
792
810
  }
793
811
  if (status.status === "expired") {