aicq-codex 0.1.3 → 0.1.4
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/database.js +8 -2
- package/lib/server-client.js +35 -3
- package/package.json +3 -3
package/lib/database.js
CHANGED
|
@@ -462,8 +462,14 @@ class PluginDatabase {
|
|
|
462
462
|
if (this._saveTimer) {
|
|
463
463
|
clearTimeout(this._saveTimer);
|
|
464
464
|
}
|
|
465
|
-
|
|
466
|
-
this.db
|
|
465
|
+
// [fix 2026-08-29] init() may still be awaiting initSqlJs() when close()
|
|
466
|
+
// is called (plugin dispose during startup): this.db is null then, and
|
|
467
|
+
// the unconditional _save()/db.close() crashed with
|
|
468
|
+
// "Cannot read properties of null (reading 'export')".
|
|
469
|
+
if (this.db) {
|
|
470
|
+
this._save(); // Final save before closing
|
|
471
|
+
this.db.close();
|
|
472
|
+
}
|
|
467
473
|
}
|
|
468
474
|
}
|
|
469
475
|
|
package/lib/server-client.js
CHANGED
|
@@ -36,9 +36,25 @@ class ServerClient {
|
|
|
36
36
|
opts.body = JSON.stringify(body);
|
|
37
37
|
}
|
|
38
38
|
const resp = await fetch(`${this.apiUrl}${path}`, opts);
|
|
39
|
-
const data = await resp.json();
|
|
39
|
+
const data = await resp.json().catch(() => ({}));
|
|
40
40
|
if (!resp.ok) {
|
|
41
|
-
|
|
41
|
+
// [fix 2026-08-29] the AICQ server errors come back as
|
|
42
|
+
// {"error": {"code": "...", "message": "..."}} — a nested OBJECT.
|
|
43
|
+
// The old `new Error(data.error || ...)` interpolated the object and
|
|
44
|
+
// every failure surfaced to users/models as "[object Object]".
|
|
45
|
+
const err = data.error;
|
|
46
|
+
let msg;
|
|
47
|
+
if (err && typeof err === 'object') {
|
|
48
|
+
msg = err.message || err.code;
|
|
49
|
+
} else if (typeof err === 'string' && err) {
|
|
50
|
+
msg = err;
|
|
51
|
+
} else {
|
|
52
|
+
msg = data.message;
|
|
53
|
+
}
|
|
54
|
+
const e = new Error(msg || `HTTP ${resp.status}`);
|
|
55
|
+
e.status = resp.status;
|
|
56
|
+
e.code = (err && typeof err === 'object' && err.code) || undefined;
|
|
57
|
+
throw e;
|
|
42
58
|
}
|
|
43
59
|
return data;
|
|
44
60
|
}
|
|
@@ -230,6 +246,9 @@ class ServerClient {
|
|
|
230
246
|
|
|
231
247
|
connectWS() {
|
|
232
248
|
if (this.ws && this.ws.readyState === WebSocket.OPEN) return;
|
|
249
|
+
// [fix 2026-08-29] a direct connectWS() call (non-start() path) also
|
|
250
|
+
// implies the client wants to stay connected.
|
|
251
|
+
this._running = true;
|
|
233
252
|
|
|
234
253
|
const identity = this.identity.loadAgent(this.currentAgentId);
|
|
235
254
|
if (!identity || !this.jwtToken) {
|
|
@@ -339,6 +358,11 @@ class ServerClient {
|
|
|
339
358
|
}
|
|
340
359
|
|
|
341
360
|
_scheduleReconnect() {
|
|
361
|
+
// [fix 2026-08-29] never reschedule after an explicit stop()/disconnect():
|
|
362
|
+
// the WS 'close' handler calls this even for intentional teardown, which
|
|
363
|
+
// left a reconnect timer (+ ping timer + open socket) keeping the host
|
|
364
|
+
// process alive forever after plugin dispose.
|
|
365
|
+
if (!this._running) return;
|
|
342
366
|
if (this._reconnectTimer) return;
|
|
343
367
|
this._reconnectTimer = setTimeout(() => {
|
|
344
368
|
this._reconnectTimer = null;
|
|
@@ -354,8 +378,10 @@ class ServerClient {
|
|
|
354
378
|
async start(agentId) {
|
|
355
379
|
try {
|
|
356
380
|
await this.ensureAuth(agentId);
|
|
357
|
-
|
|
381
|
+
// [fix 2026-08-29] set _running BEFORE connecting so a fast 'close'
|
|
382
|
+
// event (e.g. server hiccup) is allowed to schedule a reconnect.
|
|
358
383
|
this._running = true;
|
|
384
|
+
this.connectWS();
|
|
359
385
|
console.log('[ServerClient] Started for agent:', agentId);
|
|
360
386
|
} catch (e) {
|
|
361
387
|
console.error('[ServerClient] Start failed:', e.message);
|
|
@@ -372,6 +398,11 @@ class ServerClient {
|
|
|
372
398
|
}
|
|
373
399
|
|
|
374
400
|
disconnect() {
|
|
401
|
+
// [fix 2026-08-29] mark stopped FIRST so the ws 'close' handler cannot
|
|
402
|
+
// schedule a zombie reconnect, and clear the ping interval here (it was
|
|
403
|
+
// only cleared in the 'close' event handler, which never fires if the
|
|
404
|
+
// socket never opened).
|
|
405
|
+
this._running = false;
|
|
375
406
|
if (this.ws) {
|
|
376
407
|
// SPEC 合规: offline 消息必须带 nodeId 字段
|
|
377
408
|
// 见 aicqSDK/SPEC.md 第 215-219 行
|
|
@@ -383,6 +414,7 @@ class ServerClient {
|
|
|
383
414
|
this.ws = null;
|
|
384
415
|
}
|
|
385
416
|
this.connected = false;
|
|
417
|
+
if (this._pingTimer) { clearInterval(this._pingTimer); this._pingTimer = null; }
|
|
386
418
|
if (this._reconnectTimer) {
|
|
387
419
|
clearTimeout(this._reconnectTimer);
|
|
388
420
|
this._reconnectTimer = null;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aicq-codex",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "AICQ End-to-end Encrypted Chat plugin for OpenAI Codex
|
|
3
|
+
"version": "0.1.4",
|
|
4
|
+
"description": "AICQ End-to-end Encrypted Chat plugin for OpenAI Codex \u2014 Agent Plugins v1 manifest + stdio MCP server exposing AICQ friend management, chat, file transfer, and group messaging tools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./mcp/server.js",
|
|
7
7
|
"bin": {
|
|
@@ -53,4 +53,4 @@
|
|
|
53
53
|
"engines": {
|
|
54
54
|
"node": ">=20.0.0"
|
|
55
55
|
}
|
|
56
|
-
}
|
|
56
|
+
}
|