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.
- package/dist/index.js +263 -12
- 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
|
-
|
|
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
|
|
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
|
-
|
|
15173
|
-
|
|
15174
|
-
|
|
15175
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
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
|
+
}
|