aicq-chat-plugin 2.6.7 → 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.
- package/README.md +40 -44
- package/SKILL.md +27 -19
- package/cli.js +77 -211
- package/index.js +343 -620
- package/openclaw.plugin.json +42 -33
- package/package.json +11 -7
- package/postinstall.js +17 -346
- package/setup-entry.js +61 -0
- package/src/channel.js +163 -0
- package/src/ui-routes.js +469 -0
- package/extension.js +0 -204
package/openclaw.plugin.json
CHANGED
|
@@ -1,53 +1,68 @@
|
|
|
1
1
|
{
|
|
2
|
+
"kind": "channel",
|
|
2
3
|
"id": "aicq-chat",
|
|
3
4
|
"name": "AICQ Encrypted Chat",
|
|
4
|
-
"version": "
|
|
5
|
-
"description": "End-to-end encrypted chat
|
|
5
|
+
"version": "3.0.1",
|
|
6
|
+
"description": "End-to-end encrypted chat channel via AICQ protocol — in-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
|
-
"
|
|
16
|
-
"type": "
|
|
17
|
-
"description": "
|
|
18
|
-
"default":
|
|
41
|
+
"serverUrl": {
|
|
42
|
+
"type": "string",
|
|
43
|
+
"description": "AICQ 服务器地址",
|
|
44
|
+
"default": "https://aicq.online"
|
|
19
45
|
},
|
|
20
|
-
"
|
|
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": "
|
|
48
|
+
"description": "自动接受好友请求",
|
|
30
49
|
"default": true
|
|
31
50
|
},
|
|
32
51
|
"debug": {
|
|
33
52
|
"type": "boolean",
|
|
34
|
-
"description": "Enable verbose debug logging
|
|
53
|
+
"description": "Enable verbose debug logging",
|
|
35
54
|
"default": false
|
|
36
55
|
}
|
|
37
56
|
}
|
|
38
57
|
},
|
|
39
58
|
"uiHints": {
|
|
40
|
-
"
|
|
41
|
-
"label": "
|
|
42
|
-
"help": "
|
|
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
|
-
"
|
|
49
|
-
"label": "Auto
|
|
50
|
-
"help": "
|
|
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": "
|
|
4
|
-
"description": "AICQ End-to-end Encrypted Chat Plugin for OpenClaw —
|
|
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
|
-
"
|
|
63
|
-
|
|
64
|
-
"
|
|
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
|
-
*
|
|
6
|
-
*
|
|
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(' ║
|
|
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/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
|
+
};
|