aicq-chat-plugin 2.4.1 → 2.5.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.
package/lib/crypto.js CHANGED
@@ -31,7 +31,13 @@ function generateExchangeKeypair() {
31
31
 
32
32
  function signMessage(message, secretKeyHex) {
33
33
  const secretKey = Buffer.from(secretKeyHex, 'hex');
34
- const messageBytes = naclUtil.decodeUTF8(message);
34
+ // If message looks like hex (64 chars), treat as raw bytes to match server's bytes.fromhex()
35
+ let messageBytes;
36
+ if (/^[0-9a-fA-F]{64}$/.test(message)) {
37
+ messageBytes = Buffer.from(message, 'hex');
38
+ } else {
39
+ messageBytes = naclUtil.decodeUTF8(message);
40
+ }
35
41
  const signature = nacl.sign.detached(messageBytes, secretKey);
36
42
  return Buffer.from(signature).toString('hex');
37
43
  }
@@ -39,7 +45,13 @@ function signMessage(message, secretKeyHex) {
39
45
  function verifySignature(message, signatureHex, publicKeyHex) {
40
46
  try {
41
47
  const publicKey = Buffer.from(publicKeyHex, 'hex');
42
- const messageBytes = naclUtil.decodeUTF8(message);
48
+ // If message looks like hex (64 chars), treat as raw bytes to match server
49
+ let messageBytes;
50
+ if (/^[0-9a-fA-F]{64}$/.test(message)) {
51
+ messageBytes = Buffer.from(message, 'hex');
52
+ } else {
53
+ messageBytes = naclUtil.decodeUTF8(message);
54
+ }
43
55
  const signature = Buffer.from(signatureHex, 'hex');
44
56
  return nacl.sign.detached.verify(messageBytes, signature, publicKey);
45
57
  } catch (e) {
@@ -53,9 +53,13 @@ class ServerClient {
53
53
  public_key: identity.signing_public_key,
54
54
  agent_name: identity.nickname || agentId,
55
55
  });
56
- if (data.accessToken) {
57
- this.jwtToken = data.accessToken;
56
+ if (data.access_token || data.accessToken) {
57
+ this.jwtToken = data.access_token || data.accessToken;
58
58
  this.currentAgentId = agentId;
59
+ // Store server-side account ID for WS auth (nodeId must match JWT sub)
60
+ if (data.account && data.account.id) {
61
+ this.serverAccountId = data.account.id;
62
+ }
59
63
  }
60
64
  return data;
61
65
  }
@@ -83,9 +87,13 @@ class ServerClient {
83
87
  challenge,
84
88
  });
85
89
 
86
- if (loginData.accessToken) {
87
- this.jwtToken = loginData.accessToken;
90
+ if (loginData.access_token || loginData.accessToken) {
91
+ this.jwtToken = loginData.access_token || loginData.accessToken;
88
92
  this.currentAgentId = agentId;
93
+ // Store server-side account ID for WS auth (nodeId must match JWT sub)
94
+ if (loginData.account && loginData.account.id) {
95
+ this.serverAccountId = loginData.account.id;
96
+ }
89
97
  }
90
98
  return loginData;
91
99
  }
@@ -198,7 +206,7 @@ class ServerClient {
198
206
  console.log('[WS] Connected, sending auth...');
199
207
  this.ws.send(JSON.stringify({
200
208
  type: 'online',
201
- nodeId: this.currentAgentId,
209
+ nodeId: this.serverAccountId || this.currentAgentId,
202
210
  token: this.jwtToken,
203
211
  }));
204
212
  });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "aicq-chat",
3
3
  "name": "AICQ Encrypted Chat",
4
- "version": "2.2.0",
4
+ "version": "2.5.0",
5
5
  "description": "End-to-end encrypted chat plugin for OpenClaw agents — Node.js implementation with full UI",
6
6
  "entry": "index.js",
7
7
  "activation": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aicq-chat-plugin",
3
- "version": "2.4.1",
3
+ "version": "2.5.0",
4
4
  "description": "AICQ End-to-end Encrypted Chat Plugin for OpenClaw — Full UI with friend management, group chat, file transfer, and AI agent communication",
5
5
  "main": "index.js",
6
6
  "bin": {
package/postinstall.js CHANGED
@@ -2,26 +2,187 @@
2
2
  /**
3
3
  * AICQ Chat Plugin — Post-install script
4
4
  *
5
- * Displays setup information after npm install.
5
+ * Automatically installs the plugin into OpenClaw's plugins directory.
6
+ * OpenClaw requires plugins to be in ~/.openclaw/plugins/<plugin-id>/
7
+ * with an openclaw.plugin.json file to recognize them.
6
8
  */
7
9
 
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
+ // ── Find OpenClaw installation ──────────────────────────────────────
19
+ function findOpenClawDir() {
20
+ const candidates = [
21
+ path.join(os.homedir(), '.openclaw'),
22
+ path.join(os.homedir(), 'openclaw'),
23
+ path.join(os.homedir(), '.config', 'openclaw'),
24
+ ];
25
+
26
+ // Check environment variable
27
+ if (process.env.OPENCLAW_HOME) {
28
+ candidates.unshift(process.env.OPENCLAW_HOME);
29
+ }
30
+
31
+ for (const dir of candidates) {
32
+ if (fs.existsSync(dir)) {
33
+ return dir;
34
+ }
35
+ }
36
+ return null;
37
+ }
38
+
39
+ // ── Copy plugin files to OpenClaw plugins directory ─────────────────
40
+ function installToOpenClaw(openclawDir) {
41
+ const pluginsDir = path.join(openclawDir, 'plugins');
42
+ const targetDir = path.join(pluginsDir, PLUGIN_ID);
43
+
44
+ // Create plugins directory if needed
45
+ if (!fs.existsSync(pluginsDir)) {
46
+ fs.mkdirSync(pluginsDir, { recursive: true });
47
+ }
48
+
49
+ // Files to copy (from package.json "files" field)
50
+ const filesToCopy = [
51
+ 'index.js',
52
+ 'cli.js',
53
+ 'postinstall.js',
54
+ 'openclaw.plugin.json',
55
+ 'package.json',
56
+ 'README.md',
57
+ ];
58
+
59
+ const dirsToCopy = [
60
+ 'lib',
61
+ 'public',
62
+ ];
63
+
64
+ // Remove old installation if exists
65
+ if (fs.existsSync(targetDir)) {
66
+ console.log(`[AICQ] Updating existing plugin at ${targetDir}`);
67
+ // Don't remove the entire dir — preserve node_modules and data
68
+ } else {
69
+ console.log(`[AICQ] Installing plugin to ${targetDir}`);
70
+ fs.mkdirSync(targetDir, { recursive: true });
71
+ }
72
+
73
+ // Copy individual files
74
+ for (const file of filesToCopy) {
75
+ const src = path.join(PLUGIN_DIR, file);
76
+ const dest = path.join(targetDir, file);
77
+ if (fs.existsSync(src)) {
78
+ fs.copyFileSync(src, dest);
79
+ }
80
+ }
81
+
82
+ // Copy directories
83
+ for (const dir of dirsToCopy) {
84
+ const src = path.join(PLUGIN_DIR, dir);
85
+ const dest = path.join(targetDir, dir);
86
+ if (fs.existsSync(src)) {
87
+ // Remove old and copy fresh
88
+ if (fs.existsSync(dest)) {
89
+ fs.rmSync(dest, { recursive: true, force: true });
90
+ }
91
+ copyDirRecursive(src, dest);
92
+ }
93
+ }
94
+
95
+ // Install npm dependencies in the target directory
96
+ console.log('[AICQ] Installing plugin dependencies...');
97
+ try {
98
+ execSync('npm install --production', {
99
+ cwd: targetDir,
100
+ stdio: 'pipe',
101
+ timeout: 120000,
102
+ });
103
+ console.log('[AICQ] Dependencies installed.');
104
+ } catch (e) {
105
+ console.log('[AICQ] Warning: npm install failed. You may need to run it manually:');
106
+ console.log(` cd ${targetDir} && npm install`);
107
+ }
108
+
109
+ return targetDir;
110
+ }
111
+
112
+ // ── Recursively copy a directory ────────────────────────────────────
113
+ function copyDirRecursive(src, dest) {
114
+ fs.mkdirSync(dest, { recursive: true });
115
+ const entries = fs.readdirSync(src, { withFileTypes: true });
116
+
117
+ for (const entry of entries) {
118
+ const srcPath = path.join(src, entry.name);
119
+ const destPath = path.join(dest, entry.name);
120
+
121
+ if (entry.isDirectory()) {
122
+ // Skip node_modules — will be installed fresh
123
+ if (entry.name === 'node_modules') continue;
124
+ copyDirRecursive(srcPath, destPath);
125
+ } else {
126
+ fs.copyFileSync(srcPath, destPath);
127
+ }
128
+ }
129
+ }
130
+
131
+ // ── Main ────────────────────────────────────────────────────────────
8
132
  console.log('');
9
133
  console.log(' ╔══════════════════════════════════════════════╗');
10
- console.log(' ║ AICQ Chat Plugin Installed! ║');
11
- console.log(' ╠══════════════════════════════════════════════╣');
12
- console.log(' ║ ║');
13
- console.log(' ║ Start the plugin: ║');
14
- console.log(' ║ npx aicq-plugin ║');
15
- console.log(' ║ ║');
16
- console.log(' ║ Or install globally: ║');
17
- console.log(' ║ npm install -g aicq-chat-plugin ║');
18
- console.log(' ║ aicq-plugin ║');
19
- console.log(' ║ ║');
20
- console.log(' ║ Options: ║');
21
- console.log(' ║ --port <port> Server port (6109) ║');
22
- console.log(' ║ --server <url> AICQ server URL ║');
23
- console.log(' ║ ║');
24
- console.log(' ║ Chat UI: http://localhost:6109 ║');
25
- console.log(' ║ Docs: https://aicq.online ║');
134
+ console.log(' ║ AICQ Chat Plugin — Installing... ║');
26
135
  console.log(' ╚══════════════════════════════════════════════╝');
27
136
  console.log('');
137
+
138
+ // Try to auto-install into OpenClaw
139
+ const openclawDir = findOpenClawDir();
140
+
141
+ if (openclawDir) {
142
+ console.log(`[AICQ] Found OpenClaw at: ${openclawDir}`);
143
+ try {
144
+ const installedDir = installToOpenClaw(openclawDir);
145
+ console.log('');
146
+ console.log(' ╔══════════════════════════════════════════════╗');
147
+ console.log(' ║ AICQ Plugin Installed Successfully! ║');
148
+ console.log(' ╠══════════════════════════════════════════════╣');
149
+ console.log(' ║ ║');
150
+ console.log(' ║ Plugin installed to: ║');
151
+ console.log(` ║ ${installedDir}`);
152
+ console.log(' ║ ║');
153
+ console.log(' ║ Restart OpenClaw to activate the plugin. ║');
154
+ console.log(' ║ ║');
155
+ console.log(' ║ Chat UI: http://localhost:6109 ║');
156
+ console.log(' ║ Docs: https://aicq.online ║');
157
+ console.log(' ╚══════════════════════════════════════════════╝');
158
+ console.log('');
159
+ } catch (e) {
160
+ console.error('[AICQ] Auto-install failed:', e.message);
161
+ console.log('');
162
+ printManualInstructions();
163
+ }
164
+ } else {
165
+ console.log('[AICQ] OpenClaw not found — skipping auto-install.');
166
+ console.log('');
167
+ printManualInstructions();
168
+ }
169
+
170
+ function printManualInstructions() {
171
+ console.log(' ╔══════════════════════════════════════════════╗');
172
+ console.log(' ║ AICQ Chat Plugin Installed! ║');
173
+ console.log(' ╠══════════════════════════════════════════════╣');
174
+ console.log(' ║ ║');
175
+ console.log(' ║ Manual install to OpenClaw: ║');
176
+ console.log(' ║ mkdir -p ~/.openclaw/plugins/aicq-chat ║');
177
+ console.log(' ║ cp -r ' + PLUGIN_DIR + '/* ~/.openclaw/plugins/aicq-chat/ ║');
178
+ console.log(' ║ cd ~/.openclaw/plugins/aicq-chat ║');
179
+ console.log(' ║ npm install ║');
180
+ console.log(' ║ ║');
181
+ console.log(' ║ Or start standalone: ║');
182
+ console.log(' ║ npx aicq-plugin ║');
183
+ console.log(' ║ ║');
184
+ console.log(' ║ Chat UI: http://localhost:6109 ║');
185
+ console.log(' ║ Docs: https://aicq.online ║');
186
+ console.log(' ╚══════════════════════════════════════════════╝');
187
+ console.log('');
188
+ }