aicq-openclaw-plugin 1.2.0 → 1.2.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.
Files changed (2) hide show
  1. package/dist/index.js +122 -35
  2. package/package.json +12 -10
package/dist/index.js CHANGED
@@ -4922,9 +4922,9 @@ var require_lib = __commonJS({
4922
4922
  }
4923
4923
  });
4924
4924
 
4925
- // node_modules/tweetnacl/nacl-fast.js
4925
+ // ../node_modules/tweetnacl/nacl-fast.js
4926
4926
  var require_nacl_fast = __commonJS({
4927
- "node_modules/tweetnacl/nacl-fast.js"(exports, module) {
4927
+ "../node_modules/tweetnacl/nacl-fast.js"(exports, module) {
4928
4928
  (function(nacl3) {
4929
4929
  "use strict";
4930
4930
  var gf = function(init) {
@@ -7146,9 +7146,9 @@ var require_nacl_fast = __commonJS({
7146
7146
  }
7147
7147
  });
7148
7148
 
7149
- // node_modules/tweetnacl-util/nacl-util.js
7149
+ // ../node_modules/tweetnacl-util/nacl-util.js
7150
7150
  var require_nacl_util = __commonJS({
7151
- "node_modules/tweetnacl-util/nacl-util.js"(exports, module) {
7151
+ "../node_modules/tweetnacl-util/nacl-util.js"(exports, module) {
7152
7152
  (function(root, f) {
7153
7153
  "use strict";
7154
7154
  if (typeof module !== "undefined" && module.exports) module.exports = f();
@@ -7212,9 +7212,9 @@ var require_nacl_util = __commonJS({
7212
7212
  }
7213
7213
  });
7214
7214
 
7215
- // node_modules/@aicq/crypto/nacl.js
7215
+ // node_modules/@aicq/crypto/dist/nacl.js
7216
7216
  var require_nacl = __commonJS({
7217
- "node_modules/@aicq/crypto/nacl.js"(exports) {
7217
+ "node_modules/@aicq/crypto/dist/nacl.js"(exports) {
7218
7218
  "use strict";
7219
7219
  var __importDefault = exports && exports.__importDefault || function(mod) {
7220
7220
  return mod && mod.__esModule ? mod : { "default": mod };
@@ -7231,9 +7231,9 @@ var require_nacl = __commonJS({
7231
7231
  }
7232
7232
  });
7233
7233
 
7234
- // node_modules/@aicq/crypto/keygen.js
7234
+ // node_modules/@aicq/crypto/dist/keygen.js
7235
7235
  var require_keygen = __commonJS({
7236
- "node_modules/@aicq/crypto/keygen.js"(exports) {
7236
+ "node_modules/@aicq/crypto/dist/keygen.js"(exports) {
7237
7237
  "use strict";
7238
7238
  Object.defineProperty(exports, "__esModule", { value: true });
7239
7239
  exports.generateSigningKeyPair = generateSigningKeyPair2;
@@ -7272,9 +7272,9 @@ var require_keygen = __commonJS({
7272
7272
  }
7273
7273
  });
7274
7274
 
7275
- // node_modules/@aicq/crypto/signer.js
7275
+ // node_modules/@aicq/crypto/dist/signer.js
7276
7276
  var require_signer = __commonJS({
7277
- "node_modules/@aicq/crypto/signer.js"(exports) {
7277
+ "node_modules/@aicq/crypto/dist/signer.js"(exports) {
7278
7278
  "use strict";
7279
7279
  Object.defineProperty(exports, "__esModule", { value: true });
7280
7280
  exports.sign = sign;
@@ -7289,9 +7289,9 @@ var require_signer = __commonJS({
7289
7289
  }
7290
7290
  });
7291
7291
 
7292
- // node_modules/@aicq/crypto/keyExchange.js
7292
+ // node_modules/@aicq/crypto/dist/keyExchange.js
7293
7293
  var require_keyExchange = __commonJS({
7294
- "node_modules/@aicq/crypto/keyExchange.js"(exports) {
7294
+ "node_modules/@aicq/crypto/dist/keyExchange.js"(exports) {
7295
7295
  "use strict";
7296
7296
  Object.defineProperty(exports, "__esModule", { value: true });
7297
7297
  exports.computeSharedSecret = computeSharedSecret2;
@@ -7342,9 +7342,9 @@ var require_keyExchange = __commonJS({
7342
7342
  }
7343
7343
  });
7344
7344
 
7345
- // node_modules/@aicq/crypto/cipher.js
7345
+ // node_modules/@aicq/crypto/dist/cipher.js
7346
7346
  var require_cipher = __commonJS({
7347
- "node_modules/@aicq/crypto/cipher.js"(exports) {
7347
+ "node_modules/@aicq/crypto/dist/cipher.js"(exports) {
7348
7348
  "use strict";
7349
7349
  Object.defineProperty(exports, "__esModule", { value: true });
7350
7350
  exports.generateNonce = generateNonce;
@@ -7368,9 +7368,9 @@ var require_cipher = __commonJS({
7368
7368
  }
7369
7369
  });
7370
7370
 
7371
- // node_modules/@aicq/crypto/message.js
7371
+ // node_modules/@aicq/crypto/dist/message.js
7372
7372
  var require_message = __commonJS({
7373
- "node_modules/@aicq/crypto/message.js"(exports) {
7373
+ "node_modules/@aicq/crypto/dist/message.js"(exports) {
7374
7374
  "use strict";
7375
7375
  Object.defineProperty(exports, "__esModule", { value: true });
7376
7376
  exports.createMessage = createMessage;
@@ -7484,9 +7484,9 @@ var require_message = __commonJS({
7484
7484
  }
7485
7485
  });
7486
7486
 
7487
- // node_modules/@aicq/crypto/password.js
7487
+ // node_modules/@aicq/crypto/dist/password.js
7488
7488
  var require_password = __commonJS({
7489
- "node_modules/@aicq/crypto/password.js"(exports) {
7489
+ "node_modules/@aicq/crypto/dist/password.js"(exports) {
7490
7490
  "use strict";
7491
7491
  var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
7492
7492
  if (k2 === void 0) k2 = k;
@@ -7564,9 +7564,9 @@ var require_password = __commonJS({
7564
7564
  }
7565
7565
  });
7566
7566
 
7567
- // node_modules/@aicq/crypto/handshake.js
7567
+ // node_modules/@aicq/crypto/dist/handshake.js
7568
7568
  var require_handshake = __commonJS({
7569
- "node_modules/@aicq/crypto/handshake.js"(exports) {
7569
+ "node_modules/@aicq/crypto/dist/handshake.js"(exports) {
7570
7570
  "use strict";
7571
7571
  Object.defineProperty(exports, "__esModule", { value: true });
7572
7572
  exports.createHandshakeRequest = createHandshakeRequest2;
@@ -7675,9 +7675,9 @@ var require_handshake = __commonJS({
7675
7675
  }
7676
7676
  });
7677
7677
 
7678
- // node_modules/@aicq/crypto/index.js
7679
- var require_crypto = __commonJS({
7680
- "node_modules/@aicq/crypto/index.js"(exports) {
7678
+ // node_modules/@aicq/crypto/dist/index.js
7679
+ var require_dist = __commonJS({
7680
+ "node_modules/@aicq/crypto/dist/index.js"(exports) {
7681
7681
  "use strict";
7682
7682
  Object.defineProperty(exports, "__esModule", { value: true });
7683
7683
  exports.completeHandshake = exports.createHandshakeResponse = exports.createHandshakeRequest = exports.decryptWithPassword = exports.encryptWithPassword = exports.decryptMessage = exports.encryptMessage = exports.parseMessage = exports.createMessage = exports.generateNonce = exports.decrypt = exports.encrypt = exports.deriveSessionKey = exports.computeSharedSecret = exports.verify = exports.sign = exports.getPublicKeyFingerprint = exports.deriveX25519FromEd25519 = exports.generateKeyExchangeKeyPair = exports.generateSigningKeyPair = exports.encodeBase64 = exports.decodeBase64 = exports.encodeUTF8 = exports.decodeUTF8 = exports.nacl = void 0;
@@ -8191,7 +8191,7 @@ var PluginStore = class {
8191
8191
 
8192
8192
  // dist/services/identityService.js
8193
8193
  var import_qrcode = __toESM(require_lib(), 1);
8194
- var import_crypto3 = __toESM(require_crypto(), 1);
8194
+ var import_crypto3 = __toESM(require_dist(), 1);
8195
8195
  import * as crypto4 from "crypto";
8196
8196
  var IdentityService = class {
8197
8197
  constructor(store, logger) {
@@ -8680,7 +8680,7 @@ var ServerClient = class {
8680
8680
  };
8681
8681
 
8682
8682
  // dist/handshake/handshakeManager.js
8683
- var import_crypto4 = __toESM(require_crypto(), 1);
8683
+ var import_crypto4 = __toESM(require_dist(), 1);
8684
8684
  import * as crypto5 from "crypto";
8685
8685
  var HandshakeManager = class {
8686
8686
  constructor(store, serverClient, config2, logger) {
@@ -9096,7 +9096,7 @@ var P2PConnectionManager = class {
9096
9096
  };
9097
9097
 
9098
9098
  // dist/fileTransfer/transferManager.js
9099
- var import_crypto5 = __toESM(require_crypto(), 1);
9099
+ var import_crypto5 = __toESM(require_dist(), 1);
9100
9100
  import * as fs3 from "fs";
9101
9101
  import * as path3 from "path";
9102
9102
  var DEFAULT_CHUNK_SIZE = 64 * 1024;
@@ -9319,7 +9319,7 @@ var FileTransferManager = class {
9319
9319
  };
9320
9320
 
9321
9321
  // dist/channels/encryptedChat.js
9322
- var import_crypto6 = __toESM(require_crypto(), 1);
9322
+ var import_crypto6 = __toESM(require_dist(), 1);
9323
9323
  import * as fs4 from "fs";
9324
9324
  import * as path4 from "path";
9325
9325
  function safeFilePath(filePath, allowedDir) {
@@ -9759,7 +9759,7 @@ var BeforeToolCallHook = class {
9759
9759
  };
9760
9760
 
9761
9761
  // dist/hooks/messageSending.js
9762
- var import_crypto7 = __toESM(require_crypto(), 1);
9762
+ var import_crypto7 = __toESM(require_dist(), 1);
9763
9763
  var MessageSendingHook = class {
9764
9764
  constructor(store, handshakeManager, logger) {
9765
9765
  this.store = store;
@@ -10090,6 +10090,26 @@ tbody tr:hover { background: var(--bg3); }
10090
10090
  .toggle-label input:checked + .toggle-slider { background: var(--accent); }
10091
10091
  .toggle-label input:checked + .toggle-slider::after { left: 21px; background: #fff; }
10092
10092
 
10093
+ /* Offline banner */
10094
+ .offline-banner {
10095
+ background: linear-gradient(90deg, #7f1d1d, #991b1b);
10096
+ color: #fca5a5;
10097
+ padding: 10px 24px;
10098
+ font-size: 13px;
10099
+ display: flex;
10100
+ align-items: center;
10101
+ gap: 10px;
10102
+ animation: fadeIn .2s ease-out;
10103
+ }
10104
+ .offline-banner .offline-icon {
10105
+ font-size: 16px;
10106
+ animation: pulse 2s infinite;
10107
+ }
10108
+ @keyframes pulse {
10109
+ 0%, 100% { opacity: 1; }
10110
+ 50% { opacity: 0.4; }
10111
+ }
10112
+
10093
10113
  /* Responsive */
10094
10114
  @media (max-width: 768px) {
10095
10115
  .sidebar { position: fixed; left: -260px; z-index: 50; height: 100vh; transition: left var(--transition); }
@@ -10106,6 +10126,43 @@ const API = '/api';
10106
10126
  let currentPage = 'dashboard';
10107
10127
  let refreshTimer = null;
10108
10128
 
10129
+ // \u2500\u2500 Offline detection \u2500\u2500
10130
+ let isOffline = false;
10131
+ let offlineBannerEl = null;
10132
+
10133
+ function updateOnlineStatus() {
10134
+ const wasOffline = isOffline;
10135
+ isOffline = !navigator.onLine;
10136
+ if (isOffline && !wasOffline) {
10137
+ showOfflineBanner();
10138
+ } else if (!isOffline && wasOffline) {
10139
+ hideOfflineBanner();
10140
+ // Reload current page on reconnection
10141
+ loadPage(currentPage);
10142
+ }
10143
+ }
10144
+
10145
+ function showOfflineBanner() {
10146
+ if (offlineBannerEl) return;
10147
+ offlineBannerEl = document.createElement('div');
10148
+ offlineBannerEl.className = 'offline-banner';
10149
+ offlineBannerEl.innerHTML = '<span class="offline-icon">\u{1F50C}</span><span>You are offline. Some features may be limited. Data is loaded from local cache.</span>';
10150
+ const mainContent = document.querySelector('.main');
10151
+ if (mainContent) {
10152
+ mainContent.insertBefore(offlineBannerEl, mainContent.firstChild);
10153
+ }
10154
+ }
10155
+
10156
+ function hideOfflineBanner() {
10157
+ if (offlineBannerEl) {
10158
+ offlineBannerEl.remove();
10159
+ offlineBannerEl = null;
10160
+ }
10161
+ }
10162
+
10163
+ window.addEventListener('online', updateOnlineStatus);
10164
+ window.addEventListener('offline', updateOnlineStatus);
10165
+
10109
10166
  // \u2500\u2500 jQuery-style helpers \u2500\u2500
10110
10167
  const $ = (sel, ctx) => (ctx || document).querySelector(sel);
10111
10168
  const $$ = (sel, ctx) => Array.from((ctx || document).querySelectorAll(sel));
@@ -10192,7 +10249,11 @@ function loadPage(page) {
10192
10249
  async function loadDashboard() {
10193
10250
  const el = $('#dashboard-content');
10194
10251
  html(el, '<div class="loading-mask"><div class="spinner"></div>Loading dashboard...</div>');
10195
- const [status, friends, identity, mgmtUrl] = await Promise.all([api('/status'), api('/friends'), api('/identity'), api('/mgmt-url')]);
10252
+ const results = await Promise.allSettled([api('/status'), api('/friends'), api('/identity'), api('/mgmt-url')]);
10253
+ const status = results[0].status === 'fulfilled' ? results[0].value : { error: results[0].reason?.message || 'Failed' };
10254
+ const friends = results[1].status === 'fulfilled' ? results[1].value : { friends: [], error: true };
10255
+ const identity = results[2].status === 'fulfilled' ? results[2].value : { agentId: '\u2014', publicKeyFingerprint: '\u2014', serverUrl: '\u2014', connected: false };
10256
+ const mgmtUrl = results[3].status === 'fulfilled' ? results[3].value : { mgmtUrl: window.location.origin };
10196
10257
  if (status.error) { html(el, '<div class="empty"><div class="icon">\u26A0\uFE0F</div><p>Failed to connect to AICQ plugin</p></div>'); return; }
10197
10258
  const connCls = status.connected ? 'dot-ok' : 'dot-err';
10198
10259
  const connText = status.connected ? 'Connected' : 'Disconnected';
@@ -10442,7 +10503,17 @@ let friendsFilter = 'all';
10442
10503
  async function loadFriends() {
10443
10504
  const el = $('#friends-content');
10444
10505
  html(el, '<div class="loading-mask"><div class="spinner"></div>Loading friends...</div>');
10445
- const [friends, requests, sessions] = await Promise.all([api('/friends'), api('/friends/requests'), api('/sessions')]);
10506
+ const results = await Promise.allSettled([api('/friends'), api('/friends/requests'), api('/sessions')]);
10507
+ const friends = results[0].status === 'fulfilled' ? results[0].value : { friends: [] };
10508
+ const requests = results[1].status === 'fulfilled' ? results[1].value : { requests: [] };
10509
+ const sessions = results[2].status === 'fulfilled' ? results[2].value : { sessions: [] };
10510
+
10511
+ // Show offline banner if friends data came from cache
10512
+ if (friends.offline || friends.error) {
10513
+ showOfflineBanner();
10514
+ } else {
10515
+ hideOfflineBanner();
10516
+ }
10446
10517
 
10447
10518
  // Sub-tabs
10448
10519
  const friendCount = (friends.friends || []).length;
@@ -10494,7 +10565,7 @@ function renderFriendsList(friends) {
10494
10565
  <button class="filter-btn \${friendsFilter==='human'?'active':''}" onclick="friendsFilter='human';filterFriendTable()">Human</button>
10495
10566
  </div>
10496
10567
  <span style="flex:1"></span>
10497
- <button class="btn btn-sm btn-primary" onclick="showAddFriendModal()">\u2795 Add Friend</button>
10568
+ <button class="btn btn-sm btn-primary" onclick="showAddFriendModal()" \${isOffline ? 'disabled title="Unavailable while offline"' : ''}>\u2795 Add Friend</button>
10498
10569
  <button class="btn btn-sm btn-default" onclick="loadFriends()">\u{1F504}</button>
10499
10570
  </div>
10500
10571
  <div class="card" style="padding:0;overflow:hidden">
@@ -11387,6 +11458,7 @@ document.addEventListener('DOMContentLoaded', () => {
11387
11458
 
11388
11459
  // Auto-refresh status every 30s
11389
11460
  refreshTimer = setInterval(() => {
11461
+ updateOnlineStatus();
11390
11462
  if (currentPage === 'dashboard') loadDashboard();
11391
11463
  // Update status dot
11392
11464
  api('/status').then(s => {
@@ -11395,6 +11467,8 @@ document.addEventListener('DOMContentLoaded', () => {
11395
11467
  if (dot) { dot.className = 'dot ' + (s.connected ? 'dot-ok' : 'dot-err'); }
11396
11468
  const txt = $('#header-status');
11397
11469
  if (txt) txt.textContent = s.connected ? 'Connected' : 'Disconnected';
11470
+ // Auto-remove offline banner when server reconnects
11471
+ if (s.connected) hideOfflineBanner();
11398
11472
  }
11399
11473
  });
11400
11474
  }, 30000);
@@ -11964,8 +12038,16 @@ function createManagementHandler(ctx) {
11964
12038
  });
11965
12039
  return json(res, { friends });
11966
12040
  } catch (err) {
11967
- const msg = err instanceof Error ? err.message : String(err);
11968
- return json(res, { error: msg }, 500);
12041
+ const friends = Array.from(store.friends.values()).map((f) => ({
12042
+ id: f.id,
12043
+ publicKeyFingerprint: f.publicKeyFingerprint || "",
12044
+ permissions: f.permissions || [],
12045
+ addedAt: f.addedAt?.toISOString() || null,
12046
+ lastMessageAt: f.lastMessageAt?.toISOString() || null,
12047
+ friendType: f.friendType || null,
12048
+ aiName: f.aiName || null
12049
+ }));
12050
+ return json(res, { friends, offline: true });
11969
12051
  }
11970
12052
  }
11971
12053
  if (apiPath === "/friends" && method === "POST") {
@@ -12064,8 +12146,13 @@ function createManagementHandler(ctx) {
12064
12146
  const data = await resp.json();
12065
12147
  return json(res, { requests: data.requests || [] });
12066
12148
  } catch (err) {
12067
- const msg = err instanceof Error ? err.message : String(err);
12068
- return json(res, { error: msg }, 500);
12149
+ const requests = store.pendingRequests.map((p) => ({
12150
+ id: p.requesterId,
12151
+ fromId: p.requesterId,
12152
+ status: "pending",
12153
+ createdAt: p.timestamp.toISOString()
12154
+ }));
12155
+ return json(res, { requests, offline: true });
12069
12156
  }
12070
12157
  }
12071
12158
  if (apiPath.match(/^\/friends\/requests\/[^/]+\/accept$/) && method === "POST") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aicq-openclaw-plugin",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "AICQ OpenClaw plugin - end-to-end encrypted P2P chat for AI agents",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -30,24 +30,26 @@
30
30
  "openclaw": ">=2026.4.2"
31
31
  },
32
32
  "peerDependenciesMeta": {
33
- "openclaw": { "optional": true }
33
+ "openclaw": {
34
+ "optional": true
35
+ }
34
36
  },
35
37
  "dependencies": {
36
38
  "ws": "^8.16.0"
37
39
  },
38
40
  "devDependencies": {
39
41
  "@aicq/crypto": "file:../shared/crypto",
40
- "openclaw": "^2026.4.2",
41
- "esbuild": "^0.25.0",
42
- "typescript": "^5.3.3",
43
42
  "@types/node": "^20.10.0",
44
- "@types/ws": "^8.5.10",
45
- "@types/uuid": "^9.0.7",
46
43
  "@types/qrcode": "^1.5.5",
47
- "ts-node-dev": "^2.0.0",
48
- "uuid": "^9.0.0",
44
+ "@types/uuid": "^9.0.7",
45
+ "@types/ws": "^8.5.10",
46
+ "dotenv": "^16.3.1",
47
+ "esbuild": "^0.25.0",
48
+ "openclaw": "^2026.4.2",
49
49
  "qrcode": "^1.5.3",
50
- "dotenv": "^16.3.1"
50
+ "ts-node-dev": "^2.0.0",
51
+ "typescript": "^5.3.3",
52
+ "uuid": "^9.0.0"
51
53
  },
52
54
  "keywords": [
53
55
  "openclaw",