@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 CHANGED
@@ -1,28 +1,51 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026.2.2
4
+
5
+ ### Changes
6
+
7
+ - Version alignment with core OpenClaw release numbers.
8
+
9
+ ## 2026.1.31
10
+
11
+ ### Changes
12
+
13
+ - Version alignment with core OpenClaw release numbers.
14
+
15
+ ## 2026.1.30
16
+
17
+ ### Changes
18
+
19
+ - Version alignment with core OpenClaw release numbers.
20
+
3
21
  ## 2026.1.29
4
22
 
5
23
  ### Changes
24
+
6
25
  - Version alignment with core OpenClaw release numbers.
7
26
 
8
27
  ## 2026.1.23
9
28
 
10
29
  ### Changes
30
+
11
31
  - Version alignment with core OpenClaw release numbers.
12
32
 
13
33
  ## 2026.1.22
14
34
 
15
35
  ### Changes
36
+
16
37
  - Version alignment with core OpenClaw release numbers.
17
38
 
18
39
  ## 2026.1.21
19
40
 
20
41
  ### Changes
42
+
21
43
  - Version alignment with core OpenClaw release numbers.
22
44
 
23
45
  ## 2026.1.20
24
46
 
25
47
  ### Changes
48
+
26
49
  - Version alignment with core OpenClaw release numbers.
27
50
 
28
51
  ## 2026.1.17-1
package/README.md CHANGED
@@ -16,8 +16,8 @@ OpenClaw extension for Zalo Personal Account messaging via [zca-cli](https://zca
16
16
 
17
17
  Install `zca` CLI and ensure it's in your PATH:
18
18
 
19
-
20
19
  **macOS / Linux:**
20
+
21
21
  ```bash
22
22
  curl -fsSL https://get.zca-cli.dev/install.sh | bash
23
23
 
@@ -32,6 +32,7 @@ curl -fsSL https://get.zca-cli.dev/install.sh | bash -s uninstall
32
32
  ```
33
33
 
34
34
  **Windows (PowerShell):**
35
+
35
36
  ```powershell
36
37
  irm https://get.zca-cli.dev/install.ps1 | iex
37
38
 
@@ -50,16 +51,19 @@ iex "& { $(irm https://get.zca-cli.dev/install.ps1) } -Uninstall"
50
51
  Download binary directly:
51
52
 
52
53
  **macOS / Linux:**
54
+
53
55
  ```bash
54
56
  curl -fsSL https://get.zca-cli.dev/latest/zca-darwin-arm64 -o zca && chmod +x zca
55
57
  ```
56
58
 
57
59
  **Windows (PowerShell):**
60
+
58
61
  ```powershell
59
62
  Invoke-WebRequest -Uri https://get.zca-cli.dev/latest/zca-windows-x64.exe -OutFile zca.exe
60
63
  ```
61
64
 
62
65
  Available binaries:
66
+
63
67
  - `zca-darwin-arm64` - macOS Apple Silicon
64
68
  - `zca-darwin-x64` - macOS Intel
65
69
  - `zca-linux-arm64` - Linux ARM64
@@ -99,7 +103,7 @@ After onboarding, your config will include:
99
103
  channels:
100
104
  zalouser:
101
105
  enabled: true
102
- dmPolicy: pairing # pairing | allowlist | open | disabled
106
+ dmPolicy: pairing # pairing | allowlist | open | disabled
103
107
  ```
104
108
 
105
109
  For multi-account:
package/index.ts CHANGED
@@ -1,9 +1,8 @@
1
1
  import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
2
2
  import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
3
-
4
3
  import { zalouserDock, zalouserPlugin } from "./src/channel.js";
5
- import { ZalouserToolSchema, executeZalouserTool } from "./src/tool.js";
6
4
  import { setZalouserRuntime } from "./src/runtime.js";
5
+ import { ZalouserToolSchema, executeZalouserTool } from "./src/tool.js";
7
6
 
8
7
  const plugin = {
9
8
  id: "zalouser",
@@ -1,8 +1,6 @@
1
1
  {
2
2
  "id": "zalouser",
3
- "channels": [
4
- "zalouser"
5
- ],
3
+ "channels": ["zalouser"],
6
4
  "configSchema": {
7
5
  "type": "object",
8
6
  "additionalProperties": false,
package/package.json CHANGED
@@ -1,11 +1,14 @@
1
1
  {
2
2
  "name": "@openclaw/zalouser",
3
- "version": "2026.1.29",
4
- "type": "module",
3
+ "version": "2026.2.2",
5
4
  "description": "OpenClaw Zalo Personal Account plugin via zca-cli",
5
+ "type": "module",
6
6
  "dependencies": {
7
- "openclaw": "workspace:*",
8
- "@sinclair/typebox": "0.34.47"
7
+ "@sinclair/typebox": "0.34.48",
8
+ "openclaw": "workspace:*"
9
+ },
10
+ "devDependencies": {
11
+ "openclaw": "workspace:*"
9
12
  },
10
13
  "openclaw": {
11
14
  "extensions": [
package/src/accounts.ts CHANGED
@@ -1,26 +1,33 @@
1
1
  import type { OpenClawConfig } from "openclaw/plugin-sdk";
2
2
  import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk";
3
-
4
- import { runZca, parseJsonOutput } from "./zca.js";
5
3
  import type { ResolvedZalouserAccount, ZalouserAccountConfig, ZalouserConfig } from "./types.js";
4
+ import { runZca, parseJsonOutput } from "./zca.js";
6
5
 
7
6
  function listConfiguredAccountIds(cfg: OpenClawConfig): string[] {
8
7
  const accounts = (cfg.channels?.zalouser as ZalouserConfig | undefined)?.accounts;
9
- if (!accounts || typeof accounts !== "object") return [];
8
+ if (!accounts || typeof accounts !== "object") {
9
+ return [];
10
+ }
10
11
  return Object.keys(accounts).filter(Boolean);
11
12
  }
12
13
 
13
14
  export function listZalouserAccountIds(cfg: OpenClawConfig): string[] {
14
15
  const ids = listConfiguredAccountIds(cfg);
15
- if (ids.length === 0) return [DEFAULT_ACCOUNT_ID];
16
- return ids.sort((a, b) => a.localeCompare(b));
16
+ if (ids.length === 0) {
17
+ return [DEFAULT_ACCOUNT_ID];
18
+ }
19
+ return ids.toSorted((a, b) => a.localeCompare(b));
17
20
  }
18
21
 
19
22
  export function resolveDefaultZalouserAccountId(cfg: OpenClawConfig): string {
20
23
  const zalouserConfig = cfg.channels?.zalouser as ZalouserConfig | undefined;
21
- if (zalouserConfig?.defaultAccount?.trim()) return zalouserConfig.defaultAccount.trim();
24
+ if (zalouserConfig?.defaultAccount?.trim()) {
25
+ return zalouserConfig.defaultAccount.trim();
26
+ }
22
27
  const ids = listZalouserAccountIds(cfg);
23
- if (ids.includes(DEFAULT_ACCOUNT_ID)) return DEFAULT_ACCOUNT_ID;
28
+ if (ids.includes(DEFAULT_ACCOUNT_ID)) {
29
+ return DEFAULT_ACCOUNT_ID;
30
+ }
24
31
  return ids[0] ?? DEFAULT_ACCOUNT_ID;
25
32
  }
26
33
 
@@ -29,14 +36,13 @@ function resolveAccountConfig(
29
36
  accountId: string,
30
37
  ): ZalouserAccountConfig | undefined {
31
38
  const accounts = (cfg.channels?.zalouser as ZalouserConfig | undefined)?.accounts;
32
- if (!accounts || typeof accounts !== "object") return undefined;
39
+ if (!accounts || typeof accounts !== "object") {
40
+ return undefined;
41
+ }
33
42
  return accounts[accountId] as ZalouserAccountConfig | undefined;
34
43
  }
35
44
 
36
- function mergeZalouserAccountConfig(
37
- cfg: OpenClawConfig,
38
- accountId: string,
39
- ): ZalouserAccountConfig {
45
+ function mergeZalouserAccountConfig(cfg: OpenClawConfig, accountId: string): ZalouserAccountConfig {
40
46
  const raw = (cfg.channels?.zalouser ?? {}) as ZalouserConfig;
41
47
  const { accounts: _ignored, defaultAccount: _ignored2, ...base } = raw;
42
48
  const account = resolveAccountConfig(cfg, accountId) ?? {};
@@ -44,9 +50,15 @@ function mergeZalouserAccountConfig(
44
50
  }
45
51
 
46
52
  function resolveZcaProfile(config: ZalouserAccountConfig, accountId: string): string {
47
- if (config.profile?.trim()) return config.profile.trim();
48
- if (process.env.ZCA_PROFILE?.trim()) return process.env.ZCA_PROFILE.trim();
49
- if (accountId !== DEFAULT_ACCOUNT_ID) return accountId;
53
+ if (config.profile?.trim()) {
54
+ return config.profile.trim();
55
+ }
56
+ if (process.env.ZCA_PROFILE?.trim()) {
57
+ return process.env.ZCA_PROFILE.trim();
58
+ }
59
+ if (accountId !== DEFAULT_ACCOUNT_ID) {
60
+ return accountId;
61
+ }
50
62
  return "default";
51
63
  }
52
64
 
@@ -60,7 +72,8 @@ export async function resolveZalouserAccount(params: {
60
72
  accountId?: string | null;
61
73
  }): Promise<ResolvedZalouserAccount> {
62
74
  const accountId = normalizeAccountId(params.accountId);
63
- const baseEnabled = (params.cfg.channels?.zalouser as ZalouserConfig | undefined)?.enabled !== false;
75
+ const baseEnabled =
76
+ (params.cfg.channels?.zalouser as ZalouserConfig | undefined)?.enabled !== false;
64
77
  const merged = mergeZalouserAccountConfig(params.cfg, accountId);
65
78
  const accountEnabled = merged.enabled !== false;
66
79
  const enabled = baseEnabled && accountEnabled;
@@ -82,7 +95,8 @@ export function resolveZalouserAccountSync(params: {
82
95
  accountId?: string | null;
83
96
  }): ResolvedZalouserAccount {
84
97
  const accountId = normalizeAccountId(params.accountId);
85
- const baseEnabled = (params.cfg.channels?.zalouser as ZalouserConfig | undefined)?.enabled !== false;
98
+ const baseEnabled =
99
+ (params.cfg.channels?.zalouser as ZalouserConfig | undefined)?.enabled !== false;
86
100
  const merged = mergeZalouserAccountConfig(params.cfg, accountId);
87
101
  const accountEnabled = merged.enabled !== false;
88
102
  const enabled = baseEnabled && accountEnabled;
@@ -103,14 +117,18 @@ export async function listEnabledZalouserAccounts(
103
117
  ): Promise<ResolvedZalouserAccount[]> {
104
118
  const ids = listZalouserAccountIds(cfg);
105
119
  const accounts = await Promise.all(
106
- ids.map((accountId) => resolveZalouserAccount({ cfg, accountId }))
120
+ ids.map((accountId) => resolveZalouserAccount({ cfg, accountId })),
107
121
  );
108
122
  return accounts.filter((account) => account.enabled);
109
123
  }
110
124
 
111
- export async function getZcaUserInfo(profile: string): Promise<{ userId?: string; displayName?: string } | null> {
125
+ export async function getZcaUserInfo(
126
+ profile: string,
127
+ ): Promise<{ userId?: string; displayName?: string } | null> {
112
128
  const result = await runZca(["me", "info", "-j"], { profile, timeout: 10000 });
113
- if (!result.ok) return null;
129
+ if (!result.ok) {
130
+ return null;
131
+ }
114
132
  return parseJsonOutput<{ userId?: string; displayName?: string }>(result.stdout);
115
133
  }
116
134
 
@@ -1,12 +1,13 @@
1
1
  import { describe, expect, it } from "vitest";
2
-
3
2
  import { zalouserPlugin } from "./channel.js";
4
3
 
5
4
  describe("zalouser outbound chunker", () => {
6
5
  it("chunks without empty strings and respects limit", () => {
7
6
  const chunker = zalouserPlugin.outbound?.chunker;
8
7
  expect(chunker).toBeTypeOf("function");
9
- if (!chunker) return;
8
+ if (!chunker) {
9
+ return;
10
+ }
10
11
 
11
12
  const limit = 10;
12
13
  const chunks = chunker("hello world\nthis is a test", limit);