@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/onboarding.ts DELETED
@@ -1,462 +0,0 @@
1
- import type { DmPolicy } from "openclaw/plugin-sdk/matrix";
2
- import {
3
- addWildcardAllowFrom,
4
- buildSingleChannelSecretPromptState,
5
- formatResolvedUnresolvedNote,
6
- formatDocsLink,
7
- hasConfiguredSecretInput,
8
- mergeAllowFromEntries,
9
- promptSingleChannelSecretInput,
10
- promptChannelAccessConfig,
11
- setTopLevelChannelGroupPolicy,
12
- type SecretInput,
13
- type ChannelOnboardingAdapter,
14
- type ChannelOnboardingDmPolicy,
15
- type WizardPrompter,
16
- } from "openclaw/plugin-sdk/matrix";
17
- import { listMatrixDirectoryGroupsLive } from "./directory-live.js";
18
- import { resolveMatrixAccount } from "./matrix/accounts.js";
19
- import { ensureMatrixSdkInstalled, isMatrixSdkAvailable } from "./matrix/deps.js";
20
- import { resolveMatrixTargets } from "./resolve-targets.js";
21
- import type { CoreConfig } from "./types.js";
22
-
23
- const channel = "matrix" as const;
24
-
25
- function setMatrixDmPolicy(cfg: CoreConfig, policy: DmPolicy) {
26
- const allowFrom =
27
- policy === "open" ? addWildcardAllowFrom(cfg.channels?.matrix?.dm?.allowFrom) : undefined;
28
- return {
29
- ...cfg,
30
- channels: {
31
- ...cfg.channels,
32
- matrix: {
33
- ...cfg.channels?.matrix,
34
- dm: {
35
- ...cfg.channels?.matrix?.dm,
36
- policy,
37
- ...(allowFrom ? { allowFrom } : {}),
38
- },
39
- },
40
- },
41
- };
42
- }
43
-
44
- async function noteMatrixAuthHelp(prompter: WizardPrompter): Promise<void> {
45
- await prompter.note(
46
- [
47
- "Matrix requires a homeserver URL.",
48
- "Use an access token (recommended) or a password (logs in and stores a token).",
49
- "With access token: user ID is fetched automatically.",
50
- "Env vars supported: MATRIX_HOMESERVER, MATRIX_USER_ID, MATRIX_ACCESS_TOKEN, MATRIX_PASSWORD.",
51
- `Docs: ${formatDocsLink("/channels/matrix", "channels/matrix")}`,
52
- ].join("\n"),
53
- "Matrix setup",
54
- );
55
- }
56
-
57
- async function promptMatrixAllowFrom(params: {
58
- cfg: CoreConfig;
59
- prompter: WizardPrompter;
60
- }): Promise<CoreConfig> {
61
- const { cfg, prompter } = params;
62
- const existingAllowFrom = cfg.channels?.matrix?.dm?.allowFrom ?? [];
63
- const account = resolveMatrixAccount({ cfg });
64
- const canResolve = Boolean(account.configured);
65
-
66
- const parseInput = (raw: string) =>
67
- raw
68
- .split(/[\n,;]+/g)
69
- .map((entry) => entry.trim())
70
- .filter(Boolean);
71
-
72
- const isFullUserId = (value: string) => value.startsWith("@") && value.includes(":");
73
-
74
- while (true) {
75
- const entry = await prompter.text({
76
- message: "Matrix allowFrom (full @user:server; display name only if unique)",
77
- placeholder: "@user:server",
78
- initialValue: existingAllowFrom[0] ? String(existingAllowFrom[0]) : undefined,
79
- validate: (value) => (String(value ?? "").trim() ? undefined : "Required"),
80
- });
81
- const parts = parseInput(String(entry));
82
- const resolvedIds: string[] = [];
83
- const pending: string[] = [];
84
- const unresolved: string[] = [];
85
- const unresolvedNotes: string[] = [];
86
-
87
- for (const part of parts) {
88
- if (isFullUserId(part)) {
89
- resolvedIds.push(part);
90
- continue;
91
- }
92
- if (!canResolve) {
93
- unresolved.push(part);
94
- continue;
95
- }
96
- pending.push(part);
97
- }
98
-
99
- if (pending.length > 0) {
100
- const results = await resolveMatrixTargets({
101
- cfg,
102
- inputs: pending,
103
- kind: "user",
104
- }).catch(() => []);
105
- for (const result of results) {
106
- if (result?.resolved && result.id) {
107
- resolvedIds.push(result.id);
108
- continue;
109
- }
110
- if (result?.input) {
111
- unresolved.push(result.input);
112
- if (result.note) {
113
- unresolvedNotes.push(`${result.input}: ${result.note}`);
114
- }
115
- }
116
- }
117
- }
118
-
119
- if (unresolved.length > 0) {
120
- const details = unresolvedNotes.length > 0 ? unresolvedNotes : unresolved;
121
- await prompter.note(
122
- `Could not resolve:\n${details.join("\n")}\nUse full @user:server IDs.`,
123
- "Matrix allowlist",
124
- );
125
- continue;
126
- }
127
-
128
- const unique = mergeAllowFromEntries(existingAllowFrom, resolvedIds);
129
- return {
130
- ...cfg,
131
- channels: {
132
- ...cfg.channels,
133
- matrix: {
134
- ...cfg.channels?.matrix,
135
- enabled: true,
136
- dm: {
137
- ...cfg.channels?.matrix?.dm,
138
- policy: "allowlist",
139
- allowFrom: unique,
140
- },
141
- },
142
- },
143
- };
144
- }
145
- }
146
-
147
- function setMatrixGroupPolicy(cfg: CoreConfig, groupPolicy: "open" | "allowlist" | "disabled") {
148
- return setTopLevelChannelGroupPolicy({
149
- cfg,
150
- channel: "matrix",
151
- groupPolicy,
152
- enabled: true,
153
- }) as CoreConfig;
154
- }
155
-
156
- function setMatrixGroupRooms(cfg: CoreConfig, roomKeys: string[]) {
157
- const groups = Object.fromEntries(roomKeys.map((key) => [key, { allow: true }]));
158
- return {
159
- ...cfg,
160
- channels: {
161
- ...cfg.channels,
162
- matrix: {
163
- ...cfg.channels?.matrix,
164
- enabled: true,
165
- groups,
166
- },
167
- },
168
- };
169
- }
170
-
171
- const dmPolicy: ChannelOnboardingDmPolicy = {
172
- label: "Matrix",
173
- channel,
174
- policyKey: "channels.matrix.dm.policy",
175
- allowFromKey: "channels.matrix.dm.allowFrom",
176
- getCurrent: (cfg) => (cfg as CoreConfig).channels?.matrix?.dm?.policy ?? "pairing",
177
- setPolicy: (cfg, policy) => setMatrixDmPolicy(cfg as CoreConfig, policy),
178
- promptAllowFrom: promptMatrixAllowFrom,
179
- };
180
-
181
- export const matrixOnboardingAdapter: ChannelOnboardingAdapter = {
182
- channel,
183
- getStatus: async ({ cfg }) => {
184
- const account = resolveMatrixAccount({ cfg: cfg as CoreConfig });
185
- const configured = account.configured;
186
- const sdkReady = isMatrixSdkAvailable();
187
- return {
188
- channel,
189
- configured,
190
- statusLines: [
191
- `Matrix: ${configured ? "configured" : "needs homeserver + access token or password"}`,
192
- ],
193
- selectionHint: !sdkReady
194
- ? "install @vector-im/matrix-bot-sdk"
195
- : configured
196
- ? "configured"
197
- : "needs auth",
198
- };
199
- },
200
- configure: async ({ cfg, runtime, prompter, forceAllowFrom }) => {
201
- let next = cfg as CoreConfig;
202
- await ensureMatrixSdkInstalled({
203
- runtime,
204
- confirm: async (message) =>
205
- await prompter.confirm({
206
- message,
207
- initialValue: true,
208
- }),
209
- });
210
- const existing = next.channels?.matrix ?? {};
211
- const account = resolveMatrixAccount({ cfg: next });
212
- if (!account.configured) {
213
- await noteMatrixAuthHelp(prompter);
214
- }
215
-
216
- const envHomeserver = process.env.MATRIX_HOMESERVER?.trim();
217
- const envUserId = process.env.MATRIX_USER_ID?.trim();
218
- const envAccessToken = process.env.MATRIX_ACCESS_TOKEN?.trim();
219
- const envPassword = process.env.MATRIX_PASSWORD?.trim();
220
- const envReady = Boolean(envHomeserver && (envAccessToken || (envUserId && envPassword)));
221
-
222
- if (
223
- envReady &&
224
- !existing.homeserver &&
225
- !existing.userId &&
226
- !existing.accessToken &&
227
- !existing.password
228
- ) {
229
- const useEnv = await prompter.confirm({
230
- message: "Matrix env vars detected. Use env values?",
231
- initialValue: true,
232
- });
233
- if (useEnv) {
234
- next = {
235
- ...next,
236
- channels: {
237
- ...next.channels,
238
- matrix: {
239
- ...next.channels?.matrix,
240
- enabled: true,
241
- },
242
- },
243
- };
244
- if (forceAllowFrom) {
245
- next = await promptMatrixAllowFrom({ cfg: next, prompter });
246
- }
247
- return { cfg: next };
248
- }
249
- }
250
-
251
- const homeserver = String(
252
- await prompter.text({
253
- message: "Matrix homeserver URL",
254
- initialValue: existing.homeserver ?? envHomeserver,
255
- validate: (value) => {
256
- const raw = String(value ?? "").trim();
257
- if (!raw) {
258
- return "Required";
259
- }
260
- if (!/^https?:\/\//i.test(raw)) {
261
- return "Use a full URL (https://...)";
262
- }
263
- return undefined;
264
- },
265
- }),
266
- ).trim();
267
-
268
- let accessToken = existing.accessToken ?? "";
269
- let password: SecretInput | undefined = existing.password;
270
- let userId = existing.userId ?? "";
271
- const existingPasswordConfigured = hasConfiguredSecretInput(existing.password);
272
- const passwordConfigured = () => hasConfiguredSecretInput(password);
273
-
274
- if (accessToken || passwordConfigured()) {
275
- const keep = await prompter.confirm({
276
- message: "Matrix credentials already configured. Keep them?",
277
- initialValue: true,
278
- });
279
- if (!keep) {
280
- accessToken = "";
281
- password = undefined;
282
- userId = "";
283
- }
284
- }
285
-
286
- if (!accessToken && !passwordConfigured()) {
287
- // Ask auth method FIRST before asking for user ID
288
- const authMode = await prompter.select({
289
- message: "Matrix auth method",
290
- options: [
291
- { value: "token", label: "Access token (user ID fetched automatically)" },
292
- { value: "password", label: "Password (requires user ID)" },
293
- ],
294
- });
295
-
296
- if (authMode === "token") {
297
- accessToken = String(
298
- await prompter.text({
299
- message: "Matrix access token",
300
- validate: (value) => (value?.trim() ? undefined : "Required"),
301
- }),
302
- ).trim();
303
- // With access token, we can fetch the userId automatically - don't prompt for it
304
- // The client.ts will use whoami() to get it
305
- userId = "";
306
- } else {
307
- // Password auth requires user ID upfront
308
- userId = String(
309
- await prompter.text({
310
- message: "Matrix user ID",
311
- initialValue: existing.userId ?? envUserId,
312
- validate: (value) => {
313
- const raw = String(value ?? "").trim();
314
- if (!raw) {
315
- return "Required";
316
- }
317
- if (!raw.startsWith("@")) {
318
- return "Matrix user IDs should start with @";
319
- }
320
- if (!raw.includes(":")) {
321
- return "Matrix user IDs should include a server (:server)";
322
- }
323
- return undefined;
324
- },
325
- }),
326
- ).trim();
327
- const passwordPromptState = buildSingleChannelSecretPromptState({
328
- accountConfigured: Boolean(existingPasswordConfigured),
329
- hasConfigToken: existingPasswordConfigured,
330
- allowEnv: true,
331
- envValue: envPassword,
332
- });
333
- const passwordResult = await promptSingleChannelSecretInput({
334
- cfg: next,
335
- prompter,
336
- providerHint: "matrix",
337
- credentialLabel: "password",
338
- accountConfigured: passwordPromptState.accountConfigured,
339
- canUseEnv: passwordPromptState.canUseEnv,
340
- hasConfigToken: passwordPromptState.hasConfigToken,
341
- envPrompt: "MATRIX_PASSWORD detected. Use env var?",
342
- keepPrompt: "Matrix password already configured. Keep it?",
343
- inputPrompt: "Matrix password",
344
- preferredEnvVar: "MATRIX_PASSWORD",
345
- });
346
- if (passwordResult.action === "set") {
347
- password = passwordResult.value;
348
- }
349
- if (passwordResult.action === "use-env") {
350
- password = undefined;
351
- }
352
- }
353
- }
354
-
355
- const deviceName = String(
356
- await prompter.text({
357
- message: "Matrix device name (optional)",
358
- initialValue: existing.deviceName ?? "OpenClaw Gateway",
359
- }),
360
- ).trim();
361
-
362
- // Ask about E2EE encryption
363
- const enableEncryption = await prompter.confirm({
364
- message: "Enable end-to-end encryption (E2EE)?",
365
- initialValue: existing.encryption ?? false,
366
- });
367
-
368
- next = {
369
- ...next,
370
- channels: {
371
- ...next.channels,
372
- matrix: {
373
- ...next.channels?.matrix,
374
- enabled: true,
375
- homeserver,
376
- userId: userId || undefined,
377
- accessToken: accessToken || undefined,
378
- password: password,
379
- deviceName: deviceName || undefined,
380
- encryption: enableEncryption || undefined,
381
- },
382
- },
383
- };
384
-
385
- if (forceAllowFrom) {
386
- next = await promptMatrixAllowFrom({ cfg: next, prompter });
387
- }
388
-
389
- const existingGroups = next.channels?.matrix?.groups ?? next.channels?.matrix?.rooms;
390
- const accessConfig = await promptChannelAccessConfig({
391
- prompter,
392
- label: "Matrix rooms",
393
- currentPolicy: next.channels?.matrix?.groupPolicy ?? "allowlist",
394
- currentEntries: Object.keys(existingGroups ?? {}),
395
- placeholder: "!roomId:server, #alias:server, Project Room",
396
- updatePrompt: Boolean(existingGroups),
397
- });
398
- if (accessConfig) {
399
- if (accessConfig.policy !== "allowlist") {
400
- next = setMatrixGroupPolicy(next, accessConfig.policy);
401
- } else {
402
- let roomKeys = accessConfig.entries;
403
- if (accessConfig.entries.length > 0) {
404
- try {
405
- const resolvedIds: string[] = [];
406
- const unresolved: string[] = [];
407
- for (const entry of accessConfig.entries) {
408
- const trimmed = entry.trim();
409
- if (!trimmed) {
410
- continue;
411
- }
412
- const cleaned = trimmed.replace(/^(room|channel):/i, "").trim();
413
- if (cleaned.startsWith("!") && cleaned.includes(":")) {
414
- resolvedIds.push(cleaned);
415
- continue;
416
- }
417
- const matches = await listMatrixDirectoryGroupsLive({
418
- cfg: next,
419
- query: trimmed,
420
- limit: 10,
421
- });
422
- const exact = matches.find(
423
- (match) => (match.name ?? "").toLowerCase() === trimmed.toLowerCase(),
424
- );
425
- const best = exact ?? matches[0];
426
- if (best?.id) {
427
- resolvedIds.push(best.id);
428
- } else {
429
- unresolved.push(entry);
430
- }
431
- }
432
- roomKeys = [...resolvedIds, ...unresolved.map((entry) => entry.trim()).filter(Boolean)];
433
- const resolution = formatResolvedUnresolvedNote({
434
- resolved: resolvedIds,
435
- unresolved,
436
- });
437
- if (resolution) {
438
- await prompter.note(resolution, "Matrix rooms");
439
- }
440
- } catch (err) {
441
- await prompter.note(
442
- `Room lookup failed; keeping entries as typed. ${String(err)}`,
443
- "Matrix rooms",
444
- );
445
- }
446
- }
447
- next = setMatrixGroupPolicy(next, "allowlist");
448
- next = setMatrixGroupRooms(next, roomKeys);
449
- }
450
- }
451
-
452
- return { cfg: next };
453
- },
454
- dmPolicy,
455
- disable: (cfg) => ({
456
- ...(cfg as CoreConfig),
457
- channels: {
458
- ...(cfg as CoreConfig).channels,
459
- matrix: { ...(cfg as CoreConfig).channels?.matrix, enabled: false },
460
- },
461
- }),
462
- };
@@ -1,159 +0,0 @@
1
- import type { OpenClawConfig } from "openclaw/plugin-sdk/matrix";
2
- import { beforeEach, describe, expect, it, vi } from "vitest";
3
-
4
- const mocks = vi.hoisted(() => ({
5
- sendMessageMatrix: vi.fn(),
6
- sendPollMatrix: vi.fn(),
7
- }));
8
-
9
- vi.mock("./matrix/send.js", () => ({
10
- sendMessageMatrix: mocks.sendMessageMatrix,
11
- sendPollMatrix: mocks.sendPollMatrix,
12
- }));
13
-
14
- vi.mock("./runtime.js", () => ({
15
- getMatrixRuntime: () => ({
16
- channel: {
17
- text: {
18
- chunkMarkdownText: (text: string) => [text],
19
- },
20
- },
21
- }),
22
- }));
23
-
24
- import { matrixOutbound } from "./outbound.js";
25
-
26
- describe("matrixOutbound cfg threading", () => {
27
- beforeEach(() => {
28
- mocks.sendMessageMatrix.mockReset();
29
- mocks.sendPollMatrix.mockReset();
30
- mocks.sendMessageMatrix.mockResolvedValue({ messageId: "evt-1", roomId: "!room:example" });
31
- mocks.sendPollMatrix.mockResolvedValue({ eventId: "$poll", roomId: "!room:example" });
32
- });
33
-
34
- it("passes resolved cfg to sendMessageMatrix for text sends", async () => {
35
- const cfg = {
36
- channels: {
37
- matrix: {
38
- accessToken: "resolved-token",
39
- },
40
- },
41
- } as OpenClawConfig;
42
-
43
- await matrixOutbound.sendText!({
44
- cfg,
45
- to: "room:!room:example",
46
- text: "hello",
47
- accountId: "default",
48
- threadId: "$thread",
49
- replyToId: "$reply",
50
- });
51
-
52
- expect(mocks.sendMessageMatrix).toHaveBeenCalledWith(
53
- "room:!room:example",
54
- "hello",
55
- expect.objectContaining({
56
- cfg,
57
- accountId: "default",
58
- threadId: "$thread",
59
- replyToId: "$reply",
60
- }),
61
- );
62
- });
63
-
64
- it("passes resolved cfg to sendMessageMatrix for media sends", async () => {
65
- const cfg = {
66
- channels: {
67
- matrix: {
68
- accessToken: "resolved-token",
69
- },
70
- },
71
- } as OpenClawConfig;
72
-
73
- await matrixOutbound.sendMedia!({
74
- cfg,
75
- to: "room:!room:example",
76
- text: "caption",
77
- mediaUrl: "file:///tmp/cat.png",
78
- accountId: "default",
79
- });
80
-
81
- expect(mocks.sendMessageMatrix).toHaveBeenCalledWith(
82
- "room:!room:example",
83
- "caption",
84
- expect.objectContaining({
85
- cfg,
86
- mediaUrl: "file:///tmp/cat.png",
87
- }),
88
- );
89
- });
90
-
91
- it("passes resolved cfg through injected deps.sendMatrix", async () => {
92
- const cfg = {
93
- channels: {
94
- matrix: {
95
- accessToken: "resolved-token",
96
- },
97
- },
98
- } as OpenClawConfig;
99
- const sendMatrix = vi.fn(async () => ({
100
- messageId: "evt-injected",
101
- roomId: "!room:example",
102
- }));
103
-
104
- await matrixOutbound.sendText!({
105
- cfg,
106
- to: "room:!room:example",
107
- text: "hello via deps",
108
- deps: { sendMatrix },
109
- accountId: "default",
110
- threadId: "$thread",
111
- replyToId: "$reply",
112
- });
113
-
114
- expect(sendMatrix).toHaveBeenCalledWith(
115
- "room:!room:example",
116
- "hello via deps",
117
- expect.objectContaining({
118
- cfg,
119
- accountId: "default",
120
- threadId: "$thread",
121
- replyToId: "$reply",
122
- }),
123
- );
124
- });
125
-
126
- it("passes resolved cfg to sendPollMatrix", async () => {
127
- const cfg = {
128
- channels: {
129
- matrix: {
130
- accessToken: "resolved-token",
131
- },
132
- },
133
- } as OpenClawConfig;
134
-
135
- await matrixOutbound.sendPoll!({
136
- cfg,
137
- to: "room:!room:example",
138
- poll: {
139
- question: "Snack?",
140
- options: ["Pizza", "Sushi"],
141
- },
142
- accountId: "default",
143
- threadId: "$thread",
144
- });
145
-
146
- expect(mocks.sendPollMatrix).toHaveBeenCalledWith(
147
- "room:!room:example",
148
- expect.objectContaining({
149
- question: "Snack?",
150
- options: ["Pizza", "Sushi"],
151
- }),
152
- expect.objectContaining({
153
- cfg,
154
- accountId: "default",
155
- threadId: "$thread",
156
- }),
157
- );
158
- });
159
- });
package/src/outbound.ts DELETED
@@ -1,58 +0,0 @@
1
- import type { ChannelOutboundAdapter } from "openclaw/plugin-sdk/matrix";
2
- import { sendMessageMatrix, sendPollMatrix } from "./matrix/send.js";
3
- import { getMatrixRuntime } from "./runtime.js";
4
-
5
- export const matrixOutbound: ChannelOutboundAdapter = {
6
- deliveryMode: "direct",
7
- chunker: (text, limit) => getMatrixRuntime().channel.text.chunkMarkdownText(text, limit),
8
- chunkerMode: "markdown",
9
- textChunkLimit: 4000,
10
- sendText: async ({ cfg, to, text, deps, replyToId, threadId, accountId }) => {
11
- const send = deps?.sendMatrix ?? sendMessageMatrix;
12
- const resolvedThreadId =
13
- threadId !== undefined && threadId !== null ? String(threadId) : undefined;
14
- const result = await send(to, text, {
15
- cfg,
16
- replyToId: replyToId ?? undefined,
17
- threadId: resolvedThreadId,
18
- accountId: accountId ?? undefined,
19
- });
20
- return {
21
- channel: "matrix",
22
- messageId: result.messageId,
23
- roomId: result.roomId,
24
- };
25
- },
26
- sendMedia: async ({ cfg, to, text, mediaUrl, deps, replyToId, threadId, accountId }) => {
27
- const send = deps?.sendMatrix ?? sendMessageMatrix;
28
- const resolvedThreadId =
29
- threadId !== undefined && threadId !== null ? String(threadId) : undefined;
30
- const result = await send(to, text, {
31
- cfg,
32
- mediaUrl,
33
- replyToId: replyToId ?? undefined,
34
- threadId: resolvedThreadId,
35
- accountId: accountId ?? undefined,
36
- });
37
- return {
38
- channel: "matrix",
39
- messageId: result.messageId,
40
- roomId: result.roomId,
41
- };
42
- },
43
- sendPoll: async ({ cfg, to, poll, threadId, accountId }) => {
44
- const resolvedThreadId =
45
- threadId !== undefined && threadId !== null ? String(threadId) : undefined;
46
- const result = await sendPollMatrix(to, poll, {
47
- cfg,
48
- threadId: resolvedThreadId,
49
- accountId: accountId ?? undefined,
50
- });
51
- return {
52
- channel: "matrix",
53
- messageId: result.eventId,
54
- roomId: result.roomId,
55
- pollId: result.eventId,
56
- };
57
- },
58
- };