@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/CHANGELOG.md +23 -0
- package/README.md +6 -2
- package/index.ts +1 -2
- package/openclaw.plugin.json +1 -3
- package/package.json +7 -4
- package/src/accounts.ts +38 -20
- package/src/channel.test.ts +3 -2
- package/src/channel.ts +107 -62
- package/src/monitor.ts +49 -33
- package/src/onboarding.ts +63 -47
- package/src/probe.ts +1 -1
- package/src/send.ts +15 -5
- package/src/status-issues.test.ts +0 -1
- package/src/status-issues.ts +12 -4
- package/src/tool.ts +29 -21
- package/src/types.ts +8 -2
- package/src/zca.ts +3 -9
package/src/onboarding.ts
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
promptAccountId,
|
|
12
12
|
promptChannelAccessConfig,
|
|
13
13
|
} from "openclaw/plugin-sdk";
|
|
14
|
-
|
|
14
|
+
import type { ZcaFriend, ZcaGroup } from "./types.js";
|
|
15
15
|
import {
|
|
16
16
|
listZalouserAccountIds,
|
|
17
17
|
resolveDefaultZalouserAccountId,
|
|
@@ -19,7 +19,6 @@ import {
|
|
|
19
19
|
checkZcaAuthenticated,
|
|
20
20
|
} from "./accounts.js";
|
|
21
21
|
import { runZca, runZcaInteractive, checkZcaInstalled, parseJsonOutput } from "./zca.js";
|
|
22
|
-
import type { ZcaFriend, ZcaGroup } from "./types.js";
|
|
23
22
|
|
|
24
23
|
const channel = "zalouser" as const;
|
|
25
24
|
|
|
@@ -28,9 +27,7 @@ function setZalouserDmPolicy(
|
|
|
28
27
|
dmPolicy: "pairing" | "allowlist" | "open" | "disabled",
|
|
29
28
|
): OpenClawConfig {
|
|
30
29
|
const allowFrom =
|
|
31
|
-
dmPolicy === "open"
|
|
32
|
-
? addWildcardAllowFrom(cfg.channels?.zalouser?.allowFrom)
|
|
33
|
-
: undefined;
|
|
30
|
+
dmPolicy === "open" ? addWildcardAllowFrom(cfg.channels?.zalouser?.allowFrom) : undefined;
|
|
34
31
|
return {
|
|
35
32
|
...cfg,
|
|
36
33
|
channels: {
|
|
@@ -75,19 +72,29 @@ async function promptZalouserAllowFrom(params: {
|
|
|
75
72
|
|
|
76
73
|
const resolveUserId = async (input: string): Promise<string | null> => {
|
|
77
74
|
const trimmed = input.trim();
|
|
78
|
-
if (!trimmed)
|
|
79
|
-
|
|
75
|
+
if (!trimmed) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
if (/^\d+$/.test(trimmed)) {
|
|
79
|
+
return trimmed;
|
|
80
|
+
}
|
|
80
81
|
const ok = await checkZcaInstalled();
|
|
81
|
-
if (!ok)
|
|
82
|
+
if (!ok) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
82
85
|
const result = await runZca(["friend", "find", trimmed], {
|
|
83
86
|
profile: resolved.profile,
|
|
84
87
|
timeout: 15000,
|
|
85
88
|
});
|
|
86
|
-
if (!result.ok)
|
|
89
|
+
if (!result.ok) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
87
92
|
const parsed = parseJsonOutput<ZcaFriend[]>(result.stdout);
|
|
88
93
|
const rows = Array.isArray(parsed) ? parsed : [];
|
|
89
94
|
const match = rows[0];
|
|
90
|
-
if (!match?.userId)
|
|
95
|
+
if (!match?.userId) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
91
98
|
if (rows.length > 1) {
|
|
92
99
|
await prompter.note(
|
|
93
100
|
`Multiple matches for "${trimmed}", using ${match.displayName ?? match.userId}.`,
|
|
@@ -142,9 +149,9 @@ async function promptZalouserAllowFrom(params: {
|
|
|
142
149
|
...cfg.channels?.zalouser,
|
|
143
150
|
enabled: true,
|
|
144
151
|
accounts: {
|
|
145
|
-
...
|
|
152
|
+
...cfg.channels?.zalouser?.accounts,
|
|
146
153
|
[accountId]: {
|
|
147
|
-
...
|
|
154
|
+
...cfg.channels?.zalouser?.accounts?.[accountId],
|
|
148
155
|
enabled: cfg.channels?.zalouser?.accounts?.[accountId]?.enabled ?? true,
|
|
149
156
|
dmPolicy: "allowlist",
|
|
150
157
|
allowFrom: unique,
|
|
@@ -182,9 +189,9 @@ function setZalouserGroupPolicy(
|
|
|
182
189
|
...cfg.channels?.zalouser,
|
|
183
190
|
enabled: true,
|
|
184
191
|
accounts: {
|
|
185
|
-
...
|
|
192
|
+
...cfg.channels?.zalouser?.accounts,
|
|
186
193
|
[accountId]: {
|
|
187
|
-
...
|
|
194
|
+
...cfg.channels?.zalouser?.accounts?.[accountId],
|
|
188
195
|
enabled: cfg.channels?.zalouser?.accounts?.[accountId]?.enabled ?? true,
|
|
189
196
|
groupPolicy,
|
|
190
197
|
},
|
|
@@ -221,9 +228,9 @@ function setZalouserGroupAllowlist(
|
|
|
221
228
|
...cfg.channels?.zalouser,
|
|
222
229
|
enabled: true,
|
|
223
230
|
accounts: {
|
|
224
|
-
...
|
|
231
|
+
...cfg.channels?.zalouser?.accounts,
|
|
225
232
|
[accountId]: {
|
|
226
|
-
...
|
|
233
|
+
...cfg.channels?.zalouser?.accounts?.[accountId],
|
|
227
234
|
enabled: cfg.channels?.zalouser?.accounts?.[accountId]?.enabled ?? true,
|
|
228
235
|
groups,
|
|
229
236
|
},
|
|
@@ -239,15 +246,22 @@ async function resolveZalouserGroups(params: {
|
|
|
239
246
|
entries: string[];
|
|
240
247
|
}): Promise<Array<{ input: string; resolved: boolean; id?: string }>> {
|
|
241
248
|
const account = resolveZalouserAccountSync({ cfg: params.cfg, accountId: params.accountId });
|
|
242
|
-
const result = await runZca(["group", "list", "-j"], {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
249
|
+
const result = await runZca(["group", "list", "-j"], {
|
|
250
|
+
profile: account.profile,
|
|
251
|
+
timeout: 15000,
|
|
252
|
+
});
|
|
253
|
+
if (!result.ok) {
|
|
254
|
+
throw new Error(result.stderr || "Failed to list groups");
|
|
255
|
+
}
|
|
256
|
+
const groups = (parseJsonOutput<ZcaGroup[]>(result.stdout) ?? []).filter((group) =>
|
|
257
|
+
Boolean(group.groupId),
|
|
246
258
|
);
|
|
247
259
|
const byName = new Map<string, ZcaGroup[]>();
|
|
248
260
|
for (const group of groups) {
|
|
249
261
|
const name = group.name?.trim().toLowerCase();
|
|
250
|
-
if (!name)
|
|
262
|
+
if (!name) {
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
251
265
|
const list = byName.get(name) ?? [];
|
|
252
266
|
list.push(group);
|
|
253
267
|
byName.set(name, list);
|
|
@@ -255,8 +269,12 @@ async function resolveZalouserGroups(params: {
|
|
|
255
269
|
|
|
256
270
|
return params.entries.map((input) => {
|
|
257
271
|
const trimmed = input.trim();
|
|
258
|
-
if (!trimmed)
|
|
259
|
-
|
|
272
|
+
if (!trimmed) {
|
|
273
|
+
return { input, resolved: false };
|
|
274
|
+
}
|
|
275
|
+
if (/^\d+$/.test(trimmed)) {
|
|
276
|
+
return { input, resolved: true, id: trimmed };
|
|
277
|
+
}
|
|
260
278
|
const matches = byName.get(trimmed.toLowerCase()) ?? [];
|
|
261
279
|
const match = matches[0];
|
|
262
280
|
return match?.groupId
|
|
@@ -270,15 +288,15 @@ const dmPolicy: ChannelOnboardingDmPolicy = {
|
|
|
270
288
|
channel,
|
|
271
289
|
policyKey: "channels.zalouser.dmPolicy",
|
|
272
290
|
allowFromKey: "channels.zalouser.allowFrom",
|
|
273
|
-
getCurrent: (cfg) => (
|
|
274
|
-
setPolicy: (cfg, policy) => setZalouserDmPolicy(cfg
|
|
291
|
+
getCurrent: (cfg) => (cfg.channels?.zalouser?.dmPolicy ?? "pairing") as "pairing",
|
|
292
|
+
setPolicy: (cfg, policy) => setZalouserDmPolicy(cfg, policy),
|
|
275
293
|
promptAllowFrom: async ({ cfg, prompter, accountId }) => {
|
|
276
294
|
const id =
|
|
277
295
|
accountId && normalizeAccountId(accountId)
|
|
278
|
-
? normalizeAccountId(accountId) ?? DEFAULT_ACCOUNT_ID
|
|
279
|
-
: resolveDefaultZalouserAccountId(cfg
|
|
296
|
+
? (normalizeAccountId(accountId) ?? DEFAULT_ACCOUNT_ID)
|
|
297
|
+
: resolveDefaultZalouserAccountId(cfg);
|
|
280
298
|
return promptZalouserAllowFrom({
|
|
281
|
-
cfg: cfg
|
|
299
|
+
cfg: cfg,
|
|
282
300
|
prompter,
|
|
283
301
|
accountId: id,
|
|
284
302
|
});
|
|
@@ -289,10 +307,10 @@ export const zalouserOnboardingAdapter: ChannelOnboardingAdapter = {
|
|
|
289
307
|
channel,
|
|
290
308
|
dmPolicy,
|
|
291
309
|
getStatus: async ({ cfg }) => {
|
|
292
|
-
const ids = listZalouserAccountIds(cfg
|
|
310
|
+
const ids = listZalouserAccountIds(cfg);
|
|
293
311
|
let configured = false;
|
|
294
312
|
for (const accountId of ids) {
|
|
295
|
-
const account = resolveZalouserAccountSync({ cfg: cfg
|
|
313
|
+
const account = resolveZalouserAccountSync({ cfg: cfg, accountId });
|
|
296
314
|
const isAuth = await checkZcaAuthenticated(account.profile);
|
|
297
315
|
if (isAuth) {
|
|
298
316
|
configured = true;
|
|
@@ -307,7 +325,13 @@ export const zalouserOnboardingAdapter: ChannelOnboardingAdapter = {
|
|
|
307
325
|
quickstartScore: configured ? 1 : 15,
|
|
308
326
|
};
|
|
309
327
|
},
|
|
310
|
-
configure: async ({
|
|
328
|
+
configure: async ({
|
|
329
|
+
cfg,
|
|
330
|
+
prompter,
|
|
331
|
+
accountOverrides,
|
|
332
|
+
shouldPromptAccountIds,
|
|
333
|
+
forceAllowFrom,
|
|
334
|
+
}) => {
|
|
311
335
|
// Check zca is installed
|
|
312
336
|
const zcaInstalled = await checkZcaInstalled();
|
|
313
337
|
if (!zcaInstalled) {
|
|
@@ -324,14 +348,12 @@ export const zalouserOnboardingAdapter: ChannelOnboardingAdapter = {
|
|
|
324
348
|
}
|
|
325
349
|
|
|
326
350
|
const zalouserOverride = accountOverrides.zalouser?.trim();
|
|
327
|
-
const defaultAccountId = resolveDefaultZalouserAccountId(cfg
|
|
328
|
-
let accountId = zalouserOverride
|
|
329
|
-
? normalizeAccountId(zalouserOverride)
|
|
330
|
-
: defaultAccountId;
|
|
351
|
+
const defaultAccountId = resolveDefaultZalouserAccountId(cfg);
|
|
352
|
+
let accountId = zalouserOverride ? normalizeAccountId(zalouserOverride) : defaultAccountId;
|
|
331
353
|
|
|
332
354
|
if (shouldPromptAccountIds && !zalouserOverride) {
|
|
333
355
|
accountId = await promptAccountId({
|
|
334
|
-
cfg: cfg
|
|
356
|
+
cfg: cfg,
|
|
335
357
|
prompter,
|
|
336
358
|
label: "Zalo Personal",
|
|
337
359
|
currentId: accountId,
|
|
@@ -340,7 +362,7 @@ export const zalouserOnboardingAdapter: ChannelOnboardingAdapter = {
|
|
|
340
362
|
});
|
|
341
363
|
}
|
|
342
364
|
|
|
343
|
-
let next = cfg
|
|
365
|
+
let next = cfg;
|
|
344
366
|
const account = resolveZalouserAccountSync({ cfg: next, accountId });
|
|
345
367
|
const alreadyAuthenticated = await checkZcaAuthenticated(account.profile);
|
|
346
368
|
|
|
@@ -364,10 +386,7 @@ export const zalouserOnboardingAdapter: ChannelOnboardingAdapter = {
|
|
|
364
386
|
});
|
|
365
387
|
|
|
366
388
|
if (!result.ok) {
|
|
367
|
-
await prompter.note(
|
|
368
|
-
`Login failed: ${result.stderr || "Unknown error"}`,
|
|
369
|
-
"Error",
|
|
370
|
-
);
|
|
389
|
+
await prompter.note(`Login failed: ${result.stderr || "Unknown error"}`, "Error");
|
|
371
390
|
} else {
|
|
372
391
|
const isNowAuth = await checkZcaAuthenticated(account.profile);
|
|
373
392
|
if (isNowAuth) {
|
|
@@ -408,9 +427,9 @@ export const zalouserOnboardingAdapter: ChannelOnboardingAdapter = {
|
|
|
408
427
|
...next.channels?.zalouser,
|
|
409
428
|
enabled: true,
|
|
410
429
|
accounts: {
|
|
411
|
-
...
|
|
430
|
+
...next.channels?.zalouser?.accounts,
|
|
412
431
|
[accountId]: {
|
|
413
|
-
...
|
|
432
|
+
...next.channels?.zalouser?.accounts?.[accountId],
|
|
414
433
|
enabled: true,
|
|
415
434
|
profile: account.profile,
|
|
416
435
|
},
|
|
@@ -454,10 +473,7 @@ export const zalouserOnboardingAdapter: ChannelOnboardingAdapter = {
|
|
|
454
473
|
const unresolved = resolved
|
|
455
474
|
.filter((entry) => !entry.resolved)
|
|
456
475
|
.map((entry) => entry.input);
|
|
457
|
-
keys = [
|
|
458
|
-
...resolvedIds,
|
|
459
|
-
...unresolved.map((entry) => entry.trim()).filter(Boolean),
|
|
460
|
-
];
|
|
476
|
+
keys = [...resolvedIds, ...unresolved.map((entry) => entry.trim()).filter(Boolean)];
|
|
461
477
|
if (resolvedIds.length > 0 || unresolved.length > 0) {
|
|
462
478
|
await prompter.note(
|
|
463
479
|
[
|
package/src/probe.ts
CHANGED
package/src/send.ts
CHANGED
|
@@ -34,7 +34,9 @@ export async function sendMessageZalouser(
|
|
|
34
34
|
|
|
35
35
|
// Send text message
|
|
36
36
|
const args = ["msg", "send", threadId.trim(), text.slice(0, 2000)];
|
|
37
|
-
if (options.isGroup)
|
|
37
|
+
if (options.isGroup) {
|
|
38
|
+
args.push("-g");
|
|
39
|
+
}
|
|
38
40
|
|
|
39
41
|
try {
|
|
40
42
|
const result = await runZca(args, { profile });
|
|
@@ -79,7 +81,9 @@ async function sendMediaZalouser(
|
|
|
79
81
|
if (options.caption) {
|
|
80
82
|
args.push("-m", options.caption.slice(0, 2000));
|
|
81
83
|
}
|
|
82
|
-
if (options.isGroup)
|
|
84
|
+
if (options.isGroup) {
|
|
85
|
+
args.push("-g");
|
|
86
|
+
}
|
|
83
87
|
|
|
84
88
|
try {
|
|
85
89
|
const result = await runZca(args, { profile });
|
|
@@ -104,7 +108,9 @@ export async function sendImageZalouser(
|
|
|
104
108
|
if (options.caption) {
|
|
105
109
|
args.push("-m", options.caption.slice(0, 2000));
|
|
106
110
|
}
|
|
107
|
-
if (options.isGroup)
|
|
111
|
+
if (options.isGroup) {
|
|
112
|
+
args.push("-g");
|
|
113
|
+
}
|
|
108
114
|
|
|
109
115
|
try {
|
|
110
116
|
const result = await runZca(args, { profile });
|
|
@@ -124,7 +130,9 @@ export async function sendLinkZalouser(
|
|
|
124
130
|
): Promise<ZalouserSendResult> {
|
|
125
131
|
const profile = options.profile || process.env.ZCA_PROFILE || "default";
|
|
126
132
|
const args = ["msg", "link", threadId.trim(), url.trim()];
|
|
127
|
-
if (options.isGroup)
|
|
133
|
+
if (options.isGroup) {
|
|
134
|
+
args.push("-g");
|
|
135
|
+
}
|
|
128
136
|
|
|
129
137
|
try {
|
|
130
138
|
const result = await runZca(args, { profile });
|
|
@@ -140,7 +148,9 @@ export async function sendLinkZalouser(
|
|
|
140
148
|
function extractMessageId(stdout: string): string | undefined {
|
|
141
149
|
// Try to extract message ID from output
|
|
142
150
|
const match = stdout.match(/message[_\s]?id[:\s]+(\S+)/i);
|
|
143
|
-
if (match)
|
|
151
|
+
if (match) {
|
|
152
|
+
return match[1];
|
|
153
|
+
}
|
|
144
154
|
// Return first word if it looks like an ID
|
|
145
155
|
const firstWord = stdout.trim().split(/\s+/)[0];
|
|
146
156
|
if (firstWord && /^[a-zA-Z0-9_-]+$/.test(firstWord)) {
|
package/src/status-issues.ts
CHANGED
|
@@ -15,7 +15,9 @@ const asString = (value: unknown): string | undefined =>
|
|
|
15
15
|
typeof value === "string" ? value : typeof value === "number" ? String(value) : undefined;
|
|
16
16
|
|
|
17
17
|
function readZalouserAccountStatus(value: ChannelAccountSnapshot): ZalouserAccountStatus | null {
|
|
18
|
-
if (!isRecord(value))
|
|
18
|
+
if (!isRecord(value)) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
19
21
|
return {
|
|
20
22
|
accountId: value.accountId,
|
|
21
23
|
enabled: value.enabled,
|
|
@@ -26,7 +28,9 @@ function readZalouserAccountStatus(value: ChannelAccountSnapshot): ZalouserAccou
|
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
function isMissingZca(lastError?: string): boolean {
|
|
29
|
-
if (!lastError)
|
|
31
|
+
if (!lastError) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
30
34
|
const lower = lastError.toLowerCase();
|
|
31
35
|
return lower.includes("zca") && (lower.includes("not found") || lower.includes("enoent"));
|
|
32
36
|
}
|
|
@@ -37,10 +41,14 @@ export function collectZalouserStatusIssues(
|
|
|
37
41
|
const issues: ChannelStatusIssue[] = [];
|
|
38
42
|
for (const entry of accounts) {
|
|
39
43
|
const account = readZalouserAccountStatus(entry);
|
|
40
|
-
if (!account)
|
|
44
|
+
if (!account) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
41
47
|
const accountId = asString(account.accountId) ?? "default";
|
|
42
48
|
const enabled = account.enabled !== false;
|
|
43
|
-
if (!enabled)
|
|
49
|
+
if (!enabled) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
44
52
|
|
|
45
53
|
const configured = account.configured === true;
|
|
46
54
|
const lastError = asString(account.lastError)?.trim();
|
package/src/tool.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
-
|
|
3
2
|
import { runZca, parseJsonOutput } from "./zca.js";
|
|
4
3
|
|
|
5
4
|
const ACTIONS = ["send", "image", "link", "friends", "groups", "me", "status"] as const;
|
|
@@ -16,17 +15,18 @@ function stringEnum<T extends readonly string[]>(
|
|
|
16
15
|
}
|
|
17
16
|
|
|
18
17
|
// Tool schema - avoiding Type.Union per tool schema guardrails
|
|
19
|
-
export const ZalouserToolSchema = Type.Object(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
Type.String({ description: "Thread ID for messaging" }),
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
18
|
+
export const ZalouserToolSchema = Type.Object(
|
|
19
|
+
{
|
|
20
|
+
action: stringEnum(ACTIONS, { description: `Action to perform: ${ACTIONS.join(", ")}` }),
|
|
21
|
+
threadId: Type.Optional(Type.String({ description: "Thread ID for messaging" })),
|
|
22
|
+
message: Type.Optional(Type.String({ description: "Message text" })),
|
|
23
|
+
isGroup: Type.Optional(Type.Boolean({ description: "Is group chat" })),
|
|
24
|
+
profile: Type.Optional(Type.String({ description: "Profile name" })),
|
|
25
|
+
query: Type.Optional(Type.String({ description: "Search query" })),
|
|
26
|
+
url: Type.Optional(Type.String({ description: "URL for media/link" })),
|
|
27
|
+
},
|
|
28
|
+
{ additionalProperties: false },
|
|
29
|
+
);
|
|
30
30
|
|
|
31
31
|
type ToolParams = {
|
|
32
32
|
action: (typeof ACTIONS)[number];
|
|
@@ -61,7 +61,9 @@ export async function executeZalouserTool(
|
|
|
61
61
|
throw new Error("threadId and message required for send action");
|
|
62
62
|
}
|
|
63
63
|
const args = ["msg", "send", params.threadId, params.message];
|
|
64
|
-
if (params.isGroup)
|
|
64
|
+
if (params.isGroup) {
|
|
65
|
+
args.push("-g");
|
|
66
|
+
}
|
|
65
67
|
const result = await runZca(args, { profile: params.profile });
|
|
66
68
|
if (!result.ok) {
|
|
67
69
|
throw new Error(result.stderr || "Failed to send message");
|
|
@@ -77,8 +79,12 @@ export async function executeZalouserTool(
|
|
|
77
79
|
throw new Error("url required for image action");
|
|
78
80
|
}
|
|
79
81
|
const args = ["msg", "image", params.threadId, "-u", params.url];
|
|
80
|
-
if (params.message)
|
|
81
|
-
|
|
82
|
+
if (params.message) {
|
|
83
|
+
args.push("-m", params.message);
|
|
84
|
+
}
|
|
85
|
+
if (params.isGroup) {
|
|
86
|
+
args.push("-g");
|
|
87
|
+
}
|
|
82
88
|
const result = await runZca(args, { profile: params.profile });
|
|
83
89
|
if (!result.ok) {
|
|
84
90
|
throw new Error(result.stderr || "Failed to send image");
|
|
@@ -91,7 +97,9 @@ export async function executeZalouserTool(
|
|
|
91
97
|
throw new Error("threadId and url required for link action");
|
|
92
98
|
}
|
|
93
99
|
const args = ["msg", "link", params.threadId, params.url];
|
|
94
|
-
if (params.isGroup)
|
|
100
|
+
if (params.isGroup) {
|
|
101
|
+
args.push("-g");
|
|
102
|
+
}
|
|
95
103
|
const result = await runZca(args, { profile: params.profile });
|
|
96
104
|
if (!result.ok) {
|
|
97
105
|
throw new Error(result.stderr || "Failed to send link");
|
|
@@ -100,9 +108,7 @@ export async function executeZalouserTool(
|
|
|
100
108
|
}
|
|
101
109
|
|
|
102
110
|
case "friends": {
|
|
103
|
-
const args = params.query
|
|
104
|
-
? ["friend", "find", params.query]
|
|
105
|
-
: ["friend", "list", "-j"];
|
|
111
|
+
const args = params.query ? ["friend", "find", params.query] : ["friend", "list", "-j"];
|
|
106
112
|
const result = await runZca(args, { profile: params.profile });
|
|
107
113
|
if (!result.ok) {
|
|
108
114
|
throw new Error(result.stderr || "Failed to get friends");
|
|
@@ -143,10 +149,12 @@ export async function executeZalouserTool(
|
|
|
143
149
|
});
|
|
144
150
|
}
|
|
145
151
|
|
|
146
|
-
default:
|
|
152
|
+
default: {
|
|
153
|
+
params.action satisfies never;
|
|
147
154
|
throw new Error(
|
|
148
|
-
`Unknown action: ${params.action}. Valid actions: send, image, link, friends, groups, me, status`,
|
|
155
|
+
`Unknown action: ${String(params.action)}. Valid actions: send, image, link, friends, groups, me, status`,
|
|
149
156
|
);
|
|
157
|
+
}
|
|
150
158
|
}
|
|
151
159
|
} catch (err) {
|
|
152
160
|
return json({
|
package/src/types.ts
CHANGED
|
@@ -75,7 +75,10 @@ export type ZalouserAccountConfig = {
|
|
|
75
75
|
dmPolicy?: "pairing" | "allowlist" | "open" | "disabled";
|
|
76
76
|
allowFrom?: Array<string | number>;
|
|
77
77
|
groupPolicy?: "open" | "allowlist" | "disabled";
|
|
78
|
-
groups?: Record<
|
|
78
|
+
groups?: Record<
|
|
79
|
+
string,
|
|
80
|
+
{ allow?: boolean; enabled?: boolean; tools?: { allow?: string[]; deny?: string[] } }
|
|
81
|
+
>;
|
|
79
82
|
messagePrefix?: string;
|
|
80
83
|
};
|
|
81
84
|
|
|
@@ -87,7 +90,10 @@ export type ZalouserConfig = {
|
|
|
87
90
|
dmPolicy?: "pairing" | "allowlist" | "open" | "disabled";
|
|
88
91
|
allowFrom?: Array<string | number>;
|
|
89
92
|
groupPolicy?: "open" | "allowlist" | "disabled";
|
|
90
|
-
groups?: Record<
|
|
93
|
+
groups?: Record<
|
|
94
|
+
string,
|
|
95
|
+
{ allow?: boolean; enabled?: boolean; tools?: { allow?: string[]; deny?: string[] } }
|
|
96
|
+
>;
|
|
91
97
|
messagePrefix?: string;
|
|
92
98
|
accounts?: Record<string, ZalouserAccountConfig>;
|
|
93
99
|
};
|
package/src/zca.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { spawn, type SpawnOptions } from "node:child_process";
|
|
2
|
-
|
|
3
2
|
import type { ZcaResult, ZcaRunOptions } from "./types.js";
|
|
4
3
|
|
|
5
4
|
const ZCA_BINARY = "zca";
|
|
@@ -16,10 +15,7 @@ function buildArgs(args: string[], options?: ZcaRunOptions): string[] {
|
|
|
16
15
|
return result;
|
|
17
16
|
}
|
|
18
17
|
|
|
19
|
-
export async function runZca(
|
|
20
|
-
args: string[],
|
|
21
|
-
options?: ZcaRunOptions,
|
|
22
|
-
): Promise<ZcaResult> {
|
|
18
|
+
export async function runZca(args: string[], options?: ZcaRunOptions): Promise<ZcaResult> {
|
|
23
19
|
const fullArgs = buildArgs(args, options);
|
|
24
20
|
const timeout = options?.timeout ?? DEFAULT_TIMEOUT;
|
|
25
21
|
|
|
@@ -79,10 +75,7 @@ export async function runZca(
|
|
|
79
75
|
});
|
|
80
76
|
}
|
|
81
77
|
|
|
82
|
-
export function runZcaInteractive(
|
|
83
|
-
args: string[],
|
|
84
|
-
options?: ZcaRunOptions,
|
|
85
|
-
): Promise<ZcaResult> {
|
|
78
|
+
export function runZcaInteractive(args: string[], options?: ZcaRunOptions): Promise<ZcaResult> {
|
|
86
79
|
const fullArgs = buildArgs(args, options);
|
|
87
80
|
|
|
88
81
|
return new Promise((resolve) => {
|
|
@@ -115,6 +108,7 @@ export function runZcaInteractive(
|
|
|
115
108
|
}
|
|
116
109
|
|
|
117
110
|
function stripAnsi(str: string): string {
|
|
111
|
+
// oxlint-disable-next-line no-control-regex
|
|
118
112
|
return str.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "");
|
|
119
113
|
}
|
|
120
114
|
|