@openclaw/matrix 2026.3.2 → 2026.3.8-beta.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/index.ts +2 -2
  3. package/package.json +9 -1
  4. package/src/actions.ts +1 -1
  5. package/src/channel.directory.test.ts +1 -1
  6. package/src/channel.ts +40 -46
  7. package/src/config-schema.ts +1 -1
  8. package/src/directory-live.ts +1 -1
  9. package/src/group-mentions.ts +1 -1
  10. package/src/matrix/accounts.ts +7 -43
  11. package/src/matrix/client/config.ts +1 -1
  12. package/src/matrix/deps.ts +1 -1
  13. package/src/matrix/monitor/access-policy.ts +6 -7
  14. package/src/matrix/monitor/allowlist.ts +6 -2
  15. package/src/matrix/monitor/auto-join.ts +1 -1
  16. package/src/matrix/monitor/direct.test.ts +374 -39
  17. package/src/matrix/monitor/direct.ts +48 -13
  18. package/src/matrix/monitor/events.test.ts +1 -1
  19. package/src/matrix/monitor/events.ts +1 -1
  20. package/src/matrix/monitor/handler.body-for-agent.test.ts +56 -2
  21. package/src/matrix/monitor/handler.ts +118 -45
  22. package/src/matrix/monitor/index.ts +6 -7
  23. package/src/matrix/monitor/location.ts +1 -1
  24. package/src/matrix/monitor/media.test.ts +1 -1
  25. package/src/matrix/monitor/replies.test.ts +1 -1
  26. package/src/matrix/monitor/replies.ts +1 -1
  27. package/src/matrix/monitor/rooms.test.ts +85 -0
  28. package/src/matrix/monitor/rooms.ts +1 -1
  29. package/src/matrix/poll-types.ts +1 -1
  30. package/src/matrix/probe.ts +1 -1
  31. package/src/matrix/send/client.ts +8 -6
  32. package/src/matrix/send/types.ts +1 -0
  33. package/src/matrix/send.test.ts +86 -2
  34. package/src/matrix/send.ts +6 -4
  35. package/src/onboarding.ts +19 -16
  36. package/src/outbound.test.ts +159 -0
  37. package/src/outbound.ts +7 -4
  38. package/src/resolve-targets.test.ts +1 -1
  39. package/src/resolve-targets.ts +39 -40
  40. package/src/runtime.ts +5 -13
  41. package/src/secret-input.ts +8 -14
  42. package/src/tool-actions.ts +1 -1
  43. package/src/types.ts +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026.3.8-beta.1
4
+
5
+ ### Changes
6
+
7
+ - Version alignment with core OpenClaw release numbers.
8
+
9
+ ## 2026.3.8
10
+
11
+ ### Changes
12
+
13
+ - Version alignment with core OpenClaw release numbers.
14
+
15
+ ## 2026.3.7
16
+
17
+ ### Changes
18
+
19
+ - Version alignment with core OpenClaw release numbers.
20
+
21
+ ## 2026.3.3
22
+
23
+ ### Changes
24
+
25
+ - Version alignment with core OpenClaw release numbers.
26
+
3
27
  ## 2026.3.2
4
28
 
5
29
  ### Changes
package/index.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
2
- import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
1
+ import type { OpenClawPluginApi } from "openclaw/plugin-sdk/matrix";
2
+ import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/matrix";
3
3
  import { matrixPlugin } from "./src/channel.js";
4
4
  import { ensureMatrixCryptoRuntime } from "./src/matrix/deps.js";
5
5
  import { setMatrixRuntime } from "./src/runtime.js";
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "@openclaw/matrix",
3
- "version": "2026.3.2",
3
+ "version": "2026.3.8-beta.1",
4
4
  "description": "OpenClaw Matrix channel plugin",
5
5
  "type": "module",
6
6
  "dependencies": {
7
+ "@mariozechner/pi-agent-core": "0.57.1",
7
8
  "@matrix-org/matrix-sdk-crypto-nodejs": "^0.4.0",
8
9
  "@vector-im/matrix-bot-sdk": "0.8.0-element.3",
9
10
  "markdown-it": "14.1.1",
@@ -28,6 +29,13 @@
28
29
  "npmSpec": "@openclaw/matrix",
29
30
  "localPath": "extensions/matrix",
30
31
  "defaultChoice": "npm"
32
+ },
33
+ "releaseChecks": {
34
+ "rootDependencyMirrorAllowlist": [
35
+ "@matrix-org/matrix-sdk-crypto-nodejs",
36
+ "@vector-im/matrix-bot-sdk",
37
+ "music-metadata"
38
+ ]
31
39
  }
32
40
  }
33
41
  }
package/src/actions.ts CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  type ChannelMessageActionContext,
7
7
  type ChannelMessageActionName,
8
8
  type ChannelToolSend,
9
- } from "openclaw/plugin-sdk";
9
+ } from "openclaw/plugin-sdk/matrix";
10
10
  import { resolveMatrixAccount } from "./matrix/accounts.js";
11
11
  import { handleMatrixAction } from "./tool-actions.js";
12
12
  import type { CoreConfig } from "./types.js";
@@ -1,4 +1,4 @@
1
- import type { PluginRuntime, RuntimeEnv } from "openclaw/plugin-sdk";
1
+ import type { PluginRuntime, RuntimeEnv } from "openclaw/plugin-sdk/matrix";
2
2
  import { beforeEach, describe, expect, it, vi } from "vitest";
3
3
  import { matrixPlugin } from "./channel.js";
4
4
  import { setMatrixRuntime } from "./runtime.js";
package/src/channel.ts CHANGED
@@ -1,17 +1,21 @@
1
+ import {
2
+ buildAccountScopedDmSecurityPolicy,
3
+ buildOpenGroupPolicyWarning,
4
+ collectAllowlistProviderGroupPolicyWarnings,
5
+ createScopedAccountConfigAccessors,
6
+ } from "openclaw/plugin-sdk/compat";
1
7
  import {
2
8
  applyAccountNameToChannelSection,
3
9
  buildChannelConfigSchema,
4
10
  buildProbeChannelStatusSummary,
11
+ collectStatusIssuesFromLastError,
5
12
  DEFAULT_ACCOUNT_ID,
6
13
  deleteAccountFromConfigSection,
7
- formatPairingApproveHint,
8
14
  normalizeAccountId,
9
15
  PAIRING_APPROVED_MESSAGE,
10
- resolveAllowlistProviderRuntimeGroupPolicy,
11
- resolveDefaultGroupPolicy,
12
16
  setAccountEnabledInConfigSection,
13
17
  type ChannelPlugin,
14
- } from "openclaw/plugin-sdk";
18
+ } from "openclaw/plugin-sdk/matrix";
15
19
  import { matrixMessageActions } from "./actions.js";
16
20
  import { MatrixConfigSchema } from "./config-schema.js";
17
21
  import { listMatrixDirectoryGroupsLive, listMatrixDirectoryPeersLive } from "./directory-live.js";
@@ -95,6 +99,13 @@ function buildMatrixConfigUpdate(
95
99
  };
96
100
  }
97
101
 
102
+ const matrixConfigAccessors = createScopedAccountConfigAccessors({
103
+ resolveAccount: ({ cfg, accountId }) =>
104
+ resolveMatrixAccountConfig({ cfg: cfg as CoreConfig, accountId }),
105
+ resolveAllowFrom: (account) => account.dm?.allowFrom,
106
+ formatAllowFrom: (allowFrom) => normalizeMatrixAllowList(allowFrom),
107
+ });
108
+
98
109
  export const matrixPlugin: ChannelPlugin<ResolvedMatrixAccount> = {
99
110
  id: "matrix",
100
111
  meta,
@@ -150,41 +161,38 @@ export const matrixPlugin: ChannelPlugin<ResolvedMatrixAccount> = {
150
161
  configured: account.configured,
151
162
  baseUrl: account.homeserver,
152
163
  }),
153
- resolveAllowFrom: ({ cfg, accountId }) => {
154
- const matrixConfig = resolveMatrixAccountConfig({ cfg: cfg as CoreConfig, accountId });
155
- return (matrixConfig.dm?.allowFrom ?? []).map((entry: string | number) => String(entry));
156
- },
157
- formatAllowFrom: ({ allowFrom }) => normalizeMatrixAllowList(allowFrom),
164
+ ...matrixConfigAccessors,
158
165
  },
159
166
  security: {
160
- resolveDmPolicy: ({ account }) => {
161
- const accountId = account.accountId;
162
- const prefix =
163
- accountId && accountId !== "default"
164
- ? `channels.matrix.accounts.${accountId}.dm`
165
- : "channels.matrix.dm";
166
- return {
167
- policy: account.config.dm?.policy ?? "pairing",
167
+ resolveDmPolicy: ({ cfg, accountId, account }) => {
168
+ return buildAccountScopedDmSecurityPolicy({
169
+ cfg: cfg as CoreConfig,
170
+ channelKey: "matrix",
171
+ accountId,
172
+ fallbackAccountId: account.accountId ?? DEFAULT_ACCOUNT_ID,
173
+ policy: account.config.dm?.policy,
168
174
  allowFrom: account.config.dm?.allowFrom ?? [],
169
- policyPath: `${prefix}.policy`,
170
- allowFromPath: `${prefix}.allowFrom`,
171
- approveHint: formatPairingApproveHint("matrix"),
175
+ allowFromPathSuffix: "dm.",
172
176
  normalizeEntry: (raw) => normalizeMatrixUserId(raw),
173
- };
177
+ });
174
178
  },
175
179
  collectWarnings: ({ account, cfg }) => {
176
- const defaultGroupPolicy = resolveDefaultGroupPolicy(cfg as CoreConfig);
177
- const { groupPolicy } = resolveAllowlistProviderRuntimeGroupPolicy({
180
+ return collectAllowlistProviderGroupPolicyWarnings({
181
+ cfg: cfg as CoreConfig,
178
182
  providerConfigPresent: (cfg as CoreConfig).channels?.matrix !== undefined,
179
- groupPolicy: account.config.groupPolicy,
180
- defaultGroupPolicy,
183
+ configuredGroupPolicy: account.config.groupPolicy,
184
+ collect: (groupPolicy) =>
185
+ groupPolicy === "open"
186
+ ? [
187
+ buildOpenGroupPolicyWarning({
188
+ surface: "Matrix rooms",
189
+ openBehavior: "allows any room to trigger (mention-gated)",
190
+ remediation:
191
+ 'Set channels.matrix.groupPolicy="allowlist" + channels.matrix.groups (and optionally channels.matrix.groupAllowFrom) to restrict rooms',
192
+ }),
193
+ ]
194
+ : [],
181
195
  });
182
- if (groupPolicy !== "open") {
183
- return [];
184
- }
185
- return [
186
- '- Matrix rooms: groupPolicy="open" allows any room to trigger (mention-gated). Set channels.matrix.groupPolicy="allowlist" + channels.matrix.groups (and optionally channels.matrix.groupAllowFrom) to restrict rooms.',
187
- ];
188
196
  },
189
197
  },
190
198
  groups: {
@@ -380,21 +388,7 @@ export const matrixPlugin: ChannelPlugin<ResolvedMatrixAccount> = {
380
388
  lastStopAt: null,
381
389
  lastError: null,
382
390
  },
383
- collectStatusIssues: (accounts) =>
384
- accounts.flatMap((account) => {
385
- const lastError = typeof account.lastError === "string" ? account.lastError.trim() : "";
386
- if (!lastError) {
387
- return [];
388
- }
389
- return [
390
- {
391
- channel: "matrix",
392
- accountId: account.accountId,
393
- kind: "runtime",
394
- message: `Channel error: ${lastError}`,
395
- },
396
- ];
397
- }),
391
+ collectStatusIssues: (accounts) => collectStatusIssuesFromLastError("matrix", accounts),
398
392
  buildChannelSummary: ({ snapshot }) =>
399
393
  buildProbeChannelStatusSummary(snapshot, { baseUrl: snapshot.baseUrl ?? null }),
400
394
  probeAccount: async ({ account, timeoutMs, cfg }) => {
@@ -1,4 +1,4 @@
1
- import { MarkdownConfigSchema, ToolPolicySchema } from "openclaw/plugin-sdk";
1
+ import { MarkdownConfigSchema, ToolPolicySchema } from "openclaw/plugin-sdk/matrix";
2
2
  import { z } from "zod";
3
3
  import { buildSecretInputSchema } from "./secret-input.js";
4
4
 
@@ -1,4 +1,4 @@
1
- import type { ChannelDirectoryEntry } from "openclaw/plugin-sdk";
1
+ import type { ChannelDirectoryEntry } from "openclaw/plugin-sdk/matrix";
2
2
  import { resolveMatrixAuth } from "./matrix/client.js";
3
3
 
4
4
  type MatrixUserResult = {
@@ -1,4 +1,4 @@
1
- import type { ChannelGroupContext, GroupToolPolicyConfig } from "openclaw/plugin-sdk";
1
+ import type { ChannelGroupContext, GroupToolPolicyConfig } from "openclaw/plugin-sdk/matrix";
2
2
  import { resolveMatrixAccountConfig } from "./matrix/accounts.js";
3
3
  import { resolveMatrixRoomConfig } from "./matrix/monitor/rooms.js";
4
4
  import type { CoreConfig } from "./types.js";
@@ -1,8 +1,5 @@
1
- import {
2
- DEFAULT_ACCOUNT_ID,
3
- normalizeAccountId,
4
- normalizeOptionalAccountId,
5
- } from "openclaw/plugin-sdk/account-id";
1
+ import { normalizeAccountId } from "openclaw/plugin-sdk/account-id";
2
+ import { createAccountListHelpers } from "openclaw/plugin-sdk/matrix";
6
3
  import { hasConfiguredSecretInput } from "../secret-input.js";
7
4
  import type { CoreConfig, MatrixConfig } from "../types.js";
8
5
  import { resolveMatrixConfigForAccount } from "./client.js";
@@ -35,44 +32,11 @@ export type ResolvedMatrixAccount = {
35
32
  config: MatrixConfig;
36
33
  };
37
34
 
38
- function listConfiguredAccountIds(cfg: CoreConfig): string[] {
39
- const accounts = cfg.channels?.matrix?.accounts;
40
- if (!accounts || typeof accounts !== "object") {
41
- return [];
42
- }
43
- // Normalize and de-duplicate keys so listing and resolution use the same semantics
44
- return [
45
- ...new Set(
46
- Object.keys(accounts)
47
- .filter(Boolean)
48
- .map((id) => normalizeAccountId(id)),
49
- ),
50
- ];
51
- }
52
-
53
- export function listMatrixAccountIds(cfg: CoreConfig): string[] {
54
- const ids = listConfiguredAccountIds(cfg);
55
- if (ids.length === 0) {
56
- // Fall back to default if no accounts configured (legacy top-level config)
57
- return [DEFAULT_ACCOUNT_ID];
58
- }
59
- return ids.toSorted((a, b) => a.localeCompare(b));
60
- }
61
-
62
- export function resolveDefaultMatrixAccountId(cfg: CoreConfig): string {
63
- const preferred = normalizeOptionalAccountId(cfg.channels?.matrix?.defaultAccount);
64
- if (
65
- preferred &&
66
- listMatrixAccountIds(cfg).some((accountId) => normalizeAccountId(accountId) === preferred)
67
- ) {
68
- return preferred;
69
- }
70
- const ids = listMatrixAccountIds(cfg);
71
- if (ids.includes(DEFAULT_ACCOUNT_ID)) {
72
- return DEFAULT_ACCOUNT_ID;
73
- }
74
- return ids[0] ?? DEFAULT_ACCOUNT_ID;
75
- }
35
+ const {
36
+ listAccountIds: listMatrixAccountIds,
37
+ resolveDefaultAccountId: resolveDefaultMatrixAccountId,
38
+ } = createAccountListHelpers("matrix", { normalizeAccountId });
39
+ export { listMatrixAccountIds, resolveDefaultMatrixAccountId };
76
40
 
77
41
  function resolveAccountConfig(cfg: CoreConfig, accountId: string): MatrixConfig | undefined {
78
42
  const accounts = cfg.channels?.matrix?.accounts;
@@ -1,5 +1,5 @@
1
- import { fetchWithSsrFGuard } from "openclaw/plugin-sdk";
2
1
  import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-id";
2
+ import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/matrix";
3
3
  import { getMatrixRuntime } from "../../runtime.js";
4
4
  import {
5
5
  normalizeResolvedSecretInputString,
@@ -2,7 +2,7 @@ import fs from "node:fs";
2
2
  import { createRequire } from "node:module";
3
3
  import path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
- import { runPluginCommandWithTimeout, type RuntimeEnv } from "openclaw/plugin-sdk";
5
+ import { runPluginCommandWithTimeout, type RuntimeEnv } from "openclaw/plugin-sdk/matrix";
6
6
 
7
7
  const MATRIX_SDK_PACKAGE = "@vector-im/matrix-bot-sdk";
8
8
  const MATRIX_CRYPTO_DOWNLOAD_HELPER = "@matrix-org/matrix-sdk-crypto-nodejs/download-lib.js";
@@ -3,7 +3,8 @@ import {
3
3
  issuePairingChallenge,
4
4
  readStoreAllowFromForDmPolicy,
5
5
  resolveDmGroupAccessWithLists,
6
- } from "openclaw/plugin-sdk";
6
+ resolveSenderScopedGroupPolicy,
7
+ } from "openclaw/plugin-sdk/matrix";
7
8
  import {
8
9
  normalizeMatrixAllowList,
9
10
  resolveMatrixAllowListMatch,
@@ -32,12 +33,10 @@ export async function resolveMatrixAccessState(params: {
32
33
  })
33
34
  : [];
34
35
  const normalizedGroupAllowFrom = normalizeMatrixAllowList(params.groupAllowFrom);
35
- const senderGroupPolicy =
36
- params.groupPolicy === "disabled"
37
- ? "disabled"
38
- : normalizedGroupAllowFrom.length > 0
39
- ? "allowlist"
40
- : "open";
36
+ const senderGroupPolicy = resolveSenderScopedGroupPolicy({
37
+ groupPolicy: params.groupPolicy,
38
+ groupAllowFrom: normalizedGroupAllowFrom,
39
+ });
41
40
  const access = resolveDmGroupAccessWithLists({
42
41
  isGroup: !params.isDirectMessage,
43
42
  dmPolicy: params.dmPolicy,
@@ -1,7 +1,11 @@
1
- import { resolveAllowlistMatchByCandidates, type AllowlistMatch } from "openclaw/plugin-sdk";
1
+ import {
2
+ normalizeStringEntries,
3
+ resolveAllowlistMatchByCandidates,
4
+ type AllowlistMatch,
5
+ } from "openclaw/plugin-sdk/matrix";
2
6
 
3
7
  function normalizeAllowList(list?: Array<string | number>) {
4
- return (list ?? []).map((entry) => String(entry).trim()).filter(Boolean);
8
+ return normalizeStringEntries(list);
5
9
  }
6
10
 
7
11
  function normalizeMatrixUser(raw?: string | null): string {
@@ -1,5 +1,5 @@
1
1
  import type { MatrixClient } from "@vector-im/matrix-bot-sdk";
2
- import type { RuntimeEnv } from "openclaw/plugin-sdk";
2
+ import type { RuntimeEnv } from "openclaw/plugin-sdk/matrix";
3
3
  import { getMatrixRuntime } from "../../runtime.js";
4
4
  import type { CoreConfig } from "../../types.js";
5
5
  import { loadMatrixSdk } from "../sdk-runtime.js";