aicq-openclaw-plugin 1.5.6 → 1.5.8

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 +263 -12
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -7771,7 +7771,7 @@ var require_dist = __commonJS({
7771
7771
  var dotenv = __toESM(require_main(), 1);
7772
7772
  import * as path6 from "path";
7773
7773
  import * as http from "http";
7774
- import { exec } from "child_process";
7774
+ import { exec as exec2 } from "child_process";
7775
7775
  import { definePluginEntry } from "openclaw/plugin-sdk/core";
7776
7776
 
7777
7777
  // dist/config.js
@@ -8648,7 +8648,7 @@ var ServerClient = class {
8648
8648
  this.ws.terminate();
8649
8649
  }
8650
8650
  }, this.config.requestTimeoutMs);
8651
- this.ws.on("open", () => {
8651
+ this.ws.on("open", async () => {
8652
8652
  clearTimeout(connectTimeout);
8653
8653
  this.wsConnected = true;
8654
8654
  this.reconnectDelay = this.config.initialReconnectDelay;
@@ -8656,13 +8656,22 @@ var ServerClient = class {
8656
8656
  this.connectStartTimestamp = 0;
8657
8657
  this.hourlyCheckMode = false;
8658
8658
  this.cancelHourlyCheck();
8659
- this.setConnectionState("online");
8660
8659
  this.logger.info("[Server] WebSocket connected");
8660
+ if (!this.authToken) {
8661
+ this.logger.info("[Server] No auth token \u2014 attempting agent authentication...");
8662
+ const authed = await this.authenticateAsAgent();
8663
+ if (!authed) {
8664
+ this.logger.warn("[Server] Agent auth failed on reconnect \u2014 closing socket");
8665
+ this.ws?.close(1008, "Auth required");
8666
+ return;
8667
+ }
8668
+ }
8669
+ this.setConnectionState("online");
8661
8670
  this.wsSend({
8662
8671
  type: "online",
8663
8672
  nodeId: this.store.agentId,
8664
8673
  publicKey: Buffer.from(this.store.identityKeys.publicKey).toString("base64"),
8665
- ...this.authToken ? { token: this.authToken } : {}
8674
+ token: this.authToken
8666
8675
  });
8667
8676
  this.startHeartbeat();
8668
8677
  });
@@ -8812,6 +8821,47 @@ var ServerClient = class {
8812
8821
  // ----------------------------------------------------------------
8813
8822
  // REST API methods
8814
8823
  // ----------------------------------------------------------------
8824
+ /**
8825
+ * Authenticate as an AI Agent using challenge-response.
8826
+ *
8827
+ * Flow:
8828
+ * 1. POST /api/v1/auth/challenge → get challenge + challengeId
8829
+ * 2. Sign challenge with Ed25519 private key
8830
+ * 3. POST /api/v1/auth/login-agent → get JWT token
8831
+ *
8832
+ * Returns true if authentication succeeded and token was set.
8833
+ */
8834
+ async authenticateAsAgent() {
8835
+ const publicKeyBase64 = Buffer.from(this.store.identityKeys.publicKey).toString("base64");
8836
+ const challengeResp = await this.fetchPost("/api/v1/auth/challenge", {
8837
+ publicKey: publicKeyBase64
8838
+ });
8839
+ if (!challengeResp?.challenge || !challengeResp?.challengeId) {
8840
+ this.logger.warn("[Server] Failed to request agent challenge");
8841
+ return false;
8842
+ }
8843
+ let signature;
8844
+ try {
8845
+ const message = Buffer.from(challengeResp.challenge, "utf8");
8846
+ const nacl3 = await Promise.resolve().then(() => __toESM(require_nacl_fast(), 1));
8847
+ signature = nacl3.sign.detached(message, this.store.identityKeys.secretKey);
8848
+ } catch (err) {
8849
+ this.logger.error("[Server] Failed to sign challenge:", err);
8850
+ return false;
8851
+ }
8852
+ const loginResp = await this.fetchPost("/api/v1/auth/login-agent", {
8853
+ publicKey: publicKeyBase64,
8854
+ signature: Buffer.from(signature).toString("base64"),
8855
+ challengeId: challengeResp.challengeId
8856
+ });
8857
+ if (!loginResp?.session?.token) {
8858
+ this.logger.warn("[Server] Agent login failed \u2014 no token in response");
8859
+ return false;
8860
+ }
8861
+ this.setAuthToken(loginResp.session.token);
8862
+ this.logger.info("[Server] Agent authenticated successfully");
8863
+ return true;
8864
+ }
8815
8865
  /**
8816
8866
  * Register this node on the server.
8817
8867
  * Captures JWT token from response if returned.
@@ -10288,6 +10338,181 @@ var MessageSendingHook = class {
10288
10338
  }
10289
10339
  };
10290
10340
 
10341
+ // dist/services/autoUpdateService.js
10342
+ import { exec } from "child_process";
10343
+ import { promisify } from "util";
10344
+ var execAsync = promisify(exec);
10345
+ var NPM_REGISTRY_URL = "https://registry.npmjs.org/aicq-openclaw-plugin";
10346
+ var CHECK_INTERVAL_MS = 6 * 60 * 60 * 1e3;
10347
+ var AutoUpdateService = class {
10348
+ constructor(currentVersion, logger) {
10349
+ this.latestVersion = null;
10350
+ this.isUpdating = false;
10351
+ this.lastCheckTime = 0;
10352
+ this.checkTimer = null;
10353
+ this.onUpdateAvailable = null;
10354
+ this.onUpdateComplete = null;
10355
+ this.onUpdateError = null;
10356
+ this.currentVersion = currentVersion;
10357
+ this.logger = logger;
10358
+ }
10359
+ /**
10360
+ * Start the auto-update service.
10361
+ * Checks immediately, then periodically every 6 hours.
10362
+ */
10363
+ start() {
10364
+ this.checkForUpdate().catch(() => {
10365
+ });
10366
+ this.checkTimer = setInterval(() => {
10367
+ this.checkForUpdate().catch(() => {
10368
+ });
10369
+ }, CHECK_INTERVAL_MS);
10370
+ this.logger.info("[AutoUpdate] Service started \u2014 checking every " + CHECK_INTERVAL_MS / 36e5 + " hours");
10371
+ }
10372
+ /**
10373
+ * Stop the auto-update service.
10374
+ */
10375
+ stop() {
10376
+ if (this.checkTimer) {
10377
+ clearInterval(this.checkTimer);
10378
+ this.checkTimer = null;
10379
+ }
10380
+ this.logger.info("[AutoUpdate] Service stopped");
10381
+ }
10382
+ /**
10383
+ * Register callback for when an update is available.
10384
+ */
10385
+ onAvailable(callback) {
10386
+ this.onUpdateAvailable = callback;
10387
+ }
10388
+ /**
10389
+ * Register callback for when an update completes successfully.
10390
+ */
10391
+ onComplete(callback) {
10392
+ this.onUpdateComplete = callback;
10393
+ }
10394
+ /**
10395
+ * Register callback for when an update fails.
10396
+ */
10397
+ onError(callback) {
10398
+ this.onUpdateError = callback;
10399
+ }
10400
+ /**
10401
+ * Get the current update status.
10402
+ */
10403
+ getStatus() {
10404
+ return {
10405
+ currentVersion: this.currentVersion,
10406
+ latestVersion: this.latestVersion,
10407
+ hasUpdate: this.latestVersion ? this.compareVersions(this.latestVersion, this.currentVersion) > 0 : false,
10408
+ isUpdating: this.isUpdating,
10409
+ lastCheckTime: this.lastCheckTime
10410
+ };
10411
+ }
10412
+ /**
10413
+ * Manually trigger an update check.
10414
+ */
10415
+ async checkNow() {
10416
+ return this.checkForUpdate();
10417
+ }
10418
+ /**
10419
+ * Check npm registry for the latest version.
10420
+ * If a newer version is found, automatically install it.
10421
+ */
10422
+ async checkForUpdate() {
10423
+ if (this.isUpdating) {
10424
+ this.logger.info("[AutoUpdate] Already updating \u2014 skip check");
10425
+ return null;
10426
+ }
10427
+ try {
10428
+ this.logger.info("[AutoUpdate] Checking for updates... (current: " + this.currentVersion + ")");
10429
+ const controller = new AbortController();
10430
+ const timeout = setTimeout(() => controller.abort(), 15e3);
10431
+ const resp = await fetch(NPM_REGISTRY_URL, {
10432
+ signal: controller.signal,
10433
+ headers: { "Accept": "application/json" }
10434
+ });
10435
+ clearTimeout(timeout);
10436
+ if (!resp.ok) {
10437
+ this.logger.warn("[AutoUpdate] npm registry returned " + resp.status);
10438
+ return null;
10439
+ }
10440
+ const data = await resp.json();
10441
+ const latest = data?.["dist-tags"]?.latest;
10442
+ if (!latest) {
10443
+ this.logger.warn("[AutoUpdate] No 'latest' dist-tag found");
10444
+ return null;
10445
+ }
10446
+ this.latestVersion = latest;
10447
+ this.lastCheckTime = Date.now();
10448
+ const info = {
10449
+ latest,
10450
+ current: this.currentVersion,
10451
+ hasUpdate: this.compareVersions(latest, this.currentVersion) > 0
10452
+ };
10453
+ if (info.hasUpdate) {
10454
+ this.logger.info("[AutoUpdate] New version available: " + this.currentVersion + " \u2192 " + latest);
10455
+ this.onUpdateAvailable?.(info);
10456
+ await this.installUpdate(latest);
10457
+ } else {
10458
+ this.logger.info("[AutoUpdate] Plugin is up to date (" + this.currentVersion + ")");
10459
+ }
10460
+ return info;
10461
+ } catch (err) {
10462
+ if (err instanceof DOMException && err.name === "AbortError") {
10463
+ this.logger.warn("[AutoUpdate] Check timed out");
10464
+ } else {
10465
+ this.logger.error("[AutoUpdate] Check failed: " + (err instanceof Error ? err.message : String(err)));
10466
+ }
10467
+ return null;
10468
+ }
10469
+ }
10470
+ /**
10471
+ * Install the specified version from npm.
10472
+ * Uses `npm install -g` to update the plugin globally.
10473
+ */
10474
+ async installUpdate(version) {
10475
+ if (this.isUpdating)
10476
+ return false;
10477
+ this.isUpdating = true;
10478
+ try {
10479
+ this.logger.info("[AutoUpdate] Installing aicq-openclaw-plugin@" + version + "...");
10480
+ const { stdout, stderr } = await execAsync("npm install -g aicq-openclaw-plugin@" + version, { timeout: 12e4 });
10481
+ if (stdout)
10482
+ this.logger.info("[AutoUpdate] " + stdout.trim());
10483
+ if (stderr)
10484
+ this.logger.warn("[AutoUpdate] " + stderr.trim());
10485
+ this.logger.info("[AutoUpdate] Successfully updated to " + version);
10486
+ this.currentVersion = version;
10487
+ const info = { latest: version, current: version, hasUpdate: false };
10488
+ this.onUpdateComplete?.(info);
10489
+ return true;
10490
+ } catch (err) {
10491
+ const msg = err instanceof Error ? err.message : String(err);
10492
+ this.logger.error("[AutoUpdate] Install failed: " + msg);
10493
+ this.onUpdateError?.(msg);
10494
+ return false;
10495
+ } finally {
10496
+ this.isUpdating = false;
10497
+ }
10498
+ }
10499
+ /**
10500
+ * Compare two semver version strings.
10501
+ * Returns > 0 if a > b, < 0 if a < b, 0 if equal.
10502
+ */
10503
+ compareVersions(a, b) {
10504
+ const pa = a.replace(/^v/, "").split(".").map(Number);
10505
+ const pb = b.replace(/^v/, "").split(".").map(Number);
10506
+ for (let i = 0; i < 3; i++) {
10507
+ const na = pa[i] || 0;
10508
+ const nb = pb[i] || 0;
10509
+ if (na !== nb)
10510
+ return na - nb;
10511
+ }
10512
+ return 0;
10513
+ }
10514
+ };
10515
+
10291
10516
  // dist/ui/management-page.js
10292
10517
  var CSS = `
10293
10518
  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
@@ -15111,8 +15336,9 @@ var plugin = definePluginEntry({
15111
15336
  error: (msg, ...args) => ocLog.error?.(msg, ...args) ?? console.error("[aicq-chat]", msg, ...args),
15112
15337
  debug: (msg, ...args) => ocLog.debug?.(msg, ...args) ?? console.log("[aicq-chat DEBUG]", msg, ...args)
15113
15338
  };
15339
+ const pluginVersion = "1.5.8";
15114
15340
  logger.info("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
15115
- logger.info(" AICQ Encrypted Chat Plugin v1.2.0");
15341
+ logger.info(" AICQ Encrypted Chat Plugin v" + pluginVersion);
15116
15342
  logger.info("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
15117
15343
  const pluginCfg = api.pluginConfig ?? {};
15118
15344
  const config2 = loadConfig({
@@ -15169,11 +15395,24 @@ var plugin = definePluginEntry({
15169
15395
  }
15170
15396
  const serverUrl = config2.serverUrl;
15171
15397
  const aicqAgentId = identityService.getAgentId();
15172
- try {
15173
- serverClient.connectWebSocket();
15174
- } catch (e) {
15175
- logger.warn("[Init] WS connect failed: " + (e instanceof Error ? e.message : e));
15176
- }
15398
+ (async () => {
15399
+ try {
15400
+ logger.info("[Init] Authenticating agent with server...");
15401
+ const authed = await serverClient.authenticateAsAgent();
15402
+ if (authed) {
15403
+ logger.info("[Init] Agent authentication successful");
15404
+ } else {
15405
+ logger.warn("[Init] Agent authentication failed \u2014 will retry on reconnect");
15406
+ }
15407
+ } catch (e) {
15408
+ logger.warn("[Init] Agent auth error: " + (e instanceof Error ? e.message : e));
15409
+ }
15410
+ try {
15411
+ serverClient.connectWebSocket();
15412
+ } catch (e) {
15413
+ logger.warn("[Init] WS connect failed: " + (e instanceof Error ? e.message : e));
15414
+ }
15415
+ })();
15177
15416
  serverClient.onConnectionStateChange((newState, prevState) => {
15178
15417
  logger.info("[Init] Connection state changed: " + prevState + " \u2192 " + newState);
15179
15418
  });
@@ -15336,6 +15575,17 @@ var plugin = definePluginEntry({
15336
15575
  return chatExportKeyTool.handle(params || {});
15337
15576
  }
15338
15577
  });
15578
+ const autoUpdateService = new AutoUpdateService(pluginVersion, logger);
15579
+ autoUpdateService.onAvailable((info) => {
15580
+ logger.info("[AutoUpdate] \u{1F195} Update available: " + info.current + " \u2192 " + info.latest + " \u2014 installing...");
15581
+ });
15582
+ autoUpdateService.onComplete((info) => {
15583
+ logger.info("[AutoUpdate] \u2705 Updated to " + info.latest + " \u2014 restart OpenClaw to use the new version");
15584
+ });
15585
+ autoUpdateService.onError((err) => {
15586
+ logger.warn("[AutoUpdate] \u274C Update failed: " + err);
15587
+ });
15588
+ autoUpdateService.start();
15339
15589
  if (api.registerService) {
15340
15590
  api.registerService({
15341
15591
  id: "identity-service",
@@ -15354,6 +15604,7 @@ var plugin = definePluginEntry({
15354
15604
  identityService.cleanup();
15355
15605
  chatChannel.cleanup();
15356
15606
  serverClient.disconnectWebSocket();
15607
+ autoUpdateService.stop();
15357
15608
  logger.info("[Service] identity-service stopped");
15358
15609
  }
15359
15610
  });
@@ -15726,7 +15977,7 @@ var plugin = definePluginEntry({
15726
15977
  try {
15727
15978
  const url = "http://127.0.0.1:" + actualMgmtPort + "/";
15728
15979
  const cmd = process.platform === "win32" ? "start" : process.platform === "darwin" ? "open" : "xdg-open";
15729
- exec(cmd + ' "' + url + '"', (err) => {
15980
+ exec2(cmd + ' "' + url + '"', (err) => {
15730
15981
  if (err)
15731
15982
  logger.debug("[Init] Auto-open browser skipped: " + (err.message || err));
15732
15983
  else
@@ -15737,7 +15988,7 @@ var plugin = definePluginEntry({
15737
15988
  }
15738
15989
  }, 3e3);
15739
15990
  logger.info("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
15740
- logger.info(" AICQ Plugin v1.2.0 activated successfully!");
15991
+ logger.info(" AICQ Plugin v" + pluginVersion + " activated successfully!");
15741
15992
  logger.info(" Management UI: http://127.0.0.1:" + actualMgmtPort + "/");
15742
15993
  if (mgmtUiRegistered) {
15743
15994
  logger.info(" Gateway UI: /plugins/aicq-chat/");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aicq-openclaw-plugin",
3
- "version": "1.5.6",
3
+ "version": "1.5.8",
4
4
  "description": "AICQ OpenClaw plugin - end-to-end encrypted P2P chat for AI agents with offline queue support",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -64,4 +64,4 @@
64
64
  "type": "git",
65
65
  "url": "https://github.com/ctz168/aicq"
66
66
  }
67
- }
67
+ }