@openclaw/matrix 2026.2.3 → 2026.2.9
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.
- package/CHANGELOG.md +19 -1
- package/package.json +2 -2
- package/src/actions.ts +9 -9
- package/src/matrix/actions/client.ts +4 -2
- package/src/matrix/actions/summary.ts +1 -1
- package/src/matrix/client/config.ts +1 -1
- package/src/matrix/client/shared.ts +4 -2
- package/src/matrix/monitor/events.ts +9 -8
- package/src/matrix/monitor/handler.ts +17 -38
- package/src/matrix/monitor/index.ts +12 -11
- package/src/matrix/monitor/media.ts +5 -2
- package/src/matrix/poll-types.ts +4 -3
- package/src/matrix/send/client.ts +4 -2
- package/src/matrix/send/targets.ts +19 -5
- package/src/onboarding.ts +2 -1
- package/src/types.ts +16 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 2026.2.3
|
|
3
|
+
## 2026.2.6-3
|
|
4
|
+
|
|
5
|
+
### Changes
|
|
6
|
+
|
|
7
|
+
- Version alignment with core OpenClaw release numbers.
|
|
8
|
+
|
|
9
|
+
## 2026.2.6-2
|
|
10
|
+
|
|
11
|
+
### Changes
|
|
12
|
+
|
|
13
|
+
- Version alignment with core OpenClaw release numbers.
|
|
14
|
+
|
|
15
|
+
## 2026.2.6
|
|
16
|
+
|
|
17
|
+
### Changes
|
|
18
|
+
|
|
19
|
+
- Version alignment with core OpenClaw release numbers.
|
|
20
|
+
|
|
21
|
+
## 2026.2.4
|
|
4
22
|
|
|
5
23
|
### Changes
|
|
6
24
|
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/matrix",
|
|
3
|
-
"version": "2026.2.
|
|
3
|
+
"version": "2026.2.9",
|
|
4
4
|
"description": "OpenClaw Matrix channel plugin",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@matrix-org/matrix-sdk-crypto-nodejs": "^0.4.0",
|
|
8
8
|
"@vector-im/matrix-bot-sdk": "0.8.0-element.3",
|
|
9
9
|
"markdown-it": "14.1.0",
|
|
10
|
-
"music-metadata": "^11.
|
|
10
|
+
"music-metadata": "^11.12.0",
|
|
11
11
|
"zod": "^4.3.6"
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
package/src/actions.ts
CHANGED
|
@@ -78,7 +78,7 @@ export const matrixMessageActions: ChannelMessageActionAdapter = {
|
|
|
78
78
|
replyToId: replyTo ?? undefined,
|
|
79
79
|
threadId: threadId ?? undefined,
|
|
80
80
|
},
|
|
81
|
-
cfg,
|
|
81
|
+
cfg as CoreConfig,
|
|
82
82
|
);
|
|
83
83
|
}
|
|
84
84
|
|
|
@@ -94,7 +94,7 @@ export const matrixMessageActions: ChannelMessageActionAdapter = {
|
|
|
94
94
|
emoji,
|
|
95
95
|
remove,
|
|
96
96
|
},
|
|
97
|
-
cfg,
|
|
97
|
+
cfg as CoreConfig,
|
|
98
98
|
);
|
|
99
99
|
}
|
|
100
100
|
|
|
@@ -108,7 +108,7 @@ export const matrixMessageActions: ChannelMessageActionAdapter = {
|
|
|
108
108
|
messageId,
|
|
109
109
|
limit,
|
|
110
110
|
},
|
|
111
|
-
cfg,
|
|
111
|
+
cfg as CoreConfig,
|
|
112
112
|
);
|
|
113
113
|
}
|
|
114
114
|
|
|
@@ -122,7 +122,7 @@ export const matrixMessageActions: ChannelMessageActionAdapter = {
|
|
|
122
122
|
before: readStringParam(params, "before"),
|
|
123
123
|
after: readStringParam(params, "after"),
|
|
124
124
|
},
|
|
125
|
-
cfg,
|
|
125
|
+
cfg as CoreConfig,
|
|
126
126
|
);
|
|
127
127
|
}
|
|
128
128
|
|
|
@@ -136,7 +136,7 @@ export const matrixMessageActions: ChannelMessageActionAdapter = {
|
|
|
136
136
|
messageId,
|
|
137
137
|
content,
|
|
138
138
|
},
|
|
139
|
-
cfg,
|
|
139
|
+
cfg as CoreConfig,
|
|
140
140
|
);
|
|
141
141
|
}
|
|
142
142
|
|
|
@@ -148,7 +148,7 @@ export const matrixMessageActions: ChannelMessageActionAdapter = {
|
|
|
148
148
|
roomId: resolveRoomId(),
|
|
149
149
|
messageId,
|
|
150
150
|
},
|
|
151
|
-
cfg,
|
|
151
|
+
cfg as CoreConfig,
|
|
152
152
|
);
|
|
153
153
|
}
|
|
154
154
|
|
|
@@ -164,7 +164,7 @@ export const matrixMessageActions: ChannelMessageActionAdapter = {
|
|
|
164
164
|
roomId: resolveRoomId(),
|
|
165
165
|
messageId,
|
|
166
166
|
},
|
|
167
|
-
cfg,
|
|
167
|
+
cfg as CoreConfig,
|
|
168
168
|
);
|
|
169
169
|
}
|
|
170
170
|
|
|
@@ -176,7 +176,7 @@ export const matrixMessageActions: ChannelMessageActionAdapter = {
|
|
|
176
176
|
userId,
|
|
177
177
|
roomId: readStringParam(params, "roomId") ?? readStringParam(params, "channelId"),
|
|
178
178
|
},
|
|
179
|
-
cfg,
|
|
179
|
+
cfg as CoreConfig,
|
|
180
180
|
);
|
|
181
181
|
}
|
|
182
182
|
|
|
@@ -186,7 +186,7 @@ export const matrixMessageActions: ChannelMessageActionAdapter = {
|
|
|
186
186
|
action: "channelInfo",
|
|
187
187
|
roomId: resolveRoomId(),
|
|
188
188
|
},
|
|
189
|
-
cfg,
|
|
189
|
+
cfg as CoreConfig,
|
|
190
190
|
);
|
|
191
191
|
}
|
|
192
192
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CoreConfig } from "
|
|
1
|
+
import type { CoreConfig } from "../../types.js";
|
|
2
2
|
import type { MatrixActionClient, MatrixActionClientOpts } from "./types.js";
|
|
3
3
|
import { getMatrixRuntime } from "../../runtime.js";
|
|
4
4
|
import { getActiveMatrixClient } from "../active-client.js";
|
|
@@ -47,7 +47,9 @@ export async function resolveActionClient(
|
|
|
47
47
|
if (auth.encryption && client.crypto) {
|
|
48
48
|
try {
|
|
49
49
|
const joinedRooms = await client.getJoinedRooms();
|
|
50
|
-
await client.crypto.prepare(
|
|
50
|
+
await (client.crypto as { prepare: (rooms?: string[]) => Promise<void> }).prepare(
|
|
51
|
+
joinedRooms,
|
|
52
|
+
);
|
|
51
53
|
} catch {
|
|
52
54
|
// Ignore crypto prep failures for one-off actions.
|
|
53
55
|
}
|
|
@@ -63,7 +63,7 @@ export async function fetchEventSummary(
|
|
|
63
63
|
eventId: string,
|
|
64
64
|
): Promise<MatrixMessageSummary | null> {
|
|
65
65
|
try {
|
|
66
|
-
const raw = (await client.getEvent(roomId, eventId)) as MatrixRawEvent;
|
|
66
|
+
const raw = (await client.getEvent(roomId, eventId)) as unknown as MatrixRawEvent;
|
|
67
67
|
if (raw.unsigned?.redacted_because) {
|
|
68
68
|
return null;
|
|
69
69
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { MatrixClient } from "@vector-im/matrix-bot-sdk";
|
|
2
|
-
import type { CoreConfig } from "
|
|
2
|
+
import type { CoreConfig } from "../../types.js";
|
|
3
3
|
import type { MatrixAuth, MatrixResolvedConfig } from "./types.js";
|
|
4
4
|
import { getMatrixRuntime } from "../../runtime.js";
|
|
5
5
|
import { ensureMatrixSdkLoggingConfigured } from "./logging.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { MatrixClient } from "@vector-im/matrix-bot-sdk";
|
|
2
2
|
import { LogService } from "@vector-im/matrix-bot-sdk";
|
|
3
|
-
import type { CoreConfig } from "
|
|
3
|
+
import type { CoreConfig } from "../../types.js";
|
|
4
4
|
import type { MatrixAuth } from "./types.js";
|
|
5
5
|
import { resolveMatrixAuth } from "./config.js";
|
|
6
6
|
import { createMatrixClient } from "./create-client.js";
|
|
@@ -69,7 +69,9 @@ async function ensureSharedClientStarted(params: {
|
|
|
69
69
|
try {
|
|
70
70
|
const joinedRooms = await client.getJoinedRooms();
|
|
71
71
|
if (client.crypto) {
|
|
72
|
-
await client.crypto.prepare(
|
|
72
|
+
await (client.crypto as { prepare: (rooms?: string[]) => Promise<void> }).prepare(
|
|
73
|
+
joinedRooms,
|
|
74
|
+
);
|
|
73
75
|
params.state.cryptoReady = true;
|
|
74
76
|
}
|
|
75
77
|
} catch (err) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { MatrixClient } from "@vector-im/matrix-bot-sdk";
|
|
2
|
-
import type { PluginRuntime } from "openclaw/plugin-sdk";
|
|
2
|
+
import type { PluginRuntime, RuntimeLogger } from "openclaw/plugin-sdk";
|
|
3
3
|
import type { MatrixAuth } from "../client.js";
|
|
4
4
|
import type { MatrixRawEvent } from "./types.js";
|
|
5
5
|
import { EventType } from "./types.js";
|
|
@@ -10,7 +10,7 @@ export function registerMatrixMonitorEvents(params: {
|
|
|
10
10
|
logVerboseMessage: (message: string) => void;
|
|
11
11
|
warnedEncryptedRooms: Set<string>;
|
|
12
12
|
warnedCryptoMissingRooms: Set<string>;
|
|
13
|
-
logger:
|
|
13
|
+
logger: RuntimeLogger;
|
|
14
14
|
formatNativeDependencyHint: PluginRuntime["system"]["formatNativeDependencyHint"];
|
|
15
15
|
onRoomMessage: (roomId: string, event: MatrixRawEvent) => void | Promise<void>;
|
|
16
16
|
}): void {
|
|
@@ -42,10 +42,11 @@ export function registerMatrixMonitorEvents(params: {
|
|
|
42
42
|
client.on(
|
|
43
43
|
"room.failed_decryption",
|
|
44
44
|
async (roomId: string, event: MatrixRawEvent, error: Error) => {
|
|
45
|
-
logger.warn(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
logger.warn("Failed to decrypt message", {
|
|
46
|
+
roomId,
|
|
47
|
+
eventId: event.event_id,
|
|
48
|
+
error: error.message,
|
|
49
|
+
});
|
|
49
50
|
logVerboseMessage(
|
|
50
51
|
`matrix: failed decrypt room=${roomId} id=${event.event_id ?? "unknown"} error=${error.message}`,
|
|
51
52
|
);
|
|
@@ -76,7 +77,7 @@ export function registerMatrixMonitorEvents(params: {
|
|
|
76
77
|
warnedEncryptedRooms.add(roomId);
|
|
77
78
|
const warning =
|
|
78
79
|
"matrix: encrypted event received without encryption enabled; set channels.matrix.encryption=true and verify the device to decrypt";
|
|
79
|
-
logger.warn({ roomId }
|
|
80
|
+
logger.warn(warning, { roomId });
|
|
80
81
|
}
|
|
81
82
|
if (auth.encryption === true && !client.crypto && !warnedCryptoMissingRooms.has(roomId)) {
|
|
82
83
|
warnedCryptoMissingRooms.add(roomId);
|
|
@@ -86,7 +87,7 @@ export function registerMatrixMonitorEvents(params: {
|
|
|
86
87
|
downloadCommand: "node node_modules/@matrix-org/matrix-sdk-crypto-nodejs/download-lib.js",
|
|
87
88
|
});
|
|
88
89
|
const warning = `matrix: encryption enabled but crypto is unavailable; ${hint}`;
|
|
89
|
-
logger.warn({ roomId }
|
|
90
|
+
logger.warn(warning, { roomId });
|
|
90
91
|
}
|
|
91
92
|
return;
|
|
92
93
|
}
|
|
@@ -6,9 +6,11 @@ import {
|
|
|
6
6
|
logInboundDrop,
|
|
7
7
|
logTypingFailure,
|
|
8
8
|
resolveControlCommandGate,
|
|
9
|
+
type PluginRuntime,
|
|
9
10
|
type RuntimeEnv,
|
|
11
|
+
type RuntimeLogger,
|
|
10
12
|
} from "openclaw/plugin-sdk";
|
|
11
|
-
import type { CoreConfig, ReplyToMode } from "../../types.js";
|
|
13
|
+
import type { CoreConfig, MatrixRoomConfig, ReplyToMode } from "../../types.js";
|
|
12
14
|
import type { MatrixRawEvent, RoomMessageEventContent } from "./types.js";
|
|
13
15
|
import {
|
|
14
16
|
formatPollAsText,
|
|
@@ -37,34 +39,14 @@ import { EventType, RelationType } from "./types.js";
|
|
|
37
39
|
|
|
38
40
|
export type MatrixMonitorHandlerParams = {
|
|
39
41
|
client: MatrixClient;
|
|
40
|
-
core:
|
|
41
|
-
logging: {
|
|
42
|
-
shouldLogVerbose: () => boolean;
|
|
43
|
-
};
|
|
44
|
-
channel: (typeof import("openclaw/plugin-sdk"))["channel"];
|
|
45
|
-
system: {
|
|
46
|
-
enqueueSystemEvent: (
|
|
47
|
-
text: string,
|
|
48
|
-
meta: { sessionKey?: string | null; contextKey?: string | null },
|
|
49
|
-
) => void;
|
|
50
|
-
};
|
|
51
|
-
};
|
|
42
|
+
core: PluginRuntime;
|
|
52
43
|
cfg: CoreConfig;
|
|
53
44
|
runtime: RuntimeEnv;
|
|
54
|
-
logger:
|
|
55
|
-
info: (message: string | Record<string, unknown>, ...meta: unknown[]) => void;
|
|
56
|
-
warn: (meta: Record<string, unknown>, message: string) => void;
|
|
57
|
-
};
|
|
45
|
+
logger: RuntimeLogger;
|
|
58
46
|
logVerboseMessage: (message: string) => void;
|
|
59
47
|
allowFrom: string[];
|
|
60
|
-
roomsConfig:
|
|
61
|
-
|
|
62
|
-
? Groups
|
|
63
|
-
: Record<string, unknown> | undefined
|
|
64
|
-
: Record<string, unknown> | undefined;
|
|
65
|
-
mentionRegexes: ReturnType<
|
|
66
|
-
(typeof import("openclaw/plugin-sdk"))["channel"]["mentions"]["buildMentionRegexes"]
|
|
67
|
-
>;
|
|
48
|
+
roomsConfig: Record<string, MatrixRoomConfig> | undefined;
|
|
49
|
+
mentionRegexes: ReturnType<PluginRuntime["channel"]["mentions"]["buildMentionRegexes"]>;
|
|
68
50
|
groupPolicy: "open" | "allowlist" | "disabled";
|
|
69
51
|
replyToMode: ReplyToMode;
|
|
70
52
|
threadReplies: "off" | "inbound" | "always";
|
|
@@ -121,7 +103,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
|
|
121
103
|
}
|
|
122
104
|
|
|
123
105
|
const isPollEvent = isPollStartType(eventType);
|
|
124
|
-
const locationContent = event.content as LocationMessageEventContent;
|
|
106
|
+
const locationContent = event.content as unknown as LocationMessageEventContent;
|
|
125
107
|
const isLocationEvent =
|
|
126
108
|
eventType === EventType.Location ||
|
|
127
109
|
(eventType === EventType.RoomMessage && locationContent.msgtype === EventType.Location);
|
|
@@ -159,9 +141,9 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
|
|
159
141
|
const roomName = roomInfo.name;
|
|
160
142
|
const roomAliases = [roomInfo.canonicalAlias ?? "", ...roomInfo.altAliases].filter(Boolean);
|
|
161
143
|
|
|
162
|
-
let content = event.content as RoomMessageEventContent;
|
|
144
|
+
let content = event.content as unknown as RoomMessageEventContent;
|
|
163
145
|
if (isPollEvent) {
|
|
164
|
-
const pollStartContent = event.content as PollStartContent;
|
|
146
|
+
const pollStartContent = event.content as unknown as PollStartContent;
|
|
165
147
|
const pollSummary = parsePollStartContent(pollStartContent);
|
|
166
148
|
if (pollSummary) {
|
|
167
149
|
pollSummary.eventId = event.event_id ?? "";
|
|
@@ -435,7 +417,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
|
|
435
417
|
hasControlCommandInMessage;
|
|
436
418
|
const canDetectMention = mentionRegexes.length > 0 || hasExplicitMention;
|
|
437
419
|
if (isRoom && shouldRequireMention && !wasMentioned && !shouldBypassMention) {
|
|
438
|
-
logger.info({ roomId, reason: "no-mention" }
|
|
420
|
+
logger.info("skipping room message", { roomId, reason: "no-mention" });
|
|
439
421
|
return;
|
|
440
422
|
}
|
|
441
423
|
|
|
@@ -453,7 +435,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
|
|
453
435
|
cfg,
|
|
454
436
|
channel: "matrix",
|
|
455
437
|
peer: {
|
|
456
|
-
kind: isDirectMessage ? "
|
|
438
|
+
kind: isDirectMessage ? "direct" : "channel",
|
|
457
439
|
id: isDirectMessage ? senderId : roomId,
|
|
458
440
|
},
|
|
459
441
|
});
|
|
@@ -523,14 +505,11 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
|
|
523
505
|
}
|
|
524
506
|
: undefined,
|
|
525
507
|
onRecordError: (err) => {
|
|
526
|
-
logger.warn(
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
},
|
|
532
|
-
"failed updating session meta",
|
|
533
|
-
);
|
|
508
|
+
logger.warn("failed updating session meta", {
|
|
509
|
+
error: String(err),
|
|
510
|
+
storePath,
|
|
511
|
+
sessionKey: ctxPayload.SessionKey ?? route.sessionKey,
|
|
512
|
+
});
|
|
534
513
|
},
|
|
535
514
|
});
|
|
536
515
|
|
|
@@ -55,7 +55,7 @@ export async function monitorMatrixProvider(opts: MonitorMatrixOpts = {}): Promi
|
|
|
55
55
|
if (!core.logging.shouldLogVerbose()) {
|
|
56
56
|
return;
|
|
57
57
|
}
|
|
58
|
-
logger.debug(message);
|
|
58
|
+
logger.debug?.(message);
|
|
59
59
|
};
|
|
60
60
|
|
|
61
61
|
const normalizeUserEntry = (raw: string) =>
|
|
@@ -75,13 +75,13 @@ export async function monitorMatrixProvider(opts: MonitorMatrixOpts = {}): Promi
|
|
|
75
75
|
): Promise<string[]> => {
|
|
76
76
|
let allowList = list ?? [];
|
|
77
77
|
if (allowList.length === 0) {
|
|
78
|
-
return allowList;
|
|
78
|
+
return allowList.map(String);
|
|
79
79
|
}
|
|
80
80
|
const entries = allowList
|
|
81
81
|
.map((entry) => normalizeUserEntry(String(entry)))
|
|
82
82
|
.filter((entry) => entry && entry !== "*");
|
|
83
83
|
if (entries.length === 0) {
|
|
84
|
-
return allowList;
|
|
84
|
+
return allowList.map(String);
|
|
85
85
|
}
|
|
86
86
|
const mapping: string[] = [];
|
|
87
87
|
const unresolved: string[] = [];
|
|
@@ -118,12 +118,12 @@ export async function monitorMatrixProvider(opts: MonitorMatrixOpts = {}): Promi
|
|
|
118
118
|
`${label} entries must be full Matrix IDs (example: @user:server). Unresolved entries are ignored.`,
|
|
119
119
|
);
|
|
120
120
|
}
|
|
121
|
-
return allowList;
|
|
121
|
+
return allowList.map(String);
|
|
122
122
|
};
|
|
123
123
|
|
|
124
124
|
const allowlistOnly = cfg.channels?.matrix?.allowlistOnly === true;
|
|
125
|
-
let allowFrom = cfg.channels?.matrix?.dm?.allowFrom ?? [];
|
|
126
|
-
let groupAllowFrom = cfg.channels?.matrix?.groupAllowFrom ?? [];
|
|
125
|
+
let allowFrom: string[] = (cfg.channels?.matrix?.dm?.allowFrom ?? []).map(String);
|
|
126
|
+
let groupAllowFrom: string[] = (cfg.channels?.matrix?.groupAllowFrom ?? []).map(String);
|
|
127
127
|
let roomsConfig = cfg.channels?.matrix?.groups ?? cfg.channels?.matrix?.rooms;
|
|
128
128
|
|
|
129
129
|
allowFrom = await resolveUserAllowlist("matrix dm allowlist", allowFrom);
|
|
@@ -307,15 +307,16 @@ export async function monitorMatrixProvider(opts: MonitorMatrixOpts = {}): Promi
|
|
|
307
307
|
if (auth.encryption && client.crypto) {
|
|
308
308
|
try {
|
|
309
309
|
// Request verification from other sessions
|
|
310
|
-
const verificationRequest = await
|
|
310
|
+
const verificationRequest = await (
|
|
311
|
+
client.crypto as { requestOwnUserVerification?: () => Promise<unknown> }
|
|
312
|
+
).requestOwnUserVerification?.();
|
|
311
313
|
if (verificationRequest) {
|
|
312
314
|
logger.info("matrix: device verification requested - please verify in another client");
|
|
313
315
|
}
|
|
314
316
|
} catch (err) {
|
|
315
|
-
logger.debug(
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
);
|
|
317
|
+
logger.debug?.("Device verification request failed (may already be verified)", {
|
|
318
|
+
error: String(err),
|
|
319
|
+
});
|
|
319
320
|
}
|
|
320
321
|
}
|
|
321
322
|
|
|
@@ -29,7 +29,8 @@ async function fetchMatrixMediaBuffer(params: {
|
|
|
29
29
|
|
|
30
30
|
// Use the client's download method which handles auth
|
|
31
31
|
try {
|
|
32
|
-
const
|
|
32
|
+
const result = await params.client.downloadContent(params.mxcUrl);
|
|
33
|
+
const buffer = result.data;
|
|
33
34
|
if (buffer.byteLength > params.maxBytes) {
|
|
34
35
|
throw new Error("Matrix media exceeds configured size limit");
|
|
35
36
|
}
|
|
@@ -53,7 +54,9 @@ async function fetchEncryptedMediaBuffer(params: {
|
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
// decryptMedia handles downloading and decrypting the encrypted content internally
|
|
56
|
-
const decrypted = await params.client.crypto.decryptMedia(
|
|
57
|
+
const decrypted = await params.client.crypto.decryptMedia(
|
|
58
|
+
params.file as Parameters<typeof params.client.crypto.decryptMedia>[0],
|
|
59
|
+
);
|
|
57
60
|
|
|
58
61
|
if (decrypted.byteLength > params.maxBytes) {
|
|
59
62
|
throw new Error("Matrix media exceeds configured size limit");
|
package/src/matrix/poll-types.ts
CHANGED
|
@@ -73,7 +73,7 @@ export type PollSummary = {
|
|
|
73
73
|
};
|
|
74
74
|
|
|
75
75
|
export function isPollStartType(eventType: string): boolean {
|
|
76
|
-
return POLL_START_TYPES.includes(eventType);
|
|
76
|
+
return (POLL_START_TYPES as readonly string[]).includes(eventType);
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
export function getTextContent(text?: TextContent): string {
|
|
@@ -147,7 +147,8 @@ export function buildPollStartContent(poll: PollInput): PollStartContent {
|
|
|
147
147
|
...buildTextContent(option),
|
|
148
148
|
}));
|
|
149
149
|
|
|
150
|
-
const
|
|
150
|
+
const isMultiple = (poll.maxSelections ?? 1) > 1;
|
|
151
|
+
const maxSelections = isMultiple ? Math.max(1, answers.length) : 1;
|
|
151
152
|
const fallbackText = buildPollFallbackText(
|
|
152
153
|
question,
|
|
153
154
|
answers.map((answer) => getTextContent(answer)),
|
|
@@ -156,7 +157,7 @@ export function buildPollStartContent(poll: PollInput): PollStartContent {
|
|
|
156
157
|
return {
|
|
157
158
|
[M_POLL_START]: {
|
|
158
159
|
question: buildTextContent(question),
|
|
159
|
-
kind:
|
|
160
|
+
kind: isMultiple ? "m.poll.undisclosed" : "m.poll.disclosed",
|
|
160
161
|
max_selections: maxSelections,
|
|
161
162
|
answers,
|
|
162
163
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { MatrixClient } from "@vector-im/matrix-bot-sdk";
|
|
2
|
-
import type { CoreConfig } from "
|
|
2
|
+
import type { CoreConfig } from "../../types.js";
|
|
3
3
|
import { getMatrixRuntime } from "../../runtime.js";
|
|
4
4
|
import { getActiveMatrixClient } from "../active-client.js";
|
|
5
5
|
import {
|
|
@@ -55,7 +55,9 @@ export async function resolveMatrixClient(opts: {
|
|
|
55
55
|
if (auth.encryption && client.crypto) {
|
|
56
56
|
try {
|
|
57
57
|
const joinedRooms = await client.getJoinedRooms();
|
|
58
|
-
await client.crypto.prepare(
|
|
58
|
+
await (client.crypto as { prepare: (rooms?: string[]) => Promise<void> }).prepare(
|
|
59
|
+
joinedRooms,
|
|
60
|
+
);
|
|
59
61
|
} catch {
|
|
60
62
|
// Ignore crypto prep failures for one-off sends; normal sync will retry.
|
|
61
63
|
}
|
|
@@ -17,7 +17,18 @@ export function normalizeThreadId(raw?: string | number | null): string | null {
|
|
|
17
17
|
return trimmed ? trimmed : null;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
// Size-capped to prevent unbounded growth (#4948)
|
|
21
|
+
const MAX_DIRECT_ROOM_CACHE_SIZE = 1024;
|
|
20
22
|
const directRoomCache = new Map<string, string>();
|
|
23
|
+
function setDirectRoomCached(key: string, value: string): void {
|
|
24
|
+
directRoomCache.set(key, value);
|
|
25
|
+
if (directRoomCache.size > MAX_DIRECT_ROOM_CACHE_SIZE) {
|
|
26
|
+
const oldest = directRoomCache.keys().next().value;
|
|
27
|
+
if (oldest !== undefined) {
|
|
28
|
+
directRoomCache.delete(oldest);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
21
32
|
|
|
22
33
|
async function persistDirectRoom(
|
|
23
34
|
client: MatrixClient,
|
|
@@ -59,10 +70,13 @@ async function resolveDirectRoomId(client: MatrixClient, userId: string): Promis
|
|
|
59
70
|
|
|
60
71
|
// 1) Fast path: use account data (m.direct) for *this* logged-in user (the bot).
|
|
61
72
|
try {
|
|
62
|
-
const directContent = await client.getAccountData(EventType.Direct)
|
|
73
|
+
const directContent = (await client.getAccountData(EventType.Direct)) as Record<
|
|
74
|
+
string,
|
|
75
|
+
string[] | undefined
|
|
76
|
+
>;
|
|
63
77
|
const list = Array.isArray(directContent?.[trimmed]) ? directContent[trimmed] : [];
|
|
64
|
-
if (list.length > 0) {
|
|
65
|
-
|
|
78
|
+
if (list && list.length > 0) {
|
|
79
|
+
setDirectRoomCached(trimmed, list[0]);
|
|
66
80
|
return list[0];
|
|
67
81
|
}
|
|
68
82
|
} catch {
|
|
@@ -86,7 +100,7 @@ async function resolveDirectRoomId(client: MatrixClient, userId: string): Promis
|
|
|
86
100
|
}
|
|
87
101
|
// Prefer classic 1:1 rooms, but allow larger rooms if requested.
|
|
88
102
|
if (members.length === 2) {
|
|
89
|
-
|
|
103
|
+
setDirectRoomCached(trimmed, roomId);
|
|
90
104
|
await persistDirectRoom(client, trimmed, roomId);
|
|
91
105
|
return roomId;
|
|
92
106
|
}
|
|
@@ -99,7 +113,7 @@ async function resolveDirectRoomId(client: MatrixClient, userId: string): Promis
|
|
|
99
113
|
}
|
|
100
114
|
|
|
101
115
|
if (fallbackRoom) {
|
|
102
|
-
|
|
116
|
+
setDirectRoomCached(trimmed, fallbackRoom);
|
|
103
117
|
await persistDirectRoom(client, trimmed, fallbackRoom);
|
|
104
118
|
return fallbackRoom;
|
|
105
119
|
}
|
package/src/onboarding.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { DmPolicy } from "openclaw/plugin-sdk";
|
|
1
2
|
import {
|
|
2
3
|
addWildcardAllowFrom,
|
|
3
4
|
formatDocsLink,
|
|
@@ -6,7 +7,7 @@ import {
|
|
|
6
7
|
type ChannelOnboardingDmPolicy,
|
|
7
8
|
type WizardPrompter,
|
|
8
9
|
} from "openclaw/plugin-sdk";
|
|
9
|
-
import type { CoreConfig
|
|
10
|
+
import type { CoreConfig } from "./types.js";
|
|
10
11
|
import { listMatrixDirectoryGroupsLive } from "./directory-live.js";
|
|
11
12
|
import { resolveMatrixAccount } from "./matrix/accounts.js";
|
|
12
13
|
import { ensureMatrixSdkInstalled, isMatrixSdkAvailable } from "./matrix/deps.js";
|
package/src/types.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import type { DmPolicy, GroupPolicy } from "openclaw/plugin-sdk";
|
|
2
|
+
export type { DmPolicy, GroupPolicy };
|
|
3
|
+
|
|
1
4
|
export type ReplyToMode = "off" | "first" | "all";
|
|
2
|
-
export type GroupPolicy = "open" | "disabled" | "allowlist";
|
|
3
|
-
export type DmPolicy = "pairing" | "allowlist" | "open" | "disabled";
|
|
4
5
|
|
|
5
6
|
export type MatrixDmConfig = {
|
|
6
7
|
/** If false, ignore all incoming Matrix DMs. Default: true. */
|
|
@@ -92,6 +93,19 @@ export type MatrixConfig = {
|
|
|
92
93
|
export type CoreConfig = {
|
|
93
94
|
channels?: {
|
|
94
95
|
matrix?: MatrixConfig;
|
|
96
|
+
defaults?: {
|
|
97
|
+
groupPolicy?: "open" | "allowlist" | "disabled";
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
commands?: {
|
|
101
|
+
useAccessGroups?: boolean;
|
|
102
|
+
};
|
|
103
|
+
session?: {
|
|
104
|
+
store?: string;
|
|
105
|
+
};
|
|
106
|
+
messages?: {
|
|
107
|
+
ackReaction?: string;
|
|
108
|
+
ackReactionScope?: "group-mentions" | "group-all" | "direct" | "all";
|
|
95
109
|
};
|
|
96
110
|
[key: string]: unknown;
|
|
97
111
|
};
|