aicq-chat-plugin 2.5.6 → 2.5.7
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/extension.js +168 -0
- package/index.js +12 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +3 -2
- package/postinstall.js +2 -1
package/extension.js
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AICQ Chat Plugin — OpenClaw Extension Entry Point
|
|
3
|
+
*
|
|
4
|
+
* This is the lightweight entry point loaded by `openclaw plugins install`.
|
|
5
|
+
* It does NOT require native dependencies (better-sqlite3) which need C++ compilation.
|
|
6
|
+
*
|
|
7
|
+
* The actual chat server runs as a **sidecar** process (node index.js) on port 6109.
|
|
8
|
+
* This extension just registers the plugin and proxies tool calls to the sidecar.
|
|
9
|
+
*/
|
|
10
|
+
const http = require('http');
|
|
11
|
+
|
|
12
|
+
const SIDECAR_PORT = parseInt(process.env.AICQ_PORT || '6109', 10);
|
|
13
|
+
const SIDECAR_HOST = '127.0.0.1';
|
|
14
|
+
|
|
15
|
+
// ── Plugin metadata ──────────────────────────────────────────────────
|
|
16
|
+
module.exports = {
|
|
17
|
+
id: 'aicq-chat',
|
|
18
|
+
name: 'AICQ Encrypted Chat',
|
|
19
|
+
version: '2.5.7',
|
|
20
|
+
description: 'End-to-end encrypted chat plugin for OpenClaw agents',
|
|
21
|
+
|
|
22
|
+
// Sidecar configuration — OpenClaw starts this process automatically
|
|
23
|
+
sidecar: {
|
|
24
|
+
command: 'node',
|
|
25
|
+
args: ['index.js'],
|
|
26
|
+
port: SIDECAR_PORT,
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
// Tool definitions for OpenClaw agent use
|
|
30
|
+
tools: {
|
|
31
|
+
'chat-friend': {
|
|
32
|
+
description: 'Manage AICQ friends — list, add by friend code, remove, view requests, accept/reject requests',
|
|
33
|
+
parameters: {
|
|
34
|
+
type: 'object',
|
|
35
|
+
properties: {
|
|
36
|
+
action: {
|
|
37
|
+
type: 'string',
|
|
38
|
+
enum: ['list', 'add', 'remove', 'requests', 'accept', 'reject'],
|
|
39
|
+
description: 'The friend management action to perform',
|
|
40
|
+
},
|
|
41
|
+
friend_code: {
|
|
42
|
+
type: 'string',
|
|
43
|
+
description: 'Friend code or temp number for adding a friend',
|
|
44
|
+
},
|
|
45
|
+
friend_id: {
|
|
46
|
+
type: 'string',
|
|
47
|
+
description: 'Friend ID for remove/accept/reject actions',
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
required: ['action'],
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
'chat-send': {
|
|
54
|
+
description: 'Send an encrypted message to a friend or group via AICQ',
|
|
55
|
+
parameters: {
|
|
56
|
+
type: 'object',
|
|
57
|
+
properties: {
|
|
58
|
+
targetId: {
|
|
59
|
+
type: 'string',
|
|
60
|
+
description: 'The friend ID or group ID to send the message to',
|
|
61
|
+
},
|
|
62
|
+
content: {
|
|
63
|
+
type: 'string',
|
|
64
|
+
description: 'The message content to send',
|
|
65
|
+
},
|
|
66
|
+
isGroup: {
|
|
67
|
+
type: 'boolean',
|
|
68
|
+
description: 'Whether the target is a group (default: false)',
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
required: ['targetId', 'content'],
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
'chat-export-key': {
|
|
75
|
+
description: 'Export your AICQ identity public key and fingerprint for sharing',
|
|
76
|
+
parameters: {
|
|
77
|
+
type: 'object',
|
|
78
|
+
properties: {
|
|
79
|
+
format: {
|
|
80
|
+
type: 'string',
|
|
81
|
+
enum: ['json', 'qr'],
|
|
82
|
+
description: 'Output format: json for key data, qr for QR code image (default: json)',
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// ── Helper: proxy a gateway call to the sidecar ──────────────────────
|
|
91
|
+
function proxyToSidecar(method, kwargs) {
|
|
92
|
+
return new Promise((resolve, reject) => {
|
|
93
|
+
const postData = JSON.stringify({ method, kwargs });
|
|
94
|
+
const req = http.request(
|
|
95
|
+
{
|
|
96
|
+
hostname: SIDECAR_HOST,
|
|
97
|
+
port: SIDECAR_PORT,
|
|
98
|
+
path: '/api/gateway',
|
|
99
|
+
method: 'POST',
|
|
100
|
+
headers: {
|
|
101
|
+
'Content-Type': 'application/json',
|
|
102
|
+
'Content-Length': Buffer.byteLength(postData),
|
|
103
|
+
},
|
|
104
|
+
timeout: 15000,
|
|
105
|
+
},
|
|
106
|
+
(res) => {
|
|
107
|
+
let body = '';
|
|
108
|
+
res.on('data', (chunk) => { body += chunk; });
|
|
109
|
+
res.on('end', () => {
|
|
110
|
+
try {
|
|
111
|
+
resolve(JSON.parse(body));
|
|
112
|
+
} catch (e) {
|
|
113
|
+
resolve({ error: `Sidecar returned non-JSON: ${body.substring(0, 200)}` });
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
);
|
|
118
|
+
req.on('error', (e) => {
|
|
119
|
+
resolve({ error: `Sidecar not reachable: ${e.message}. Is the AICQ sidecar running?` });
|
|
120
|
+
});
|
|
121
|
+
req.on('timeout', () => {
|
|
122
|
+
req.destroy();
|
|
123
|
+
resolve({ error: 'Sidecar request timed out' });
|
|
124
|
+
});
|
|
125
|
+
req.write(postData);
|
|
126
|
+
req.end();
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ── Tool handlers (proxy to sidecar) ─────────────────────────────────
|
|
131
|
+
module.exports.handleTool = async function (toolName, params) {
|
|
132
|
+
switch (toolName) {
|
|
133
|
+
case 'chat-friend': {
|
|
134
|
+
const { action, friend_code, friend_id } = params;
|
|
135
|
+
switch (action) {
|
|
136
|
+
case 'list':
|
|
137
|
+
return proxyToSidecar('aicq.friends.list', {});
|
|
138
|
+
case 'add':
|
|
139
|
+
return proxyToSidecar('aicq.friends.add', { temp_number: friend_code });
|
|
140
|
+
case 'remove':
|
|
141
|
+
return proxyToSidecar('aicq.friends.remove', { friend_id });
|
|
142
|
+
case 'requests':
|
|
143
|
+
return proxyToSidecar('aicq.friends.requests', {});
|
|
144
|
+
case 'accept':
|
|
145
|
+
return proxyToSidecar('aicq.friends.acceptRequest', { request_id: friend_id });
|
|
146
|
+
case 'reject':
|
|
147
|
+
return proxyToSidecar('aicq.friends.rejectRequest', { request_id: friend_id });
|
|
148
|
+
default:
|
|
149
|
+
return { error: `Unknown friend action: ${action}` };
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
case 'chat-send':
|
|
153
|
+
return proxyToSidecar('aicq.chat.send', {
|
|
154
|
+
targetId: params.targetId,
|
|
155
|
+
content: params.content,
|
|
156
|
+
isGroup: params.isGroup || false,
|
|
157
|
+
});
|
|
158
|
+
case 'chat-export-key':
|
|
159
|
+
return proxyToSidecar('aicq.identity.info', {});
|
|
160
|
+
default:
|
|
161
|
+
return { error: `Unknown tool: ${toolName}` };
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
// ── Gateway handler (proxy to sidecar via IPC or HTTP) ───────────────
|
|
166
|
+
module.exports.handleGateway = async function (method, kwargs) {
|
|
167
|
+
return proxyToSidecar(method, kwargs || {});
|
|
168
|
+
};
|
package/index.js
CHANGED
|
@@ -577,6 +577,18 @@ app.post('/api/sync', async (req, res) => {
|
|
|
577
577
|
}
|
|
578
578
|
});
|
|
579
579
|
|
|
580
|
+
// ─── Gateway Proxy Endpoint (for extension.js) ──────────────────────
|
|
581
|
+
app.post('/api/gateway', async (req, res) => {
|
|
582
|
+
try {
|
|
583
|
+
const { method, kwargs } = req.body;
|
|
584
|
+
if (!method) return res.status(400).json({ error: 'method is required' });
|
|
585
|
+
const result = await handleGatewayCall(method, kwargs);
|
|
586
|
+
res.json(result);
|
|
587
|
+
} catch (e) {
|
|
588
|
+
res.status(500).json({ error: e.message });
|
|
589
|
+
}
|
|
590
|
+
});
|
|
591
|
+
|
|
580
592
|
// ─── Start Server ───────────────────────────────────────────────────
|
|
581
593
|
app.listen(PORT, '0.0.0.0', () => {
|
|
582
594
|
console.log(`[AICQ Plugin] Running on http://0.0.0.0:${PORT}`);
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aicq-chat-plugin",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.7",
|
|
4
4
|
"description": "AICQ End-to-end Encrypted Chat Plugin for OpenClaw \u2014 Full UI 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",
|
|
10
11
|
"index.js",
|
|
11
12
|
"cli.js",
|
|
12
13
|
"postinstall.js",
|
|
@@ -60,7 +61,7 @@
|
|
|
60
61
|
"openclaw": {
|
|
61
62
|
"id": "aicq-chat",
|
|
62
63
|
"extensions": [
|
|
63
|
-
"./
|
|
64
|
+
"./extension.js"
|
|
64
65
|
],
|
|
65
66
|
"compat": {
|
|
66
67
|
"pluginApi": ">=2026.3.24-beta.2"
|
package/postinstall.js
CHANGED
|
@@ -157,6 +157,7 @@ function copyDirRecursive(src, dest) {
|
|
|
157
157
|
// ── Install plugin files to a target directory ─────────────────────
|
|
158
158
|
function installToDir(sourceDir, targetDir, version) {
|
|
159
159
|
const filesToCopy = [
|
|
160
|
+
'extension.js',
|
|
160
161
|
'index.js',
|
|
161
162
|
'cli.js',
|
|
162
163
|
'postinstall.js',
|
|
@@ -269,7 +270,7 @@ console.log(' ╚════════════════════
|
|
|
269
270
|
console.log('');
|
|
270
271
|
|
|
271
272
|
// Read version from package.json
|
|
272
|
-
let version = '2.5.
|
|
273
|
+
let version = '2.5.7';
|
|
273
274
|
try {
|
|
274
275
|
const pkg = JSON.parse(fs.readFileSync(path.join(PLUGIN_DIR, 'package.json'), 'utf8'));
|
|
275
276
|
version = pkg.version;
|