aicq-chat-plugin 2.6.5 → 3.0.1

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.
@@ -1,53 +1,68 @@
1
1
  {
2
+ "kind": "channel",
2
3
  "id": "aicq-chat",
3
4
  "name": "AICQ Encrypted Chat",
4
- "version": "2.6.5",
5
- "description": "End-to-end encrypted chat plugin for OpenClaw agentsNode.js implementation with full UI",
5
+ "version": "3.0.1",
6
+ "description": "End-to-end encrypted chat channel via AICQ protocolin-process Channel plugin",
6
7
  "entry": "index.js",
7
8
  "activation": {
8
9
  "onStartup": true
9
10
  },
10
11
  "enabledByDefault": true,
12
+ "channels": [
13
+ "aicq-chat"
14
+ ],
15
+ "channelConfigs": {
16
+ "aicq-chat": {
17
+ "accounts": {
18
+ "type": "object",
19
+ "properties": {
20
+ "accountId": {
21
+ "type": "string",
22
+ "description": "绑定到 OpenClaw 智能体的账户 ID",
23
+ "default": "{{agent.id}}"
24
+ },
25
+ "autoAcceptFriends": {
26
+ "type": "boolean",
27
+ "default": true,
28
+ "description": "是否自动接受好友请求"
29
+ }
30
+ },
31
+ "required": [
32
+ "accountId"
33
+ ]
34
+ }
35
+ }
36
+ },
11
37
  "configSchema": {
12
38
  "type": "object",
13
39
  "additionalProperties": false,
14
40
  "properties": {
15
- "enabled": {
16
- "type": "boolean",
17
- "description": "Enable the AICQ chat plugin (default: true).",
18
- "default": true
41
+ "serverUrl": {
42
+ "type": "string",
43
+ "description": "AICQ 服务器地址",
44
+ "default": "https://aicq.online"
19
45
  },
20
- "port": {
21
- "type": "number",
22
- "description": "Port for the AICQ sidecar server (default: 6109).",
23
- "default": 6109,
24
- "minimum": 1024,
25
- "maximum": 65535
26
- },
27
- "autoStart": {
46
+ "autoAcceptFriends": {
28
47
  "type": "boolean",
29
- "description": "Automatically start the sidecar server on gateway startup (default: true).",
48
+ "description": "自动接受好友请求",
30
49
  "default": true
31
50
  },
32
51
  "debug": {
33
52
  "type": "boolean",
34
- "description": "Enable verbose debug logging (default: false).",
53
+ "description": "Enable verbose debug logging",
35
54
  "default": false
36
55
  }
37
56
  }
38
57
  },
39
58
  "uiHints": {
40
- "enabled": {
41
- "label": "Enable AICQ",
42
- "help": "Toggle the AICQ encrypted chat plugin on or off."
43
- },
44
- "port": {
45
- "label": "Sidecar Port",
46
- "help": "The port the AICQ sidecar server listens on."
59
+ "serverUrl": {
60
+ "label": "AICQ Server URL",
61
+ "help": "The AICQ signaling server URL for WebSocket connections."
47
62
  },
48
- "autoStart": {
49
- "label": "Auto Start",
50
- "help": "Start the AICQ server automatically when OpenClaw gateway starts."
63
+ "autoAcceptFriends": {
64
+ "label": "Auto Accept Friends",
65
+ "help": "Automatically accept incoming friend requests."
51
66
  },
52
67
  "debug": {
53
68
  "label": "Debug Mode",
@@ -85,19 +100,13 @@
85
100
  "aicq.groups.silent"
86
101
  ]
87
102
  },
88
- "sidecar": {
89
- "command": "node",
90
- "args": [
91
- "index.js"
92
- ],
93
- "port": 6109
94
- },
95
103
  "runtime": "node",
96
104
  "requires": {
97
105
  "node": ">=18.0.0",
98
106
  "packages": [
99
107
  "sql.js",
100
108
  "tweetnacl",
109
+ "tweetnacl-util",
101
110
  "ws",
102
111
  "qrcode",
103
112
  "express"
package/package.json CHANGED
@@ -1,16 +1,17 @@
1
1
  {
2
2
  "name": "aicq-chat-plugin",
3
- "version": "2.6.5",
4
- "description": "AICQ End-to-end Encrypted Chat Plugin for OpenClaw — Full UI with friend management, group chat, file transfer, and AI agent communication",
3
+ "version": "3.0.1",
4
+ "description": "AICQ End-to-end Encrypted Chat Channel Plugin for OpenClaw — In-process Channel architecture with friend management, group chat, file transfer, and AI agent communication",
5
5
  "main": "index.js",
6
6
  "bin": {
7
7
  "aicq-plugin": "cli.js"
8
8
  },
9
9
  "files": [
10
- "extension.js",
11
10
  "index.js",
11
+ "setup-entry.js",
12
12
  "cli.js",
13
13
  "postinstall.js",
14
+ "src/",
14
15
  "lib/",
15
16
  "public/",
16
17
  "openclaw.plugin.json",
@@ -29,6 +30,7 @@
29
30
  "e2ee",
30
31
  "openclaw",
31
32
  "plugin",
33
+ "channel",
32
34
  "ai-agent",
33
35
  "messaging",
34
36
  "p2p"
@@ -59,10 +61,12 @@
59
61
  "node": ">=18.0.0"
60
62
  },
61
63
  "openclaw": {
62
- "id": "aicq-chat",
63
- "extensions": [
64
- "./extension.js"
65
- ],
64
+ "channel": {
65
+ "id": "aicq-chat",
66
+ "label": "AICQ Encrypted Chat",
67
+ "blurb": "端到端加密即时通讯频道,基于 NaCl (X25519 + XSalsa20-Poly1305)",
68
+ "icon": "🔐"
69
+ },
66
70
  "compat": {
67
71
  "pluginApi": ">=2026.3.24-beta.2"
68
72
  }
package/postinstall.js CHANGED
@@ -1,355 +1,26 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * AICQ Chat Plugin — Post-install script
3
+ * AICQ Chat Plugin — Post-install script (v3.0 Channel)
4
4
  *
5
- * Automatically installs the plugin into OpenClaw's skills/ and plugins/ directories.
6
- * OpenClaw discovers skills by scanning skills/ directories for SKILL.md marker files.
7
- * OpenClaw reads openclaw.plugin.json from plugins/ to launch sidecar processes.
5
+ * Displays setup information after npm install.
6
+ * v3.0 uses Channel architecture - no independent port needed.
8
7
  */
9
8
 
10
- const fs = require('fs');
11
- const path = require('path');
12
- const os = require('os');
13
- const { execSync } = require('child_process');
14
-
15
- const PLUGIN_ID = 'aicq-chat';
16
- const PLUGIN_DIR = path.resolve(__dirname);
17
-
18
- // ── SKILL.md template ─────────────────────────────────────────────
19
- const SKILL_MD_TEMPLATE = `---
20
- name: aicq-chat
21
- description: AICQ End-to-end Encrypted Chat Plugin for OpenClaw — Full UI with friend management, group chat, file transfer, and AI agent communication
22
- license: MIT
23
- metadata:
24
- author: AICQ
25
- version: "{VERSION}"
26
- ---
27
-
28
- # AICQ Encrypted Chat
29
-
30
- AICQ 是一个端到端加密聊天插件,适用于 OpenClaw 的完整聊天 UI。支持好友管理、群组聊天、文件传输和 AI Agent 通信。
31
-
32
- ## 功能特性
33
-
34
- - **端到端加密 (E2EE)** — 基于 NaCl (libsodium) 的加密体系,消息仅通信双方可读
35
- - **Agent 管理** — 支持多 Agent 切换、创建和删除
36
- - **好友管理** — 好友码添加、QR 码扫描、好友列表同步
37
- - **群组聊天** — 创建群组、邀请成员、静默模式
38
- - **消息功能** — Markdown/LaTeX 渲染、图片/文件上传、@提及
39
- - **密钥管理** — 公钥/私钥显示、密钥轮换、指纹验证
40
- - **P2P 通信** — 握手、文本传输、文件传输
41
-
42
- ## 一键启动
43
-
44
- \`\`\`bash
45
- # 1. 卸载旧版
46
- openclaw plugins uninstall aicq-chat
47
-
48
- # 2. 安装新版
49
- openclaw plugins install npm:aicq-chat-plugin
50
-
51
- # 3. 重启 gateway
52
- openclaw gateway restart
53
-
54
- # 4. 浏览器访问聊天界面
55
- open http://localhost:6109
56
- \`\`\`
57
-
58
- ## OpenClaw 集成
59
-
60
- 插件会自动注册为 OpenClaw sidecar,提供以下工具和网关:
61
-
62
- ### 工具
63
- - \`chat-friend\` — 好友管理
64
- - \`chat-send\` — 发送消息
65
- - \`chat-export-key\` — 导出密钥
66
-
67
- ### 网关方法
68
- - \`aicq.status\` — 插件状态
69
- - \`aicq.friends.list/add/remove\` — 好友操作
70
- - \`aicq.chat.send/history/delete\` — 聊天操作
71
- - \`aicq.groups.list/create/join\` — 群组操作
72
- - \`aicq.identity.info\` — 身份信息
73
-
74
- ## 配置
75
-
76
- | 变量 | 默认值 | 说明 |
77
- |------|--------|------|
78
- | \`AICQ_PORT\` | 6109 | 插件服务端口 |
79
- | \`AICQ_SERVER_URL\` | https://aicq.online | AICQ 服务器地址 |
80
- | \`AICQ_DATA_DIR\` | ~/.aicq-plugin | 数据存储目录 |
81
-
82
- ## Chat UI
83
-
84
- 启动后访问 http://localhost:6109 即可使用完整的聊天界面。
85
- `;
86
-
87
- // ── Find OpenClaw installation ──────────────────────────────────────
88
- function findOpenClawDir() {
89
- const candidates = [
90
- path.join(os.homedir(), '.openclaw'),
91
- path.join(os.homedir(), 'openclaw'),
92
- path.join(os.homedir(), '.config', 'openclaw'),
93
- ];
94
-
95
- if (process.env.OPENCLAW_HOME) {
96
- candidates.unshift(process.env.OPENCLAW_HOME);
97
- }
98
-
99
- for (const dir of candidates) {
100
- if (fs.existsSync(dir)) {
101
- return dir;
102
- }
103
- }
104
- return null;
105
- }
106
-
107
- // ── Find OpenClaw workspace (for skills/ directory) ────────────────
108
- function findOpenClawWorkspace() {
109
- if (process.env.OPENCLAW_WORKSPACE) {
110
- return process.env.OPENCLAW_WORKSPACE;
111
- }
112
-
113
- const home = os.homedir();
114
- const candidates = [
115
- process.cwd(),
116
- path.join(home, 'my-project'),
117
- path.join(home, 'openclaw'),
118
- path.join(home, '.openclaw'),
119
- ];
120
-
121
- for (const dir of candidates) {
122
- const skillsDir = path.join(dir, 'skills');
123
- if (fs.existsSync(skillsDir)) {
124
- return dir;
125
- }
126
- }
127
-
128
- // Check parent directories
129
- let current = process.cwd();
130
- for (let i = 0; i < 3; i++) {
131
- const skillsDir = path.join(current, 'skills');
132
- if (fs.existsSync(skillsDir)) {
133
- return current;
134
- }
135
- current = path.dirname(current);
136
- }
137
-
138
- // If no existing skills/ found, fall back to the OpenClaw directory itself.
139
- // This handles the case where ~/.openclaw/ exists but has no skills/ yet.
140
- // We'll auto-create skills/ inside it during installation.
141
- const openclawDir = findOpenClawDir();
142
- if (openclawDir) {
143
- return openclawDir;
144
- }
145
-
146
- return null;
147
- }
148
-
149
- // ── Recursively copy a directory ────────────────────────────────────
150
- function copyDirRecursive(src, dest) {
151
- fs.mkdirSync(dest, { recursive: true });
152
- const entries = fs.readdirSync(src, { withFileTypes: true });
153
-
154
- for (const entry of entries) {
155
- const srcPath = path.join(src, entry.name);
156
- const destPath = path.join(dest, entry.name);
157
-
158
- if (entry.isDirectory()) {
159
- if (entry.name === 'node_modules') continue;
160
- copyDirRecursive(srcPath, destPath);
161
- } else {
162
- fs.copyFileSync(srcPath, destPath);
163
- }
164
- }
165
- }
166
-
167
- // ── Install plugin files to a target directory ─────────────────────
168
- function installToDir(sourceDir, targetDir, version) {
169
- const filesToCopy = [
170
- 'extension.js',
171
- 'index.js',
172
- 'cli.js',
173
- 'postinstall.js',
174
- 'openclaw.plugin.json',
175
- 'package.json',
176
- 'README.md',
177
- ];
178
-
179
- const dirsToCopy = [
180
- 'lib',
181
- 'public',
182
- ];
183
-
184
- // Create target directory if needed
185
- if (!fs.existsSync(targetDir)) {
186
- fs.mkdirSync(targetDir, { recursive: true });
187
- }
188
-
189
- // Copy individual files
190
- for (const file of filesToCopy) {
191
- const src = path.join(sourceDir, file);
192
- const dest = path.join(targetDir, file);
193
- if (fs.existsSync(src)) {
194
- fs.copyFileSync(src, dest);
195
- }
196
- }
197
-
198
- // Copy directories
199
- for (const dir of dirsToCopy) {
200
- const src = path.join(sourceDir, dir);
201
- const dest = path.join(targetDir, dir);
202
- if (fs.existsSync(src)) {
203
- if (fs.existsSync(dest)) {
204
- fs.rmSync(dest, { recursive: true, force: true });
205
- }
206
- copyDirRecursive(src, dest);
207
- }
208
- }
209
-
210
- // Generate SKILL.md with current version
211
- const skillMd = SKILL_MD_TEMPLATE.replace('{VERSION}', version);
212
- fs.writeFileSync(path.join(targetDir, 'SKILL.md'), skillMd, 'utf8');
213
- }
214
-
215
- // ── Install to skills/ directory ────────────────────────────────────
216
- function installToSkillsDir(workspace, version) {
217
- const skillsDir = path.join(workspace, 'skills');
218
- const targetDir = path.join(skillsDir, PLUGIN_ID);
219
-
220
- if (!fs.existsSync(skillsDir)) {
221
- fs.mkdirSync(skillsDir, { recursive: true });
222
- }
223
-
224
- console.log(`[AICQ] Installing skill to ${targetDir}`);
225
-
226
- installToDir(PLUGIN_DIR, targetDir, version);
227
-
228
- // Install npm dependencies
229
- console.log('[AICQ] Installing skill dependencies...');
230
- try {
231
- execSync('npm install --omit=dev', {
232
- cwd: targetDir,
233
- stdio: 'pipe',
234
- timeout: 120000,
235
- });
236
- console.log('[AICQ] Skill dependencies installed.');
237
- } catch (e) {
238
- console.log('[AICQ] Warning: npm install failed. You may need to run it manually:');
239
- console.log(` cd ${targetDir} && npm install`);
240
- }
241
-
242
- return targetDir;
243
- }
244
-
245
- // ── Install to plugins/ directory ───────────────────────────────────
246
- function installToPluginsDir(openclawDir, version) {
247
- const pluginsDir = path.join(openclawDir, 'plugins');
248
- const targetDir = path.join(pluginsDir, PLUGIN_ID);
249
-
250
- if (!fs.existsSync(pluginsDir)) {
251
- fs.mkdirSync(pluginsDir, { recursive: true });
252
- }
253
-
254
- console.log(`[AICQ] Installing plugin to ${targetDir}`);
255
-
256
- installToDir(PLUGIN_DIR, targetDir, version);
257
-
258
- // Install npm dependencies
259
- console.log('[AICQ] Installing plugin dependencies...');
260
- try {
261
- execSync('npm install --omit=dev', {
262
- cwd: targetDir,
263
- stdio: 'pipe',
264
- timeout: 120000,
265
- });
266
- console.log('[AICQ] Plugin dependencies installed.');
267
- } catch (e) {
268
- console.log('[AICQ] Warning: npm install failed. You may need to run it manually:');
269
- console.log(` cd ${targetDir} && npm install`);
270
- }
271
-
272
- return targetDir;
273
- }
274
-
275
- // ── Main ────────────────────────────────────────────────────────────
276
9
  console.log('');
277
10
  console.log(' ╔══════════════════════════════════════════════╗');
278
- console.log(' ║ AICQ Chat Plugin Installing... ║');
11
+ console.log(' ║ AICQ Chat Plugin v3.0 Installed! ║');
12
+ console.log(' ╠══════════════════════════════════════════════╣');
13
+ console.log(' ║ ║');
14
+ console.log(' ║ Architecture: Channel (in-process) ║');
15
+ console.log(' ║ No independent port needed! ║');
16
+ console.log(' ║ ║');
17
+ console.log(' ║ Install via openclaw CLI: ║');
18
+ console.log(' ║ openclaw plugins uninstall aicq-chat ║');
19
+ console.log(' ║ openclaw plugins install npm:aicq-chat-plugin ║');
20
+ console.log(' ║ openclaw gateway restart ║');
21
+ console.log(' ║ ║');
22
+ console.log(' ║ UI: /plugins/aicq-chat/ui/ ║');
23
+ console.log(' ║ API: /plugins/aicq-chat/api/* ║');
24
+ console.log(' ║ Docs: https://aicq.online ║');
279
25
  console.log(' ╚══════════════════════════════════════════════╝');
280
26
  console.log('');
281
-
282
- // Read version from package.json
283
- let version = '2.6.0';
284
- try {
285
- const pkg = JSON.parse(fs.readFileSync(path.join(PLUGIN_DIR, 'package.json'), 'utf8'));
286
- version = pkg.version;
287
- } catch (e) {}
288
-
289
- let skillInstalled = false;
290
- let pluginInstalled = false;
291
-
292
- // Step 1: Install to skills/ directory (for dashboard discovery)
293
- const workspace = findOpenClawWorkspace();
294
- if (workspace) {
295
- console.log(`[AICQ] Found workspace at: ${workspace}`);
296
- try {
297
- const skillDir = installToSkillsDir(workspace, version);
298
- console.log(`[AICQ] Skill installed to: ${skillDir}`);
299
- skillInstalled = true;
300
- } catch (e) {
301
- console.error('[AICQ] Skill install failed:', e.message);
302
- }
303
- }
304
-
305
- // Step 2: Install to plugins/ directory (for sidecar startup)
306
- const openclawDir = findOpenClawDir();
307
- if (openclawDir) {
308
- console.log(`[AICQ] Found OpenClaw at: ${openclawDir}`);
309
- try {
310
- const pluginDir = installToPluginsDir(openclawDir, version);
311
- console.log(`[AICQ] Plugin installed to: ${pluginDir}`);
312
- pluginInstalled = true;
313
- } catch (e) {
314
- console.error('[AICQ] Plugin install failed:', e.message);
315
- }
316
- }
317
-
318
- // Summary
319
- console.log('');
320
- if (skillInstalled || pluginInstalled) {
321
- console.log(' ╔══════════════════════════════════════════════╗');
322
- console.log(' ║ AICQ Plugin Installed Successfully! ║');
323
- console.log(' ╠══════════════════════════════════════════════╣');
324
- console.log(' ║ ║');
325
- if (skillInstalled) {
326
- console.log(' ║ ✅ Skill installed (dashboard visible) ║');
327
- }
328
- if (pluginInstalled) {
329
- console.log(' ║ ✅ Plugin installed (sidecar ready) ║');
330
- }
331
- console.log(' ║ ║');
332
- console.log(' ║ Restart OpenClaw to activate the plugin. ║');
333
- console.log(' ║ ║');
334
- console.log(' ║ Chat UI: http://localhost:6109 ║');
335
- console.log(' ║ Docs: https://aicq.online ║');
336
- console.log(' ╚══════════════════════════════════════════════╝');
337
- } else {
338
- console.log(' ╔══════════════════════════════════════════════╗');
339
- console.log(' ║ AICQ Chat Plugin Installed! ║');
340
- console.log(' ╠══════════════════════════════════════════════╣');
341
- console.log(' ║ ║');
342
- console.log(' ║ OpenClaw not found — auto-install skipped ║');
343
- console.log(' ║ ║');
344
- console.log(' ║ Set environment variables: ║');
345
- console.log(' ║ OPENCLAW_HOME=<openclaw-root> ║');
346
- console.log(' ║ OPENCLAW_WORKSPACE=<workspace-dir> ║');
347
- console.log(' ║ ║');
348
- console.log(' ║ Or install via openclaw CLI: ║');
349
- console.log(' ║ openclaw plugins install npm:aicq-chat-plugin ║');
350
- console.log(' ║ ║');
351
- console.log(' ║ Chat UI: http://localhost:6109 ║');
352
- console.log(' ║ Docs: https://aicq.online ║');
353
- console.log(' ╚══════════════════════════════════════════════╝');
354
- }
355
- console.log('');
package/public/index.html CHANGED
@@ -419,11 +419,24 @@ let pendingDeleteMsgId = null;
419
419
  const API = '';
420
420
 
421
421
  // ─── API Helper ─────────────────────────────────────────────────────
422
+ function errMsg(err) {
423
+ if (!err) return '未知错误';
424
+ if (typeof err === 'string') return err;
425
+ if (err.message) return err.message;
426
+ if (err.error && typeof err.error === 'string') return err.error;
427
+ if (err.error && typeof err.error === 'object') return errMsg(err.error);
428
+ try { return JSON.stringify(err); } catch { return '未知错误'; }
429
+ }
430
+
422
431
  async function api(method, path, body = null) {
423
432
  const opts = { method, headers: { 'Content-Type': 'application/json' } };
424
433
  if (body) opts.body = JSON.stringify(body);
425
434
  const resp = await fetch(API + path, opts);
426
- return resp.json();
435
+ const data = await resp.json();
436
+ if (!resp.ok && !data.success) {
437
+ throw new Error(errMsg(data.error) || `HTTP ${resp.status}`);
438
+ }
439
+ return data;
427
440
  }
428
441
 
429
442
  // ─── Agents ─────────────────────────────────────────────────────────
@@ -791,7 +804,7 @@ async function uploadFile(input, type) {
791
804
  if (data.success) {
792
805
  await loadMessages();
793
806
  } else {
794
- alert('上传失败: ' + (data.error || '未知错误'));
807
+ alert('上传失败: ' + errMsg(data.error));
795
808
  }
796
809
  } catch (e) {
797
810
  alert('上传失败: ' + e.message);
@@ -882,7 +895,7 @@ async function addFriendByCode() {
882
895
  document.getElementById('friendCodeInput').value = '';
883
896
  await loadFriends();
884
897
  } else {
885
- alert('添加失败: ' + (result.error || '未知错误'));
898
+ alert('添加失败: ' + errMsg(result.error));
886
899
  }
887
900
  } catch (e) {
888
901
  alert('添加失败: ' + e.message);
@@ -1041,7 +1054,7 @@ async function handlePluginAvatarUpload(input) {
1041
1054
  }
1042
1055
  alert('头像已更新');
1043
1056
  } else {
1044
- alert('上传失败: ' + (data.error || '未知错误'));
1057
+ alert('上传失败: ' + errMsg(data.error));
1045
1058
  }
1046
1059
  } catch (e) {
1047
1060
  alert('头像上传失败: ' + e.message);
package/setup-entry.js ADDED
@@ -0,0 +1,61 @@
1
+ /**
2
+ * AICQ Chat Plugin — Setup Wizard Entry Point
3
+ *
4
+ * Provides a multi-step setup wizard for first-time configuration.
5
+ * OpenClaw loads this via defineSetupPluginEntry convention.
6
+ */
7
+
8
+ const SETUP_STEPS = [
9
+ {
10
+ id: 'welcome',
11
+ title: '欢迎使用 AICQ 加密聊天',
12
+ description: '本插件为您的智能体提供端到端加密即时通讯能力,基于 NaCl (X25519 + XSalsa20-Poly1305) 加密体系',
13
+ type: 'info',
14
+ },
15
+ {
16
+ id: 'server',
17
+ title: 'AICQ 服务器配置',
18
+ type: 'form',
19
+ fields: [
20
+ {
21
+ name: 'serverUrl',
22
+ label: '服务器地址',
23
+ type: 'text',
24
+ default: 'https://aicq.online',
25
+ description: 'AICQ 信令服务器地址,用于 WebSocket 连接',
26
+ },
27
+ {
28
+ name: 'autoAccept',
29
+ label: '自动接受好友请求',
30
+ type: 'checkbox',
31
+ default: true,
32
+ description: '是否自动接受来自其他智能体的好友请求',
33
+ },
34
+ ],
35
+ },
36
+ {
37
+ id: 'complete',
38
+ title: '配置完成',
39
+ description: '您的智能体现在可以通过 AICQ 进行加密通讯了。在频道设置中管理好友列表,或使用 chat-friend 工具添加好友。',
40
+ type: 'info',
41
+ },
42
+ ];
43
+
44
+ function register() {
45
+ return {
46
+ id: 'aicq-chat-setup',
47
+ label: 'AICQ Chat Setup',
48
+ version: '3.0.0',
49
+ steps: SETUP_STEPS,
50
+ };
51
+ }
52
+
53
+ function getSteps() {
54
+ return SETUP_STEPS;
55
+ }
56
+
57
+ module.exports = {
58
+ register,
59
+ getSteps,
60
+ SETUP_STEPS,
61
+ };