openclaw-channel-xiaozhu 2.1.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/dist/channel.d.ts +183 -16
  2. package/dist/channel.d.ts.map +1 -1
  3. package/dist/channel.js +244 -25
  4. package/dist/channel.js.map +1 -1
  5. package/dist/index.js +2 -2
  6. package/dist/index.js.map +1 -1
  7. package/dist/relay/client.d.ts.map +1 -1
  8. package/dist/relay/client.js +6 -2
  9. package/dist/relay/client.js.map +1 -1
  10. package/dist/server.d.ts +18 -1
  11. package/dist/server.d.ts.map +1 -1
  12. package/dist/server.js +151 -2
  13. package/dist/server.js.map +1 -1
  14. package/dist/shared/inbound.js +1 -1
  15. package/dist/shared/inbound.js.map +1 -1
  16. package/dist/shared/security.d.ts +2 -1
  17. package/dist/shared/security.d.ts.map +1 -1
  18. package/dist/shared/security.js +3 -2
  19. package/dist/shared/security.js.map +1 -1
  20. package/dist/types.d.ts +18 -0
  21. package/dist/types.d.ts.map +1 -1
  22. package/dist/utils/openclaw-sessions.d.ts +79 -0
  23. package/dist/utils/openclaw-sessions.d.ts.map +1 -0
  24. package/dist/utils/openclaw-sessions.js +49 -0
  25. package/dist/utils/openclaw-sessions.js.map +1 -0
  26. package/dist/utils/rate-limiter.d.ts.map +1 -1
  27. package/dist/utils/rate-limiter.js +2 -4
  28. package/dist/utils/rate-limiter.js.map +1 -1
  29. package/openclaw.plugin.json +138 -3
  30. package/package.json +8 -55
  31. package/skills/xiaozhu-cron-job/SKILL.md +6 -6
  32. package/LICENSE +0 -21
  33. package/README.md +0 -499
  34. package/demo/app.js +0 -350
  35. package/demo/index.html +0 -36
  36. package/demo/style.css +0 -249
  37. package/demo/think.css +0 -590
  38. package/demo/think.html +0 -92
  39. package/demo/think.js +0 -532
  40. package/dist/relay/cli.d.ts +0 -10
  41. package/dist/relay/cli.d.ts.map +0 -1
  42. package/dist/relay/cli.js +0 -28
  43. package/dist/relay/cli.js.map +0 -1
  44. package/dist/relay/server.d.ts +0 -16
  45. package/dist/relay/server.d.ts.map +0 -1
  46. package/dist/relay/server.js +0 -322
  47. package/dist/relay/server.js.map +0 -1
  48. package/dist/sdk/index.d.ts +0 -259
  49. package/dist/sdk/index.d.ts.map +0 -1
  50. package/dist/sdk/index.js +0 -415
  51. package/dist/sdk/index.js.map +0 -1
  52. package/dist/sdk/sse.d.ts +0 -18
  53. package/dist/sdk/sse.d.ts.map +0 -1
  54. package/dist/sdk/sse.js +0 -67
  55. package/dist/sdk/sse.js.map +0 -1
  56. package/dist/sdk/types.d.ts +0 -231
  57. package/dist/sdk/types.d.ts.map +0 -1
  58. package/dist/sdk/types.js +0 -5
  59. package/dist/sdk/types.js.map +0 -1
  60. package/dist/shared/errors.d.ts +0 -47
  61. package/dist/shared/errors.d.ts.map +0 -1
  62. package/dist/shared/errors.js +0 -52
  63. package/dist/shared/errors.js.map +0 -1
  64. package/dist/standalone/app.d.ts +0 -16
  65. package/dist/standalone/app.d.ts.map +0 -1
  66. package/dist/standalone/app.js +0 -194
  67. package/dist/standalone/app.js.map +0 -1
  68. package/dist/standalone/auth.d.ts +0 -19
  69. package/dist/standalone/auth.d.ts.map +0 -1
  70. package/dist/standalone/auth.js +0 -45
  71. package/dist/standalone/auth.js.map +0 -1
  72. package/dist/standalone/cli.d.ts +0 -10
  73. package/dist/standalone/cli.d.ts.map +0 -1
  74. package/dist/standalone/cli.js +0 -107
  75. package/dist/standalone/cli.js.map +0 -1
  76. package/dist/standalone/media-store.d.ts +0 -30
  77. package/dist/standalone/media-store.d.ts.map +0 -1
  78. package/dist/standalone/media-store.js +0 -150
  79. package/dist/standalone/media-store.js.map +0 -1
  80. package/dist/standalone/migrate-to-sqlite.d.ts +0 -10
  81. package/dist/standalone/migrate-to-sqlite.d.ts.map +0 -1
  82. package/dist/standalone/migrate-to-sqlite.js +0 -194
  83. package/dist/standalone/migrate-to-sqlite.js.map +0 -1
  84. package/dist/standalone/router.d.ts +0 -34
  85. package/dist/standalone/router.d.ts.map +0 -1
  86. package/dist/standalone/router.js +0 -94
  87. package/dist/standalone/router.js.map +0 -1
  88. package/dist/standalone/routes.d.ts +0 -12
  89. package/dist/standalone/routes.d.ts.map +0 -1
  90. package/dist/standalone/routes.js +0 -508
  91. package/dist/standalone/routes.js.map +0 -1
  92. package/dist/standalone/server-context.d.ts +0 -73
  93. package/dist/standalone/server-context.d.ts.map +0 -1
  94. package/dist/standalone/server-context.js +0 -38
  95. package/dist/standalone/server-context.js.map +0 -1
  96. package/dist/standalone/store.d.ts +0 -36
  97. package/dist/standalone/store.d.ts.map +0 -1
  98. package/dist/standalone/store.js +0 -163
  99. package/dist/standalone/store.js.map +0 -1
  100. package/dist/standalone/thought-db.d.ts +0 -92
  101. package/dist/standalone/thought-db.d.ts.map +0 -1
  102. package/dist/standalone/thought-db.js +0 -677
  103. package/dist/standalone/thought-db.js.map +0 -1
  104. package/dist/standalone/thought-processor.d.ts +0 -36
  105. package/dist/standalone/thought-processor.d.ts.map +0 -1
  106. package/dist/standalone/thought-processor.js +0 -352
  107. package/dist/standalone/thought-processor.js.map +0 -1
  108. package/dist/standalone/thought-routes.d.ts +0 -13
  109. package/dist/standalone/thought-routes.d.ts.map +0 -1
  110. package/dist/standalone/thought-routes.js +0 -326
  111. package/dist/standalone/thought-routes.js.map +0 -1
  112. package/dist/standalone/thought-store-factory.d.ts +0 -12
  113. package/dist/standalone/thought-store-factory.d.ts.map +0 -1
  114. package/dist/standalone/thought-store-factory.js +0 -20
  115. package/dist/standalone/thought-store-factory.js.map +0 -1
  116. package/dist/standalone/thought-store.d.ts +0 -103
  117. package/dist/standalone/thought-store.d.ts.map +0 -1
  118. package/dist/standalone/thought-store.js +0 -502
  119. package/dist/standalone/thought-store.js.map +0 -1
  120. package/dist/standalone/thought-types.d.ts +0 -169
  121. package/dist/standalone/thought-types.d.ts.map +0 -1
  122. package/dist/standalone/thought-types.js +0 -5
  123. package/dist/standalone/thought-types.js.map +0 -1
  124. package/dist/standalone/types.d.ts +0 -105
  125. package/dist/standalone/types.d.ts.map +0 -1
  126. package/dist/standalone/types.js +0 -5
  127. package/dist/standalone/types.js.map +0 -1
  128. package/dist/standalone/ws-handler.d.ts +0 -16
  129. package/dist/standalone/ws-handler.d.ts.map +0 -1
  130. package/dist/standalone/ws-handler.js +0 -183
  131. package/dist/standalone/ws-handler.js.map +0 -1
  132. package/docs/API.md +0 -1844
  133. package/docs/DEVELOPMENT.md +0 -299
  134. package/docs/MILESTONES.md +0 -135
  135. package/docs/RISKS.md +0 -179
  136. package/docs/ROADMAP.md +0 -144
package/dist/channel.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  /**
2
- * Channel 插件对象 — config / gateway / outbound / status 四个适配器
2
+ * Channel 插件对象 — 16 个适配器(config / gateway / outbound / status +
3
+ * messaging / groups / mentions / pairing / security / commands /
4
+ * streaming / threading / agentPrompt / directory / actions / heartbeat)
3
5
  */
4
6
  import type { HttpApiAccount, PluginRuntime, ChannelConfig, GatewayContext } from "./types.js";
5
7
  export declare function setRuntime(rt: PluginRuntime): void;
@@ -10,6 +12,7 @@ export declare const httpChannelPlugin: {
10
12
  label: string;
11
13
  selectionLabel: string;
12
14
  blurb: string;
15
+ docsPath: string;
13
16
  order: number;
14
17
  aliases: string[];
15
18
  };
@@ -20,17 +23,15 @@ export declare const httpChannelPlugin: {
20
23
  media: boolean;
21
24
  nativeCommands: boolean;
22
25
  blockStreaming: boolean;
23
- fileUpload: boolean;
24
- sessionManagement: boolean;
25
- stt: boolean;
26
- tts: boolean;
27
- typing: boolean;
28
- heartbeat: boolean;
29
- webhookSigning: boolean;
26
+ };
27
+ defaults: {
28
+ queue: {
29
+ debounceMs: number;
30
+ };
30
31
  };
31
32
  config: {
32
33
  listAccountIds: (cfg: ChannelConfig) => string[];
33
- resolveAccount: (cfg: ChannelConfig, accountId: string) => HttpApiAccount;
34
+ resolveAccount: (cfg: ChannelConfig, accountId?: string | null) => HttpApiAccount;
34
35
  defaultAccountId: (_cfg: ChannelConfig) => string;
35
36
  isConfigured: (account: HttpApiAccount) => boolean;
36
37
  describeAccount: (account: HttpApiAccount) => {
@@ -38,11 +39,6 @@ export declare const httpChannelPlugin: {
38
39
  name: string;
39
40
  enabled: boolean;
40
41
  configured: boolean;
41
- features: {
42
- perIpRateLimit: boolean;
43
- webhookSigning: boolean;
44
- commands: boolean;
45
- };
46
42
  };
47
43
  setAccountEnabled: ({ cfg, accountId, enabled }: {
48
44
  cfg: ChannelConfig;
@@ -50,7 +46,7 @@ export declare const httpChannelPlugin: {
50
46
  enabled: boolean;
51
47
  }) => {
52
48
  channels: {
53
- "channel-xiaozhu": {
49
+ "openclaw-channel-xiaozhu": {
54
50
  accounts: {
55
51
  [x: string]: Record<string, unknown>;
56
52
  };
@@ -58,7 +54,7 @@ export declare const httpChannelPlugin: {
58
54
  };
59
55
  } | {
60
56
  channels: {
61
- "channel-xiaozhu": {
57
+ "openclaw-channel-xiaozhu": {
62
58
  enabled: boolean;
63
59
  };
64
60
  };
@@ -71,6 +67,16 @@ export declare const httpChannelPlugin: {
71
67
  [x: string]: Record<string, unknown>;
72
68
  };
73
69
  };
70
+ resolveAllowFrom: ({ cfg, accountId }: {
71
+ cfg: ChannelConfig;
72
+ accountId?: string | null;
73
+ }) => string[] | undefined;
74
+ formatAllowFrom: ({ allowFrom }: {
75
+ cfg: ChannelConfig;
76
+ accountId?: string | null;
77
+ allowFrom: Array<string | number>;
78
+ }) => string[];
79
+ resolveDefaultTo: () => string | undefined;
74
80
  };
75
81
  gateway: {
76
82
  startAccount: (ctx: GatewayContext) => Promise<void>;
@@ -78,6 +84,8 @@ export declare const httpChannelPlugin: {
78
84
  outbound: {
79
85
  deliveryMode: "direct";
80
86
  textChunkLimit: number;
87
+ chunker: (text: string, limit: number) => string[];
88
+ chunkerMode: "markdown";
81
89
  sendText: (opts: Record<string, unknown>) => Promise<{
82
90
  channel: string;
83
91
  ok: boolean;
@@ -96,6 +104,22 @@ export declare const httpChannelPlugin: {
96
104
  ok: boolean;
97
105
  error?: undefined;
98
106
  }>;
107
+ sendPayload: (ctx: Record<string, unknown>) => Promise<{
108
+ channel: string;
109
+ ok: boolean;
110
+ error: Error;
111
+ messageId?: undefined;
112
+ } | {
113
+ channel: string;
114
+ ok: boolean;
115
+ error: Error;
116
+ messageId: string;
117
+ } | {
118
+ channel: string;
119
+ ok: boolean;
120
+ messageId: string;
121
+ error?: undefined;
122
+ }>;
99
123
  };
100
124
  status: {
101
125
  defaultRuntime: {
@@ -103,7 +127,10 @@ export declare const httpChannelPlugin: {
103
127
  running: boolean;
104
128
  connected: boolean;
105
129
  lastStartAt: null;
130
+ lastStopAt: null;
106
131
  lastError: null;
132
+ lastInboundAt: null;
133
+ lastOutboundAt: null;
107
134
  };
108
135
  probeAccount: ({ account, timeoutMs }: {
109
136
  account: HttpApiAccount;
@@ -112,6 +139,146 @@ export declare const httpChannelPlugin: {
112
139
  ok: boolean;
113
140
  latencyMs: number;
114
141
  }>;
142
+ buildAccountSnapshot: ({ account, runtime }: {
143
+ account: HttpApiAccount;
144
+ cfg: ChannelConfig;
145
+ runtime?: Record<string, unknown>;
146
+ }) => {
147
+ accountId: string;
148
+ name: string;
149
+ enabled: boolean;
150
+ configured: boolean;
151
+ running: boolean;
152
+ connected: boolean;
153
+ lastStartAt: number | null;
154
+ lastStopAt: number | null;
155
+ lastError: string | null;
156
+ mode: "webhook" | "cloud";
157
+ lastInboundAt: number | null;
158
+ lastOutboundAt: number | null;
159
+ };
160
+ buildChannelSummary: ({ snapshot }: {
161
+ account: HttpApiAccount;
162
+ cfg: ChannelConfig;
163
+ defaultAccountId: string;
164
+ snapshot: Record<string, unknown>;
165
+ }) => {
166
+ configured: boolean;
167
+ running: boolean;
168
+ connected: boolean;
169
+ mode: string;
170
+ lastStartAt: {} | null;
171
+ lastStopAt: {} | null;
172
+ lastError: {} | null;
173
+ lastInboundAt: {} | null;
174
+ lastOutboundAt: {} | null;
175
+ };
176
+ };
177
+ messaging: {
178
+ normalizeTarget: (raw: string) => string | undefined;
179
+ targetResolver: {
180
+ looksLikeId: (raw: string) => boolean;
181
+ hint: string;
182
+ };
183
+ formatTargetDisplay: ({ target, display }: {
184
+ target: string;
185
+ display?: string;
186
+ kind?: string;
187
+ }) => string;
188
+ };
189
+ groups: {
190
+ resolveRequireMention: ({ cfg, accountId }: {
191
+ cfg: ChannelConfig;
192
+ accountId?: string | null;
193
+ }) => boolean | undefined;
194
+ resolveGroupIntroHint: ({ cfg, accountId }: {
195
+ cfg: ChannelConfig;
196
+ accountId?: string | null;
197
+ }) => string | undefined;
198
+ };
199
+ mentions: {
200
+ stripPatterns: () => string[];
201
+ stripMentions: ({ text }: {
202
+ text: string;
203
+ }) => string;
204
+ };
205
+ pairing: {
206
+ idLabel: string;
207
+ normalizeAllowEntry: (entry: string) => string;
208
+ notifyApproval: () => Promise<void>;
209
+ };
210
+ security: {
211
+ resolveDmPolicy: () => null;
212
+ collectWarnings: ({ account }: {
213
+ account: HttpApiAccount;
214
+ }) => string[];
215
+ };
216
+ commands: {
217
+ enforceOwnerForCommands: boolean;
218
+ skipWhenConfigEmpty: boolean;
219
+ };
220
+ streaming: {
221
+ blockStreamingCoalesceDefaults: {
222
+ minChars: number;
223
+ idleMs: number;
224
+ };
225
+ };
226
+ threading: {
227
+ resolveReplyToMode: ({ cfg, accountId }: {
228
+ cfg: ChannelConfig;
229
+ accountId?: string | null;
230
+ }) => "off" | "first" | "all";
231
+ allowExplicitReplyTagsWhenOff: boolean;
232
+ };
233
+ agentPrompt: {
234
+ messageToolHints: () => string[];
235
+ };
236
+ directory: {
237
+ self: ({ accountId }: {
238
+ accountId?: string;
239
+ }) => Promise<{
240
+ id: string;
241
+ name: string;
242
+ kind: string;
243
+ } | null>;
244
+ listPeers: ({ accountId }: {
245
+ accountId?: string;
246
+ }) => Promise<{
247
+ id: string;
248
+ name: string;
249
+ kind: string;
250
+ }[]>;
251
+ listGroups: ({ accountId }: {
252
+ accountId?: string;
253
+ }) => Promise<{
254
+ id: string;
255
+ name: string;
256
+ kind: string;
257
+ }[]>;
258
+ };
259
+ actions: {
260
+ listActions: () => string[];
261
+ supportsAction: ({ action }: {
262
+ action: string;
263
+ }) => boolean;
264
+ supportsButtons: () => boolean;
265
+ supportsCards: () => boolean;
266
+ };
267
+ heartbeat: {
268
+ checkReady: ({ cfg, accountId }: {
269
+ cfg: ChannelConfig;
270
+ accountId?: string | null;
271
+ }) => Promise<{
272
+ ok: boolean;
273
+ reason: string;
274
+ }>;
275
+ resolveRecipients: ({ cfg, accountId }: {
276
+ cfg: ChannelConfig;
277
+ accountId?: string | null;
278
+ }) => {
279
+ recipients: string[];
280
+ source: string;
281
+ };
115
282
  };
116
283
  };
117
284
  //# sourceMappingURL=channel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAU,MAAM,YAAY,CAAC;AAQvG,wBAAgB,UAAU,CAAC,EAAE,EAAE,aAAa,QAE3C;AAwCD,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;8BA8BJ,aAAa,KAAG,MAAM,EAAE;8BAcxB,aAAa,aAAa,MAAM,KAAG,cAAc;iCAc9C,aAAa,KAAG,MAAM;gCAEvB,cAAc,KAAG,OAAO;mCAIrB,cAAc;;;;;;;;;;;yDAYQ;YAAE,GAAG,EAAE,aAAa,CAAC;YAAC,SAAS,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,OAAO,CAAA;SAAE;;;;;;;;;;;;;;;4CAYxE;YAAE,GAAG,EAAE,aAAa,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE;;;;;;;4BAiBnD,cAAc;;;;;yBA8EjB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;0BAoCtB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;;;;;;;;+CA0CF;YAAE,OAAO,EAAE,cAAc,CAAC;YAAC,SAAS,CAAC,EAAE,MAAM,CAAA;SAAE;;;;;CAa/F,CAAC"}
1
+ {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"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"}
package/dist/channel.js CHANGED
@@ -1,11 +1,13 @@
1
1
  /**
2
- * Channel 插件对象 — config / gateway / outbound / status 四个适配器
2
+ * Channel 插件对象 — 16 个适配器(config / gateway / outbound / status +
3
+ * messaging / groups / mentions / pairing / security / commands /
4
+ * streaming / threading / agentPrompt / directory / actions / heartbeat)
3
5
  */
4
- import { startHttpServer, getRuntimeWebhookUrl } from "./server.js";
6
+ import { startHttpServer, getRuntimeWebhookUrl, getAccountState } from "./server.js";
5
7
  import { startRelayClient } from "./relay/client.js";
6
8
  import { sendWithRetry } from "./utils/webhook-sender.js";
7
9
  import { chunkText } from "./utils/text-chunker.js";
8
- const CHANNEL_ID = "channel-xiaozhu";
10
+ const CHANNEL_ID = "openclaw-channel-xiaozhu";
9
11
  const DEFAULT_PORT = 18800;
10
12
  const DEFAULT_RELAY_URL = "wss://relay.xiaozhu.ai/ws/bot";
11
13
  let pluginRuntime = null;
@@ -46,15 +48,24 @@ function parseAccountFromRaw(raw, accountId) {
46
48
  networkMode: raw.networkMode,
47
49
  relayUrl: raw.relayUrl,
48
50
  relayToken: raw.relayToken,
51
+ requireMention: raw.requireMention,
52
+ groupIntroHint: raw.groupIntroHint,
53
+ replyToMode: raw.replyToMode,
54
+ dmPolicy: raw.dmPolicy,
49
55
  };
50
56
  }
57
+ /** 解析账号的快捷方式(供多个适配器复用) */
58
+ function resolveAccount(cfg, accountId) {
59
+ return httpChannelPlugin.config.resolveAccount(cfg, accountId || "default");
60
+ }
51
61
  export const httpChannelPlugin = {
52
62
  id: CHANNEL_ID,
53
63
  meta: {
54
64
  id: CHANNEL_ID,
55
65
  label: "小助",
56
- selectionLabel: "小助",
66
+ selectionLabel: "小助 (HTTP/SSE)",
57
67
  blurb: "通过 HTTP/SSE 接口接入对话的通用渠道",
68
+ docsPath: "/docs/channels/xiaozhu",
58
69
  order: 90,
59
70
  aliases: ["xiaozhu", "http", "api", "rest"],
60
71
  },
@@ -65,13 +76,9 @@ export const httpChannelPlugin = {
65
76
  media: true,
66
77
  nativeCommands: true,
67
78
  blockStreaming: true,
68
- fileUpload: true,
69
- sessionManagement: true,
70
- stt: true,
71
- tts: true,
72
- typing: true,
73
- heartbeat: true,
74
- webhookSigning: true,
79
+ },
80
+ defaults: {
81
+ queue: { debounceMs: 300 },
75
82
  },
76
83
  // ── config 适配器 ──
77
84
  config: {
@@ -90,14 +97,15 @@ export const httpChannelPlugin = {
90
97
  },
91
98
  resolveAccount: (cfg, accountId) => {
92
99
  const ch = getChannelConfig(cfg) || {};
100
+ const id = accountId || "default";
93
101
  // 多账号模式
94
102
  if (ch.accounts && typeof ch.accounts === "object" && !Array.isArray(ch.accounts)) {
95
103
  const accounts = ch.accounts;
96
- const raw = accounts[accountId] || {};
97
- return parseAccountFromRaw(raw, accountId);
104
+ const raw = accounts[id] || {};
105
+ return parseAccountFromRaw(raw, id);
98
106
  }
99
107
  // 单账号模式
100
- return parseAccountFromRaw(ch, accountId);
108
+ return parseAccountFromRaw(ch, id);
101
109
  },
102
110
  defaultAccountId: (_cfg) => "default",
103
111
  isConfigured: (account) => {
@@ -108,36 +116,35 @@ export const httpChannelPlugin = {
108
116
  name: `小助 :${account.port}`,
109
117
  enabled: account.enabled,
110
118
  configured: !!account.token,
111
- features: {
112
- perIpRateLimit: !!account.perIpRateLimit,
113
- webhookSigning: !!account.webhookSecret,
114
- commands: account.commandsEnabled !== false,
115
- },
116
119
  }),
117
120
  setAccountEnabled: ({ cfg, accountId, enabled }) => {
118
121
  const ch = getChannelConfig(cfg) || {};
119
- // 多账号模式:设置具体账号的 enabled
120
122
  if (ch.accounts && typeof ch.accounts === "object" && !Array.isArray(ch.accounts)) {
121
123
  const accounts = { ...ch.accounts };
122
124
  accounts[accountId] = { ...accounts[accountId], enabled };
123
125
  return { ...cfg, channels: { ...cfg.channels, [CHANNEL_ID]: { ...ch, accounts } } };
124
126
  }
125
- // 单账号模式
126
127
  return { ...cfg, channels: { ...cfg.channels, [CHANNEL_ID]: { ...ch, enabled } } };
127
128
  },
128
129
  deleteAccount: ({ cfg, accountId }) => {
129
130
  const ch = getChannelConfig(cfg) || {};
130
- // 多账号模式:只删除指定账号
131
131
  if (ch.accounts && typeof ch.accounts === "object" && !Array.isArray(ch.accounts)) {
132
132
  const accounts = { ...ch.accounts };
133
133
  delete accounts[accountId];
134
134
  return { ...cfg, channels: { ...cfg.channels, [CHANNEL_ID]: { ...ch, accounts } } };
135
135
  }
136
- // 单账号模式:删除整个渠道
137
136
  const channels = { ...cfg.channels };
138
137
  delete channels[CHANNEL_ID];
139
138
  return { ...cfg, channels };
140
139
  },
140
+ resolveAllowFrom: ({ cfg, accountId }) => {
141
+ const account = resolveAccount(cfg, accountId);
142
+ return account.allowFrom;
143
+ },
144
+ formatAllowFrom: ({ allowFrom }) => {
145
+ return allowFrom.map((e) => String(e).trim()).filter(Boolean);
146
+ },
147
+ resolveDefaultTo: () => undefined,
141
148
  },
142
149
  // ── gateway 适配器 ──
143
150
  gateway: {
@@ -212,6 +219,8 @@ export const httpChannelPlugin = {
212
219
  outbound: {
213
220
  deliveryMode: "direct",
214
221
  textChunkLimit: 4000,
222
+ chunker: (text, limit) => chunkText(text, { maxLength: limit }),
223
+ chunkerMode: "markdown",
215
224
  sendText: async (opts) => {
216
225
  const account = opts?.account;
217
226
  const text = opts?.text || "";
@@ -223,7 +232,6 @@ export const httpChannelPlugin = {
223
232
  if (!text) {
224
233
  return { channel: CHANNEL_ID, ok: true };
225
234
  }
226
- // Fence-aware chunking for long messages
227
235
  const chunks = chunkText(text, { maxLength: account?.textChunkLimit || 4000 });
228
236
  for (const chunk of chunks) {
229
237
  const result = await sendWithRetry({
@@ -264,6 +272,40 @@ export const httpChannelPlugin = {
264
272
  }
265
273
  return { channel: CHANNEL_ID, ok: true };
266
274
  },
275
+ sendPayload: async (ctx) => {
276
+ const cfg = ctx.cfg;
277
+ const accountId = ctx.accountId;
278
+ const to = ctx.to;
279
+ const payload = ctx.payload;
280
+ const account = cfg ? resolveAccount(cfg, accountId) : undefined;
281
+ const webhookUrl = getRuntimeWebhookUrl(accountId) || account?.webhookUrl;
282
+ if (!webhookUrl) {
283
+ return { channel: CHANNEL_ID, ok: false, error: new Error("No webhookUrl configured for payload delivery") };
284
+ }
285
+ // 优先发送渠道专属数据(channelData.xiaozhu),回退到通用 text
286
+ const channelData = payload?.channelData?.xiaozhu;
287
+ const webhookPayload = channelData || {
288
+ type: "payload",
289
+ text: payload?.text || "",
290
+ session: to || "",
291
+ from: "openclaw",
292
+ channel: CHANNEL_ID,
293
+ timestamp: Date.now(),
294
+ ...(payload?.mediaUrl ? { mediaUrl: payload.mediaUrl } : {}),
295
+ };
296
+ const result = await sendWithRetry({
297
+ url: webhookUrl,
298
+ payload: webhookPayload,
299
+ token: account?.token || "",
300
+ secret: account?.webhookSecret,
301
+ maxAttempts: account?.webhookRetry?.maxAttempts ?? 3,
302
+ baseDelayMs: account?.webhookRetry?.baseDelayMs ?? 1000,
303
+ });
304
+ if (!result.ok) {
305
+ return { channel: CHANNEL_ID, ok: false, error: result.error || new Error("Webhook payload failed"), messageId: "" };
306
+ }
307
+ return { channel: CHANNEL_ID, ok: true, messageId: "" };
308
+ },
267
309
  },
268
310
  // ── status 适配器 ──
269
311
  status: {
@@ -272,12 +314,20 @@ export const httpChannelPlugin = {
272
314
  running: false,
273
315
  connected: false,
274
316
  lastStartAt: null,
317
+ lastStopAt: null,
275
318
  lastError: null,
319
+ lastInboundAt: null,
320
+ lastOutboundAt: null,
276
321
  },
277
322
  probeAccount: async ({ account, timeoutMs }) => {
278
323
  const start = Date.now();
279
324
  try {
280
- const res = await fetch(`http://127.0.0.1:${account.port}/api/health`, { signal: AbortSignal.timeout(timeoutMs ?? 3000) });
325
+ const ctrl = new AbortController();
326
+ const timer = setTimeout(() => ctrl.abort(), timeoutMs ?? 3000);
327
+ if (timer.unref)
328
+ timer.unref();
329
+ const res = await fetch(`http://127.0.0.1:${account.port}/api/health`, { signal: ctrl.signal });
330
+ clearTimeout(timer);
281
331
  const latencyMs = Date.now() - start;
282
332
  let data = null;
283
333
  try {
@@ -290,6 +340,175 @@ export const httpChannelPlugin = {
290
340
  return { ok: false, latencyMs: Date.now() - start };
291
341
  }
292
342
  },
343
+ buildAccountSnapshot: ({ account, runtime }) => ({
344
+ accountId: account.accountId,
345
+ name: `小助 :${account.port}`,
346
+ enabled: account.enabled,
347
+ configured: !!account.token,
348
+ running: runtime?.running ?? false,
349
+ connected: runtime?.connected ?? false,
350
+ lastStartAt: runtime?.lastStartAt ?? null,
351
+ lastStopAt: runtime?.lastStopAt ?? null,
352
+ lastError: runtime?.lastError ?? null,
353
+ mode: account.networkMode || "webhook",
354
+ lastInboundAt: runtime?.lastInboundAt ?? null,
355
+ lastOutboundAt: runtime?.lastOutboundAt ?? null,
356
+ }),
357
+ buildChannelSummary: ({ snapshot }) => ({
358
+ configured: snapshot.configured ?? false,
359
+ running: snapshot.running ?? false,
360
+ connected: snapshot.connected ?? false,
361
+ mode: snapshot.mode ?? "webhook",
362
+ lastStartAt: snapshot.lastStartAt ?? null,
363
+ lastStopAt: snapshot.lastStopAt ?? null,
364
+ lastError: snapshot.lastError ?? null,
365
+ lastInboundAt: snapshot.lastInboundAt ?? null,
366
+ lastOutboundAt: snapshot.lastOutboundAt ?? null,
367
+ }),
368
+ },
369
+ // ── messaging 适配器 ──
370
+ messaging: {
371
+ normalizeTarget: (raw) => {
372
+ const trimmed = raw.trim().toLowerCase();
373
+ return trimmed || undefined;
374
+ },
375
+ targetResolver: {
376
+ looksLikeId: (raw) => /^[\w.@:+\-]{1,128}$/.test(raw.trim()),
377
+ hint: "用户 ID(字母、数字、下划线、点、@、冒号、加号、减号)",
378
+ },
379
+ formatTargetDisplay: ({ target, display }) => {
380
+ return display || target;
381
+ },
382
+ },
383
+ // ── groups 适配器 ──
384
+ groups: {
385
+ resolveRequireMention: ({ cfg, accountId }) => {
386
+ const account = resolveAccount(cfg, accountId);
387
+ return account.requireMention;
388
+ },
389
+ resolveGroupIntroHint: ({ cfg, accountId }) => {
390
+ const account = resolveAccount(cfg, accountId);
391
+ return account.groupIntroHint;
392
+ },
393
+ },
394
+ // ── mentions 适配器 ──
395
+ mentions: {
396
+ stripPatterns: () => [
397
+ "^@小助\\s*",
398
+ "^@xiaozhu\\s*",
399
+ "^@bot\\s*",
400
+ ],
401
+ stripMentions: ({ text }) => {
402
+ return text.replace(/^@(?:小助|xiaozhu|bot)\s*/i, "").trim();
403
+ },
404
+ },
405
+ // ── pairing 适配器 ──
406
+ pairing: {
407
+ idLabel: "用户 ID",
408
+ normalizeAllowEntry: (entry) => entry.trim().toLowerCase(),
409
+ notifyApproval: async () => {
410
+ // HTTP 渠道无原生推送通道,审批通知通过 webhook 推送(如已配置)
411
+ },
412
+ },
413
+ // ── security 适配器 ──
414
+ security: {
415
+ resolveDmPolicy: () => null, // 使用 OpenClaw 默认策略(HTTP 已有 token 鉴权)
416
+ collectWarnings: ({ account }) => {
417
+ const warnings = [];
418
+ if (!account.token)
419
+ warnings.push("未配置 token,服务不可用");
420
+ if (account.allowFrom?.includes("*"))
421
+ warnings.push("allowFrom 设为 *,任何人可发送消息");
422
+ if (!account.webhookUrl && account.networkMode !== "cloud") {
423
+ warnings.push("未配置 webhookUrl,outbound 消息无法推送");
424
+ }
425
+ return warnings;
426
+ },
427
+ },
428
+ // ── commands 适配器 ──
429
+ commands: {
430
+ enforceOwnerForCommands: false,
431
+ skipWhenConfigEmpty: false,
432
+ },
433
+ // ── streaming 适配器 ──
434
+ streaming: {
435
+ blockStreamingCoalesceDefaults: { minChars: 200, idleMs: 500 },
436
+ },
437
+ // ── threading 适配器 ──
438
+ threading: {
439
+ resolveReplyToMode: ({ cfg, accountId }) => {
440
+ if (!accountId)
441
+ return "off";
442
+ const account = resolveAccount(cfg, accountId);
443
+ return account.replyToMode || "off";
444
+ },
445
+ allowExplicitReplyTagsWhenOff: false,
446
+ },
447
+ // ── agentPrompt 适配器 ──
448
+ agentPrompt: {
449
+ messageToolHints: () => [
450
+ "用户通过 HTTP API 发送消息,支持文本、图片、文件和语音",
451
+ "回复支持 Markdown 格式,长回复会自动分块(围栏感知)",
452
+ ],
453
+ },
454
+ // ── directory 适配器 ──
455
+ directory: {
456
+ self: async ({ accountId }) => {
457
+ return {
458
+ id: `${CHANNEL_ID}:${accountId || "default"}`,
459
+ name: `小助 (${accountId || "default"})`,
460
+ kind: "bot",
461
+ };
462
+ },
463
+ listPeers: async ({ accountId }) => {
464
+ const state = getAccountState(accountId);
465
+ if (!state)
466
+ return [];
467
+ const sessions = state.sessionStore.list({ accountId, chatType: "direct" });
468
+ const seen = new Set();
469
+ return sessions
470
+ .filter((s) => { if (seen.has(s.from))
471
+ return false; seen.add(s.from); return true; })
472
+ .map((s) => ({ id: s.from, name: s.from, kind: "user" }));
473
+ },
474
+ listGroups: async ({ accountId }) => {
475
+ const state = getAccountState(accountId);
476
+ if (!state)
477
+ return [];
478
+ return state.sessionStore.list({ accountId, chatType: "group" })
479
+ .map((s) => ({ id: s.session, name: s.session, kind: "group" }));
480
+ },
481
+ },
482
+ // ── actions 适配器 ──
483
+ actions: {
484
+ listActions: () => ["reply", "forward"],
485
+ supportsAction: ({ action }) => action === "reply" || action === "forward",
486
+ supportsButtons: () => false,
487
+ supportsCards: () => false,
488
+ },
489
+ // ── heartbeat 适配器 ──
490
+ heartbeat: {
491
+ checkReady: async ({ cfg, accountId }) => {
492
+ const account = resolveAccount(cfg, accountId);
493
+ try {
494
+ const ctrl = new AbortController();
495
+ const timer = setTimeout(() => ctrl.abort(), 3000);
496
+ if (timer.unref)
497
+ timer.unref();
498
+ const res = await fetch(`http://127.0.0.1:${account.port}/api/health`, { signal: ctrl.signal });
499
+ clearTimeout(timer);
500
+ const data = await res.json();
501
+ return { ok: data.ok === true, reason: data.ok ? "healthy" : "health check returned ok=false" };
502
+ }
503
+ catch (err) {
504
+ return { ok: false, reason: err instanceof Error ? err.message : "health check failed" };
505
+ }
506
+ },
507
+ resolveRecipients: ({ cfg, accountId }) => {
508
+ const account = resolveAccount(cfg, accountId);
509
+ const url = getRuntimeWebhookUrl(account.accountId) || account.webhookUrl;
510
+ return url ? { recipients: [url], source: "webhook" } : { recipients: [], source: "none" };
511
+ },
293
512
  },
294
513
  };
295
514
  //# sourceMappingURL=channel.js.map