openclaw-heychat 2026.2.25
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 +265 -0
- package/index.ts +17 -0
- package/package.json +44 -0
- package/src/accounts.ts +150 -0
- package/src/channel.ts +811 -0
- package/src/config-schema.ts +38 -0
- package/src/policy.ts +99 -0
- package/src/runtime.ts +14 -0
- package/src/types.ts +28 -0
package/README.md
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# OpenClaw Heychat Plugin
|
|
2
|
+
|
|
3
|
+
[Heychat](https://www.xiaoheihe.cn/) (黑盒语音) channel plugin for [OpenClaw](https://github.com/openclaw-ai/openclaw) - 集成 AI 聊天功能。
|
|
4
|
+
|
|
5
|
+
## 功能特性
|
|
6
|
+
|
|
7
|
+
- ✅ 支持私信和群组消息
|
|
8
|
+
- ✅ 多账户配置
|
|
9
|
+
- ✅ 群组策略控制(开放/白名单/阻止)
|
|
10
|
+
- ✅ 消息去重
|
|
11
|
+
- ✅ WebSocket 自动重连
|
|
12
|
+
- ✅ 与 OpenClaw AI 聊天集成
|
|
13
|
+
|
|
14
|
+
## 安装
|
|
15
|
+
|
|
16
|
+
### 前提条件
|
|
17
|
+
|
|
18
|
+
1. 已安装 [OpenClaw](https://github.com/openclaw-ai/openclaw)
|
|
19
|
+
2. 已获取 Heychat App Token
|
|
20
|
+
|
|
21
|
+
### 安装步骤
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# 克隆插件到 OpenClaw 扩展目录
|
|
25
|
+
git clone https://github.com/DefinerSy/openclaw-heychat.git ~/.openclaw/extensions/heychat
|
|
26
|
+
|
|
27
|
+
# 或者安装到全局 node_modules
|
|
28
|
+
cd ~/.openclaw/extensions/heychat
|
|
29
|
+
npm install
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## 获取 Heychat Token
|
|
33
|
+
|
|
34
|
+
1. 打开黑盒语音 APP
|
|
35
|
+
2. 进入设置 -> 开发者选项
|
|
36
|
+
3. 创建机器人应用
|
|
37
|
+
4. 复制 App Token
|
|
38
|
+
|
|
39
|
+
## 配置
|
|
40
|
+
|
|
41
|
+
### 方式一:通过 UI 面板配置(推荐)
|
|
42
|
+
|
|
43
|
+
1. 启动 OpenClaw:`openclaw`
|
|
44
|
+
2. 打开浏览器访问:http://127.0.0.1:18789
|
|
45
|
+
3. 进入 **Channels** -> **Heychat**
|
|
46
|
+
4. 填写 Token 和其他配置
|
|
47
|
+
|
|
48
|
+
### 方式二:编辑配置文件
|
|
49
|
+
|
|
50
|
+
编辑 `~/.openclaw/openclaw.json`:
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"channels": {
|
|
55
|
+
"heychat": {
|
|
56
|
+
"enabled": true,
|
|
57
|
+
"token": "YOUR_HEYCHAT_APP_TOKEN",
|
|
58
|
+
"dmPolicy": "pairing",
|
|
59
|
+
"groupPolicy": "allowlist",
|
|
60
|
+
"allowFrom": ["群组 ID 1", "群组 ID 2"],
|
|
61
|
+
"groups": {
|
|
62
|
+
"*": {
|
|
63
|
+
"requireMention": true
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 方式三:环境变量
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
export HEYCHAT_APP_TOKEN="YOUR_HEYCHAT_APP_TOKEN"
|
|
75
|
+
openclaw
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## 配置项说明
|
|
79
|
+
|
|
80
|
+
### 基础配置
|
|
81
|
+
|
|
82
|
+
| 配置项 | 类型 | 必填 | 说明 | 示例 |
|
|
83
|
+
|--------|------|------|------|------|
|
|
84
|
+
| `enabled` | boolean | 否 | 是否启用此账户 | `true` |
|
|
85
|
+
| `token` | string | 是 | Heychat 机器人 Token | `"OTU3Mzg4..."` |
|
|
86
|
+
| `tokenFile` | string | 否 | Token 文件路径 | `"~/.heychat/token"` |
|
|
87
|
+
| `name` | string | 否 | 账户显示名称 | `"我的黑盒助手"` |
|
|
88
|
+
|
|
89
|
+
### 私信策略 (dmPolicy)
|
|
90
|
+
|
|
91
|
+
| 值 | 说明 |
|
|
92
|
+
|-----|------|
|
|
93
|
+
| `pairing` | 配对模式 - 需要用户先配对才能对话(默认) |
|
|
94
|
+
| `open` | 开放模式 - 任何用户都可以直接对话 |
|
|
95
|
+
| `allowlist` | 白名单模式 - 只有 allowFrom 列表中的用户可以对话 |
|
|
96
|
+
|
|
97
|
+
### 群组策略 (groupPolicy)
|
|
98
|
+
|
|
99
|
+
| 值 | 说明 |
|
|
100
|
+
|-----|------|
|
|
101
|
+
| `open` | 开放模式 - 任何群组成员都可以触发机器人 |
|
|
102
|
+
| `allowlist` | 白名单模式 - 只有 allowFrom 列表中的群组可以对话 |
|
|
103
|
+
| `disabled` | 阻止模式 - 禁止所有群组对话 |
|
|
104
|
+
|
|
105
|
+
### 白名单 (allowFrom)
|
|
106
|
+
|
|
107
|
+
数组类型,允许对话的用户/群组 ID 列表。
|
|
108
|
+
|
|
109
|
+
### 群组配置 (groups)
|
|
110
|
+
|
|
111
|
+
针对特定群组的精细控制:
|
|
112
|
+
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"groups": {
|
|
116
|
+
"*": {
|
|
117
|
+
"requireMention": true // 所有群组需要 @机器人 才能触发
|
|
118
|
+
},
|
|
119
|
+
"4052815029845475328": {
|
|
120
|
+
"requireMention": false // 特定群组不需要 @
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## 多账户配置
|
|
127
|
+
|
|
128
|
+
支持配置多个 Heychat 账户:
|
|
129
|
+
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"channels": {
|
|
133
|
+
"heychat": {
|
|
134
|
+
"enabled": true,
|
|
135
|
+
"token": "default-token",
|
|
136
|
+
"accounts": {
|
|
137
|
+
"客服 1 号": {
|
|
138
|
+
"name": "客服账号 1",
|
|
139
|
+
"token": "token-xxx-1",
|
|
140
|
+
"enabled": true,
|
|
141
|
+
"dmPolicy": "pairing",
|
|
142
|
+
"groupPolicy": "allowlist",
|
|
143
|
+
"allowFrom": ["group-id-1"]
|
|
144
|
+
},
|
|
145
|
+
"客服 2 号": {
|
|
146
|
+
"name": "客服账号 2",
|
|
147
|
+
"token": "token-xxx-2",
|
|
148
|
+
"enabled": false
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## 使用示例
|
|
157
|
+
|
|
158
|
+
### 配对私信用户
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
# 1. 在配置中添加用户到 allowFrom
|
|
162
|
+
# 2. 用户发送消息触发配对
|
|
163
|
+
# 3. 配对成功后可正常对话
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### 群组中使用
|
|
167
|
+
|
|
168
|
+
在群组中,默认需要 @机器人 才能触发回复:
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
@机器人 今天天气怎么样?
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## 故障排除
|
|
175
|
+
|
|
176
|
+
### Token 无效
|
|
177
|
+
|
|
178
|
+
- 确认 Token 格式正确(Base64 编码)
|
|
179
|
+
- 确认 Token 未过期
|
|
180
|
+
- 检查环境变量 `HEYCHAT_APP_TOKEN` 是否覆盖配置
|
|
181
|
+
|
|
182
|
+
### 群组消息无响应
|
|
183
|
+
|
|
184
|
+
- 检查 `groupPolicy` 配置
|
|
185
|
+
- 如果在白名单模式,确认群组 ID 在 `allowFrom` 中
|
|
186
|
+
- 检查是否需要 @机器人
|
|
187
|
+
|
|
188
|
+
### WebSocket 频繁断连
|
|
189
|
+
|
|
190
|
+
- 检查网络连接
|
|
191
|
+
- 确认 Token 有效
|
|
192
|
+
- 查看 OpenClaw 日志:`openclaw logs --follow`
|
|
193
|
+
|
|
194
|
+
### 私信消息无响应
|
|
195
|
+
|
|
196
|
+
**问题描述**:直接发送私信消息时,机器人没有响应。
|
|
197
|
+
|
|
198
|
+
**原因**:Heychat 平台的 WebSocket 只推送通知事件(event: "80"),不包含实际的消息内容。私信消息需要使用 `/chat` 命令触发才会通过 WebSocket 推送。
|
|
199
|
+
|
|
200
|
+
**解决方案**:
|
|
201
|
+
|
|
202
|
+
1. **使用 `/chat` 命令发送私信**(推荐):
|
|
203
|
+
```
|
|
204
|
+
/chat 你好,这是一条测试消息
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
2. **确认配置正确**:
|
|
208
|
+
- `dmPolicy` 设置为 `open`(开放模式)或 `pairing`(配对模式)
|
|
209
|
+
- 如果使用 `allowlist` 模式,确保用户 ID 在 `allowFrom` 列表中
|
|
210
|
+
|
|
211
|
+
3. **查看日志确认事件**:
|
|
212
|
+
```bash
|
|
213
|
+
openclaw logs --follow
|
|
214
|
+
```
|
|
215
|
+
正常收到消息时应该看到 `Type 5` 或 `Type 50` 事件。
|
|
216
|
+
|
|
217
|
+
**技术说明**:
|
|
218
|
+
- Heychat WebSocket 推送的事件类型:
|
|
219
|
+
- `event: "80", type: "notify"` - 心跳/状态通知,仅包含机器人 ID,无消息内容
|
|
220
|
+
- `type: "50"` - Bot 命令事件(如 `/chat` 命令)
|
|
221
|
+
- `type: "5"` - 普通消息事件
|
|
222
|
+
- 只有 Type 5 和 Type 50 事件才包含实际消息内容
|
|
223
|
+
|
|
224
|
+
## 开发
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
# 克隆仓库
|
|
228
|
+
git clone https://github.com/DefinerSy/openclaw-heychat.git
|
|
229
|
+
|
|
230
|
+
# 安装依赖
|
|
231
|
+
cd openclaw-heychat
|
|
232
|
+
npm install
|
|
233
|
+
|
|
234
|
+
# 修改代码后重启 OpenClaw
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## 项目结构
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
openclaw-heychat/
|
|
241
|
+
├── index.ts # 插件入口
|
|
242
|
+
├── package.json # 依赖配置
|
|
243
|
+
├── src/
|
|
244
|
+
│ ├── channel.ts # 频道主逻辑
|
|
245
|
+
│ ├── accounts.ts # 账户解析
|
|
246
|
+
│ ├── config-schema.ts # 配置 Schema
|
|
247
|
+
│ ├── policy.ts # 群组策略
|
|
248
|
+
│ ├── types.ts # 类型定义
|
|
249
|
+
│ └── runtime.ts # 运行时
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## 许可证
|
|
253
|
+
|
|
254
|
+
MIT License
|
|
255
|
+
|
|
256
|
+
## 致谢
|
|
257
|
+
|
|
258
|
+
- [OpenClaw](https://github.com/openclaw-ai/openclaw) - 基础框架
|
|
259
|
+
- [Heychat](https://www.xiaoheihe.cn/) - 黑盒语音平台
|
|
260
|
+
|
|
261
|
+
## 相关链接
|
|
262
|
+
|
|
263
|
+
- [GitHub 仓库](https://github.com/DefinerSy/openclaw-heychat)
|
|
264
|
+
- [OpenClaw 文档](https://docs.openclaw.ai/)
|
|
265
|
+
- [问题反馈](https://github.com/DefinerSy/openclaw-heychat/issues)
|
package/index.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
2
|
+
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
|
3
|
+
import { heychatPlugin } from "./src/channel.js";
|
|
4
|
+
import { setHeychatRuntime } from "./src/runtime.js";
|
|
5
|
+
|
|
6
|
+
const plugin = {
|
|
7
|
+
id: "heychat",
|
|
8
|
+
name: "Heychat",
|
|
9
|
+
description: "Heychat (黑盒语音) channel plugin",
|
|
10
|
+
configSchema: emptyPluginConfigSchema(),
|
|
11
|
+
register(api: OpenClawPluginApi) {
|
|
12
|
+
setHeychatRuntime(api.runtime);
|
|
13
|
+
api.registerChannel({ plugin: heychatPlugin });
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default plugin;
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "openclaw-heychat",
|
|
3
|
+
"version": "2026.2.25",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "OpenClaw Heychat (黑盒语音) channel plugin",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./index.ts",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"openclaw",
|
|
10
|
+
"heychat",
|
|
11
|
+
"黑盒语音",
|
|
12
|
+
"chatbot",
|
|
13
|
+
"plugin"
|
|
14
|
+
],
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/DefinerSy/openclaw-heychat.git"
|
|
18
|
+
},
|
|
19
|
+
"author": "DefinerSy <1780389351@qq.com>",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"ws": "^8.18.0",
|
|
23
|
+
"zod": "^4.3.6"
|
|
24
|
+
},
|
|
25
|
+
"openclaw": {
|
|
26
|
+
"extensions": [
|
|
27
|
+
"./index.ts"
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"index.ts",
|
|
32
|
+
"src/",
|
|
33
|
+
"package.json",
|
|
34
|
+
"README.md",
|
|
35
|
+
"LICENSE"
|
|
36
|
+
],
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"prepublishOnly": "echo 'Publishing TypeScript source files...'",
|
|
42
|
+
"version": "echo \"Version: $npm_package_version\""
|
|
43
|
+
}
|
|
44
|
+
}
|
package/src/accounts.ts
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import type { ClawdbotConfig } from "openclaw/plugin-sdk";
|
|
2
|
+
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-id";
|
|
3
|
+
import type { HeychatConfig, HeychatAccountConfig, ResolvedHeychatAccount } from "./types.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* List all configured account IDs from the accounts field.
|
|
7
|
+
*/
|
|
8
|
+
function listConfiguredAccountIds(cfg: ClawdbotConfig): string[] {
|
|
9
|
+
const accounts = (cfg.channels?.heychat as HeychatConfig)?.accounts;
|
|
10
|
+
if (!accounts || typeof accounts !== "object") {
|
|
11
|
+
return [];
|
|
12
|
+
}
|
|
13
|
+
return Object.keys(accounts).filter(Boolean);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* List all Heychat account IDs.
|
|
18
|
+
* If no accounts are configured, returns [DEFAULT_ACCOUNT_ID] for backward compatibility.
|
|
19
|
+
*/
|
|
20
|
+
export function listHeychatAccountIds(cfg: ClawdbotConfig): string[] {
|
|
21
|
+
const ids = listConfiguredAccountIds(cfg);
|
|
22
|
+
if (ids.length === 0) {
|
|
23
|
+
// Backward compatibility: no accounts configured, use default
|
|
24
|
+
return [DEFAULT_ACCOUNT_ID];
|
|
25
|
+
}
|
|
26
|
+
return [...ids].toSorted((a, b) => a.localeCompare(b));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Resolve the default account ID.
|
|
31
|
+
*/
|
|
32
|
+
export function resolveDefaultHeychatAccountId(cfg: ClawdbotConfig): string {
|
|
33
|
+
const ids = listHeychatAccountIds(cfg);
|
|
34
|
+
if (ids.includes(DEFAULT_ACCOUNT_ID)) {
|
|
35
|
+
return DEFAULT_ACCOUNT_ID;
|
|
36
|
+
}
|
|
37
|
+
return ids[0] ?? DEFAULT_ACCOUNT_ID;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Get the raw account-specific config.
|
|
42
|
+
*/
|
|
43
|
+
function resolveAccountConfig(cfg: ClawdbotConfig, accountId: string): HeychatAccountConfig | undefined {
|
|
44
|
+
const accounts = (cfg.channels?.heychat as HeychatConfig)?.accounts;
|
|
45
|
+
if (!accounts || typeof accounts !== "object") {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
return accounts[accountId];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Merge top-level config with account-specific config.
|
|
53
|
+
* Account-specific fields override top-level fields.
|
|
54
|
+
*/
|
|
55
|
+
function mergeHeychatAccountConfig(cfg: ClawdbotConfig, accountId: string): HeychatConfig {
|
|
56
|
+
const heychatCfg = cfg.channels?.heychat as HeychatConfig | undefined;
|
|
57
|
+
|
|
58
|
+
// Extract base config (exclude accounts field to avoid recursion)
|
|
59
|
+
const { accounts: _ignored, ...base } = heychatCfg ?? {};
|
|
60
|
+
|
|
61
|
+
// Get account-specific overrides
|
|
62
|
+
const account = resolveAccountConfig(cfg, accountId) ?? {};
|
|
63
|
+
|
|
64
|
+
// Merge: account config overrides base config
|
|
65
|
+
return { ...base, ...account } as HeychatConfig;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Resolve Heychat token from a config.
|
|
70
|
+
* Priority: env > config > file
|
|
71
|
+
*/
|
|
72
|
+
export function resolveHeychatToken(cfg?: HeychatConfig): {
|
|
73
|
+
token: string;
|
|
74
|
+
source: "config" | "file" | "env" | "none";
|
|
75
|
+
} | null {
|
|
76
|
+
// Check environment variable first
|
|
77
|
+
const envToken = process.env.HEYCHAT_APP_TOKEN?.trim();
|
|
78
|
+
if (envToken) {
|
|
79
|
+
return { token: envToken, source: "env" };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Check config token
|
|
83
|
+
const configToken = cfg?.token?.trim();
|
|
84
|
+
if (configToken) {
|
|
85
|
+
return { token: configToken, source: "config" };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Check token file
|
|
89
|
+
const tokenFile = cfg?.tokenFile?.trim();
|
|
90
|
+
if (tokenFile) {
|
|
91
|
+
// Token file handling would require fs import, return as file source
|
|
92
|
+
return { token: "", source: "file" };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return { token: "", source: "none" };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Resolve a complete Heychat account with merged config.
|
|
100
|
+
*/
|
|
101
|
+
export function resolveHeychatAccount(params: {
|
|
102
|
+
cfg: ClawdbotConfig;
|
|
103
|
+
accountId?: string | null;
|
|
104
|
+
}): ResolvedHeychatAccount {
|
|
105
|
+
const accountId = normalizeAccountId(params.accountId);
|
|
106
|
+
const heychatCfg = params.cfg.channels?.heychat as HeychatConfig | undefined;
|
|
107
|
+
|
|
108
|
+
// Base enabled state (top-level)
|
|
109
|
+
const baseEnabled = heychatCfg?.enabled !== false;
|
|
110
|
+
|
|
111
|
+
// Merge configs
|
|
112
|
+
const merged = mergeHeychatAccountConfig(params.cfg, accountId);
|
|
113
|
+
|
|
114
|
+
// Account-level enabled state
|
|
115
|
+
const accountEnabled = merged.enabled !== false;
|
|
116
|
+
const enabled = baseEnabled && accountEnabled;
|
|
117
|
+
|
|
118
|
+
// Resolve token from merged config
|
|
119
|
+
const tokenInfo = resolveHeychatToken(merged);
|
|
120
|
+
|
|
121
|
+
// Build display name
|
|
122
|
+
const name = (merged as HeychatAccountConfig).name?.trim() || `heychat:${accountId}`;
|
|
123
|
+
|
|
124
|
+
// Build merged policy config
|
|
125
|
+
const config = {
|
|
126
|
+
dmPolicy: merged.dmPolicy ?? "pairing",
|
|
127
|
+
groupPolicy: merged.groupPolicy ?? "open",
|
|
128
|
+
allowFrom: merged.allowFrom ?? [],
|
|
129
|
+
groups: merged.groups ?? {},
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
accountId,
|
|
134
|
+
enabled,
|
|
135
|
+
configured: Boolean(tokenInfo?.token),
|
|
136
|
+
name,
|
|
137
|
+
token: tokenInfo?.token,
|
|
138
|
+
tokenSource: tokenInfo?.source ?? "none",
|
|
139
|
+
config,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* List all enabled and configured accounts.
|
|
145
|
+
*/
|
|
146
|
+
export function listEnabledHeychatAccounts(cfg: ClawdbotConfig): ResolvedHeychatAccount[] {
|
|
147
|
+
return listHeychatAccountIds(cfg)
|
|
148
|
+
.map((accountId) => resolveHeychatAccount({ cfg, accountId }))
|
|
149
|
+
.filter((account) => account.enabled && account.configured);
|
|
150
|
+
}
|