@openclaw/matrix 2026.1.29

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 (67) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/index.ts +18 -0
  3. package/openclaw.plugin.json +11 -0
  4. package/package.json +36 -0
  5. package/src/actions.ts +185 -0
  6. package/src/channel.directory.test.ts +56 -0
  7. package/src/channel.ts +417 -0
  8. package/src/config-schema.ts +62 -0
  9. package/src/directory-live.ts +175 -0
  10. package/src/group-mentions.ts +61 -0
  11. package/src/matrix/accounts.test.ts +83 -0
  12. package/src/matrix/accounts.ts +63 -0
  13. package/src/matrix/actions/client.ts +53 -0
  14. package/src/matrix/actions/messages.ts +120 -0
  15. package/src/matrix/actions/pins.ts +70 -0
  16. package/src/matrix/actions/reactions.ts +84 -0
  17. package/src/matrix/actions/room.ts +88 -0
  18. package/src/matrix/actions/summary.ts +77 -0
  19. package/src/matrix/actions/types.ts +84 -0
  20. package/src/matrix/actions.ts +15 -0
  21. package/src/matrix/active-client.ts +11 -0
  22. package/src/matrix/client/config.ts +165 -0
  23. package/src/matrix/client/create-client.ts +127 -0
  24. package/src/matrix/client/logging.ts +35 -0
  25. package/src/matrix/client/runtime.ts +4 -0
  26. package/src/matrix/client/shared.ts +169 -0
  27. package/src/matrix/client/storage.ts +131 -0
  28. package/src/matrix/client/types.ts +34 -0
  29. package/src/matrix/client.test.ts +57 -0
  30. package/src/matrix/client.ts +9 -0
  31. package/src/matrix/credentials.ts +103 -0
  32. package/src/matrix/deps.ts +57 -0
  33. package/src/matrix/format.test.ts +34 -0
  34. package/src/matrix/format.ts +22 -0
  35. package/src/matrix/index.ts +11 -0
  36. package/src/matrix/monitor/allowlist.ts +58 -0
  37. package/src/matrix/monitor/auto-join.ts +68 -0
  38. package/src/matrix/monitor/direct.ts +105 -0
  39. package/src/matrix/monitor/events.ts +103 -0
  40. package/src/matrix/monitor/handler.ts +645 -0
  41. package/src/matrix/monitor/index.ts +279 -0
  42. package/src/matrix/monitor/location.ts +83 -0
  43. package/src/matrix/monitor/media.test.ts +103 -0
  44. package/src/matrix/monitor/media.ts +113 -0
  45. package/src/matrix/monitor/mentions.ts +31 -0
  46. package/src/matrix/monitor/replies.ts +96 -0
  47. package/src/matrix/monitor/room-info.ts +58 -0
  48. package/src/matrix/monitor/rooms.ts +43 -0
  49. package/src/matrix/monitor/threads.ts +64 -0
  50. package/src/matrix/monitor/types.ts +39 -0
  51. package/src/matrix/poll-types.test.ts +22 -0
  52. package/src/matrix/poll-types.ts +157 -0
  53. package/src/matrix/probe.ts +70 -0
  54. package/src/matrix/send/client.ts +63 -0
  55. package/src/matrix/send/formatting.ts +92 -0
  56. package/src/matrix/send/media.ts +220 -0
  57. package/src/matrix/send/targets.test.ts +102 -0
  58. package/src/matrix/send/targets.ts +144 -0
  59. package/src/matrix/send/types.ts +109 -0
  60. package/src/matrix/send.test.ts +172 -0
  61. package/src/matrix/send.ts +255 -0
  62. package/src/onboarding.ts +432 -0
  63. package/src/outbound.ts +53 -0
  64. package/src/resolve-targets.ts +89 -0
  65. package/src/runtime.ts +14 -0
  66. package/src/tool-actions.ts +160 -0
  67. package/src/types.ts +95 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,59 @@
1
+ # Changelog
2
+
3
+ ## 2026.1.29
4
+
5
+ ### Changes
6
+ - Version alignment with core OpenClaw release numbers.
7
+
8
+ ## 2026.1.23
9
+
10
+ ### Changes
11
+ - Version alignment with core OpenClaw release numbers.
12
+
13
+ ## 2026.1.22
14
+
15
+ ### Changes
16
+ - Version alignment with core OpenClaw release numbers.
17
+
18
+ ## 2026.1.21
19
+
20
+ ### Changes
21
+ - Version alignment with core OpenClaw release numbers.
22
+
23
+ ## 2026.1.20
24
+
25
+ ### Changes
26
+ - Version alignment with core OpenClaw release numbers.
27
+
28
+ ## 2026.1.17-1
29
+
30
+ ### Changes
31
+ - Version alignment with core OpenClaw release numbers.
32
+
33
+ ## 2026.1.17
34
+
35
+ ### Changes
36
+ - Version alignment with core OpenClaw release numbers.
37
+
38
+ ## 2026.1.16
39
+
40
+ ### Changes
41
+ - Version alignment with core OpenClaw release numbers.
42
+
43
+ ## 2026.1.15
44
+
45
+ ### Changes
46
+ - Version alignment with core OpenClaw release numbers.
47
+
48
+ ## 2026.1.14
49
+
50
+ ### Features
51
+ - Version alignment with core OpenClaw release numbers.
52
+ - Matrix channel plugin with homeserver + user ID auth (access token or password login with device name).
53
+ - Direct messages with pairing/allowlist/open/disabled policies and allowFrom support.
54
+ - Group/room controls: allowlist policy, per-room config, mention gating, auto-reply, per-room skills/system prompts.
55
+ - Threads: replyToMode controls and thread replies (off/inbound/always).
56
+ - Messaging: text chunking, media uploads with size caps, reactions, polls, typing, and message edits/deletes.
57
+ - Actions: read messages, list/remove reactions, pin/unpin/list pins, member info, room info.
58
+ - Auto-join invites with allowlist support.
59
+ - Status + probe reporting for health checks.
package/index.ts ADDED
@@ -0,0 +1,18 @@
1
+ import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
2
+ import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
3
+
4
+ import { matrixPlugin } from "./src/channel.js";
5
+ import { setMatrixRuntime } from "./src/runtime.js";
6
+
7
+ const plugin = {
8
+ id: "matrix",
9
+ name: "Matrix",
10
+ description: "Matrix channel plugin (matrix-js-sdk)",
11
+ configSchema: emptyPluginConfigSchema(),
12
+ register(api: OpenClawPluginApi) {
13
+ setMatrixRuntime(api.runtime);
14
+ api.registerChannel({ plugin: matrixPlugin });
15
+ },
16
+ };
17
+
18
+ export default plugin;
@@ -0,0 +1,11 @@
1
+ {
2
+ "id": "matrix",
3
+ "channels": [
4
+ "matrix"
5
+ ],
6
+ "configSchema": {
7
+ "type": "object",
8
+ "additionalProperties": false,
9
+ "properties": {}
10
+ }
11
+ }
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@openclaw/matrix",
3
+ "version": "2026.1.29",
4
+ "type": "module",
5
+ "description": "OpenClaw Matrix channel plugin",
6
+ "openclaw": {
7
+ "extensions": [
8
+ "./index.ts"
9
+ ],
10
+ "channel": {
11
+ "id": "matrix",
12
+ "label": "Matrix",
13
+ "selectionLabel": "Matrix (plugin)",
14
+ "docsPath": "/channels/matrix",
15
+ "docsLabel": "matrix",
16
+ "blurb": "open protocol; install the plugin to enable.",
17
+ "order": 70,
18
+ "quickstartAllowFrom": true
19
+ },
20
+ "install": {
21
+ "npmSpec": "@openclaw/matrix",
22
+ "localPath": "extensions/matrix",
23
+ "defaultChoice": "npm"
24
+ }
25
+ },
26
+ "dependencies": {
27
+ "@matrix-org/matrix-sdk-crypto-nodejs": "^0.4.0",
28
+ "markdown-it": "14.1.0",
29
+ "@vector-im/matrix-bot-sdk": "0.8.0-element.3",
30
+ "music-metadata": "^11.10.6",
31
+ "zod": "^4.3.6"
32
+ },
33
+ "devDependencies": {
34
+ "openclaw": "workspace:*"
35
+ }
36
+ }
package/src/actions.ts ADDED
@@ -0,0 +1,185 @@
1
+ import {
2
+ createActionGate,
3
+ readNumberParam,
4
+ readStringParam,
5
+ type ChannelMessageActionAdapter,
6
+ type ChannelMessageActionContext,
7
+ type ChannelMessageActionName,
8
+ type ChannelToolSend,
9
+ } from "openclaw/plugin-sdk";
10
+ import { resolveMatrixAccount } from "./matrix/accounts.js";
11
+ import { handleMatrixAction } from "./tool-actions.js";
12
+ import type { CoreConfig } from "./types.js";
13
+
14
+ export const matrixMessageActions: ChannelMessageActionAdapter = {
15
+ listActions: ({ cfg }) => {
16
+ const account = resolveMatrixAccount({ cfg: cfg as CoreConfig });
17
+ if (!account.enabled || !account.configured) return [];
18
+ const gate = createActionGate((cfg as CoreConfig).channels?.matrix?.actions);
19
+ const actions = new Set<ChannelMessageActionName>(["send", "poll"]);
20
+ if (gate("reactions")) {
21
+ actions.add("react");
22
+ actions.add("reactions");
23
+ }
24
+ if (gate("messages")) {
25
+ actions.add("read");
26
+ actions.add("edit");
27
+ actions.add("delete");
28
+ }
29
+ if (gate("pins")) {
30
+ actions.add("pin");
31
+ actions.add("unpin");
32
+ actions.add("list-pins");
33
+ }
34
+ if (gate("memberInfo")) actions.add("member-info");
35
+ if (gate("channelInfo")) actions.add("channel-info");
36
+ return Array.from(actions);
37
+ },
38
+ supportsAction: ({ action }) => action !== "poll",
39
+ extractToolSend: ({ args }): ChannelToolSend | null => {
40
+ const action = typeof args.action === "string" ? args.action.trim() : "";
41
+ if (action !== "sendMessage") return null;
42
+ const to = typeof args.to === "string" ? args.to : undefined;
43
+ if (!to) return null;
44
+ return { to };
45
+ },
46
+ handleAction: async (ctx: ChannelMessageActionContext) => {
47
+ const { action, params, cfg } = ctx;
48
+ const resolveRoomId = () =>
49
+ readStringParam(params, "roomId") ??
50
+ readStringParam(params, "channelId") ??
51
+ readStringParam(params, "to", { required: true });
52
+
53
+ if (action === "send") {
54
+ const to = readStringParam(params, "to", { required: true });
55
+ const content = readStringParam(params, "message", {
56
+ required: true,
57
+ allowEmpty: true,
58
+ });
59
+ const mediaUrl = readStringParam(params, "media", { trim: false });
60
+ const replyTo = readStringParam(params, "replyTo");
61
+ const threadId = readStringParam(params, "threadId");
62
+ return await handleMatrixAction(
63
+ {
64
+ action: "sendMessage",
65
+ to,
66
+ content,
67
+ mediaUrl: mediaUrl ?? undefined,
68
+ replyToId: replyTo ?? undefined,
69
+ threadId: threadId ?? undefined,
70
+ },
71
+ cfg,
72
+ );
73
+ }
74
+
75
+ if (action === "react") {
76
+ const messageId = readStringParam(params, "messageId", { required: true });
77
+ const emoji = readStringParam(params, "emoji", { allowEmpty: true });
78
+ const remove = typeof params.remove === "boolean" ? params.remove : undefined;
79
+ return await handleMatrixAction(
80
+ {
81
+ action: "react",
82
+ roomId: resolveRoomId(),
83
+ messageId,
84
+ emoji,
85
+ remove,
86
+ },
87
+ cfg,
88
+ );
89
+ }
90
+
91
+ if (action === "reactions") {
92
+ const messageId = readStringParam(params, "messageId", { required: true });
93
+ const limit = readNumberParam(params, "limit", { integer: true });
94
+ return await handleMatrixAction(
95
+ {
96
+ action: "reactions",
97
+ roomId: resolveRoomId(),
98
+ messageId,
99
+ limit,
100
+ },
101
+ cfg,
102
+ );
103
+ }
104
+
105
+ if (action === "read") {
106
+ const limit = readNumberParam(params, "limit", { integer: true });
107
+ return await handleMatrixAction(
108
+ {
109
+ action: "readMessages",
110
+ roomId: resolveRoomId(),
111
+ limit,
112
+ before: readStringParam(params, "before"),
113
+ after: readStringParam(params, "after"),
114
+ },
115
+ cfg,
116
+ );
117
+ }
118
+
119
+ if (action === "edit") {
120
+ const messageId = readStringParam(params, "messageId", { required: true });
121
+ const content = readStringParam(params, "message", { required: true });
122
+ return await handleMatrixAction(
123
+ {
124
+ action: "editMessage",
125
+ roomId: resolveRoomId(),
126
+ messageId,
127
+ content,
128
+ },
129
+ cfg,
130
+ );
131
+ }
132
+
133
+ if (action === "delete") {
134
+ const messageId = readStringParam(params, "messageId", { required: true });
135
+ return await handleMatrixAction(
136
+ {
137
+ action: "deleteMessage",
138
+ roomId: resolveRoomId(),
139
+ messageId,
140
+ },
141
+ cfg,
142
+ );
143
+ }
144
+
145
+ if (action === "pin" || action === "unpin" || action === "list-pins") {
146
+ const messageId =
147
+ action === "list-pins"
148
+ ? undefined
149
+ : readStringParam(params, "messageId", { required: true });
150
+ return await handleMatrixAction(
151
+ {
152
+ action:
153
+ action === "pin" ? "pinMessage" : action === "unpin" ? "unpinMessage" : "listPins",
154
+ roomId: resolveRoomId(),
155
+ messageId,
156
+ },
157
+ cfg,
158
+ );
159
+ }
160
+
161
+ if (action === "member-info") {
162
+ const userId = readStringParam(params, "userId", { required: true });
163
+ return await handleMatrixAction(
164
+ {
165
+ action: "memberInfo",
166
+ userId,
167
+ roomId: readStringParam(params, "roomId") ?? readStringParam(params, "channelId"),
168
+ },
169
+ cfg,
170
+ );
171
+ }
172
+
173
+ if (action === "channel-info") {
174
+ return await handleMatrixAction(
175
+ {
176
+ action: "channelInfo",
177
+ roomId: resolveRoomId(),
178
+ },
179
+ cfg,
180
+ );
181
+ }
182
+
183
+ throw new Error(`Action ${action} is not supported for provider matrix.`);
184
+ },
185
+ };
@@ -0,0 +1,56 @@
1
+ import { beforeEach, describe, expect, it } from "vitest";
2
+
3
+ import type { PluginRuntime } from "openclaw/plugin-sdk";
4
+ import type { CoreConfig } from "./types.js";
5
+
6
+ import { matrixPlugin } from "./channel.js";
7
+ import { setMatrixRuntime } from "./runtime.js";
8
+
9
+ describe("matrix directory", () => {
10
+ beforeEach(() => {
11
+ setMatrixRuntime({
12
+ state: {
13
+ resolveStateDir: (_env, homeDir) => homeDir(),
14
+ },
15
+ } as PluginRuntime);
16
+ });
17
+
18
+ it("lists peers and groups from config", async () => {
19
+ const cfg = {
20
+ channels: {
21
+ matrix: {
22
+ dm: { allowFrom: ["matrix:@alice:example.org", "bob"] },
23
+ groupAllowFrom: ["@dana:example.org"],
24
+ groups: {
25
+ "!room1:example.org": { users: ["@carol:example.org"] },
26
+ "#alias:example.org": { users: [] },
27
+ },
28
+ },
29
+ },
30
+ } as unknown as CoreConfig;
31
+
32
+ expect(matrixPlugin.directory).toBeTruthy();
33
+ expect(matrixPlugin.directory?.listPeers).toBeTruthy();
34
+ expect(matrixPlugin.directory?.listGroups).toBeTruthy();
35
+
36
+ await expect(
37
+ matrixPlugin.directory!.listPeers({ cfg, accountId: undefined, query: undefined, limit: undefined }),
38
+ ).resolves.toEqual(
39
+ expect.arrayContaining([
40
+ { kind: "user", id: "user:@alice:example.org" },
41
+ { kind: "user", id: "bob", name: "incomplete id; expected @user:server" },
42
+ { kind: "user", id: "user:@carol:example.org" },
43
+ { kind: "user", id: "user:@dana:example.org" },
44
+ ]),
45
+ );
46
+
47
+ await expect(
48
+ matrixPlugin.directory!.listGroups({ cfg, accountId: undefined, query: undefined, limit: undefined }),
49
+ ).resolves.toEqual(
50
+ expect.arrayContaining([
51
+ { kind: "group", id: "room:!room1:example.org" },
52
+ { kind: "group", id: "#alias:example.org" },
53
+ ]),
54
+ );
55
+ });
56
+ });