@openclaw/zalouser 2026.1.29 → 2026.2.2

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/src/channel.ts CHANGED
@@ -17,6 +17,7 @@ import {
17
17
  normalizeAccountId,
18
18
  setAccountEnabledInConfigSection,
19
19
  } from "openclaw/plugin-sdk";
20
+ import type { ZcaFriend, ZcaGroup, ZcaUserInfo } from "./types.js";
20
21
  import {
21
22
  listZalouserAccountIds,
22
23
  resolveDefaultZalouserAccountId,
@@ -25,13 +26,12 @@ import {
25
26
  checkZcaAuthenticated,
26
27
  type ResolvedZalouserAccount,
27
28
  } from "./accounts.js";
29
+ import { ZalouserConfigSchema } from "./config-schema.js";
28
30
  import { zalouserOnboardingAdapter } from "./onboarding.js";
31
+ import { probeZalouser } from "./probe.js";
29
32
  import { sendMessageZalouser } from "./send.js";
30
- import { checkZcaInstalled, parseJsonOutput, runZca, runZcaInteractive } from "./zca.js";
31
- import type { ZcaFriend, ZcaGroup, ZcaUserInfo } from "./types.js";
32
- import { ZalouserConfigSchema } from "./config-schema.js";
33
33
  import { collectZalouserStatusIssues } from "./status-issues.js";
34
- import { probeZalouser } from "./probe.js";
34
+ import { checkZcaInstalled, parseJsonOutput, runZca, runZcaInteractive } from "./zca.js";
35
35
 
36
36
  const meta = {
37
37
  id: "zalouser",
@@ -85,18 +85,20 @@ function resolveZalouserGroupToolPolicy(
85
85
  params: ChannelGroupContext,
86
86
  ): GroupToolPolicyConfig | undefined {
87
87
  const account = resolveZalouserAccountSync({
88
- cfg: params.cfg as OpenClawConfig,
88
+ cfg: params.cfg,
89
89
  accountId: params.accountId ?? undefined,
90
90
  });
91
91
  const groups = account.config.groups ?? {};
92
92
  const groupId = params.groupId?.trim();
93
93
  const groupChannel = params.groupChannel?.trim();
94
- const candidates = [groupId, groupChannel, "*"].filter(
95
- (value): value is string => Boolean(value),
94
+ const candidates = [groupId, groupChannel, "*"].filter((value): value is string =>
95
+ Boolean(value),
96
96
  );
97
97
  for (const key of candidates) {
98
98
  const entry = groups[key];
99
- if (entry?.tools) return entry.tools;
99
+ if (entry?.tools) {
100
+ return entry.tools;
101
+ }
100
102
  }
101
103
  return undefined;
102
104
  }
@@ -111,8 +113,8 @@ export const zalouserDock: ChannelDock = {
111
113
  outbound: { textChunkLimit: 2000 },
112
114
  config: {
113
115
  resolveAllowFrom: ({ cfg, accountId }) =>
114
- (resolveZalouserAccountSync({ cfg: cfg as OpenClawConfig, accountId }).config.allowFrom ?? []).map(
115
- (entry) => String(entry),
116
+ (resolveZalouserAccountSync({ cfg: cfg, accountId }).config.allowFrom ?? []).map((entry) =>
117
+ String(entry),
116
118
  ),
117
119
  formatAllowFrom: ({ allowFrom }) =>
118
120
  allowFrom
@@ -146,13 +148,12 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
146
148
  reload: { configPrefixes: ["channels.zalouser"] },
147
149
  configSchema: buildChannelConfigSchema(ZalouserConfigSchema),
148
150
  config: {
149
- listAccountIds: (cfg) => listZalouserAccountIds(cfg as OpenClawConfig),
150
- resolveAccount: (cfg, accountId) =>
151
- resolveZalouserAccountSync({ cfg: cfg as OpenClawConfig, accountId }),
152
- defaultAccountId: (cfg) => resolveDefaultZalouserAccountId(cfg as OpenClawConfig),
151
+ listAccountIds: (cfg) => listZalouserAccountIds(cfg),
152
+ resolveAccount: (cfg, accountId) => resolveZalouserAccountSync({ cfg: cfg, accountId }),
153
+ defaultAccountId: (cfg) => resolveDefaultZalouserAccountId(cfg),
153
154
  setAccountEnabled: ({ cfg, accountId, enabled }) =>
154
155
  setAccountEnabledInConfigSection({
155
- cfg: cfg as OpenClawConfig,
156
+ cfg: cfg,
156
157
  sectionKey: "zalouser",
157
158
  accountId,
158
159
  enabled,
@@ -160,10 +161,18 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
160
161
  }),
161
162
  deleteAccount: ({ cfg, accountId }) =>
162
163
  deleteAccountFromConfigSection({
163
- cfg: cfg as OpenClawConfig,
164
+ cfg: cfg,
164
165
  sectionKey: "zalouser",
165
166
  accountId,
166
- clearBaseFields: ["profile", "name", "dmPolicy", "allowFrom", "groupPolicy", "groups", "messagePrefix"],
167
+ clearBaseFields: [
168
+ "profile",
169
+ "name",
170
+ "dmPolicy",
171
+ "allowFrom",
172
+ "groupPolicy",
173
+ "groups",
174
+ "messagePrefix",
175
+ ],
167
176
  }),
168
177
  isConfigured: async (account) => {
169
178
  // Check if zca auth status is OK for this profile
@@ -180,8 +189,8 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
180
189
  configured: undefined,
181
190
  }),
182
191
  resolveAllowFrom: ({ cfg, accountId }) =>
183
- (resolveZalouserAccountSync({ cfg: cfg as OpenClawConfig, accountId }).config.allowFrom ?? []).map(
184
- (entry) => String(entry),
192
+ (resolveZalouserAccountSync({ cfg: cfg, accountId }).config.allowFrom ?? []).map((entry) =>
193
+ String(entry),
185
194
  ),
186
195
  formatAllowFrom: ({ allowFrom }) =>
187
196
  allowFrom
@@ -193,9 +202,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
193
202
  security: {
194
203
  resolveDmPolicy: ({ cfg, accountId, account }) => {
195
204
  const resolvedAccountId = accountId ?? account.accountId ?? DEFAULT_ACCOUNT_ID;
196
- const useAccountPath = Boolean(
197
- (cfg as OpenClawConfig).channels?.zalouser?.accounts?.[resolvedAccountId],
198
- );
205
+ const useAccountPath = Boolean(cfg.channels?.zalouser?.accounts?.[resolvedAccountId]);
199
206
  const basePath = useAccountPath
200
207
  ? `channels.zalouser.accounts.${resolvedAccountId}.`
201
208
  : "channels.zalouser.";
@@ -220,7 +227,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
220
227
  resolveAccountId: ({ accountId }) => normalizeAccountId(accountId),
221
228
  applyAccountName: ({ cfg, accountId, name }) =>
222
229
  applyAccountNameToChannelSection({
223
- cfg: cfg as OpenClawConfig,
230
+ cfg: cfg,
224
231
  channelKey: "zalouser",
225
232
  accountId,
226
233
  name,
@@ -228,7 +235,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
228
235
  validateInput: () => null,
229
236
  applyAccountConfig: ({ cfg, accountId, input }) => {
230
237
  const namedConfig = applyAccountNameToChannelSection({
231
- cfg: cfg as OpenClawConfig,
238
+ cfg: cfg,
232
239
  channelKey: "zalouser",
233
240
  accountId,
234
241
  name: input.name,
@@ -260,9 +267,9 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
260
267
  ...next.channels?.zalouser,
261
268
  enabled: true,
262
269
  accounts: {
263
- ...(next.channels?.zalouser?.accounts ?? {}),
270
+ ...next.channels?.zalouser?.accounts,
264
271
  [accountId]: {
265
- ...(next.channels?.zalouser?.accounts?.[accountId] ?? {}),
272
+ ...next.channels?.zalouser?.accounts?.[accountId],
266
273
  enabled: true,
267
274
  },
268
275
  },
@@ -274,13 +281,17 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
274
281
  messaging: {
275
282
  normalizeTarget: (raw) => {
276
283
  const trimmed = raw?.trim();
277
- if (!trimmed) return undefined;
284
+ if (!trimmed) {
285
+ return undefined;
286
+ }
278
287
  return trimmed.replace(/^(zalouser|zlu):/i, "");
279
288
  },
280
289
  targetResolver: {
281
290
  looksLikeId: (raw) => {
282
291
  const trimmed = raw.trim();
283
- if (!trimmed) return false;
292
+ if (!trimmed) {
293
+ return false;
294
+ }
284
295
  return /^\d{3,}$/.test(trimmed);
285
296
  },
286
297
  hint: "<threadId>",
@@ -289,15 +300,22 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
289
300
  directory: {
290
301
  self: async ({ cfg, accountId, runtime }) => {
291
302
  const ok = await checkZcaInstalled();
292
- if (!ok) throw new Error("Missing dependency: `zca` not found in PATH");
293
- const account = resolveZalouserAccountSync({ cfg: cfg as OpenClawConfig, accountId });
294
- const result = await runZca(["me", "info", "-j"], { profile: account.profile, timeout: 10000 });
303
+ if (!ok) {
304
+ throw new Error("Missing dependency: `zca` not found in PATH");
305
+ }
306
+ const account = resolveZalouserAccountSync({ cfg: cfg, accountId });
307
+ const result = await runZca(["me", "info", "-j"], {
308
+ profile: account.profile,
309
+ timeout: 10000,
310
+ });
295
311
  if (!result.ok) {
296
312
  runtime.error(result.stderr || "Failed to fetch profile");
297
313
  return null;
298
314
  }
299
315
  const parsed = parseJsonOutput<ZcaUserInfo>(result.stdout);
300
- if (!parsed?.userId) return null;
316
+ if (!parsed?.userId) {
317
+ return null;
318
+ }
301
319
  return mapUser({
302
320
  id: String(parsed.userId),
303
321
  name: parsed.displayName ?? null,
@@ -307,11 +325,11 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
307
325
  },
308
326
  listPeers: async ({ cfg, accountId, query, limit }) => {
309
327
  const ok = await checkZcaInstalled();
310
- if (!ok) throw new Error("Missing dependency: `zca` not found in PATH");
311
- const account = resolveZalouserAccountSync({ cfg: cfg as OpenClawConfig, accountId });
312
- const args = query?.trim()
313
- ? ["friend", "find", query.trim()]
314
- : ["friend", "list", "-j"];
328
+ if (!ok) {
329
+ throw new Error("Missing dependency: `zca` not found in PATH");
330
+ }
331
+ const account = resolveZalouserAccountSync({ cfg: cfg, accountId });
332
+ const args = query?.trim() ? ["friend", "find", query.trim()] : ["friend", "list", "-j"];
315
333
  const result = await runZca(args, { profile: account.profile, timeout: 15000 });
316
334
  if (!result.ok) {
317
335
  throw new Error(result.stderr || "Failed to list peers");
@@ -331,9 +349,14 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
331
349
  },
332
350
  listGroups: async ({ cfg, accountId, query, limit }) => {
333
351
  const ok = await checkZcaInstalled();
334
- if (!ok) throw new Error("Missing dependency: `zca` not found in PATH");
335
- const account = resolveZalouserAccountSync({ cfg: cfg as OpenClawConfig, accountId });
336
- const result = await runZca(["group", "list", "-j"], { profile: account.profile, timeout: 15000 });
352
+ if (!ok) {
353
+ throw new Error("Missing dependency: `zca` not found in PATH");
354
+ }
355
+ const account = resolveZalouserAccountSync({ cfg: cfg, accountId });
356
+ const result = await runZca(["group", "list", "-j"], {
357
+ profile: account.profile,
358
+ timeout: 15000,
359
+ });
337
360
  if (!result.ok) {
338
361
  throw new Error(result.stderr || "Failed to list groups");
339
362
  }
@@ -355,8 +378,10 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
355
378
  },
356
379
  listGroupMembers: async ({ cfg, accountId, groupId, limit }) => {
357
380
  const ok = await checkZcaInstalled();
358
- if (!ok) throw new Error("Missing dependency: `zca` not found in PATH");
359
- const account = resolveZalouserAccountSync({ cfg: cfg as OpenClawConfig, accountId });
381
+ if (!ok) {
382
+ throw new Error("Missing dependency: `zca` not found in PATH");
383
+ }
384
+ const account = resolveZalouserAccountSync({ cfg: cfg, accountId });
360
385
  const result = await runZca(["group", "members", groupId, "-j"], {
361
386
  profile: account.profile,
362
387
  timeout: 20000,
@@ -364,12 +389,16 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
364
389
  if (!result.ok) {
365
390
  throw new Error(result.stderr || "Failed to list group members");
366
391
  }
367
- const parsed = parseJsonOutput<Array<Partial<ZcaFriend> & { userId?: string | number }>>(result.stdout);
392
+ const parsed = parseJsonOutput<Array<Partial<ZcaFriend> & { userId?: string | number }>>(
393
+ result.stdout,
394
+ );
368
395
  const rows = Array.isArray(parsed)
369
396
  ? parsed
370
397
  .map((m) => {
371
398
  const id = m.userId ?? (m as { id?: string | number }).id;
372
- if (!id) return null;
399
+ if (!id) {
400
+ return null;
401
+ }
373
402
  return mapUser({
374
403
  id: String(id),
375
404
  name: (m as { displayName?: string }).displayName ?? null,
@@ -398,7 +427,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
398
427
  }
399
428
  try {
400
429
  const account = resolveZalouserAccountSync({
401
- cfg: cfg as OpenClawConfig,
430
+ cfg: cfg,
402
431
  accountId: accountId ?? DEFAULT_ACCOUNT_ID,
403
432
  });
404
433
  const args =
@@ -408,7 +437,9 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
408
437
  : ["friend", "list", "-j"]
409
438
  : ["group", "list", "-j"];
410
439
  const result = await runZca(args, { profile: account.profile, timeout: 15000 });
411
- if (!result.ok) throw new Error(result.stderr || "zca lookup failed");
440
+ if (!result.ok) {
441
+ throw new Error(result.stderr || "zca lookup failed");
442
+ }
412
443
  if (kind === "user") {
413
444
  const parsed = parseJsonOutput<ZcaFriend[]>(result.stdout) ?? [];
414
445
  const matches = Array.isArray(parsed)
@@ -433,7 +464,8 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
433
464
  name: g.name ?? undefined,
434
465
  }))
435
466
  : [];
436
- const best = matches.find((g) => g.name?.toLowerCase() === trimmed.toLowerCase()) ?? matches[0];
467
+ const best =
468
+ matches.find((g) => g.name?.toLowerCase() === trimmed.toLowerCase()) ?? matches[0];
437
469
  results.push({
438
470
  input,
439
471
  resolved: Boolean(best?.id),
@@ -454,9 +486,11 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
454
486
  idLabel: "zalouserUserId",
455
487
  normalizeAllowEntry: (entry) => entry.replace(/^(zalouser|zlu):/i, ""),
456
488
  notifyApproval: async ({ cfg, id }) => {
457
- const account = resolveZalouserAccountSync({ cfg: cfg as OpenClawConfig });
489
+ const account = resolveZalouserAccountSync({ cfg: cfg });
458
490
  const authenticated = await checkZcaAuthenticated(account.profile);
459
- if (!authenticated) throw new Error("Zalouser not authenticated");
491
+ if (!authenticated) {
492
+ throw new Error("Zalouser not authenticated");
493
+ }
460
494
  await sendMessageZalouser(id, "Your pairing request has been approved.", {
461
495
  profile: account.profile,
462
496
  });
@@ -465,7 +499,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
465
499
  auth: {
466
500
  login: async ({ cfg, accountId, runtime }) => {
467
501
  const account = resolveZalouserAccountSync({
468
- cfg: cfg as OpenClawConfig,
502
+ cfg: cfg,
469
503
  accountId: accountId ?? DEFAULT_ACCOUNT_ID,
470
504
  });
471
505
  const ok = await checkZcaInstalled();
@@ -486,8 +520,12 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
486
520
  outbound: {
487
521
  deliveryMode: "direct",
488
522
  chunker: (text, limit) => {
489
- if (!text) return [];
490
- if (limit <= 0 || text.length <= limit) return [text];
523
+ if (!text) {
524
+ return [];
525
+ }
526
+ if (limit <= 0 || text.length <= limit) {
527
+ return [text];
528
+ }
491
529
  const chunks: string[] = [];
492
530
  let remaining = text;
493
531
  while (remaining.length > limit) {
@@ -495,21 +533,27 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
495
533
  const lastNewline = window.lastIndexOf("\n");
496
534
  const lastSpace = window.lastIndexOf(" ");
497
535
  let breakIdx = lastNewline > 0 ? lastNewline : lastSpace;
498
- if (breakIdx <= 0) breakIdx = limit;
536
+ if (breakIdx <= 0) {
537
+ breakIdx = limit;
538
+ }
499
539
  const rawChunk = remaining.slice(0, breakIdx);
500
540
  const chunk = rawChunk.trimEnd();
501
- if (chunk.length > 0) chunks.push(chunk);
541
+ if (chunk.length > 0) {
542
+ chunks.push(chunk);
543
+ }
502
544
  const brokeOnSeparator = breakIdx < remaining.length && /\s/.test(remaining[breakIdx]);
503
545
  const nextStart = Math.min(remaining.length, breakIdx + (brokeOnSeparator ? 1 : 0));
504
546
  remaining = remaining.slice(nextStart).trimStart();
505
547
  }
506
- if (remaining.length) chunks.push(remaining);
548
+ if (remaining.length) {
549
+ chunks.push(remaining);
550
+ }
507
551
  return chunks;
508
552
  },
509
553
  chunkerMode: "text",
510
554
  textChunkLimit: 2000,
511
555
  sendText: async ({ to, text, accountId, cfg }) => {
512
- const account = resolveZalouserAccountSync({ cfg: cfg as OpenClawConfig, accountId });
556
+ const account = resolveZalouserAccountSync({ cfg: cfg, accountId });
513
557
  const result = await sendMessageZalouser(to, text, { profile: account.profile });
514
558
  return {
515
559
  channel: "zalouser",
@@ -519,7 +563,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
519
563
  };
520
564
  },
521
565
  sendMedia: async ({ to, text, mediaUrl, accountId, cfg }) => {
522
- const account = resolveZalouserAccountSync({ cfg: cfg as OpenClawConfig, accountId });
566
+ const account = resolveZalouserAccountSync({ cfg: cfg, accountId });
523
567
  const result = await sendMessageZalouser(to, text, {
524
568
  profile: account.profile,
525
569
  mediaUrl,
@@ -550,8 +594,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
550
594
  probe: snapshot.probe,
551
595
  lastProbeAt: snapshot.lastProbeAt ?? null,
552
596
  }),
553
- probeAccount: async ({ account, timeoutMs }) =>
554
- probeZalouser(account.profile, timeoutMs),
597
+ probeAccount: async ({ account, timeoutMs }) => probeZalouser(account.profile, timeoutMs),
555
598
  buildAccountSnapshot: async ({ account, runtime }) => {
556
599
  const zcaInstalled = await checkZcaInstalled();
557
600
  const configured = zcaInstalled ? await checkZcaAuthenticated(account.profile) : false;
@@ -564,7 +607,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
564
607
  running: runtime?.running ?? false,
565
608
  lastStartAt: runtime?.lastStartAt ?? null,
566
609
  lastStopAt: runtime?.lastStopAt ?? null,
567
- lastError: configured ? (runtime?.lastError ?? null) : runtime?.lastError ?? configError,
610
+ lastError: configured ? (runtime?.lastError ?? null) : (runtime?.lastError ?? configError),
568
611
  lastInboundAt: runtime?.lastInboundAt ?? null,
569
612
  lastOutboundAt: runtime?.lastOutboundAt ?? null,
570
613
  dmPolicy: account.config.dmPolicy ?? "pairing",
@@ -577,7 +620,9 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
577
620
  let userLabel = "";
578
621
  try {
579
622
  const userInfo = await getZcaUserInfo(account.profile);
580
- if (userInfo?.displayName) userLabel = ` (${userInfo.displayName})`;
623
+ if (userInfo?.displayName) {
624
+ userLabel = ` (${userInfo.displayName})`;
625
+ }
581
626
  ctx.setStatus({
582
627
  accountId: account.accountId,
583
628
  user: userInfo,
@@ -589,7 +634,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
589
634
  const { monitorZalouserProvider } = await import("./monitor.js");
590
635
  return monitorZalouserProvider({
591
636
  account,
592
- config: ctx.cfg as OpenClawConfig,
637
+ config: ctx.cfg,
593
638
  runtime: ctx.runtime,
594
639
  abortSignal: ctx.abortSignal,
595
640
  statusSink: (patch) => ctx.setStatus({ accountId: ctx.accountId, ...patch }),
package/src/monitor.ts CHANGED
@@ -1,15 +1,9 @@
1
1
  import type { ChildProcess } from "node:child_process";
2
-
3
2
  import type { OpenClawConfig, MarkdownTableMode, RuntimeEnv } from "openclaw/plugin-sdk";
4
3
  import { mergeAllowlist, summarizeMapping } from "openclaw/plugin-sdk";
5
- import { sendMessageZalouser } from "./send.js";
6
- import type {
7
- ResolvedZalouserAccount,
8
- ZcaFriend,
9
- ZcaGroup,
10
- ZcaMessage,
11
- } from "./types.js";
4
+ import type { ResolvedZalouserAccount, ZcaFriend, ZcaGroup, ZcaMessage } from "./types.js";
12
5
  import { getZalouserRuntime } from "./runtime.js";
6
+ import { sendMessageZalouser } from "./send.js";
13
7
  import { parseJsonOutput, runZca, runZcaStreaming } from "./zca.js";
14
8
 
15
9
  export type ZalouserMonitorOptions = {
@@ -30,14 +24,13 @@ function normalizeZalouserEntry(entry: string): string {
30
24
  return entry.replace(/^(zalouser|zlu):/i, "").trim();
31
25
  }
32
26
 
33
- function buildNameIndex<T>(
34
- items: T[],
35
- nameFn: (item: T) => string | undefined,
36
- ): Map<string, T[]> {
27
+ function buildNameIndex<T>(items: T[], nameFn: (item: T) => string | undefined): Map<string, T[]> {
37
28
  const index = new Map<string, T[]>();
38
29
  for (const item of items) {
39
30
  const name = nameFn(item)?.trim().toLowerCase();
40
- if (!name) continue;
31
+ if (!name) {
32
+ continue;
33
+ }
41
34
  const list = index.get(name) ?? [];
42
35
  list.push(item);
43
36
  index.set(name, list);
@@ -54,7 +47,9 @@ function logVerbose(core: ZalouserCoreRuntime, runtime: RuntimeEnv, message: str
54
47
  }
55
48
 
56
49
  function isSenderAllowed(senderId: string, allowFrom: string[]): boolean {
57
- if (allowFrom.includes("*")) return true;
50
+ if (allowFrom.includes("*")) {
51
+ return true;
52
+ }
58
53
  const normalizedSenderId = senderId.toLowerCase();
59
54
  return allowFrom.some((entry) => {
60
55
  const normalized = entry.toLowerCase().replace(/^(zalouser|zlu):/i, "");
@@ -64,7 +59,9 @@ function isSenderAllowed(senderId: string, allowFrom: string[]): boolean {
64
59
 
65
60
  function normalizeGroupSlug(raw?: string | null): string {
66
61
  const trimmed = raw?.trim().toLowerCase() ?? "";
67
- if (!trimmed) return "";
62
+ if (!trimmed) {
63
+ return "";
64
+ }
68
65
  return trimmed
69
66
  .replace(/^#/, "")
70
67
  .replace(/[^a-z0-9]+/g, "-")
@@ -78,7 +75,9 @@ function isGroupAllowed(params: {
78
75
  }): boolean {
79
76
  const groups = params.groups ?? {};
80
77
  const keys = Object.keys(groups);
81
- if (keys.length === 0) return false;
78
+ if (keys.length === 0) {
79
+ return false;
80
+ }
82
81
  const candidates = [
83
82
  params.groupId,
84
83
  `group:${params.groupId}`,
@@ -87,11 +86,15 @@ function isGroupAllowed(params: {
87
86
  ].filter(Boolean);
88
87
  for (const candidate of candidates) {
89
88
  const entry = groups[candidate];
90
- if (!entry) continue;
89
+ if (!entry) {
90
+ continue;
91
+ }
91
92
  return entry.allow !== false && entry.enabled !== false;
92
93
  }
93
94
  const wildcard = groups["*"];
94
- if (wildcard) return wildcard.allow !== false && wildcard.enabled !== false;
95
+ if (wildcard) {
96
+ return wildcard.allow !== false && wildcard.enabled !== false;
97
+ }
95
98
  return false;
96
99
  }
97
100
 
@@ -112,7 +115,9 @@ function startZcaListener(
112
115
  buffer = lines.pop() ?? "";
113
116
  for (const line of lines) {
114
117
  const trimmed = line.trim();
115
- if (!trimmed) continue;
118
+ if (!trimmed) {
119
+ continue;
120
+ }
116
121
  try {
117
122
  const parsed = JSON.parse(trimmed) as ZcaMessage;
118
123
  onMessage(parsed);
@@ -126,7 +131,9 @@ function startZcaListener(
126
131
 
127
132
  proc.stderr?.on("data", (data: Buffer) => {
128
133
  const text = data.toString().trim();
129
- if (text) runtime.error(`[zalouser] zca stderr: ${text}`);
134
+ if (text) {
135
+ runtime.error(`[zalouser] zca stderr: ${text}`);
136
+ }
130
137
  });
131
138
 
132
139
  void promise.then((result) => {
@@ -155,7 +162,9 @@ async function processMessage(
155
162
  statusSink?: (patch: { lastInboundAt?: number; lastOutboundAt?: number }) => void,
156
163
  ): Promise<void> {
157
164
  const { threadId, content, timestamp, metadata } = message;
158
- if (!content?.trim()) return;
165
+ if (!content?.trim()) {
166
+ return;
167
+ }
159
168
 
160
169
  const isGroup = metadata?.isGroup ?? false;
161
170
  const senderId = metadata?.fromId ?? threadId;
@@ -183,10 +192,7 @@ async function processMessage(
183
192
  const dmPolicy = account.config.dmPolicy ?? "pairing";
184
193
  const configAllowFrom = (account.config.allowFrom ?? []).map((v) => String(v));
185
194
  const rawBody = content.trim();
186
- const shouldComputeAuth = core.channel.commands.shouldComputeCommandAuthorized(
187
- rawBody,
188
- config,
189
- );
195
+ const shouldComputeAuth = core.channel.commands.shouldComputeCommandAuthorized(rawBody, config);
190
196
  const storeAllowFrom =
191
197
  !isGroup && (dmPolicy !== "open" || shouldComputeAuth)
192
198
  ? await core.channel.pairing.readAllowFromStore("zalouser").catch(() => [])
@@ -197,7 +203,9 @@ async function processMessage(
197
203
  const commandAuthorized = shouldComputeAuth
198
204
  ? core.channel.commands.resolveCommandAuthorizedFromAuthorizers({
199
205
  useAccessGroups,
200
- authorizers: [{ configured: effectiveAllowFrom.length > 0, allowed: senderAllowedForCommands }],
206
+ authorizers: [
207
+ { configured: effectiveAllowFrom.length > 0, allowed: senderAllowedForCommands },
208
+ ],
201
209
  })
202
210
  : undefined;
203
211
 
@@ -256,11 +264,17 @@ async function processMessage(
256
264
  core.channel.commands.isControlCommandMessage(rawBody, config) &&
257
265
  commandAuthorized !== true
258
266
  ) {
259
- logVerbose(core, runtime, `zalouser: drop control command from unauthorized sender ${senderId}`);
267
+ logVerbose(
268
+ core,
269
+ runtime,
270
+ `zalouser: drop control command from unauthorized sender ${senderId}`,
271
+ );
260
272
  return;
261
273
  }
262
274
 
263
- const peer = isGroup ? { kind: "group" as const, id: chatId } : { kind: "group" as const, id: senderId };
275
+ const peer = isGroup
276
+ ? { kind: "group" as const, id: chatId }
277
+ : { kind: "group" as const, id: senderId };
264
278
 
265
279
  const route = core.channel.routing.resolveAgentRoute({
266
280
  cfg: config,
@@ -343,9 +357,7 @@ async function processMessage(
343
357
  });
344
358
  },
345
359
  onError: (err, info) => {
346
- runtime.error(
347
- `[${account.accountId}] Zalouser ${info.kind} reply failed: ${String(err)}`,
348
- );
360
+ runtime.error(`[${account.accountId}] Zalouser ${info.kind} reply failed: ${String(err)}`);
349
361
  },
350
362
  },
351
363
  });
@@ -481,7 +493,9 @@ export async function monitorZalouserProvider(
481
493
  for (const entry of groupKeys) {
482
494
  const cleaned = normalizeZalouserEntry(entry);
483
495
  if (/^\d+$/.test(cleaned)) {
484
- if (!nextGroups[cleaned]) nextGroups[cleaned] = groupsConfig[entry];
496
+ if (!nextGroups[cleaned]) {
497
+ nextGroups[cleaned] = groupsConfig[entry];
498
+ }
485
499
  mapping.push(`${entry}→${cleaned}`);
486
500
  continue;
487
501
  }
@@ -489,7 +503,9 @@ export async function monitorZalouserProvider(
489
503
  const match = matches[0];
490
504
  const id = match?.groupId ? String(match.groupId) : undefined;
491
505
  if (id) {
492
- if (!nextGroups[id]) nextGroups[id] = groupsConfig[entry];
506
+ if (!nextGroups[id]) {
507
+ nextGroups[id] = groupsConfig[entry];
508
+ }
493
509
  mapping.push(`${entry}→${id}`);
494
510
  } else {
495
511
  unresolved.push(entry);