aicq-chat-plugin 3.5.3 → 3.6.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.
package/index.js CHANGED
@@ -132,7 +132,7 @@ async function handleGatewayMethod(method, kwargs = {}) {
132
132
  return {
133
133
  state: _serverClient.connected ? "connected" : "disconnected",
134
134
  agent_id: currentAgentId,
135
- version: "3.2.0",
135
+ version: "3.6.0",
136
136
  architecture: "channel",
137
137
  };
138
138
  case "aicq.friends.list":
@@ -268,6 +268,11 @@ function registerCliMetadata(api) {
268
268
 
269
269
  // ── Full runtime registration ────────────────────────────────────────
270
270
  async function registerFull(api) {
271
+ // Expose ensureInitialized on the runtime store immediately so that
272
+ // startAccount (called by the channel loader) can trigger init even
273
+ // if no gateway method has been invoked yet.
274
+ runtime.ensureInitialized = ensureInitialized;
275
+
271
276
  // Register gateway RPC methods — each wraps handleGatewayMethod
272
277
  const GATEWAY_METHODS = [
273
278
  "aicq.status",
@@ -2,7 +2,7 @@
2
2
  "kind": "channel",
3
3
  "id": "aicq-chat",
4
4
  "name": "AICQ Encrypted Chat",
5
- "version": "3.5.3",
5
+ "version": "3.6.1",
6
6
  "description": "End-to-end encrypted chat channel via AICQ protocol — in-process Channel plugin using OpenClaw Channel SDK",
7
7
  "entry": "index.js",
8
8
  "activation": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aicq-chat-plugin",
3
- "version": "3.5.3",
3
+ "version": "3.6.1",
4
4
  "description": "AICQ End-to-end Encrypted Chat Channel Plugin for OpenClaw — In-process Channel SDK architecture with friend management, group chat, file transfer, and AI agent communication",
5
5
  "type": "module",
6
6
  "main": "index.js",
package/src/channel.js CHANGED
@@ -122,8 +122,46 @@ const _plugin = createChatChannelPlugin({
122
122
  id: "aicq-chat",
123
123
 
124
124
  setup: {
125
- resolveAccount,
126
- inspectAccount,
125
+ /**
126
+ * Resolve the account ID from setup input.
127
+ * Called by the setup wizard when a user configures the channel.
128
+ */
129
+ resolveAccountId(params) {
130
+ const { cfg, accountId, input } = params;
131
+ return accountId || input?.accountId || resolveTemplateVar(cfg, "{{agent.id}}");
132
+ },
133
+
134
+ /**
135
+ * Apply the account config after the setup wizard completes.
136
+ * Must return the updated OpenClawConfig.
137
+ */
138
+ applyAccountConfig(params) {
139
+ const { cfg, accountId, input } = params;
140
+ const section = (cfg.channels || {})["aicq-chat"] || {};
141
+ return {
142
+ ...cfg,
143
+ channels: {
144
+ ...(cfg.channels || {}),
145
+ "aicq-chat": {
146
+ ...section,
147
+ accountId: accountId || input?.accountId || "{{agent.id}}",
148
+ serverUrl: input?.serverUrl || section.serverUrl || "https://aicq.online",
149
+ autoAcceptFriends: input?.autoAcceptFriends ?? section.autoAcceptFriends ?? true,
150
+ enabled: true,
151
+ dmPolicy: input?.dmPolicy || section.dmPolicy || "allowlist",
152
+ allowFrom: input?.allowFrom || section.allowFrom || [],
153
+ },
154
+ },
155
+ };
156
+ },
157
+
158
+ /**
159
+ * Validate setup input before applying.
160
+ * Return an error message string or null if valid.
161
+ */
162
+ validateInput(params) {
163
+ return null;
164
+ },
127
165
  },
128
166
 
129
167
  // Gateway method descriptors — these are the method names the plugin
@@ -236,7 +274,7 @@ _plugin.gateway = {
236
274
  * listening for inbound messages.
237
275
  */
238
276
  async startAccount(ctx) {
239
- const { cfg, accountId, account, setStatus, log } = ctx;
277
+ const { cfg, accountId, account, setStatus, log, abortSignal } = ctx;
240
278
 
241
279
  const logger = log || console;
242
280
  logger.info?.(`[AICQ Channel] startAccount called for ${accountId}`) || console.log(`[AICQ Channel] startAccount called for ${accountId}`);
@@ -287,7 +325,6 @@ _plugin.gateway = {
287
325
  console.log(`[AICQ Channel] Authenticated as ${agentId}`);
288
326
 
289
327
  // Connect WebSocket for real-time messages
290
- // ServerClient.start() does ensureAuth + connectWS
291
328
  if (typeof runtime.serverClient.start === "function") {
292
329
  await runtime.serverClient.start(agentId);
293
330
  console.log("[AICQ Channel] WebSocket connected");
@@ -316,7 +353,6 @@ _plugin.gateway = {
316
353
  if (reply && routing) {
317
354
  console.log("[AICQ Channel] channelRuntime available — AI dispatch enabled");
318
355
 
319
- // Register inbound message handler on the serverClient
320
356
  if (runtime.serverClient && typeof runtime.serverClient.onMessage === "function") {
321
357
  runtime.serverClient.onMessage(async (msg) => {
322
358
  try {
@@ -340,7 +376,6 @@ _plugin.gateway = {
340
376
  cfg,
341
377
  dispatcherOptions: {
342
378
  deliver: async (payload) => {
343
- // Send AI reply back through AICQ
344
379
  if (runtime.chat && payload.text) {
345
380
  await runtime.chat.sendMessage(
346
381
  resolvedAgentId,
@@ -374,6 +409,17 @@ _plugin.gateway = {
374
409
  });
375
410
 
376
411
  console.log(`[AICQ Channel] Account ${accountId} started successfully`);
412
+
413
+ // ── Keep startAccount alive until abort signal ──────────────────
414
+ // OpenClaw expects startAccount to be a long-lived task. If it
415
+ // resolves immediately, the gateway treats it as an unexpected
416
+ // exit and enters a restart loop. We wait on the abort signal.
417
+ await new Promise((resolve) => {
418
+ if (abortSignal?.aborted) { resolve(); return; }
419
+ const onAbort = () => { cleanup(); resolve(); };
420
+ const cleanup = () => { abortSignal?.removeEventListener("abort", onAbort); };
421
+ abortSignal?.addEventListener("abort", onAbort, { once: true });
422
+ });
377
423
  },
378
424
 
379
425
  /**
@@ -409,6 +455,8 @@ _plugin.config = {
409
455
  /**
410
456
  * List all account IDs configured for this channel.
411
457
  * Resolves template variables like {{agent.id}}.
458
+ *
459
+ * Signature: (cfg: OpenClawConfig) => string[]
412
460
  */
413
461
  listAccountIds(cfg) {
414
462
  const section = (cfg.channels || {})["aicq-chat"] || {};
@@ -421,17 +469,22 @@ _plugin.config = {
421
469
 
422
470
  /**
423
471
  * Resolve an account from config. Reuses the setup resolver.
472
+ *
473
+ * Signature: (cfg: OpenClawConfig, accountId?: string | null) => ResolvedAccount
424
474
  */
425
475
  resolveAccount,
426
476
 
427
477
  /**
428
478
  * Lightweight account inspection.
479
+ *
480
+ * Signature: (cfg: OpenClawConfig, accountId?: string | null) => unknown
429
481
  */
430
482
  inspectAccount,
431
483
 
432
484
  /**
433
485
  * Default account ID for this channel.
434
- * Resolves {{agent.id}} to the actual agent ID.
486
+ *
487
+ * Signature: (cfg: OpenClawConfig) => string
435
488
  */
436
489
  defaultAccountId(cfg) {
437
490
  const section = (cfg.channels || {})["aicq-chat"] || {};
@@ -442,19 +495,39 @@ _plugin.config = {
442
495
  },
443
496
 
444
497
  /**
445
- * Check if the channel is configured.
498
+ * Check if the account is enabled.
499
+ *
500
+ * IMPORTANT: OpenClaw calls this with (account, cfg) where `account`
501
+ * is the RESOLVED account object from resolveAccount(), not the config.
502
+ *
503
+ * Signature: (account: ResolvedAccount, cfg: OpenClawConfig) => boolean
446
504
  */
447
- isConfigured(cfg) {
448
- const section = (cfg.channels || {})["aicq-chat"] || {};
449
- return Boolean(section.accountId);
505
+ isEnabled(account, cfg) {
506
+ return account.enabled !== false;
507
+ },
508
+
509
+ /**
510
+ * Check if the channel account is configured.
511
+ *
512
+ * IMPORTANT: OpenClaw calls this with (account, cfg) where `account`
513
+ * is the RESOLVED account object from resolveAccount(), not the config.
514
+ * Our old code had isConfigured(cfg) which received the account object
515
+ * as `cfg`, causing it to always return false — this was the root cause
516
+ * of the "not-running" bug.
517
+ *
518
+ * Signature: (account: ResolvedAccount, cfg: OpenClawConfig) => boolean
519
+ */
520
+ isConfigured(account, cfg) {
521
+ return Boolean(account && account.accountId);
450
522
  },
451
523
 
452
524
  /**
453
525
  * Return the reason the channel is not configured.
526
+ *
527
+ * Signature: (account: ResolvedAccount, cfg: OpenClawConfig) => string
454
528
  */
455
- unconfiguredReason(cfg) {
456
- const section = (cfg.channels || {})["aicq-chat"] || {};
457
- if (!section.accountId) {
529
+ unconfiguredReason(account, cfg) {
530
+ if (!account || !account.accountId) {
458
531
  return "accountId is required — set channels.aicq-chat.accountId in openclaw.json";
459
532
  }
460
533
  return null;
@@ -462,14 +535,17 @@ _plugin.config = {
462
535
 
463
536
  /**
464
537
  * Describe the account for status surfaces.
538
+ *
539
+ * IMPORTANT: OpenClaw calls this with (account, cfg) where `account`
540
+ * is the RESOLVED account object, not the config.
541
+ *
542
+ * Signature: (account: ResolvedAccount, cfg: OpenClawConfig) => ChannelAccountSnapshot
465
543
  */
466
- describeAccount(cfg, accountId) {
467
- const section = (cfg.channels || {})["aicq-chat"] || {};
468
- const rawId = accountId || section.accountId || null;
544
+ describeAccount(account, cfg) {
469
545
  return {
470
- accountId: rawId ? resolveTemplateVar(cfg, rawId) : null,
546
+ accountId: account?.accountId || null,
471
547
  label: "AICQ Encrypted Chat",
472
- enabled: section.enabled !== false,
548
+ enabled: account?.enabled !== false,
473
549
  };
474
550
  },
475
551
  };