@openclaw/matrix 2026.3.12 → 2026.5.9-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 (205) hide show
  1. package/dist/account-config-D2W-V1eQ.js +96 -0
  2. package/dist/account-selection-BWwIruri.js +158 -0
  3. package/dist/accounts-Bm90Rzvp.js +130 -0
  4. package/dist/active-client-uhlxdhEy.js +20 -0
  5. package/dist/allowlist-sTzpCn5d.js +68 -0
  6. package/dist/api.js +12 -0
  7. package/dist/approval-handler.runtime-DWTQfd4m.js +370 -0
  8. package/dist/approval-ids-DoC2z7tR.js +7 -0
  9. package/dist/approval-reaction-auth-DbcA1gGd.js +27 -0
  10. package/dist/approval-reactions-o2_tuH8D.js +162 -0
  11. package/dist/async-lock-uQfhfQIY.js +19 -0
  12. package/dist/auth-presence.js +26 -0
  13. package/dist/backup-health-Cabu_WQC.js +60 -0
  14. package/dist/channel-DJNir3Rb.js +1116 -0
  15. package/dist/channel-plugin-api.js +2 -0
  16. package/dist/channel.runtime-BQu0hTih.js +246 -0
  17. package/dist/cli-BmfTmg7x.js +1340 -0
  18. package/dist/cli-metadata-B-PCEzrA.js +22 -0
  19. package/dist/cli-metadata.js +2 -0
  20. package/dist/client-DkcXnm0X.js +25 -0
  21. package/dist/client-_hckQNGW.js +31 -0
  22. package/dist/client-bootstrap-Rb8oHvhH.js +114 -0
  23. package/dist/config--5-S2Akv.js +452 -0
  24. package/dist/config-paths-nsVaysCu.js +19 -0
  25. package/dist/config-schema-nPLpEgHl.js +200 -0
  26. package/dist/config-secret-input.runtime-DiKFehsE.js +2 -0
  27. package/dist/config-update-wZX-HLMn.js +143 -0
  28. package/dist/contract-api.js +9 -0
  29. package/dist/create-client-DCnqDaqd.js +64 -0
  30. package/dist/credentials-DV6fWXhC.js +56 -0
  31. package/dist/credentials-read-cmHgousK.js +112 -0
  32. package/dist/credentials-write.runtime-zniTq-Gr.js +17 -0
  33. package/dist/crypto-node.runtime-pihzdpY7.js +12 -0
  34. package/dist/crypto-runtime-ZI0zAtn3.js +1214 -0
  35. package/dist/deps-C6WqKY7m.js +235 -0
  36. package/dist/device-health-UVYpbA_W.js +16 -0
  37. package/dist/direct-management-DMMMgtTB.js +249 -0
  38. package/dist/direct-room-XkutHjES.js +76 -0
  39. package/dist/directory-live-DmOtMhyr.js +150 -0
  40. package/dist/doctor-C4__7c-U.js +153 -0
  41. package/dist/doctor-contract-D4-64QuJ.js +246 -0
  42. package/dist/doctor-contract-api.js +2 -0
  43. package/dist/draft-stream-BE2QevQQ.js +144 -0
  44. package/dist/encryption-guidance-BPi3A_m3.js +15 -0
  45. package/dist/env-auth-BJqGI8M6.js +63 -0
  46. package/dist/env-vars-C7uQCTKn.js +63 -0
  47. package/dist/errors-CTcpEDq-.js +17 -0
  48. package/dist/exec-approval-resolver-Bza9Dhlm.js +15 -0
  49. package/dist/exec-approvals-Crnh543m.js +196 -0
  50. package/dist/helper-api.js +4 -0
  51. package/dist/http-client-C7AeVJay.js +319 -0
  52. package/dist/index.js +46 -0
  53. package/dist/legacy-crypto-inspector-poDWldgy.js +41 -0
  54. package/dist/legacy-crypto-restore-Biw-w2ng.js +85 -0
  55. package/dist/logger-CnZRVrux.js +78 -0
  56. package/dist/logging-DZHSPP5N.js +99 -0
  57. package/dist/matrix-migration.runtime-WY6ffcrf.js +525 -0
  58. package/dist/media-text-DU6nWZuj.js +146 -0
  59. package/dist/messages-BpihMh82.js +140 -0
  60. package/dist/migration-snapshot-backup-DaCHTp8C.js +69 -0
  61. package/dist/migration-snapshot.runtime-CKHE3xF9.js +2 -0
  62. package/dist/monitor-C_81r_Ck.js +4125 -0
  63. package/dist/plugin-entry.handlers.runtime.js +51 -0
  64. package/dist/probe.runtime-BvAzYAIe.js +3 -0
  65. package/dist/profile-BlHu0wDX.js +111 -0
  66. package/dist/profile-update-DjeBNgIV.js +69 -0
  67. package/dist/reaction-common-ejrL19w-.js +71 -0
  68. package/dist/reaction-events-CiARZfjk.js +121 -0
  69. package/dist/record-shared-CHWJCTWf.js +2 -0
  70. package/dist/recovery-key-store-BTJ6jz5v.js +294 -0
  71. package/dist/resolve-targets-YtJnw1Tb.js +140 -0
  72. package/dist/resolver.runtime-D9piiGEl.js +5 -0
  73. package/dist/rolldown-runtime-DUslC3ob.js +14 -0
  74. package/dist/route-D6rg-iXN.js +161 -0
  75. package/dist/runtime-C6X4h_SJ.js +6 -0
  76. package/dist/runtime-Dog86njy.js +8 -0
  77. package/dist/runtime-api-BXWBFIqm.js +25 -0
  78. package/dist/runtime-api.js +25 -0
  79. package/dist/runtime-heavy-api.js +3 -0
  80. package/dist/runtime-setter-api.js +2 -0
  81. package/dist/sdk-B2vZA27-.js +1416 -0
  82. package/dist/secret-contract-DcrJWCQI.js +120 -0
  83. package/dist/secret-contract-api.js +2 -0
  84. package/dist/send-Bo0DU1ca.js +1200 -0
  85. package/dist/session-store-metadata-DI5SCofx.js +77 -0
  86. package/dist/setup-bootstrap-ImenBsMt.js +62 -0
  87. package/dist/setup-core-CfZy05oW.js +116 -0
  88. package/dist/setup-dm-policy-2-r1FrQh.js +194 -0
  89. package/dist/setup-entry.js +19 -0
  90. package/dist/setup-plugin-api.js +44 -0
  91. package/dist/setup-surface-CqT_o61M.js +540 -0
  92. package/dist/shared-CpMoYKm1.js +195 -0
  93. package/dist/startup-abort-56edvmbM.js +32 -0
  94. package/dist/startup-verification-Demyp0bP.js +132 -0
  95. package/dist/storage-paths-BJLdnCjV.js +52 -0
  96. package/dist/storage-tC3ujLiW.js +281 -0
  97. package/dist/subagent-hooks-DQbyqq9V.js +149 -0
  98. package/dist/subagent-hooks-api.js +23 -0
  99. package/dist/sync-state-C_beeevA.js +12 -0
  100. package/dist/target-ids-80nQ2gql.js +77 -0
  101. package/dist/test-api.js +4 -0
  102. package/dist/thread-binding-api-Cq_E-E1K.js +17 -0
  103. package/dist/thread-binding-api.js +2 -0
  104. package/dist/thread-bindings-B9mesxXk.js +352 -0
  105. package/dist/thread-bindings-runtime.js +2 -0
  106. package/dist/thread-bindings-shared-DK-d-oYX.js +97 -0
  107. package/dist/timeout-abort-signal-CtaIaP1v.js +2 -0
  108. package/dist/tool-actions.runtime-BIH49vRr.js +532 -0
  109. package/dist/url-validation-DiK9j7jz.js +36 -0
  110. package/dist/verification-CZ2rDeHL.js +345 -0
  111. package/openclaw.plugin.json +788 -1
  112. package/package.json +82 -16
  113. package/CHANGELOG.md +0 -98
  114. package/index.ts +0 -22
  115. package/src/actions.ts +0 -195
  116. package/src/channel.directory.test.ts +0 -154
  117. package/src/channel.ts +0 -461
  118. package/src/config-schema.test.ts +0 -26
  119. package/src/config-schema.ts +0 -62
  120. package/src/directory-live.test.ts +0 -85
  121. package/src/directory-live.ts +0 -209
  122. package/src/group-mentions.ts +0 -52
  123. package/src/matrix/accounts.test.ts +0 -131
  124. package/src/matrix/accounts.ts +0 -114
  125. package/src/matrix/actions/client.ts +0 -47
  126. package/src/matrix/actions/limits.test.ts +0 -15
  127. package/src/matrix/actions/limits.ts +0 -6
  128. package/src/matrix/actions/messages.ts +0 -126
  129. package/src/matrix/actions/pins.test.ts +0 -74
  130. package/src/matrix/actions/pins.ts +0 -84
  131. package/src/matrix/actions/reactions.test.ts +0 -109
  132. package/src/matrix/actions/reactions.ts +0 -102
  133. package/src/matrix/actions/room.ts +0 -85
  134. package/src/matrix/actions/summary.ts +0 -75
  135. package/src/matrix/actions/types.ts +0 -85
  136. package/src/matrix/actions.ts +0 -15
  137. package/src/matrix/active-client.ts +0 -32
  138. package/src/matrix/client/config.ts +0 -245
  139. package/src/matrix/client/create-client.ts +0 -125
  140. package/src/matrix/client/logging.ts +0 -46
  141. package/src/matrix/client/runtime.ts +0 -4
  142. package/src/matrix/client/shared.test.ts +0 -85
  143. package/src/matrix/client/shared.ts +0 -210
  144. package/src/matrix/client/startup.test.ts +0 -49
  145. package/src/matrix/client/startup.ts +0 -29
  146. package/src/matrix/client/storage.ts +0 -131
  147. package/src/matrix/client/types.ts +0 -34
  148. package/src/matrix/client-bootstrap.ts +0 -47
  149. package/src/matrix/client.test.ts +0 -56
  150. package/src/matrix/client.ts +0 -14
  151. package/src/matrix/credentials.ts +0 -125
  152. package/src/matrix/deps.test.ts +0 -74
  153. package/src/matrix/deps.ts +0 -126
  154. package/src/matrix/format.test.ts +0 -33
  155. package/src/matrix/format.ts +0 -22
  156. package/src/matrix/index.ts +0 -11
  157. package/src/matrix/monitor/access-policy.ts +0 -126
  158. package/src/matrix/monitor/allowlist.test.ts +0 -45
  159. package/src/matrix/monitor/allowlist.ts +0 -100
  160. package/src/matrix/monitor/auto-join.ts +0 -72
  161. package/src/matrix/monitor/direct.test.ts +0 -400
  162. package/src/matrix/monitor/direct.ts +0 -152
  163. package/src/matrix/monitor/events.test.ts +0 -172
  164. package/src/matrix/monitor/events.ts +0 -168
  165. package/src/matrix/monitor/handler.body-for-agent.test.ts +0 -196
  166. package/src/matrix/monitor/handler.ts +0 -767
  167. package/src/matrix/monitor/inbound-body.test.ts +0 -73
  168. package/src/matrix/monitor/inbound-body.ts +0 -28
  169. package/src/matrix/monitor/index.test.ts +0 -18
  170. package/src/matrix/monitor/index.ts +0 -414
  171. package/src/matrix/monitor/location.ts +0 -100
  172. package/src/matrix/monitor/media.test.ts +0 -86
  173. package/src/matrix/monitor/media.ts +0 -118
  174. package/src/matrix/monitor/mentions.test.ts +0 -154
  175. package/src/matrix/monitor/mentions.ts +0 -62
  176. package/src/matrix/monitor/replies.test.ts +0 -184
  177. package/src/matrix/monitor/replies.ts +0 -124
  178. package/src/matrix/monitor/room-info.ts +0 -55
  179. package/src/matrix/monitor/rooms.test.ts +0 -124
  180. package/src/matrix/monitor/rooms.ts +0 -47
  181. package/src/matrix/monitor/threads.ts +0 -68
  182. package/src/matrix/monitor/types.ts +0 -39
  183. package/src/matrix/poll-types.test.ts +0 -21
  184. package/src/matrix/poll-types.ts +0 -167
  185. package/src/matrix/probe.ts +0 -69
  186. package/src/matrix/sdk-runtime.ts +0 -18
  187. package/src/matrix/send/client.ts +0 -99
  188. package/src/matrix/send/formatting.ts +0 -93
  189. package/src/matrix/send/media.ts +0 -230
  190. package/src/matrix/send/targets.test.ts +0 -98
  191. package/src/matrix/send/targets.ts +0 -150
  192. package/src/matrix/send/types.ts +0 -110
  193. package/src/matrix/send-queue.test.ts +0 -154
  194. package/src/matrix/send-queue.ts +0 -28
  195. package/src/matrix/send.test.ts +0 -326
  196. package/src/matrix/send.ts +0 -267
  197. package/src/onboarding.ts +0 -462
  198. package/src/outbound.test.ts +0 -159
  199. package/src/outbound.ts +0 -58
  200. package/src/resolve-targets.test.ts +0 -67
  201. package/src/resolve-targets.ts +0 -125
  202. package/src/runtime.ts +0 -6
  203. package/src/secret-input.ts +0 -13
  204. package/src/tool-actions.ts +0 -164
  205. package/src/types.ts +0 -118
package/src/channel.ts DELETED
@@ -1,461 +0,0 @@
1
- import {
2
- buildOpenGroupPolicyWarning,
3
- collectAllowlistProviderGroupPolicyWarnings,
4
- createScopedAccountConfigAccessors,
5
- createScopedChannelConfigBase,
6
- createScopedDmSecurityResolver,
7
- } from "openclaw/plugin-sdk/compat";
8
- import {
9
- applyAccountNameToChannelSection,
10
- buildChannelConfigSchema,
11
- buildProbeChannelStatusSummary,
12
- collectStatusIssuesFromLastError,
13
- DEFAULT_ACCOUNT_ID,
14
- normalizeAccountId,
15
- PAIRING_APPROVED_MESSAGE,
16
- type ChannelPlugin,
17
- } from "openclaw/plugin-sdk/matrix";
18
- import { matrixMessageActions } from "./actions.js";
19
- import { MatrixConfigSchema } from "./config-schema.js";
20
- import { listMatrixDirectoryGroupsLive, listMatrixDirectoryPeersLive } from "./directory-live.js";
21
- import {
22
- resolveMatrixGroupRequireMention,
23
- resolveMatrixGroupToolPolicy,
24
- } from "./group-mentions.js";
25
- import {
26
- listMatrixAccountIds,
27
- resolveMatrixAccountConfig,
28
- resolveDefaultMatrixAccountId,
29
- resolveMatrixAccount,
30
- type ResolvedMatrixAccount,
31
- } from "./matrix/accounts.js";
32
- import { resolveMatrixAuth } from "./matrix/client.js";
33
- import { normalizeMatrixAllowList, normalizeMatrixUserId } from "./matrix/monitor/allowlist.js";
34
- import { probeMatrix } from "./matrix/probe.js";
35
- import { sendMessageMatrix } from "./matrix/send.js";
36
- import { matrixOnboardingAdapter } from "./onboarding.js";
37
- import { matrixOutbound } from "./outbound.js";
38
- import { resolveMatrixTargets } from "./resolve-targets.js";
39
- import { normalizeSecretInputString } from "./secret-input.js";
40
- import type { CoreConfig } from "./types.js";
41
-
42
- // Mutex for serializing account startup (workaround for concurrent dynamic import race condition)
43
- let matrixStartupLock: Promise<void> = Promise.resolve();
44
-
45
- const meta = {
46
- id: "matrix",
47
- label: "Matrix",
48
- selectionLabel: "Matrix (plugin)",
49
- docsPath: "/channels/matrix",
50
- docsLabel: "matrix",
51
- blurb: "open protocol; configure a homeserver + access token.",
52
- order: 70,
53
- quickstartAllowFrom: true,
54
- };
55
-
56
- function normalizeMatrixMessagingTarget(raw: string): string | undefined {
57
- let normalized = raw.trim();
58
- if (!normalized) {
59
- return undefined;
60
- }
61
- const lowered = normalized.toLowerCase();
62
- if (lowered.startsWith("matrix:")) {
63
- normalized = normalized.slice("matrix:".length).trim();
64
- }
65
- const stripped = normalized.replace(/^(room|channel|user):/i, "").trim();
66
- return stripped || undefined;
67
- }
68
-
69
- function buildMatrixConfigUpdate(
70
- cfg: CoreConfig,
71
- input: {
72
- homeserver?: string;
73
- userId?: string;
74
- accessToken?: string;
75
- password?: string;
76
- deviceName?: string;
77
- initialSyncLimit?: number;
78
- },
79
- ): CoreConfig {
80
- const existing = cfg.channels?.matrix ?? {};
81
- return {
82
- ...cfg,
83
- channels: {
84
- ...cfg.channels,
85
- matrix: {
86
- ...existing,
87
- enabled: true,
88
- ...(input.homeserver ? { homeserver: input.homeserver } : {}),
89
- ...(input.userId ? { userId: input.userId } : {}),
90
- ...(input.accessToken ? { accessToken: input.accessToken } : {}),
91
- ...(input.password ? { password: input.password } : {}),
92
- ...(input.deviceName ? { deviceName: input.deviceName } : {}),
93
- ...(typeof input.initialSyncLimit === "number"
94
- ? { initialSyncLimit: input.initialSyncLimit }
95
- : {}),
96
- },
97
- },
98
- };
99
- }
100
-
101
- const matrixConfigAccessors = createScopedAccountConfigAccessors({
102
- resolveAccount: ({ cfg, accountId }) =>
103
- resolveMatrixAccountConfig({ cfg: cfg as CoreConfig, accountId }),
104
- resolveAllowFrom: (account) => account.dm?.allowFrom,
105
- formatAllowFrom: (allowFrom) => normalizeMatrixAllowList(allowFrom),
106
- });
107
-
108
- const matrixConfigBase = createScopedChannelConfigBase<ResolvedMatrixAccount, CoreConfig>({
109
- sectionKey: "matrix",
110
- listAccountIds: listMatrixAccountIds,
111
- resolveAccount: (cfg, accountId) => resolveMatrixAccount({ cfg, accountId }),
112
- defaultAccountId: resolveDefaultMatrixAccountId,
113
- clearBaseFields: [
114
- "name",
115
- "homeserver",
116
- "userId",
117
- "accessToken",
118
- "password",
119
- "deviceName",
120
- "initialSyncLimit",
121
- ],
122
- });
123
-
124
- const resolveMatrixDmPolicy = createScopedDmSecurityResolver<ResolvedMatrixAccount>({
125
- channelKey: "matrix",
126
- resolvePolicy: (account) => account.config.dm?.policy,
127
- resolveAllowFrom: (account) => account.config.dm?.allowFrom,
128
- allowFromPathSuffix: "dm.",
129
- normalizeEntry: (raw) => normalizeMatrixUserId(raw),
130
- });
131
-
132
- export const matrixPlugin: ChannelPlugin<ResolvedMatrixAccount> = {
133
- id: "matrix",
134
- meta,
135
- onboarding: matrixOnboardingAdapter,
136
- pairing: {
137
- idLabel: "matrixUserId",
138
- normalizeAllowEntry: (entry) => entry.replace(/^matrix:/i, ""),
139
- notifyApproval: async ({ id }) => {
140
- await sendMessageMatrix(`user:${id}`, PAIRING_APPROVED_MESSAGE);
141
- },
142
- },
143
- capabilities: {
144
- chatTypes: ["direct", "group", "thread"],
145
- polls: true,
146
- reactions: true,
147
- threads: true,
148
- media: true,
149
- },
150
- reload: { configPrefixes: ["channels.matrix"] },
151
- configSchema: buildChannelConfigSchema(MatrixConfigSchema),
152
- config: {
153
- ...matrixConfigBase,
154
- isConfigured: (account) => account.configured,
155
- describeAccount: (account) => ({
156
- accountId: account.accountId,
157
- name: account.name,
158
- enabled: account.enabled,
159
- configured: account.configured,
160
- baseUrl: account.homeserver,
161
- }),
162
- ...matrixConfigAccessors,
163
- },
164
- security: {
165
- resolveDmPolicy: resolveMatrixDmPolicy,
166
- collectWarnings: ({ account, cfg }) => {
167
- return collectAllowlistProviderGroupPolicyWarnings({
168
- cfg: cfg as CoreConfig,
169
- providerConfigPresent: (cfg as CoreConfig).channels?.matrix !== undefined,
170
- configuredGroupPolicy: account.config.groupPolicy,
171
- collect: (groupPolicy) =>
172
- groupPolicy === "open"
173
- ? [
174
- buildOpenGroupPolicyWarning({
175
- surface: "Matrix rooms",
176
- openBehavior: "allows any room to trigger (mention-gated)",
177
- remediation:
178
- 'Set channels.matrix.groupPolicy="allowlist" + channels.matrix.groups (and optionally channels.matrix.groupAllowFrom) to restrict rooms',
179
- }),
180
- ]
181
- : [],
182
- });
183
- },
184
- },
185
- groups: {
186
- resolveRequireMention: resolveMatrixGroupRequireMention,
187
- resolveToolPolicy: resolveMatrixGroupToolPolicy,
188
- },
189
- threading: {
190
- resolveReplyToMode: ({ cfg, accountId }) =>
191
- resolveMatrixAccountConfig({ cfg: cfg as CoreConfig, accountId }).replyToMode ?? "off",
192
- buildToolContext: ({ context, hasRepliedRef }) => {
193
- const currentTarget = context.To;
194
- return {
195
- currentChannelId: currentTarget?.trim() || undefined,
196
- currentThreadTs:
197
- context.MessageThreadId != null ? String(context.MessageThreadId) : context.ReplyToId,
198
- hasRepliedRef,
199
- };
200
- },
201
- },
202
- messaging: {
203
- normalizeTarget: normalizeMatrixMessagingTarget,
204
- targetResolver: {
205
- looksLikeId: (raw) => {
206
- const trimmed = raw.trim();
207
- if (!trimmed) {
208
- return false;
209
- }
210
- if (/^(matrix:)?[!#@]/i.test(trimmed)) {
211
- return true;
212
- }
213
- return trimmed.includes(":");
214
- },
215
- hint: "<room|alias|user>",
216
- },
217
- },
218
- directory: {
219
- self: async () => null,
220
- listPeers: async ({ cfg, accountId, query, limit }) => {
221
- const account = resolveMatrixAccount({ cfg: cfg as CoreConfig, accountId });
222
- const q = query?.trim().toLowerCase() || "";
223
- const ids = new Set<string>();
224
-
225
- for (const entry of account.config.dm?.allowFrom ?? []) {
226
- const raw = String(entry).trim();
227
- if (!raw || raw === "*") {
228
- continue;
229
- }
230
- ids.add(raw.replace(/^matrix:/i, ""));
231
- }
232
-
233
- for (const entry of account.config.groupAllowFrom ?? []) {
234
- const raw = String(entry).trim();
235
- if (!raw || raw === "*") {
236
- continue;
237
- }
238
- ids.add(raw.replace(/^matrix:/i, ""));
239
- }
240
-
241
- const groups = account.config.groups ?? account.config.rooms ?? {};
242
- for (const room of Object.values(groups)) {
243
- for (const entry of room.users ?? []) {
244
- const raw = String(entry).trim();
245
- if (!raw || raw === "*") {
246
- continue;
247
- }
248
- ids.add(raw.replace(/^matrix:/i, ""));
249
- }
250
- }
251
-
252
- return Array.from(ids)
253
- .map((raw) => raw.trim())
254
- .filter(Boolean)
255
- .map((raw) => {
256
- const lowered = raw.toLowerCase();
257
- const cleaned = lowered.startsWith("user:") ? raw.slice("user:".length).trim() : raw;
258
- if (cleaned.startsWith("@")) {
259
- return `user:${cleaned}`;
260
- }
261
- return cleaned;
262
- })
263
- .filter((id) => (q ? id.toLowerCase().includes(q) : true))
264
- .slice(0, limit && limit > 0 ? limit : undefined)
265
- .map((id) => {
266
- const raw = id.startsWith("user:") ? id.slice("user:".length) : id;
267
- const incomplete = !raw.startsWith("@") || !raw.includes(":");
268
- return {
269
- kind: "user",
270
- id,
271
- ...(incomplete ? { name: "incomplete id; expected @user:server" } : {}),
272
- };
273
- });
274
- },
275
- listGroups: async ({ cfg, accountId, query, limit }) => {
276
- const account = resolveMatrixAccount({ cfg: cfg as CoreConfig, accountId });
277
- const q = query?.trim().toLowerCase() || "";
278
- const groups = account.config.groups ?? account.config.rooms ?? {};
279
- const ids = Object.keys(groups)
280
- .map((raw) => raw.trim())
281
- .filter((raw) => Boolean(raw) && raw !== "*")
282
- .map((raw) => raw.replace(/^matrix:/i, ""))
283
- .map((raw) => {
284
- const lowered = raw.toLowerCase();
285
- if (lowered.startsWith("room:") || lowered.startsWith("channel:")) {
286
- return raw;
287
- }
288
- if (raw.startsWith("!")) {
289
- return `room:${raw}`;
290
- }
291
- return raw;
292
- })
293
- .filter((id) => (q ? id.toLowerCase().includes(q) : true))
294
- .slice(0, limit && limit > 0 ? limit : undefined)
295
- .map((id) => ({ kind: "group", id }) as const);
296
- return ids;
297
- },
298
- listPeersLive: async ({ cfg, accountId, query, limit }) =>
299
- listMatrixDirectoryPeersLive({ cfg, accountId, query, limit }),
300
- listGroupsLive: async ({ cfg, accountId, query, limit }) =>
301
- listMatrixDirectoryGroupsLive({ cfg, accountId, query, limit }),
302
- },
303
- resolver: {
304
- resolveTargets: async ({ cfg, inputs, kind, runtime }) =>
305
- resolveMatrixTargets({ cfg, inputs, kind, runtime }),
306
- },
307
- actions: matrixMessageActions,
308
- setup: {
309
- resolveAccountId: ({ accountId }) => normalizeAccountId(accountId),
310
- applyAccountName: ({ cfg, accountId, name }) =>
311
- applyAccountNameToChannelSection({
312
- cfg: cfg as CoreConfig,
313
- channelKey: "matrix",
314
- accountId,
315
- name,
316
- }),
317
- validateInput: ({ input }) => {
318
- if (input.useEnv) {
319
- return null;
320
- }
321
- if (!input.homeserver?.trim()) {
322
- return "Matrix requires --homeserver";
323
- }
324
- const accessToken = input.accessToken?.trim();
325
- const password = normalizeSecretInputString(input.password);
326
- const userId = input.userId?.trim();
327
- if (!accessToken && !password) {
328
- return "Matrix requires --access-token or --password";
329
- }
330
- if (!accessToken) {
331
- if (!userId) {
332
- return "Matrix requires --user-id when using --password";
333
- }
334
- if (!password) {
335
- return "Matrix requires --password when using --user-id";
336
- }
337
- }
338
- return null;
339
- },
340
- applyAccountConfig: ({ cfg, input }) => {
341
- const namedConfig = applyAccountNameToChannelSection({
342
- cfg: cfg as CoreConfig,
343
- channelKey: "matrix",
344
- accountId: DEFAULT_ACCOUNT_ID,
345
- name: input.name,
346
- });
347
- if (input.useEnv) {
348
- return {
349
- ...namedConfig,
350
- channels: {
351
- ...namedConfig.channels,
352
- matrix: {
353
- ...namedConfig.channels?.matrix,
354
- enabled: true,
355
- },
356
- },
357
- } as CoreConfig;
358
- }
359
- return buildMatrixConfigUpdate(namedConfig as CoreConfig, {
360
- homeserver: input.homeserver?.trim(),
361
- userId: input.userId?.trim(),
362
- accessToken: input.accessToken?.trim(),
363
- password: normalizeSecretInputString(input.password),
364
- deviceName: input.deviceName?.trim(),
365
- initialSyncLimit: input.initialSyncLimit,
366
- });
367
- },
368
- },
369
- outbound: matrixOutbound,
370
- status: {
371
- defaultRuntime: {
372
- accountId: DEFAULT_ACCOUNT_ID,
373
- running: false,
374
- lastStartAt: null,
375
- lastStopAt: null,
376
- lastError: null,
377
- },
378
- collectStatusIssues: (accounts) => collectStatusIssuesFromLastError("matrix", accounts),
379
- buildChannelSummary: ({ snapshot }) =>
380
- buildProbeChannelStatusSummary(snapshot, { baseUrl: snapshot.baseUrl ?? null }),
381
- probeAccount: async ({ account, timeoutMs, cfg }) => {
382
- try {
383
- const auth = await resolveMatrixAuth({
384
- cfg: cfg as CoreConfig,
385
- accountId: account.accountId,
386
- });
387
- return await probeMatrix({
388
- homeserver: auth.homeserver,
389
- accessToken: auth.accessToken,
390
- userId: auth.userId,
391
- timeoutMs,
392
- });
393
- } catch (err) {
394
- return {
395
- ok: false,
396
- error: err instanceof Error ? err.message : String(err),
397
- elapsedMs: 0,
398
- };
399
- }
400
- },
401
- buildAccountSnapshot: ({ account, runtime, probe }) => ({
402
- accountId: account.accountId,
403
- name: account.name,
404
- enabled: account.enabled,
405
- configured: account.configured,
406
- baseUrl: account.homeserver,
407
- running: runtime?.running ?? false,
408
- lastStartAt: runtime?.lastStartAt ?? null,
409
- lastStopAt: runtime?.lastStopAt ?? null,
410
- lastError: runtime?.lastError ?? null,
411
- probe,
412
- lastProbeAt: runtime?.lastProbeAt ?? null,
413
- lastInboundAt: runtime?.lastInboundAt ?? null,
414
- lastOutboundAt: runtime?.lastOutboundAt ?? null,
415
- }),
416
- },
417
- gateway: {
418
- startAccount: async (ctx) => {
419
- const account = ctx.account;
420
- ctx.setStatus({
421
- accountId: account.accountId,
422
- baseUrl: account.homeserver,
423
- });
424
- ctx.log?.info(`[${account.accountId}] starting provider (${account.homeserver ?? "matrix"})`);
425
-
426
- // Serialize startup: wait for any previous startup to complete import phase.
427
- // This works around a race condition with concurrent dynamic imports.
428
- //
429
- // INVARIANT: The import() below cannot hang because:
430
- // 1. It only loads local ESM modules with no circular awaits
431
- // 2. Module initialization is synchronous (no top-level await in ./matrix/index.js)
432
- // 3. The lock only serializes the import phase, not the provider startup
433
- const previousLock = matrixStartupLock;
434
- let releaseLock: () => void = () => {};
435
- matrixStartupLock = new Promise<void>((resolve) => {
436
- releaseLock = resolve;
437
- });
438
- await previousLock;
439
-
440
- // Lazy import: the monitor pulls the reply pipeline; avoid ESM init cycles.
441
- // Wrap in try/finally to ensure lock is released even if import fails.
442
- let monitorMatrixProvider: typeof import("./matrix/index.js").monitorMatrixProvider;
443
- try {
444
- const module = await import("./matrix/index.js");
445
- monitorMatrixProvider = module.monitorMatrixProvider;
446
- } finally {
447
- // Release lock after import completes or fails
448
- releaseLock();
449
- }
450
-
451
- return monitorMatrixProvider({
452
- runtime: ctx.runtime,
453
- abortSignal: ctx.abortSignal,
454
- mediaMaxMb: account.config.mediaMaxMb,
455
- initialSyncLimit: account.config.initialSyncLimit,
456
- replyToMode: account.config.replyToMode,
457
- accountId: account.accountId,
458
- });
459
- },
460
- },
461
- };
@@ -1,26 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { MatrixConfigSchema } from "./config-schema.js";
3
-
4
- describe("MatrixConfigSchema SecretInput", () => {
5
- it("accepts SecretRef password at top-level", () => {
6
- const result = MatrixConfigSchema.safeParse({
7
- homeserver: "https://matrix.example.org",
8
- userId: "@bot:example.org",
9
- password: { source: "env", provider: "default", id: "MATRIX_PASSWORD" },
10
- });
11
- expect(result.success).toBe(true);
12
- });
13
-
14
- it("accepts SecretRef password on account", () => {
15
- const result = MatrixConfigSchema.safeParse({
16
- accounts: {
17
- work: {
18
- homeserver: "https://matrix.example.org",
19
- userId: "@bot:example.org",
20
- password: { source: "env", provider: "default", id: "MATRIX_WORK_PASSWORD" },
21
- },
22
- },
23
- });
24
- expect(result.success).toBe(true);
25
- });
26
- });
@@ -1,62 +0,0 @@
1
- import {
2
- AllowFromListSchema,
3
- buildNestedDmConfigSchema,
4
- DmPolicySchema,
5
- GroupPolicySchema,
6
- } from "openclaw/plugin-sdk/compat";
7
- import { MarkdownConfigSchema, ToolPolicySchema } from "openclaw/plugin-sdk/matrix";
8
- import { z } from "zod";
9
- import { buildSecretInputSchema } from "./secret-input.js";
10
-
11
- const matrixActionSchema = z
12
- .object({
13
- reactions: z.boolean().optional(),
14
- messages: z.boolean().optional(),
15
- pins: z.boolean().optional(),
16
- memberInfo: z.boolean().optional(),
17
- channelInfo: z.boolean().optional(),
18
- })
19
- .optional();
20
-
21
- const matrixRoomSchema = z
22
- .object({
23
- enabled: z.boolean().optional(),
24
- allow: z.boolean().optional(),
25
- requireMention: z.boolean().optional(),
26
- tools: ToolPolicySchema,
27
- autoReply: z.boolean().optional(),
28
- users: AllowFromListSchema,
29
- skills: z.array(z.string()).optional(),
30
- systemPrompt: z.string().optional(),
31
- })
32
- .optional();
33
-
34
- export const MatrixConfigSchema = z.object({
35
- name: z.string().optional(),
36
- enabled: z.boolean().optional(),
37
- defaultAccount: z.string().optional(),
38
- accounts: z.record(z.string(), z.unknown()).optional(),
39
- markdown: MarkdownConfigSchema,
40
- homeserver: z.string().optional(),
41
- userId: z.string().optional(),
42
- accessToken: z.string().optional(),
43
- password: buildSecretInputSchema().optional(),
44
- deviceName: z.string().optional(),
45
- initialSyncLimit: z.number().optional(),
46
- encryption: z.boolean().optional(),
47
- allowlistOnly: z.boolean().optional(),
48
- groupPolicy: GroupPolicySchema.optional(),
49
- replyToMode: z.enum(["off", "first", "all"]).optional(),
50
- threadReplies: z.enum(["off", "inbound", "always"]).optional(),
51
- textChunkLimit: z.number().optional(),
52
- chunkMode: z.enum(["length", "newline"]).optional(),
53
- responsePrefix: z.string().optional(),
54
- mediaMaxMb: z.number().optional(),
55
- autoJoin: z.enum(["always", "allowlist", "off"]).optional(),
56
- autoJoinAllowlist: AllowFromListSchema,
57
- groupAllowFrom: AllowFromListSchema,
58
- dm: buildNestedDmConfigSchema(),
59
- groups: z.object({}).catchall(matrixRoomSchema).optional(),
60
- rooms: z.object({}).catchall(matrixRoomSchema).optional(),
61
- actions: matrixActionSchema,
62
- });
@@ -1,85 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
- import { listMatrixDirectoryGroupsLive, listMatrixDirectoryPeersLive } from "./directory-live.js";
3
- import { resolveMatrixAuth } from "./matrix/client.js";
4
-
5
- vi.mock("./matrix/client.js", () => ({
6
- resolveMatrixAuth: vi.fn(),
7
- }));
8
-
9
- describe("matrix directory live", () => {
10
- const cfg = { channels: { matrix: {} } };
11
-
12
- beforeEach(() => {
13
- vi.mocked(resolveMatrixAuth).mockReset();
14
- vi.mocked(resolveMatrixAuth).mockResolvedValue({
15
- homeserver: "https://matrix.example.org",
16
- userId: "@bot:example.org",
17
- accessToken: "test-token",
18
- });
19
- vi.stubGlobal(
20
- "fetch",
21
- vi.fn().mockResolvedValue({
22
- ok: true,
23
- json: async () => ({ results: [] }),
24
- text: async () => "",
25
- }),
26
- );
27
- });
28
-
29
- afterEach(() => {
30
- vi.unstubAllGlobals();
31
- });
32
-
33
- it("passes accountId to peer directory auth resolution", async () => {
34
- await listMatrixDirectoryPeersLive({
35
- cfg,
36
- accountId: "assistant",
37
- query: "alice",
38
- limit: 10,
39
- });
40
-
41
- expect(resolveMatrixAuth).toHaveBeenCalledWith({ cfg, accountId: "assistant" });
42
- });
43
-
44
- it("passes accountId to group directory auth resolution", async () => {
45
- await listMatrixDirectoryGroupsLive({
46
- cfg,
47
- accountId: "assistant",
48
- query: "!room:example.org",
49
- limit: 10,
50
- });
51
-
52
- expect(resolveMatrixAuth).toHaveBeenCalledWith({ cfg, accountId: "assistant" });
53
- });
54
-
55
- it("returns no peer results for empty query without resolving auth", async () => {
56
- const result = await listMatrixDirectoryPeersLive({
57
- cfg,
58
- query: " ",
59
- });
60
-
61
- expect(result).toEqual([]);
62
- expect(resolveMatrixAuth).not.toHaveBeenCalled();
63
- });
64
-
65
- it("returns no group results for empty query without resolving auth", async () => {
66
- const result = await listMatrixDirectoryGroupsLive({
67
- cfg,
68
- query: "",
69
- });
70
-
71
- expect(result).toEqual([]);
72
- expect(resolveMatrixAuth).not.toHaveBeenCalled();
73
- });
74
-
75
- it("preserves original casing for room IDs without :server suffix", async () => {
76
- const mixedCaseId = "!EonMPPbOuhntHEHgZ2dnBO-c_EglMaXlIh2kdo8cgiA";
77
- const result = await listMatrixDirectoryGroupsLive({
78
- cfg,
79
- query: mixedCaseId,
80
- });
81
-
82
- expect(result).toHaveLength(1);
83
- expect(result[0].id).toBe(mixedCaseId);
84
- });
85
- });