@xiaozhi-pro/openclaw-plugin 1.0.4 → 1.0.6

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.
@@ -2,6 +2,12 @@ import type { OpenClawConfig } from "openclaw/plugin-sdk/account-resolution";
2
2
  import { type ResolvedXiaozhiProAccount } from "./types.js";
3
3
  export type { ResolvedXiaozhiProAccount };
4
4
  export declare function listAccountIds(cfg: OpenClawConfig): string[];
5
+ /**
6
+ * 解析小智Pro账号配置。
7
+ * 签名兼容 createHybridChannelConfigAdapter 要求: (cfg, accountId?) => Account
8
+ * 内部用 adaptScopedAccountAccessor 包裹后传给 createHybridChannelConfigAdapter,
9
+ * 因为该函数内部以 ({ cfg, accountId }) 对象方式调用 resolveAccount。
10
+ */
5
11
  export declare function resolveAccount(cfg: OpenClawConfig, accountId?: string | null): ResolvedXiaozhiProAccount;
6
12
  /** 获取小智Pro WS URL(固定地址) */
7
13
  export declare function getXiaozhiProWsUrl(): string;
@@ -1,7 +1,13 @@
1
1
  import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
2
2
  import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
3
- import { formatAllowFromLowercase } from "openclaw/plugin-sdk/allow-from";
4
3
  import { XIAOZHI_PRO_WS_URL } from "./types.js";
4
+ function normalizeAllowFrom(value) {
5
+ if (!value)
6
+ return [];
7
+ if (Array.isArray(value))
8
+ return value.map((v) => String(v).toLowerCase().trim()).filter(Boolean);
9
+ return [];
10
+ }
5
11
  export function listAccountIds(cfg) {
6
12
  const section = cfg.channels?.["xiaozhi-pro"];
7
13
  if (!section)
@@ -11,6 +17,12 @@ export function listAccountIds(cfg) {
11
17
  }
12
18
  return [DEFAULT_ACCOUNT_ID];
13
19
  }
20
+ /**
21
+ * 解析小智Pro账号配置。
22
+ * 签名兼容 createHybridChannelConfigAdapter 要求: (cfg, accountId?) => Account
23
+ * 内部用 adaptScopedAccountAccessor 包裹后传给 createHybridChannelConfigAdapter,
24
+ * 因为该函数内部以 ({ cfg, accountId }) 对象方式调用 resolveAccount。
25
+ */
14
26
  export function resolveAccount(cfg, accountId) {
15
27
  const section = (cfg.channels?.["xiaozhi-pro"] ?? {});
16
28
  const accounts = section.accounts;
@@ -20,7 +32,7 @@ export function resolveAccount(cfg, accountId) {
20
32
  enabled: raw.enabled !== false,
21
33
  token: normalizeLowercaseStringOrEmpty(raw.token),
22
34
  dmPolicy: raw.dmPolicy ?? "open",
23
- allowedUserIds: formatAllowFromLowercase(raw.allowedUserIds ?? raw.allowFrom),
35
+ allowedUserIds: normalizeAllowFrom(raw.allowedUserIds ?? raw.allowFrom),
24
36
  };
25
37
  }
26
38
  /** 获取小智Pro WS URL(固定地址) */
@@ -8,6 +8,7 @@ import { createChatChannelPlugin, } from "openclaw/plugin-sdk/channel-core";
8
8
  import { waitUntilAbort } from "openclaw/plugin-sdk/channel-runtime";
9
9
  import { createEmptyChannelDirectoryAdapter } from "openclaw/plugin-sdk/directory-runtime";
10
10
  import { createHybridChannelConfigAdapter, createScopedDmSecurityResolver, } from "openclaw/plugin-sdk/channel-config-helpers";
11
+ import { formatAllowFromLowercase } from "openclaw/plugin-sdk/allow-from";
11
12
  import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
12
13
  import { getXiaozhiProRuntime } from "./runtime.js";
13
14
  import { listAccountIds, resolveAccount, } from "./accounts.js";
@@ -50,7 +51,7 @@ export const xiaozhiProPlugin = createChatChannelPlugin({
50
51
  defaultAccountId: () => DEFAULT_ACCOUNT_ID,
51
52
  clearBaseFields: ["token", "dmPolicy", "allowedUserIds"],
52
53
  resolveAllowFrom: (account) => account.allowedUserIds,
53
- formatAllowFrom: (ids) => ids.map(String),
54
+ formatAllowFrom: (allowFrom) => formatAllowFromLowercase({ allowFrom: Array.isArray(allowFrom) ? allowFrom : allowFrom?.allowFrom ?? [] }),
54
55
  }),
55
56
  // 目标寻址
56
57
  messaging: {
@@ -9,16 +9,22 @@ export function connectXiaozhiProWs(config) {
9
9
  let ws = null;
10
10
  let reconnectTimer = null;
11
11
  let reconnectAttempts = 0;
12
+ let authFatal = false;
12
13
  const MAX_RECONNECT_DELAY = 30_000;
13
14
  function connect() {
14
- if (abortSignal.aborted)
15
+ if (abortSignal.aborted || authFatal)
15
16
  return;
16
17
  ws = new WebSocket(url);
17
18
  ws.on("open", () => {
18
19
  reconnectAttempts = 0;
19
20
  log?.info?.(`[xiaozhi-pro] WS 已连接: ${url}`);
20
21
  // 发送 auth 消息(和小智Pro服务端协议对齐)
21
- ws.send(JSON.stringify({ type: "auth", token: account.token }));
22
+ const token = account.token;
23
+ const masked = token.length > 8
24
+ ? `${token.slice(0, 4)}****${token.slice(-4)}`
25
+ : "****";
26
+ log?.info?.(`[xiaozhi-pro] 发送认证: token=${masked} (长度=${token.length})`);
27
+ ws.send(JSON.stringify({ type: "auth", token }));
22
28
  });
23
29
  ws.on("message", (raw) => {
24
30
  try {
@@ -29,6 +35,8 @@ export function connectXiaozhiProWs(config) {
29
35
  }
30
36
  if (data.type === "auth_fail") {
31
37
  log?.error?.(`[xiaozhi-pro] 认证失败: ${data.error} - ${data.message}`);
38
+ log?.error?.(`[xiaozhi-pro] 认证失败为不可恢复错误,停止重连。请检查 token 配置后重启服务。`);
39
+ authFatal = true;
32
40
  ws?.close();
33
41
  return;
34
42
  }
@@ -75,7 +83,7 @@ export function connectXiaozhiProWs(config) {
75
83
  activeConnections.set(accountId, ws);
76
84
  }
77
85
  function scheduleReconnect() {
78
- if (abortSignal.aborted)
86
+ if (abortSignal.aborted || authFatal)
79
87
  return;
80
88
  const delay = Math.min(1000 * Math.pow(2, reconnectAttempts), MAX_RECONNECT_DELAY);
81
89
  reconnectAttempts++;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiaozhi-pro/openclaw-plugin",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "小智Pro (XiaoZhi Pro) channel plugin for OpenClaw via WebSocket",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",