@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
@@ -1,124 +0,0 @@
1
- import type { MatrixClient } from "@vector-im/matrix-bot-sdk";
2
- import type { MarkdownTableMode, ReplyPayload, RuntimeEnv } from "openclaw/plugin-sdk/matrix";
3
- import { getMatrixRuntime } from "../../runtime.js";
4
- import { sendMessageMatrix } from "../send.js";
5
-
6
- export async function deliverMatrixReplies(params: {
7
- replies: ReplyPayload[];
8
- roomId: string;
9
- client: MatrixClient;
10
- runtime: RuntimeEnv;
11
- textLimit: number;
12
- replyToMode: "off" | "first" | "all";
13
- threadId?: string;
14
- accountId?: string;
15
- tableMode?: MarkdownTableMode;
16
- }): Promise<void> {
17
- const core = getMatrixRuntime();
18
- const cfg = core.config.loadConfig();
19
- const tableMode =
20
- params.tableMode ??
21
- core.channel.text.resolveMarkdownTableMode({
22
- cfg,
23
- channel: "matrix",
24
- accountId: params.accountId,
25
- });
26
- const logVerbose = (message: string) => {
27
- if (core.logging.shouldLogVerbose()) {
28
- params.runtime.log?.(message);
29
- }
30
- };
31
- const chunkLimit = Math.min(params.textLimit, 4000);
32
- const chunkMode = core.channel.text.resolveChunkMode(cfg, "matrix", params.accountId);
33
- let hasReplied = false;
34
- for (const reply of params.replies) {
35
- const hasMedia = Boolean(reply?.mediaUrl) || (reply?.mediaUrls?.length ?? 0) > 0;
36
- if (!reply?.text && !hasMedia) {
37
- if (reply?.audioAsVoice) {
38
- logVerbose("matrix reply has audioAsVoice without media/text; skipping");
39
- continue;
40
- }
41
- params.runtime.error?.("matrix reply missing text/media");
42
- continue;
43
- }
44
- // Skip pure reasoning messages so internal thinking traces are never delivered.
45
- if (reply.text && isReasoningOnlyMessage(reply.text)) {
46
- logVerbose("matrix reply is reasoning-only; skipping");
47
- continue;
48
- }
49
- const replyToIdRaw = reply.replyToId?.trim();
50
- const replyToId = params.threadId || params.replyToMode === "off" ? undefined : replyToIdRaw;
51
- const rawText = reply.text ?? "";
52
- const text = core.channel.text.convertMarkdownTables(rawText, tableMode);
53
- const mediaList = reply.mediaUrls?.length
54
- ? reply.mediaUrls
55
- : reply.mediaUrl
56
- ? [reply.mediaUrl]
57
- : [];
58
-
59
- const shouldIncludeReply = (id?: string) =>
60
- Boolean(id) && (params.replyToMode === "all" || !hasReplied);
61
- const replyToIdForReply = shouldIncludeReply(replyToId) ? replyToId : undefined;
62
-
63
- if (mediaList.length === 0) {
64
- let sentTextChunk = false;
65
- for (const chunk of core.channel.text.chunkMarkdownTextWithMode(
66
- text,
67
- chunkLimit,
68
- chunkMode,
69
- )) {
70
- const trimmed = chunk.trim();
71
- if (!trimmed) {
72
- continue;
73
- }
74
- await sendMessageMatrix(params.roomId, trimmed, {
75
- client: params.client,
76
- replyToId: replyToIdForReply,
77
- threadId: params.threadId,
78
- accountId: params.accountId,
79
- });
80
- sentTextChunk = true;
81
- }
82
- if (replyToIdForReply && !hasReplied && sentTextChunk) {
83
- hasReplied = true;
84
- }
85
- continue;
86
- }
87
-
88
- let first = true;
89
- for (const mediaUrl of mediaList) {
90
- const caption = first ? text : "";
91
- await sendMessageMatrix(params.roomId, caption, {
92
- client: params.client,
93
- mediaUrl,
94
- replyToId: replyToIdForReply,
95
- threadId: params.threadId,
96
- audioAsVoice: reply.audioAsVoice,
97
- accountId: params.accountId,
98
- });
99
- first = false;
100
- }
101
- if (replyToIdForReply && !hasReplied) {
102
- hasReplied = true;
103
- }
104
- }
105
- }
106
-
107
- const REASONING_PREFIX = "Reasoning:\n";
108
- const THINKING_TAG_RE = /^\s*<\s*(?:think(?:ing)?|thought|antthinking)\b/i;
109
-
110
- /**
111
- * Detect messages that contain only reasoning/thinking content and no user-facing answer.
112
- * These are emitted by the agent when `includeReasoning` is active but should not
113
- * be forwarded to channels that do not support a dedicated reasoning lane.
114
- */
115
- function isReasoningOnlyMessage(text: string): boolean {
116
- const trimmed = text.trim();
117
- if (trimmed.startsWith(REASONING_PREFIX)) {
118
- return true;
119
- }
120
- if (THINKING_TAG_RE.test(trimmed)) {
121
- return true;
122
- }
123
- return false;
124
- }
@@ -1,55 +0,0 @@
1
- import type { MatrixClient } from "@vector-im/matrix-bot-sdk";
2
-
3
- export type MatrixRoomInfo = {
4
- name?: string;
5
- canonicalAlias?: string;
6
- altAliases: string[];
7
- };
8
-
9
- export function createMatrixRoomInfoResolver(client: MatrixClient) {
10
- const roomInfoCache = new Map<string, MatrixRoomInfo>();
11
-
12
- const getRoomInfo = async (roomId: string): Promise<MatrixRoomInfo> => {
13
- const cached = roomInfoCache.get(roomId);
14
- if (cached) {
15
- return cached;
16
- }
17
- let name: string | undefined;
18
- let canonicalAlias: string | undefined;
19
- let altAliases: string[] = [];
20
- try {
21
- const nameState = await client.getRoomStateEvent(roomId, "m.room.name", "").catch(() => null);
22
- name = nameState?.name;
23
- } catch {
24
- // ignore
25
- }
26
- try {
27
- const aliasState = await client
28
- .getRoomStateEvent(roomId, "m.room.canonical_alias", "")
29
- .catch(() => null);
30
- canonicalAlias = aliasState?.alias;
31
- altAliases = aliasState?.alt_aliases ?? [];
32
- } catch {
33
- // ignore
34
- }
35
- const info = { name, canonicalAlias, altAliases };
36
- roomInfoCache.set(roomId, info);
37
- return info;
38
- };
39
-
40
- const getMemberDisplayName = async (roomId: string, userId: string): Promise<string> => {
41
- try {
42
- const memberState = await client
43
- .getRoomStateEvent(roomId, "m.room.member", userId)
44
- .catch(() => null);
45
- return memberState?.displayname ?? userId;
46
- } catch {
47
- return userId;
48
- }
49
- };
50
-
51
- return {
52
- getRoomInfo,
53
- getMemberDisplayName,
54
- };
55
- }
@@ -1,124 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { resolveMatrixRoomConfig } from "./rooms.js";
3
-
4
- describe("resolveMatrixRoomConfig", () => {
5
- it("matches room IDs and aliases, not names", () => {
6
- const rooms = {
7
- "!room:example.org": { allow: true },
8
- "#alias:example.org": { allow: true },
9
- "Project Room": { allow: true },
10
- };
11
-
12
- const byId = resolveMatrixRoomConfig({
13
- rooms,
14
- roomId: "!room:example.org",
15
- aliases: [],
16
- name: "Project Room",
17
- });
18
- expect(byId.allowed).toBe(true);
19
- expect(byId.matchKey).toBe("!room:example.org");
20
-
21
- const byAlias = resolveMatrixRoomConfig({
22
- rooms,
23
- roomId: "!other:example.org",
24
- aliases: ["#alias:example.org"],
25
- name: "Other Room",
26
- });
27
- expect(byAlias.allowed).toBe(true);
28
- expect(byAlias.matchKey).toBe("#alias:example.org");
29
-
30
- const byName = resolveMatrixRoomConfig({
31
- rooms: { "Project Room": { allow: true } },
32
- roomId: "!different:example.org",
33
- aliases: [],
34
- name: "Project Room",
35
- });
36
- expect(byName.allowed).toBe(false);
37
- expect(byName.config).toBeUndefined();
38
- });
39
-
40
- describe("matchSource classification", () => {
41
- it('returns matchSource="direct" for exact room ID match', () => {
42
- const result = resolveMatrixRoomConfig({
43
- rooms: { "!room:example.org": { allow: true } },
44
- roomId: "!room:example.org",
45
- aliases: [],
46
- });
47
- expect(result.matchSource).toBe("direct");
48
- expect(result.config).toBeDefined();
49
- });
50
-
51
- it('returns matchSource="direct" for alias match', () => {
52
- const result = resolveMatrixRoomConfig({
53
- rooms: { "#alias:example.org": { allow: true } },
54
- roomId: "!room:example.org",
55
- aliases: ["#alias:example.org"],
56
- });
57
- expect(result.matchSource).toBe("direct");
58
- expect(result.config).toBeDefined();
59
- });
60
-
61
- it('returns matchSource="wildcard" for wildcard match', () => {
62
- const result = resolveMatrixRoomConfig({
63
- rooms: { "*": { allow: true } },
64
- roomId: "!any:example.org",
65
- aliases: [],
66
- });
67
- expect(result.matchSource).toBe("wildcard");
68
- expect(result.config).toBeDefined();
69
- });
70
-
71
- it("returns undefined matchSource when no match", () => {
72
- const result = resolveMatrixRoomConfig({
73
- rooms: { "!other:example.org": { allow: true } },
74
- roomId: "!room:example.org",
75
- aliases: [],
76
- });
77
- expect(result.matchSource).toBeUndefined();
78
- expect(result.config).toBeUndefined();
79
- });
80
-
81
- it("direct match takes priority over wildcard", () => {
82
- const result = resolveMatrixRoomConfig({
83
- rooms: {
84
- "!room:example.org": { allow: true, systemPrompt: "room-specific" },
85
- "*": { allow: true, systemPrompt: "generic" },
86
- },
87
- roomId: "!room:example.org",
88
- aliases: [],
89
- });
90
- expect(result.matchSource).toBe("direct");
91
- expect(result.config?.systemPrompt).toBe("room-specific");
92
- });
93
- });
94
-
95
- describe("DM override safety (matchSource distinction)", () => {
96
- // These tests verify the matchSource property that handler.ts uses
97
- // to decide whether a configured room should override DM classification.
98
- // Only "direct" matches should trigger the override -- never "wildcard".
99
-
100
- it("wildcard config should NOT be usable to override DM classification", () => {
101
- const result = resolveMatrixRoomConfig({
102
- rooms: { "*": { allow: true, skills: ["general"] } },
103
- roomId: "!dm-room:example.org",
104
- aliases: [],
105
- });
106
- // handler.ts checks: matchSource === "direct" -> this is "wildcard", so no override
107
- expect(result.matchSource).not.toBe("direct");
108
- expect(result.matchSource).toBe("wildcard");
109
- });
110
-
111
- it("explicitly configured room should be usable to override DM classification", () => {
112
- const result = resolveMatrixRoomConfig({
113
- rooms: {
114
- "!configured-room:example.org": { allow: true },
115
- "*": { allow: true },
116
- },
117
- roomId: "!configured-room:example.org",
118
- aliases: [],
119
- });
120
- // handler.ts checks: matchSource === "direct" -> this IS "direct", so override is safe
121
- expect(result.matchSource).toBe("direct");
122
- });
123
- });
124
- });
@@ -1,47 +0,0 @@
1
- import { buildChannelKeyCandidates, resolveChannelEntryMatch } from "openclaw/plugin-sdk/matrix";
2
- import type { MatrixRoomConfig } from "../../types.js";
3
-
4
- export type MatrixRoomConfigResolved = {
5
- allowed: boolean;
6
- allowlistConfigured: boolean;
7
- config?: MatrixRoomConfig;
8
- matchKey?: string;
9
- matchSource?: "direct" | "wildcard";
10
- };
11
-
12
- export function resolveMatrixRoomConfig(params: {
13
- rooms?: Record<string, MatrixRoomConfig>;
14
- roomId: string;
15
- aliases: string[];
16
- name?: string | null;
17
- }): MatrixRoomConfigResolved {
18
- const rooms = params.rooms ?? {};
19
- const keys = Object.keys(rooms);
20
- const allowlistConfigured = keys.length > 0;
21
- const candidates = buildChannelKeyCandidates(
22
- params.roomId,
23
- `room:${params.roomId}`,
24
- ...params.aliases,
25
- );
26
- const {
27
- entry: matched,
28
- key: matchedKey,
29
- wildcardEntry,
30
- wildcardKey,
31
- } = resolveChannelEntryMatch({
32
- entries: rooms,
33
- keys: candidates,
34
- wildcardKey: "*",
35
- });
36
- const resolved = matched ?? wildcardEntry;
37
- const allowed = resolved ? resolved.enabled !== false && resolved.allow !== false : false;
38
- const matchKey = matchedKey ?? wildcardKey;
39
- const matchSource = matched ? "direct" : wildcardEntry ? "wildcard" : undefined;
40
- return {
41
- allowed,
42
- allowlistConfigured,
43
- config: resolved,
44
- matchKey,
45
- matchSource,
46
- };
47
- }
@@ -1,68 +0,0 @@
1
- // Type for raw Matrix event from @vector-im/matrix-bot-sdk
2
- type MatrixRawEvent = {
3
- event_id: string;
4
- sender: string;
5
- type: string;
6
- origin_server_ts: number;
7
- content: Record<string, unknown>;
8
- };
9
-
10
- type RoomMessageEventContent = {
11
- msgtype: string;
12
- body: string;
13
- "m.relates_to"?: {
14
- rel_type?: string;
15
- event_id?: string;
16
- "m.in_reply_to"?: { event_id?: string };
17
- };
18
- };
19
-
20
- const RelationType = {
21
- Thread: "m.thread",
22
- } as const;
23
-
24
- export function resolveMatrixThreadTarget(params: {
25
- threadReplies: "off" | "inbound" | "always";
26
- messageId: string;
27
- threadRootId?: string;
28
- isThreadRoot?: boolean;
29
- }): string | undefined {
30
- const { threadReplies, messageId, threadRootId } = params;
31
- if (threadReplies === "off") {
32
- return undefined;
33
- }
34
- const isThreadRoot = params.isThreadRoot === true;
35
- const hasInboundThread = Boolean(threadRootId && threadRootId !== messageId && !isThreadRoot);
36
- if (threadReplies === "inbound") {
37
- return hasInboundThread ? threadRootId : undefined;
38
- }
39
- if (threadReplies === "always") {
40
- return threadRootId ?? messageId;
41
- }
42
- return undefined;
43
- }
44
-
45
- export function resolveMatrixThreadRootId(params: {
46
- event: MatrixRawEvent;
47
- content: RoomMessageEventContent;
48
- }): string | undefined {
49
- const relates = params.content["m.relates_to"];
50
- if (!relates || typeof relates !== "object") {
51
- return undefined;
52
- }
53
- if ("rel_type" in relates && relates.rel_type === RelationType.Thread) {
54
- if ("event_id" in relates && typeof relates.event_id === "string") {
55
- return relates.event_id;
56
- }
57
- if (
58
- "m.in_reply_to" in relates &&
59
- typeof relates["m.in_reply_to"] === "object" &&
60
- relates["m.in_reply_to"] &&
61
- "event_id" in relates["m.in_reply_to"] &&
62
- typeof relates["m.in_reply_to"].event_id === "string"
63
- ) {
64
- return relates["m.in_reply_to"].event_id;
65
- }
66
- }
67
- return undefined;
68
- }
@@ -1,39 +0,0 @@
1
- import type { EncryptedFile, MessageEventContent } from "@vector-im/matrix-bot-sdk";
2
-
3
- export const EventType = {
4
- RoomMessage: "m.room.message",
5
- RoomMessageEncrypted: "m.room.encrypted",
6
- RoomMember: "m.room.member",
7
- Location: "m.location",
8
- } as const;
9
-
10
- export const RelationType = {
11
- Replace: "m.replace",
12
- Thread: "m.thread",
13
- } as const;
14
-
15
- export type MatrixRawEvent = {
16
- event_id: string;
17
- sender: string;
18
- type: string;
19
- origin_server_ts: number;
20
- content: Record<string, unknown>;
21
- unsigned?: {
22
- age?: number;
23
- redacted_because?: unknown;
24
- };
25
- };
26
-
27
- export type RoomMessageEventContent = MessageEventContent & {
28
- url?: string;
29
- file?: EncryptedFile;
30
- info?: {
31
- mimetype?: string;
32
- size?: number;
33
- };
34
- "m.relates_to"?: {
35
- rel_type?: string;
36
- event_id?: string;
37
- "m.in_reply_to"?: { event_id?: string };
38
- };
39
- };
@@ -1,21 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { parsePollStartContent } from "./poll-types.js";
3
-
4
- describe("parsePollStartContent", () => {
5
- it("parses legacy m.poll payloads", () => {
6
- const summary = parsePollStartContent({
7
- "m.poll": {
8
- question: { "m.text": "Lunch?" },
9
- kind: "m.poll.disclosed",
10
- max_selections: 1,
11
- answers: [
12
- { id: "answer1", "m.text": "Yes" },
13
- { id: "answer2", "m.text": "No" },
14
- ],
15
- },
16
- });
17
-
18
- expect(summary?.question).toBe("Lunch?");
19
- expect(summary?.answers).toEqual(["Yes", "No"]);
20
- });
21
- });
@@ -1,167 +0,0 @@
1
- /**
2
- * Matrix Poll Types (MSC3381)
3
- *
4
- * Defines types for Matrix poll events:
5
- * - m.poll.start - Creates a new poll
6
- * - m.poll.response - Records a vote
7
- * - m.poll.end - Closes a poll
8
- */
9
-
10
- import type { PollInput } from "openclaw/plugin-sdk/matrix";
11
-
12
- export const M_POLL_START = "m.poll.start" as const;
13
- export const M_POLL_RESPONSE = "m.poll.response" as const;
14
- export const M_POLL_END = "m.poll.end" as const;
15
-
16
- export const ORG_POLL_START = "org.matrix.msc3381.poll.start" as const;
17
- export const ORG_POLL_RESPONSE = "org.matrix.msc3381.poll.response" as const;
18
- export const ORG_POLL_END = "org.matrix.msc3381.poll.end" as const;
19
-
20
- export const POLL_EVENT_TYPES = [
21
- M_POLL_START,
22
- M_POLL_RESPONSE,
23
- M_POLL_END,
24
- ORG_POLL_START,
25
- ORG_POLL_RESPONSE,
26
- ORG_POLL_END,
27
- ];
28
-
29
- export const POLL_START_TYPES = [M_POLL_START, ORG_POLL_START];
30
- export const POLL_RESPONSE_TYPES = [M_POLL_RESPONSE, ORG_POLL_RESPONSE];
31
- export const POLL_END_TYPES = [M_POLL_END, ORG_POLL_END];
32
-
33
- export type PollKind = "m.poll.disclosed" | "m.poll.undisclosed";
34
-
35
- export type TextContent = {
36
- "m.text"?: string;
37
- "org.matrix.msc1767.text"?: string;
38
- body?: string;
39
- };
40
-
41
- export type PollAnswer = {
42
- id: string;
43
- } & TextContent;
44
-
45
- export type PollStartSubtype = {
46
- question: TextContent;
47
- kind?: PollKind;
48
- max_selections?: number;
49
- answers: PollAnswer[];
50
- };
51
-
52
- export type LegacyPollStartContent = {
53
- "m.poll"?: PollStartSubtype;
54
- };
55
-
56
- export type PollStartContent = {
57
- [M_POLL_START]?: PollStartSubtype;
58
- [ORG_POLL_START]?: PollStartSubtype;
59
- "m.poll"?: PollStartSubtype;
60
- "m.text"?: string;
61
- "org.matrix.msc1767.text"?: string;
62
- };
63
-
64
- export type PollSummary = {
65
- eventId: string;
66
- roomId: string;
67
- sender: string;
68
- senderName: string;
69
- question: string;
70
- answers: string[];
71
- kind: PollKind;
72
- maxSelections: number;
73
- };
74
-
75
- export function isPollStartType(eventType: string): boolean {
76
- return (POLL_START_TYPES as readonly string[]).includes(eventType);
77
- }
78
-
79
- export function getTextContent(text?: TextContent): string {
80
- if (!text) {
81
- return "";
82
- }
83
- return text["m.text"] ?? text["org.matrix.msc1767.text"] ?? text.body ?? "";
84
- }
85
-
86
- export function parsePollStartContent(content: PollStartContent): PollSummary | null {
87
- const poll =
88
- (content as Record<string, PollStartSubtype | undefined>)[M_POLL_START] ??
89
- (content as Record<string, PollStartSubtype | undefined>)[ORG_POLL_START] ??
90
- (content as Record<string, PollStartSubtype | undefined>)["m.poll"];
91
- if (!poll) {
92
- return null;
93
- }
94
-
95
- const question = getTextContent(poll.question);
96
- if (!question) {
97
- return null;
98
- }
99
-
100
- const answers = poll.answers
101
- .map((answer) => getTextContent(answer))
102
- .filter((a) => a.trim().length > 0);
103
-
104
- return {
105
- eventId: "",
106
- roomId: "",
107
- sender: "",
108
- senderName: "",
109
- question,
110
- answers,
111
- kind: poll.kind ?? "m.poll.disclosed",
112
- maxSelections: poll.max_selections ?? 1,
113
- };
114
- }
115
-
116
- export function formatPollAsText(summary: PollSummary): string {
117
- const lines = [
118
- "[Poll]",
119
- summary.question,
120
- "",
121
- ...summary.answers.map((answer, idx) => `${idx + 1}. ${answer}`),
122
- ];
123
- return lines.join("\n");
124
- }
125
-
126
- function buildTextContent(body: string): TextContent {
127
- return {
128
- "m.text": body,
129
- "org.matrix.msc1767.text": body,
130
- };
131
- }
132
-
133
- function buildPollFallbackText(question: string, answers: string[]): string {
134
- if (answers.length === 0) {
135
- return question;
136
- }
137
- return `${question}\n${answers.map((answer, idx) => `${idx + 1}. ${answer}`).join("\n")}`;
138
- }
139
-
140
- export function buildPollStartContent(poll: PollInput): PollStartContent {
141
- const question = poll.question.trim();
142
- const answers = poll.options
143
- .map((option) => option.trim())
144
- .filter((option) => option.length > 0)
145
- .map((option, idx) => ({
146
- id: `answer${idx + 1}`,
147
- ...buildTextContent(option),
148
- }));
149
-
150
- const isMultiple = (poll.maxSelections ?? 1) > 1;
151
- const maxSelections = isMultiple ? Math.max(1, answers.length) : 1;
152
- const fallbackText = buildPollFallbackText(
153
- question,
154
- answers.map((answer) => getTextContent(answer)),
155
- );
156
-
157
- return {
158
- [M_POLL_START]: {
159
- question: buildTextContent(question),
160
- kind: isMultiple ? "m.poll.undisclosed" : "m.poll.disclosed",
161
- max_selections: maxSelections,
162
- answers,
163
- },
164
- "m.text": fallbackText,
165
- "org.matrix.msc1767.text": fallbackText,
166
- };
167
- }