@openclaw/matrix 2026.3.13 → 2026.5.10-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 (206) 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-H_6lMgwf.js +1116 -0
  15. package/dist/channel-plugin-api.js +2 -0
  16. package/dist/channel.runtime-BnO9f0pR.js +246 -0
  17. package/dist/cli-CYZ9yVcB.js +1340 -0
  18. package/dist/cli-metadata-DPIHnoa6.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-BaRCKyLd.js +4175 -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-DTKcXOhp.js +24 -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-DQXjgNLt.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-ThYhfHtZ.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 +796 -1
  112. package/package.json +82 -16
  113. package/CHANGELOG.md +0 -104
  114. package/index.ts +0 -22
  115. package/src/actions.ts +0 -195
  116. package/src/channel.directory.test.ts +0 -135
  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 -94
  160. package/src/matrix/monitor/auto-join.ts +0 -72
  161. package/src/matrix/monitor/direct.test.ts +0 -396
  162. package/src/matrix/monitor/direct.ts +0 -152
  163. package/src/matrix/monitor/events.test.ts +0 -186
  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 -768
  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 -145
  194. package/src/matrix/send-queue.ts +0 -28
  195. package/src/matrix/send.test.ts +0 -319
  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 -68
  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/test-mocks.ts +0 -53
  205. package/src/tool-actions.ts +0 -164
  206. package/src/types.ts +0 -118
@@ -1,73 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import {
3
- resolveMatrixBodyForAgent,
4
- resolveMatrixInboundSenderLabel,
5
- resolveMatrixSenderUsername,
6
- } from "./inbound-body.js";
7
-
8
- describe("resolveMatrixSenderUsername", () => {
9
- it("extracts localpart without leading @", () => {
10
- expect(resolveMatrixSenderUsername("@bu:matrix.example.org")).toBe("bu");
11
- });
12
- });
13
-
14
- describe("resolveMatrixInboundSenderLabel", () => {
15
- it("uses provided senderUsername when present", () => {
16
- expect(
17
- resolveMatrixInboundSenderLabel({
18
- senderName: "Bu",
19
- senderId: "@bu:matrix.example.org",
20
- senderUsername: "BU_CUSTOM",
21
- }),
22
- ).toBe("Bu (BU_CUSTOM)");
23
- });
24
-
25
- it("includes sender username when it differs from display name", () => {
26
- expect(
27
- resolveMatrixInboundSenderLabel({
28
- senderName: "Bu",
29
- senderId: "@bu:matrix.example.org",
30
- }),
31
- ).toBe("Bu (bu)");
32
- });
33
-
34
- it("falls back to sender username when display name is blank", () => {
35
- expect(
36
- resolveMatrixInboundSenderLabel({
37
- senderName: " ",
38
- senderId: "@zhang:matrix.example.org",
39
- }),
40
- ).toBe("zhang");
41
- });
42
-
43
- it("falls back to sender id when username cannot be parsed", () => {
44
- expect(
45
- resolveMatrixInboundSenderLabel({
46
- senderName: "",
47
- senderId: "matrix-user-without-colon",
48
- }),
49
- ).toBe("matrix-user-without-colon");
50
- });
51
- });
52
-
53
- describe("resolveMatrixBodyForAgent", () => {
54
- it("keeps direct message body unchanged", () => {
55
- expect(
56
- resolveMatrixBodyForAgent({
57
- isDirectMessage: true,
58
- bodyText: "show me my commits",
59
- senderLabel: "Bu (bu)",
60
- }),
61
- ).toBe("show me my commits");
62
- });
63
-
64
- it("prefixes non-direct message body with sender label", () => {
65
- expect(
66
- resolveMatrixBodyForAgent({
67
- isDirectMessage: false,
68
- bodyText: "show me my commits",
69
- senderLabel: "Bu (bu)",
70
- }),
71
- ).toBe("Bu (bu): show me my commits");
72
- });
73
- });
@@ -1,28 +0,0 @@
1
- export function resolveMatrixSenderUsername(senderId: string): string | undefined {
2
- const username = senderId.split(":")[0]?.replace(/^@/, "").trim();
3
- return username ? username : undefined;
4
- }
5
-
6
- export function resolveMatrixInboundSenderLabel(params: {
7
- senderName: string;
8
- senderId: string;
9
- senderUsername?: string;
10
- }): string {
11
- const senderName = params.senderName.trim();
12
- const senderUsername = params.senderUsername ?? resolveMatrixSenderUsername(params.senderId);
13
- if (senderName && senderUsername && senderName !== senderUsername) {
14
- return `${senderName} (${senderUsername})`;
15
- }
16
- return senderName || senderUsername || params.senderId;
17
- }
18
-
19
- export function resolveMatrixBodyForAgent(params: {
20
- isDirectMessage: boolean;
21
- bodyText: string;
22
- senderLabel: string;
23
- }): string {
24
- if (params.isDirectMessage) {
25
- return params.bodyText;
26
- }
27
- return `${params.senderLabel}: ${params.bodyText}`;
28
- }
@@ -1,18 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { DEFAULT_STARTUP_GRACE_MS, isConfiguredMatrixRoomEntry } from "./index.js";
3
-
4
- describe("monitorMatrixProvider helpers", () => {
5
- it("treats !-prefixed room IDs as configured room entries", () => {
6
- expect(isConfiguredMatrixRoomEntry("!abc123")).toBe(true);
7
- expect(isConfiguredMatrixRoomEntry("!RoomMixedCase")).toBe(true);
8
- });
9
-
10
- it("requires a homeserver suffix for # aliases", () => {
11
- expect(isConfiguredMatrixRoomEntry("#alias:example.org")).toBe(true);
12
- expect(isConfiguredMatrixRoomEntry("#alias")).toBe(false);
13
- });
14
-
15
- it("uses a non-zero startup grace window", () => {
16
- expect(DEFAULT_STARTUP_GRACE_MS).toBe(5000);
17
- });
18
- });
@@ -1,414 +0,0 @@
1
- import {
2
- GROUP_POLICY_BLOCKED_LABEL,
3
- mergeAllowlist,
4
- resolveRuntimeEnv,
5
- resolveAllowlistProviderRuntimeGroupPolicy,
6
- resolveDefaultGroupPolicy,
7
- summarizeMapping,
8
- warnMissingProviderGroupPolicyFallbackOnce,
9
- type RuntimeEnv,
10
- } from "openclaw/plugin-sdk/matrix";
11
- import { resolveMatrixTargets } from "../../resolve-targets.js";
12
- import { getMatrixRuntime } from "../../runtime.js";
13
- import type { CoreConfig, MatrixConfig, MatrixRoomConfig, ReplyToMode } from "../../types.js";
14
- import { resolveMatrixAccount } from "../accounts.js";
15
- import { setActiveMatrixClient } from "../active-client.js";
16
- import {
17
- isBunRuntime,
18
- resolveMatrixAuth,
19
- resolveSharedMatrixClient,
20
- stopSharedClientForAccount,
21
- } from "../client.js";
22
- import { normalizeMatrixUserId } from "./allowlist.js";
23
- import { registerMatrixAutoJoin } from "./auto-join.js";
24
- import { createDirectRoomTracker } from "./direct.js";
25
- import { registerMatrixMonitorEvents } from "./events.js";
26
- import { createMatrixRoomMessageHandler } from "./handler.js";
27
- import { createMatrixRoomInfoResolver } from "./room-info.js";
28
-
29
- export type MonitorMatrixOpts = {
30
- runtime?: RuntimeEnv;
31
- abortSignal?: AbortSignal;
32
- mediaMaxMb?: number;
33
- initialSyncLimit?: number;
34
- replyToMode?: ReplyToMode;
35
- accountId?: string | null;
36
- };
37
-
38
- const DEFAULT_MEDIA_MAX_MB = 20;
39
- export const DEFAULT_STARTUP_GRACE_MS = 5000;
40
-
41
- export function isConfiguredMatrixRoomEntry(entry: string): boolean {
42
- return entry.startsWith("!") || (entry.startsWith("#") && entry.includes(":"));
43
- }
44
-
45
- function normalizeMatrixUserEntry(raw: string): string {
46
- return raw
47
- .replace(/^matrix:/i, "")
48
- .replace(/^user:/i, "")
49
- .trim();
50
- }
51
-
52
- function normalizeMatrixRoomEntry(raw: string): string {
53
- return raw
54
- .replace(/^matrix:/i, "")
55
- .replace(/^(room|channel):/i, "")
56
- .trim();
57
- }
58
-
59
- function isMatrixUserId(value: string): boolean {
60
- return value.startsWith("@") && value.includes(":");
61
- }
62
-
63
- async function resolveMatrixUserAllowlist(params: {
64
- cfg: CoreConfig;
65
- runtime: RuntimeEnv;
66
- label: string;
67
- list?: Array<string | number>;
68
- }): Promise<string[]> {
69
- let allowList = params.list ?? [];
70
- if (allowList.length === 0) {
71
- return allowList.map(String);
72
- }
73
- const entries = allowList
74
- .map((entry) => normalizeMatrixUserEntry(String(entry)))
75
- .filter((entry) => entry && entry !== "*");
76
- if (entries.length === 0) {
77
- return allowList.map(String);
78
- }
79
- const mapping: string[] = [];
80
- const unresolved: string[] = [];
81
- const additions: string[] = [];
82
- const pending: string[] = [];
83
- for (const entry of entries) {
84
- if (isMatrixUserId(entry)) {
85
- additions.push(normalizeMatrixUserId(entry));
86
- continue;
87
- }
88
- pending.push(entry);
89
- }
90
- if (pending.length > 0) {
91
- const resolved = await resolveMatrixTargets({
92
- cfg: params.cfg,
93
- inputs: pending,
94
- kind: "user",
95
- runtime: params.runtime,
96
- });
97
- for (const entry of resolved) {
98
- if (entry.resolved && entry.id) {
99
- const normalizedId = normalizeMatrixUserId(entry.id);
100
- additions.push(normalizedId);
101
- mapping.push(`${entry.input}→${normalizedId}`);
102
- } else {
103
- unresolved.push(entry.input);
104
- }
105
- }
106
- }
107
- allowList = mergeAllowlist({ existing: allowList, additions });
108
- summarizeMapping(params.label, mapping, unresolved, params.runtime);
109
- if (unresolved.length > 0) {
110
- params.runtime.log?.(
111
- `${params.label} entries must be full Matrix IDs (example: @user:server). Unresolved entries are ignored.`,
112
- );
113
- }
114
- return allowList.map(String);
115
- }
116
-
117
- async function resolveMatrixRoomsConfig(params: {
118
- cfg: CoreConfig;
119
- runtime: RuntimeEnv;
120
- roomsConfig?: Record<string, MatrixRoomConfig>;
121
- }): Promise<Record<string, MatrixRoomConfig> | undefined> {
122
- let roomsConfig = params.roomsConfig;
123
- if (!roomsConfig || Object.keys(roomsConfig).length === 0) {
124
- return roomsConfig;
125
- }
126
- const mapping: string[] = [];
127
- const unresolved: string[] = [];
128
- const nextRooms: Record<string, MatrixRoomConfig> = {};
129
- if (roomsConfig["*"]) {
130
- nextRooms["*"] = roomsConfig["*"];
131
- }
132
- const pending: Array<{ input: string; query: string; config: MatrixRoomConfig }> = [];
133
- for (const [entry, roomConfig] of Object.entries(roomsConfig)) {
134
- if (entry === "*") {
135
- continue;
136
- }
137
- const trimmed = entry.trim();
138
- if (!trimmed) {
139
- continue;
140
- }
141
- const cleaned = normalizeMatrixRoomEntry(trimmed);
142
- if (isConfiguredMatrixRoomEntry(cleaned)) {
143
- if (!nextRooms[cleaned]) {
144
- nextRooms[cleaned] = roomConfig;
145
- }
146
- if (cleaned !== entry) {
147
- mapping.push(`${entry}→${cleaned}`);
148
- }
149
- continue;
150
- }
151
- pending.push({ input: entry, query: trimmed, config: roomConfig });
152
- }
153
- if (pending.length > 0) {
154
- const resolved = await resolveMatrixTargets({
155
- cfg: params.cfg,
156
- inputs: pending.map((entry) => entry.query),
157
- kind: "group",
158
- runtime: params.runtime,
159
- });
160
- resolved.forEach((entry, index) => {
161
- const source = pending[index];
162
- if (!source) {
163
- return;
164
- }
165
- if (entry.resolved && entry.id) {
166
- if (!nextRooms[entry.id]) {
167
- nextRooms[entry.id] = source.config;
168
- }
169
- mapping.push(`${source.input}→${entry.id}`);
170
- } else {
171
- unresolved.push(source.input);
172
- }
173
- });
174
- }
175
- roomsConfig = nextRooms;
176
- summarizeMapping("matrix rooms", mapping, unresolved, params.runtime);
177
- if (unresolved.length > 0) {
178
- params.runtime.log?.(
179
- "matrix rooms must be room IDs or aliases (example: !room:server or #alias:server). Unresolved entries are ignored.",
180
- );
181
- }
182
- if (Object.keys(roomsConfig).length === 0) {
183
- return roomsConfig;
184
- }
185
- const nextRoomsWithUsers = { ...roomsConfig };
186
- for (const [roomKey, roomConfig] of Object.entries(roomsConfig)) {
187
- const users = roomConfig?.users ?? [];
188
- if (users.length === 0) {
189
- continue;
190
- }
191
- const resolvedUsers = await resolveMatrixUserAllowlist({
192
- cfg: params.cfg,
193
- runtime: params.runtime,
194
- label: `matrix room users (${roomKey})`,
195
- list: users,
196
- });
197
- if (resolvedUsers !== users) {
198
- nextRoomsWithUsers[roomKey] = { ...roomConfig, users: resolvedUsers };
199
- }
200
- }
201
- return nextRoomsWithUsers;
202
- }
203
-
204
- async function resolveMatrixMonitorConfig(params: {
205
- cfg: CoreConfig;
206
- runtime: RuntimeEnv;
207
- accountConfig: MatrixConfig;
208
- }): Promise<{
209
- allowFrom: string[];
210
- groupAllowFrom: string[];
211
- roomsConfig?: Record<string, MatrixRoomConfig>;
212
- }> {
213
- const allowFrom = await resolveMatrixUserAllowlist({
214
- cfg: params.cfg,
215
- runtime: params.runtime,
216
- label: "matrix dm allowlist",
217
- list: params.accountConfig.dm?.allowFrom ?? [],
218
- });
219
- const groupAllowFrom = await resolveMatrixUserAllowlist({
220
- cfg: params.cfg,
221
- runtime: params.runtime,
222
- label: "matrix group allowlist",
223
- list: params.accountConfig.groupAllowFrom ?? [],
224
- });
225
- const roomsConfig = await resolveMatrixRoomsConfig({
226
- cfg: params.cfg,
227
- runtime: params.runtime,
228
- roomsConfig: params.accountConfig.groups ?? params.accountConfig.rooms,
229
- });
230
- return { allowFrom, groupAllowFrom, roomsConfig };
231
- }
232
-
233
- export async function monitorMatrixProvider(opts: MonitorMatrixOpts = {}): Promise<void> {
234
- if (isBunRuntime()) {
235
- throw new Error("Matrix provider requires Node (bun runtime not supported)");
236
- }
237
- const core = getMatrixRuntime();
238
- let cfg = core.config.loadConfig() as CoreConfig;
239
- if (cfg.channels?.matrix?.enabled === false) {
240
- return;
241
- }
242
-
243
- const logger = core.logging.getChildLogger({ module: "matrix-auto-reply" });
244
- const runtime: RuntimeEnv = resolveRuntimeEnv({
245
- runtime: opts.runtime,
246
- logger,
247
- });
248
- const logVerboseMessage = (message: string) => {
249
- if (!core.logging.shouldLogVerbose()) {
250
- return;
251
- }
252
- logger.debug?.(message);
253
- };
254
-
255
- // Resolve account-specific config for multi-account support
256
- const account = resolveMatrixAccount({ cfg, accountId: opts.accountId });
257
- const accountConfig = account.config;
258
- const allowlistOnly = accountConfig.allowlistOnly === true;
259
- const { allowFrom, groupAllowFrom, roomsConfig } = await resolveMatrixMonitorConfig({
260
- cfg,
261
- runtime,
262
- accountConfig,
263
- });
264
-
265
- cfg = {
266
- ...cfg,
267
- channels: {
268
- ...cfg.channels,
269
- matrix: {
270
- ...cfg.channels?.matrix,
271
- dm: {
272
- ...cfg.channels?.matrix?.dm,
273
- allowFrom,
274
- },
275
- groupAllowFrom,
276
- ...(roomsConfig ? { groups: roomsConfig } : {}),
277
- },
278
- },
279
- };
280
-
281
- const auth = await resolveMatrixAuth({ cfg, accountId: opts.accountId });
282
- const resolvedInitialSyncLimit =
283
- typeof opts.initialSyncLimit === "number"
284
- ? Math.max(0, Math.floor(opts.initialSyncLimit))
285
- : auth.initialSyncLimit;
286
- const authWithLimit =
287
- resolvedInitialSyncLimit === auth.initialSyncLimit
288
- ? auth
289
- : { ...auth, initialSyncLimit: resolvedInitialSyncLimit };
290
- const client = await resolveSharedMatrixClient({
291
- cfg,
292
- auth: authWithLimit,
293
- startClient: false,
294
- accountId: opts.accountId,
295
- });
296
- setActiveMatrixClient(client, opts.accountId);
297
-
298
- const mentionRegexes = core.channel.mentions.buildMentionRegexes(cfg);
299
- const defaultGroupPolicy = resolveDefaultGroupPolicy(cfg);
300
- const { groupPolicy: groupPolicyRaw, providerMissingFallbackApplied } =
301
- resolveAllowlistProviderRuntimeGroupPolicy({
302
- providerConfigPresent: cfg.channels?.matrix !== undefined,
303
- groupPolicy: accountConfig.groupPolicy,
304
- defaultGroupPolicy,
305
- });
306
- warnMissingProviderGroupPolicyFallbackOnce({
307
- providerMissingFallbackApplied,
308
- providerKey: "matrix",
309
- accountId: account.accountId,
310
- blockedLabel: GROUP_POLICY_BLOCKED_LABEL.room,
311
- log: (message) => logVerboseMessage(message),
312
- });
313
- const groupPolicy = allowlistOnly && groupPolicyRaw === "open" ? "allowlist" : groupPolicyRaw;
314
- const replyToMode = opts.replyToMode ?? accountConfig.replyToMode ?? "off";
315
- const threadReplies = accountConfig.threadReplies ?? "inbound";
316
- const dmConfig = accountConfig.dm;
317
- const dmEnabled = dmConfig?.enabled ?? true;
318
- const dmPolicyRaw = dmConfig?.policy ?? "pairing";
319
- const dmPolicy = allowlistOnly && dmPolicyRaw !== "disabled" ? "allowlist" : dmPolicyRaw;
320
- const textLimit = core.channel.text.resolveTextChunkLimit(cfg, "matrix");
321
- const mediaMaxMb = opts.mediaMaxMb ?? accountConfig.mediaMaxMb ?? DEFAULT_MEDIA_MAX_MB;
322
- const mediaMaxBytes = Math.max(1, mediaMaxMb) * 1024 * 1024;
323
- const startupMs = Date.now();
324
- const startupGraceMs = DEFAULT_STARTUP_GRACE_MS;
325
- const directTracker = createDirectRoomTracker(client, {
326
- log: logVerboseMessage,
327
- includeMemberCountInLogs: core.logging.shouldLogVerbose(),
328
- });
329
- registerMatrixAutoJoin({ client, cfg, runtime });
330
- const warnedEncryptedRooms = new Set<string>();
331
- const warnedCryptoMissingRooms = new Set<string>();
332
-
333
- const { getRoomInfo, getMemberDisplayName } = createMatrixRoomInfoResolver(client);
334
- const handleRoomMessage = createMatrixRoomMessageHandler({
335
- client,
336
- core,
337
- cfg,
338
- runtime,
339
- logger,
340
- logVerboseMessage,
341
- allowFrom,
342
- roomsConfig,
343
- mentionRegexes,
344
- groupPolicy,
345
- replyToMode,
346
- threadReplies,
347
- dmEnabled,
348
- dmPolicy,
349
- textLimit,
350
- mediaMaxBytes,
351
- startupMs,
352
- startupGraceMs,
353
- directTracker,
354
- getRoomInfo,
355
- getMemberDisplayName,
356
- accountId: opts.accountId,
357
- });
358
-
359
- registerMatrixMonitorEvents({
360
- client,
361
- auth,
362
- logVerboseMessage,
363
- warnedEncryptedRooms,
364
- warnedCryptoMissingRooms,
365
- logger,
366
- formatNativeDependencyHint: core.system.formatNativeDependencyHint,
367
- onRoomMessage: handleRoomMessage,
368
- });
369
-
370
- logVerboseMessage("matrix: starting client");
371
- await resolveSharedMatrixClient({
372
- cfg,
373
- auth: authWithLimit,
374
- accountId: opts.accountId,
375
- });
376
- logVerboseMessage("matrix: client started");
377
-
378
- // @vector-im/matrix-bot-sdk client is already started via resolveSharedMatrixClient
379
- logger.info(`matrix: logged in as ${auth.userId}`);
380
-
381
- // If E2EE is enabled, trigger device verification
382
- if (auth.encryption && client.crypto) {
383
- try {
384
- // Request verification from other sessions
385
- const verificationRequest = await (
386
- client.crypto as { requestOwnUserVerification?: () => Promise<unknown> }
387
- ).requestOwnUserVerification?.();
388
- if (verificationRequest) {
389
- logger.info("matrix: device verification requested - please verify in another client");
390
- }
391
- } catch (err) {
392
- logger.debug?.("Device verification request failed (may already be verified)", {
393
- error: String(err),
394
- });
395
- }
396
- }
397
-
398
- await new Promise<void>((resolve) => {
399
- const onAbort = () => {
400
- try {
401
- logVerboseMessage("matrix: stopping client");
402
- stopSharedClientForAccount(auth, opts.accountId);
403
- } finally {
404
- setActiveMatrixClient(null, opts.accountId);
405
- resolve();
406
- }
407
- };
408
- if (opts.abortSignal?.aborted) {
409
- onAbort();
410
- return;
411
- }
412
- opts.abortSignal?.addEventListener("abort", onAbort, { once: true });
413
- });
414
- }
@@ -1,100 +0,0 @@
1
- import type { LocationMessageEventContent } from "@vector-im/matrix-bot-sdk";
2
- import {
3
- formatLocationText,
4
- toLocationContext,
5
- type NormalizedLocation,
6
- } from "openclaw/plugin-sdk/matrix";
7
- import { EventType } from "./types.js";
8
-
9
- export type MatrixLocationPayload = {
10
- text: string;
11
- context: ReturnType<typeof toLocationContext>;
12
- };
13
-
14
- type GeoUriParams = {
15
- latitude: number;
16
- longitude: number;
17
- accuracy?: number;
18
- };
19
-
20
- function parseGeoUri(value: string): GeoUriParams | null {
21
- const trimmed = value.trim();
22
- if (!trimmed) {
23
- return null;
24
- }
25
- if (!trimmed.toLowerCase().startsWith("geo:")) {
26
- return null;
27
- }
28
- const payload = trimmed.slice(4);
29
- const [coordsPart, ...paramParts] = payload.split(";");
30
- const coords = coordsPart.split(",");
31
- if (coords.length < 2) {
32
- return null;
33
- }
34
- const latitude = Number.parseFloat(coords[0] ?? "");
35
- const longitude = Number.parseFloat(coords[1] ?? "");
36
- if (!Number.isFinite(latitude) || !Number.isFinite(longitude)) {
37
- return null;
38
- }
39
-
40
- const params = new Map<string, string>();
41
- for (const part of paramParts) {
42
- const segment = part.trim();
43
- if (!segment) {
44
- continue;
45
- }
46
- const eqIndex = segment.indexOf("=");
47
- const rawKey = eqIndex === -1 ? segment : segment.slice(0, eqIndex);
48
- const rawValue = eqIndex === -1 ? "" : segment.slice(eqIndex + 1);
49
- const key = rawKey.trim().toLowerCase();
50
- if (!key) {
51
- continue;
52
- }
53
- const valuePart = rawValue.trim();
54
- params.set(key, valuePart ? decodeURIComponent(valuePart) : "");
55
- }
56
-
57
- const accuracyRaw = params.get("u");
58
- const accuracy = accuracyRaw ? Number.parseFloat(accuracyRaw) : undefined;
59
-
60
- return {
61
- latitude,
62
- longitude,
63
- accuracy: Number.isFinite(accuracy) ? accuracy : undefined,
64
- };
65
- }
66
-
67
- export function resolveMatrixLocation(params: {
68
- eventType: string;
69
- content: LocationMessageEventContent;
70
- }): MatrixLocationPayload | null {
71
- const { eventType, content } = params;
72
- const isLocation =
73
- eventType === EventType.Location ||
74
- (eventType === EventType.RoomMessage && content.msgtype === EventType.Location);
75
- if (!isLocation) {
76
- return null;
77
- }
78
- const geoUri = typeof content.geo_uri === "string" ? content.geo_uri.trim() : "";
79
- if (!geoUri) {
80
- return null;
81
- }
82
- const parsed = parseGeoUri(geoUri);
83
- if (!parsed) {
84
- return null;
85
- }
86
- const caption = typeof content.body === "string" ? content.body.trim() : "";
87
- const location: NormalizedLocation = {
88
- latitude: parsed.latitude,
89
- longitude: parsed.longitude,
90
- accuracy: parsed.accuracy,
91
- caption: caption || undefined,
92
- source: "pin",
93
- isLive: false,
94
- };
95
-
96
- return {
97
- text: formatLocationText(location),
98
- context: toLocationContext(location),
99
- };
100
- }