@openclaw/matrix 2026.3.13 → 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.
- package/dist/account-config-D2W-V1eQ.js +96 -0
- package/dist/account-selection-BWwIruri.js +158 -0
- package/dist/accounts-Bm90Rzvp.js +130 -0
- package/dist/active-client-uhlxdhEy.js +20 -0
- package/dist/allowlist-sTzpCn5d.js +68 -0
- package/dist/api.js +12 -0
- package/dist/approval-handler.runtime-DWTQfd4m.js +370 -0
- package/dist/approval-ids-DoC2z7tR.js +7 -0
- package/dist/approval-reaction-auth-DbcA1gGd.js +27 -0
- package/dist/approval-reactions-o2_tuH8D.js +162 -0
- package/dist/async-lock-uQfhfQIY.js +19 -0
- package/dist/auth-presence.js +26 -0
- package/dist/backup-health-Cabu_WQC.js +60 -0
- package/dist/channel-DJNir3Rb.js +1116 -0
- package/dist/channel-plugin-api.js +2 -0
- package/dist/channel.runtime-BQu0hTih.js +246 -0
- package/dist/cli-BmfTmg7x.js +1340 -0
- package/dist/cli-metadata-B-PCEzrA.js +22 -0
- package/dist/cli-metadata.js +2 -0
- package/dist/client-DkcXnm0X.js +25 -0
- package/dist/client-_hckQNGW.js +31 -0
- package/dist/client-bootstrap-Rb8oHvhH.js +114 -0
- package/dist/config--5-S2Akv.js +452 -0
- package/dist/config-paths-nsVaysCu.js +19 -0
- package/dist/config-schema-nPLpEgHl.js +200 -0
- package/dist/config-secret-input.runtime-DiKFehsE.js +2 -0
- package/dist/config-update-wZX-HLMn.js +143 -0
- package/dist/contract-api.js +9 -0
- package/dist/create-client-DCnqDaqd.js +64 -0
- package/dist/credentials-DV6fWXhC.js +56 -0
- package/dist/credentials-read-cmHgousK.js +112 -0
- package/dist/credentials-write.runtime-zniTq-Gr.js +17 -0
- package/dist/crypto-node.runtime-pihzdpY7.js +12 -0
- package/dist/crypto-runtime-ZI0zAtn3.js +1214 -0
- package/dist/deps-C6WqKY7m.js +235 -0
- package/dist/device-health-UVYpbA_W.js +16 -0
- package/dist/direct-management-DMMMgtTB.js +249 -0
- package/dist/direct-room-XkutHjES.js +76 -0
- package/dist/directory-live-DmOtMhyr.js +150 -0
- package/dist/doctor-C4__7c-U.js +153 -0
- package/dist/doctor-contract-D4-64QuJ.js +246 -0
- package/dist/doctor-contract-api.js +2 -0
- package/dist/draft-stream-BE2QevQQ.js +144 -0
- package/dist/encryption-guidance-BPi3A_m3.js +15 -0
- package/dist/env-auth-BJqGI8M6.js +63 -0
- package/dist/env-vars-C7uQCTKn.js +63 -0
- package/dist/errors-CTcpEDq-.js +17 -0
- package/dist/exec-approval-resolver-Bza9Dhlm.js +15 -0
- package/dist/exec-approvals-Crnh543m.js +196 -0
- package/dist/helper-api.js +4 -0
- package/dist/http-client-C7AeVJay.js +319 -0
- package/dist/index.js +46 -0
- package/dist/legacy-crypto-inspector-poDWldgy.js +41 -0
- package/dist/legacy-crypto-restore-Biw-w2ng.js +85 -0
- package/dist/logger-CnZRVrux.js +78 -0
- package/dist/logging-DZHSPP5N.js +99 -0
- package/dist/matrix-migration.runtime-WY6ffcrf.js +525 -0
- package/dist/media-text-DU6nWZuj.js +146 -0
- package/dist/messages-BpihMh82.js +140 -0
- package/dist/migration-snapshot-backup-DaCHTp8C.js +69 -0
- package/dist/migration-snapshot.runtime-CKHE3xF9.js +2 -0
- package/dist/monitor-C_81r_Ck.js +4125 -0
- package/dist/plugin-entry.handlers.runtime.js +51 -0
- package/dist/probe.runtime-BvAzYAIe.js +3 -0
- package/dist/profile-BlHu0wDX.js +111 -0
- package/dist/profile-update-DjeBNgIV.js +69 -0
- package/dist/reaction-common-ejrL19w-.js +71 -0
- package/dist/reaction-events-CiARZfjk.js +121 -0
- package/dist/record-shared-CHWJCTWf.js +2 -0
- package/dist/recovery-key-store-BTJ6jz5v.js +294 -0
- package/dist/resolve-targets-YtJnw1Tb.js +140 -0
- package/dist/resolver.runtime-D9piiGEl.js +5 -0
- package/dist/rolldown-runtime-DUslC3ob.js +14 -0
- package/dist/route-D6rg-iXN.js +161 -0
- package/dist/runtime-C6X4h_SJ.js +6 -0
- package/dist/runtime-Dog86njy.js +8 -0
- package/dist/runtime-api-BXWBFIqm.js +25 -0
- package/dist/runtime-api.js +25 -0
- package/dist/runtime-heavy-api.js +3 -0
- package/dist/runtime-setter-api.js +2 -0
- package/dist/sdk-B2vZA27-.js +1416 -0
- package/dist/secret-contract-DcrJWCQI.js +120 -0
- package/dist/secret-contract-api.js +2 -0
- package/dist/send-Bo0DU1ca.js +1200 -0
- package/dist/session-store-metadata-DI5SCofx.js +77 -0
- package/dist/setup-bootstrap-ImenBsMt.js +62 -0
- package/dist/setup-core-CfZy05oW.js +116 -0
- package/dist/setup-dm-policy-2-r1FrQh.js +194 -0
- package/dist/setup-entry.js +19 -0
- package/dist/setup-plugin-api.js +44 -0
- package/dist/setup-surface-CqT_o61M.js +540 -0
- package/dist/shared-CpMoYKm1.js +195 -0
- package/dist/startup-abort-56edvmbM.js +32 -0
- package/dist/startup-verification-Demyp0bP.js +132 -0
- package/dist/storage-paths-BJLdnCjV.js +52 -0
- package/dist/storage-tC3ujLiW.js +281 -0
- package/dist/subagent-hooks-DQbyqq9V.js +149 -0
- package/dist/subagent-hooks-api.js +23 -0
- package/dist/sync-state-C_beeevA.js +12 -0
- package/dist/target-ids-80nQ2gql.js +77 -0
- package/dist/test-api.js +4 -0
- package/dist/thread-binding-api-Cq_E-E1K.js +17 -0
- package/dist/thread-binding-api.js +2 -0
- package/dist/thread-bindings-B9mesxXk.js +352 -0
- package/dist/thread-bindings-runtime.js +2 -0
- package/dist/thread-bindings-shared-DK-d-oYX.js +97 -0
- package/dist/timeout-abort-signal-CtaIaP1v.js +2 -0
- package/dist/tool-actions.runtime-BIH49vRr.js +532 -0
- package/dist/url-validation-DiK9j7jz.js +36 -0
- package/dist/verification-CZ2rDeHL.js +345 -0
- package/openclaw.plugin.json +788 -1
- package/package.json +82 -16
- package/CHANGELOG.md +0 -104
- package/index.ts +0 -22
- package/src/actions.ts +0 -195
- package/src/channel.directory.test.ts +0 -135
- package/src/channel.ts +0 -461
- package/src/config-schema.test.ts +0 -26
- package/src/config-schema.ts +0 -62
- package/src/directory-live.test.ts +0 -85
- package/src/directory-live.ts +0 -209
- package/src/group-mentions.ts +0 -52
- package/src/matrix/accounts.test.ts +0 -131
- package/src/matrix/accounts.ts +0 -114
- package/src/matrix/actions/client.ts +0 -47
- package/src/matrix/actions/limits.test.ts +0 -15
- package/src/matrix/actions/limits.ts +0 -6
- package/src/matrix/actions/messages.ts +0 -126
- package/src/matrix/actions/pins.test.ts +0 -74
- package/src/matrix/actions/pins.ts +0 -84
- package/src/matrix/actions/reactions.test.ts +0 -109
- package/src/matrix/actions/reactions.ts +0 -102
- package/src/matrix/actions/room.ts +0 -85
- package/src/matrix/actions/summary.ts +0 -75
- package/src/matrix/actions/types.ts +0 -85
- package/src/matrix/actions.ts +0 -15
- package/src/matrix/active-client.ts +0 -32
- package/src/matrix/client/config.ts +0 -245
- package/src/matrix/client/create-client.ts +0 -125
- package/src/matrix/client/logging.ts +0 -46
- package/src/matrix/client/runtime.ts +0 -4
- package/src/matrix/client/shared.test.ts +0 -85
- package/src/matrix/client/shared.ts +0 -210
- package/src/matrix/client/startup.test.ts +0 -49
- package/src/matrix/client/startup.ts +0 -29
- package/src/matrix/client/storage.ts +0 -131
- package/src/matrix/client/types.ts +0 -34
- package/src/matrix/client-bootstrap.ts +0 -47
- package/src/matrix/client.test.ts +0 -56
- package/src/matrix/client.ts +0 -14
- package/src/matrix/credentials.ts +0 -125
- package/src/matrix/deps.test.ts +0 -74
- package/src/matrix/deps.ts +0 -126
- package/src/matrix/format.test.ts +0 -33
- package/src/matrix/format.ts +0 -22
- package/src/matrix/index.ts +0 -11
- package/src/matrix/monitor/access-policy.ts +0 -126
- package/src/matrix/monitor/allowlist.test.ts +0 -45
- package/src/matrix/monitor/allowlist.ts +0 -94
- package/src/matrix/monitor/auto-join.ts +0 -72
- package/src/matrix/monitor/direct.test.ts +0 -396
- package/src/matrix/monitor/direct.ts +0 -152
- package/src/matrix/monitor/events.test.ts +0 -186
- package/src/matrix/monitor/events.ts +0 -168
- package/src/matrix/monitor/handler.body-for-agent.test.ts +0 -196
- package/src/matrix/monitor/handler.ts +0 -768
- package/src/matrix/monitor/inbound-body.test.ts +0 -73
- package/src/matrix/monitor/inbound-body.ts +0 -28
- package/src/matrix/monitor/index.test.ts +0 -18
- package/src/matrix/monitor/index.ts +0 -414
- package/src/matrix/monitor/location.ts +0 -100
- package/src/matrix/monitor/media.test.ts +0 -86
- package/src/matrix/monitor/media.ts +0 -118
- package/src/matrix/monitor/mentions.test.ts +0 -154
- package/src/matrix/monitor/mentions.ts +0 -62
- package/src/matrix/monitor/replies.test.ts +0 -184
- package/src/matrix/monitor/replies.ts +0 -124
- package/src/matrix/monitor/room-info.ts +0 -55
- package/src/matrix/monitor/rooms.test.ts +0 -124
- package/src/matrix/monitor/rooms.ts +0 -47
- package/src/matrix/monitor/threads.ts +0 -68
- package/src/matrix/monitor/types.ts +0 -39
- package/src/matrix/poll-types.test.ts +0 -21
- package/src/matrix/poll-types.ts +0 -167
- package/src/matrix/probe.ts +0 -69
- package/src/matrix/sdk-runtime.ts +0 -18
- package/src/matrix/send/client.ts +0 -99
- package/src/matrix/send/formatting.ts +0 -93
- package/src/matrix/send/media.ts +0 -230
- package/src/matrix/send/targets.test.ts +0 -98
- package/src/matrix/send/targets.ts +0 -150
- package/src/matrix/send/types.ts +0 -110
- package/src/matrix/send-queue.test.ts +0 -145
- package/src/matrix/send-queue.ts +0 -28
- package/src/matrix/send.test.ts +0 -319
- package/src/matrix/send.ts +0 -267
- package/src/onboarding.ts +0 -462
- package/src/outbound.test.ts +0 -159
- package/src/outbound.ts +0 -58
- package/src/resolve-targets.test.ts +0 -68
- package/src/resolve-targets.ts +0 -125
- package/src/runtime.ts +0 -6
- package/src/secret-input.ts +0 -13
- package/src/test-mocks.ts +0 -53
- package/src/tool-actions.ts +0 -164
- package/src/types.ts +0 -118
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
import type { MatrixClient } from "@vector-im/matrix-bot-sdk";
|
|
2
|
-
import type { PluginRuntime, RuntimeLogger } from "openclaw/plugin-sdk/matrix";
|
|
3
|
-
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
4
|
-
import type { MatrixAuth } from "../client.js";
|
|
5
|
-
import { registerMatrixMonitorEvents } from "./events.js";
|
|
6
|
-
import type { MatrixRawEvent } from "./types.js";
|
|
7
|
-
|
|
8
|
-
const sendReadReceiptMatrixMock = vi.hoisted(() => vi.fn().mockResolvedValue(undefined));
|
|
9
|
-
|
|
10
|
-
vi.mock("../send.js", () => ({
|
|
11
|
-
sendReadReceiptMatrix: (...args: unknown[]) => sendReadReceiptMatrixMock(...args),
|
|
12
|
-
}));
|
|
13
|
-
|
|
14
|
-
describe("registerMatrixMonitorEvents", () => {
|
|
15
|
-
const roomId = "!room:example.org";
|
|
16
|
-
|
|
17
|
-
function makeEvent(overrides: Partial<MatrixRawEvent>): MatrixRawEvent {
|
|
18
|
-
return {
|
|
19
|
-
event_id: "$event",
|
|
20
|
-
sender: "@alice:example.org",
|
|
21
|
-
type: "m.room.message",
|
|
22
|
-
origin_server_ts: 0,
|
|
23
|
-
content: {},
|
|
24
|
-
...overrides,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
beforeEach(() => {
|
|
29
|
-
sendReadReceiptMatrixMock.mockClear();
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
function createHarness(options?: { getUserId?: ReturnType<typeof vi.fn> }) {
|
|
33
|
-
const handlers = new Map<string, (...args: unknown[]) => void>();
|
|
34
|
-
const getUserId = options?.getUserId ?? vi.fn().mockResolvedValue("@bot:example.org");
|
|
35
|
-
const client = {
|
|
36
|
-
on: vi.fn((event: string, handler: (...args: unknown[]) => void) => {
|
|
37
|
-
handlers.set(event, handler);
|
|
38
|
-
}),
|
|
39
|
-
getUserId,
|
|
40
|
-
crypto: undefined,
|
|
41
|
-
} as unknown as MatrixClient;
|
|
42
|
-
|
|
43
|
-
const onRoomMessage = vi.fn();
|
|
44
|
-
const logVerboseMessage = vi.fn();
|
|
45
|
-
const logger = {
|
|
46
|
-
warn: vi.fn(),
|
|
47
|
-
} as unknown as RuntimeLogger;
|
|
48
|
-
|
|
49
|
-
registerMatrixMonitorEvents({
|
|
50
|
-
client,
|
|
51
|
-
auth: { encryption: false } as MatrixAuth,
|
|
52
|
-
logVerboseMessage,
|
|
53
|
-
warnedEncryptedRooms: new Set<string>(),
|
|
54
|
-
warnedCryptoMissingRooms: new Set<string>(),
|
|
55
|
-
logger,
|
|
56
|
-
formatNativeDependencyHint: (() =>
|
|
57
|
-
"") as PluginRuntime["system"]["formatNativeDependencyHint"],
|
|
58
|
-
onRoomMessage,
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
const roomMessageHandler = handlers.get("room.message");
|
|
62
|
-
if (!roomMessageHandler) {
|
|
63
|
-
throw new Error("missing room.message handler");
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return { client, getUserId, onRoomMessage, roomMessageHandler, logVerboseMessage };
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
async function expectForwardedWithoutReadReceipt(event: MatrixRawEvent) {
|
|
70
|
-
const { onRoomMessage, roomMessageHandler } = createHarness();
|
|
71
|
-
|
|
72
|
-
roomMessageHandler(roomId, event);
|
|
73
|
-
await vi.waitFor(() => {
|
|
74
|
-
expect(onRoomMessage).toHaveBeenCalledWith(roomId, event);
|
|
75
|
-
});
|
|
76
|
-
expect(sendReadReceiptMatrixMock).not.toHaveBeenCalled();
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
it("sends read receipt immediately for non-self messages", async () => {
|
|
80
|
-
const { client, onRoomMessage, roomMessageHandler } = createHarness();
|
|
81
|
-
const event = makeEvent({
|
|
82
|
-
event_id: "$e1",
|
|
83
|
-
sender: "@alice:example.org",
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
roomMessageHandler("!room:example.org", event);
|
|
87
|
-
|
|
88
|
-
expect(onRoomMessage).toHaveBeenCalledWith("!room:example.org", event);
|
|
89
|
-
await vi.waitFor(() => {
|
|
90
|
-
expect(sendReadReceiptMatrixMock).toHaveBeenCalledWith("!room:example.org", "$e1", client);
|
|
91
|
-
});
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
it("does not send read receipts for self messages", async () => {
|
|
95
|
-
await expectForwardedWithoutReadReceipt(
|
|
96
|
-
makeEvent({
|
|
97
|
-
event_id: "$e2",
|
|
98
|
-
sender: "@bot:example.org",
|
|
99
|
-
}),
|
|
100
|
-
);
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
it("skips receipt when message lacks sender or event id", async () => {
|
|
104
|
-
await expectForwardedWithoutReadReceipt(
|
|
105
|
-
makeEvent({
|
|
106
|
-
sender: "@alice:example.org",
|
|
107
|
-
event_id: "",
|
|
108
|
-
}),
|
|
109
|
-
);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it("caches self user id across messages", async () => {
|
|
113
|
-
const { getUserId, roomMessageHandler } = createHarness();
|
|
114
|
-
const first = makeEvent({ event_id: "$e3", sender: "@alice:example.org" });
|
|
115
|
-
const second = makeEvent({ event_id: "$e4", sender: "@bob:example.org" });
|
|
116
|
-
|
|
117
|
-
roomMessageHandler("!room:example.org", first);
|
|
118
|
-
roomMessageHandler("!room:example.org", second);
|
|
119
|
-
|
|
120
|
-
await vi.waitFor(() => {
|
|
121
|
-
expect(sendReadReceiptMatrixMock).toHaveBeenCalledTimes(2);
|
|
122
|
-
});
|
|
123
|
-
expect(getUserId).toHaveBeenCalledTimes(1);
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it("logs and continues when sending read receipt fails", async () => {
|
|
127
|
-
sendReadReceiptMatrixMock.mockRejectedValueOnce(new Error("network boom"));
|
|
128
|
-
const { roomMessageHandler, onRoomMessage, logVerboseMessage } = createHarness();
|
|
129
|
-
const event = makeEvent({ event_id: "$e5", sender: "@alice:example.org" });
|
|
130
|
-
|
|
131
|
-
roomMessageHandler("!room:example.org", event);
|
|
132
|
-
|
|
133
|
-
await vi.waitFor(() => {
|
|
134
|
-
expect(onRoomMessage).toHaveBeenCalledWith("!room:example.org", event);
|
|
135
|
-
expect(logVerboseMessage).toHaveBeenCalledWith(
|
|
136
|
-
expect.stringContaining("matrix: early read receipt failed"),
|
|
137
|
-
);
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
it("skips read receipts if self-user lookup fails", async () => {
|
|
142
|
-
const { roomMessageHandler, onRoomMessage, getUserId } = createHarness({
|
|
143
|
-
getUserId: vi.fn().mockRejectedValue(new Error("cannot resolve self")),
|
|
144
|
-
});
|
|
145
|
-
const event = makeEvent({ event_id: "$e6", sender: "@alice:example.org" });
|
|
146
|
-
|
|
147
|
-
roomMessageHandler("!room:example.org", event);
|
|
148
|
-
|
|
149
|
-
await vi.waitFor(() => {
|
|
150
|
-
expect(onRoomMessage).toHaveBeenCalledWith("!room:example.org", event);
|
|
151
|
-
});
|
|
152
|
-
expect(getUserId).toHaveBeenCalledTimes(1);
|
|
153
|
-
expect(sendReadReceiptMatrixMock).not.toHaveBeenCalled();
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
it("skips duplicate listener registration for the same client", () => {
|
|
157
|
-
const handlers = new Map<string, (...args: unknown[]) => void>();
|
|
158
|
-
const onMock = vi.fn((event: string, handler: (...args: unknown[]) => void) => {
|
|
159
|
-
handlers.set(event, handler);
|
|
160
|
-
});
|
|
161
|
-
const client = {
|
|
162
|
-
on: onMock,
|
|
163
|
-
getUserId: vi.fn().mockResolvedValue("@bot:example.org"),
|
|
164
|
-
crypto: undefined,
|
|
165
|
-
} as unknown as MatrixClient;
|
|
166
|
-
const params = {
|
|
167
|
-
client,
|
|
168
|
-
auth: { encryption: false } as MatrixAuth,
|
|
169
|
-
logVerboseMessage: vi.fn(),
|
|
170
|
-
warnedEncryptedRooms: new Set<string>(),
|
|
171
|
-
warnedCryptoMissingRooms: new Set<string>(),
|
|
172
|
-
logger: { warn: vi.fn() } as unknown as RuntimeLogger,
|
|
173
|
-
formatNativeDependencyHint: (() =>
|
|
174
|
-
"") as PluginRuntime["system"]["formatNativeDependencyHint"],
|
|
175
|
-
onRoomMessage: vi.fn(),
|
|
176
|
-
};
|
|
177
|
-
registerMatrixMonitorEvents(params);
|
|
178
|
-
const initialCallCount = onMock.mock.calls.length;
|
|
179
|
-
registerMatrixMonitorEvents(params);
|
|
180
|
-
|
|
181
|
-
expect(onMock).toHaveBeenCalledTimes(initialCallCount);
|
|
182
|
-
expect(params.logVerboseMessage).toHaveBeenCalledWith(
|
|
183
|
-
"matrix: skipping duplicate listener registration for client",
|
|
184
|
-
);
|
|
185
|
-
});
|
|
186
|
-
});
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import type { MatrixClient } from "@vector-im/matrix-bot-sdk";
|
|
2
|
-
import type { PluginRuntime, RuntimeLogger } from "openclaw/plugin-sdk/matrix";
|
|
3
|
-
import type { MatrixAuth } from "../client.js";
|
|
4
|
-
import { sendReadReceiptMatrix } from "../send.js";
|
|
5
|
-
import type { MatrixRawEvent } from "./types.js";
|
|
6
|
-
import { EventType } from "./types.js";
|
|
7
|
-
|
|
8
|
-
const matrixMonitorListenerRegistry = (() => {
|
|
9
|
-
// Prevent duplicate listener registration when both bundled and extension
|
|
10
|
-
// paths attempt to start monitors against the same shared client.
|
|
11
|
-
const registeredClients = new WeakSet<object>();
|
|
12
|
-
return {
|
|
13
|
-
tryRegister(client: object): boolean {
|
|
14
|
-
if (registeredClients.has(client)) {
|
|
15
|
-
return false;
|
|
16
|
-
}
|
|
17
|
-
registeredClients.add(client);
|
|
18
|
-
return true;
|
|
19
|
-
},
|
|
20
|
-
};
|
|
21
|
-
})();
|
|
22
|
-
|
|
23
|
-
function createSelfUserIdResolver(client: Pick<MatrixClient, "getUserId">) {
|
|
24
|
-
let selfUserId: string | undefined;
|
|
25
|
-
let selfUserIdLookup: Promise<string | undefined> | undefined;
|
|
26
|
-
|
|
27
|
-
return async (): Promise<string | undefined> => {
|
|
28
|
-
if (selfUserId) {
|
|
29
|
-
return selfUserId;
|
|
30
|
-
}
|
|
31
|
-
if (!selfUserIdLookup) {
|
|
32
|
-
selfUserIdLookup = client
|
|
33
|
-
.getUserId()
|
|
34
|
-
.then((userId) => {
|
|
35
|
-
selfUserId = userId;
|
|
36
|
-
return userId;
|
|
37
|
-
})
|
|
38
|
-
.catch(() => undefined)
|
|
39
|
-
.finally(() => {
|
|
40
|
-
if (!selfUserId) {
|
|
41
|
-
selfUserIdLookup = undefined;
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
return await selfUserIdLookup;
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function registerMatrixMonitorEvents(params: {
|
|
50
|
-
client: MatrixClient;
|
|
51
|
-
auth: MatrixAuth;
|
|
52
|
-
logVerboseMessage: (message: string) => void;
|
|
53
|
-
warnedEncryptedRooms: Set<string>;
|
|
54
|
-
warnedCryptoMissingRooms: Set<string>;
|
|
55
|
-
logger: RuntimeLogger;
|
|
56
|
-
formatNativeDependencyHint: PluginRuntime["system"]["formatNativeDependencyHint"];
|
|
57
|
-
onRoomMessage: (roomId: string, event: MatrixRawEvent) => void | Promise<void>;
|
|
58
|
-
}): void {
|
|
59
|
-
if (!matrixMonitorListenerRegistry.tryRegister(params.client)) {
|
|
60
|
-
params.logVerboseMessage("matrix: skipping duplicate listener registration for client");
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const {
|
|
65
|
-
client,
|
|
66
|
-
auth,
|
|
67
|
-
logVerboseMessage,
|
|
68
|
-
warnedEncryptedRooms,
|
|
69
|
-
warnedCryptoMissingRooms,
|
|
70
|
-
logger,
|
|
71
|
-
formatNativeDependencyHint,
|
|
72
|
-
onRoomMessage,
|
|
73
|
-
} = params;
|
|
74
|
-
|
|
75
|
-
const resolveSelfUserId = createSelfUserIdResolver(client);
|
|
76
|
-
client.on("room.message", (roomId: string, event: MatrixRawEvent) => {
|
|
77
|
-
const eventId = event?.event_id;
|
|
78
|
-
const senderId = event?.sender;
|
|
79
|
-
if (eventId && senderId) {
|
|
80
|
-
void (async () => {
|
|
81
|
-
const currentSelfUserId = await resolveSelfUserId();
|
|
82
|
-
if (!currentSelfUserId || senderId === currentSelfUserId) {
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
await sendReadReceiptMatrix(roomId, eventId, client).catch((err) => {
|
|
86
|
-
logVerboseMessage(
|
|
87
|
-
`matrix: early read receipt failed room=${roomId} id=${eventId}: ${String(err)}`,
|
|
88
|
-
);
|
|
89
|
-
});
|
|
90
|
-
})();
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
onRoomMessage(roomId, event);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
client.on("room.encrypted_event", (roomId: string, event: MatrixRawEvent) => {
|
|
97
|
-
const eventId = event?.event_id ?? "unknown";
|
|
98
|
-
const eventType = event?.type ?? "unknown";
|
|
99
|
-
logVerboseMessage(`matrix: encrypted event room=${roomId} type=${eventType} id=${eventId}`);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
client.on("room.decrypted_event", (roomId: string, event: MatrixRawEvent) => {
|
|
103
|
-
const eventId = event?.event_id ?? "unknown";
|
|
104
|
-
const eventType = event?.type ?? "unknown";
|
|
105
|
-
logVerboseMessage(`matrix: decrypted event room=${roomId} type=${eventType} id=${eventId}`);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
client.on(
|
|
109
|
-
"room.failed_decryption",
|
|
110
|
-
async (roomId: string, event: MatrixRawEvent, error: Error) => {
|
|
111
|
-
logger.warn("Failed to decrypt message", {
|
|
112
|
-
roomId,
|
|
113
|
-
eventId: event.event_id,
|
|
114
|
-
error: error.message,
|
|
115
|
-
});
|
|
116
|
-
logVerboseMessage(
|
|
117
|
-
`matrix: failed decrypt room=${roomId} id=${event.event_id ?? "unknown"} error=${error.message}`,
|
|
118
|
-
);
|
|
119
|
-
},
|
|
120
|
-
);
|
|
121
|
-
|
|
122
|
-
client.on("room.invite", (roomId: string, event: MatrixRawEvent) => {
|
|
123
|
-
const eventId = event?.event_id ?? "unknown";
|
|
124
|
-
const sender = event?.sender ?? "unknown";
|
|
125
|
-
const isDirect = (event?.content as { is_direct?: boolean } | undefined)?.is_direct === true;
|
|
126
|
-
logVerboseMessage(
|
|
127
|
-
`matrix: invite room=${roomId} sender=${sender} direct=${String(isDirect)} id=${eventId}`,
|
|
128
|
-
);
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
client.on("room.join", (roomId: string, event: MatrixRawEvent) => {
|
|
132
|
-
const eventId = event?.event_id ?? "unknown";
|
|
133
|
-
logVerboseMessage(`matrix: join room=${roomId} id=${eventId}`);
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
client.on("room.event", (roomId: string, event: MatrixRawEvent) => {
|
|
137
|
-
const eventType = event?.type ?? "unknown";
|
|
138
|
-
if (eventType === EventType.RoomMessageEncrypted) {
|
|
139
|
-
logVerboseMessage(
|
|
140
|
-
`matrix: encrypted raw event room=${roomId} id=${event?.event_id ?? "unknown"}`,
|
|
141
|
-
);
|
|
142
|
-
if (auth.encryption !== true && !warnedEncryptedRooms.has(roomId)) {
|
|
143
|
-
warnedEncryptedRooms.add(roomId);
|
|
144
|
-
const warning =
|
|
145
|
-
"matrix: encrypted event received without encryption enabled; set channels.matrix.encryption=true and verify the device to decrypt";
|
|
146
|
-
logger.warn(warning, { roomId });
|
|
147
|
-
}
|
|
148
|
-
if (auth.encryption === true && !client.crypto && !warnedCryptoMissingRooms.has(roomId)) {
|
|
149
|
-
warnedCryptoMissingRooms.add(roomId);
|
|
150
|
-
const hint = formatNativeDependencyHint({
|
|
151
|
-
packageName: "@matrix-org/matrix-sdk-crypto-nodejs",
|
|
152
|
-
manager: "pnpm",
|
|
153
|
-
downloadCommand: "node node_modules/@matrix-org/matrix-sdk-crypto-nodejs/download-lib.js",
|
|
154
|
-
});
|
|
155
|
-
const warning = `matrix: encryption enabled but crypto is unavailable; ${hint}`;
|
|
156
|
-
logger.warn(warning, { roomId });
|
|
157
|
-
}
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
if (eventType === EventType.RoomMember) {
|
|
161
|
-
const membership = (event?.content as { membership?: string } | undefined)?.membership;
|
|
162
|
-
const stateKey = (event as { state_key?: string }).state_key ?? "";
|
|
163
|
-
logVerboseMessage(
|
|
164
|
-
`matrix: member event room=${roomId} stateKey=${stateKey} membership=${membership ?? "unknown"}`,
|
|
165
|
-
);
|
|
166
|
-
}
|
|
167
|
-
});
|
|
168
|
-
}
|
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
import type { MatrixClient } from "@vector-im/matrix-bot-sdk";
|
|
2
|
-
import type { PluginRuntime, RuntimeEnv, RuntimeLogger } from "openclaw/plugin-sdk/matrix";
|
|
3
|
-
import { describe, expect, it, vi } from "vitest";
|
|
4
|
-
import {
|
|
5
|
-
createMatrixRoomMessageHandler,
|
|
6
|
-
resolveMatrixBaseRouteSession,
|
|
7
|
-
shouldOverrideMatrixDmToGroup,
|
|
8
|
-
} from "./handler.js";
|
|
9
|
-
import { EventType, type MatrixRawEvent } from "./types.js";
|
|
10
|
-
|
|
11
|
-
describe("createMatrixRoomMessageHandler BodyForAgent sender label", () => {
|
|
12
|
-
it("stores sender-labeled BodyForAgent for group thread messages", async () => {
|
|
13
|
-
const recordInboundSession = vi.fn().mockResolvedValue(undefined);
|
|
14
|
-
const formatInboundEnvelope = vi
|
|
15
|
-
.fn()
|
|
16
|
-
.mockImplementation((params: { senderLabel?: string; body: string }) => params.body);
|
|
17
|
-
const finalizeInboundContext = vi
|
|
18
|
-
.fn()
|
|
19
|
-
.mockImplementation((ctx: Record<string, unknown>) => ctx);
|
|
20
|
-
|
|
21
|
-
const core = {
|
|
22
|
-
channel: {
|
|
23
|
-
pairing: {
|
|
24
|
-
readAllowFromStore: vi.fn().mockResolvedValue([]),
|
|
25
|
-
upsertPairingRequest: vi.fn().mockResolvedValue(undefined),
|
|
26
|
-
},
|
|
27
|
-
routing: {
|
|
28
|
-
buildAgentSessionKey: vi
|
|
29
|
-
.fn()
|
|
30
|
-
.mockImplementation(
|
|
31
|
-
(params: { agentId: string; channel: string; peer?: { kind: string; id: string } }) =>
|
|
32
|
-
`agent:${params.agentId}:${params.channel}:${params.peer?.kind ?? "direct"}:${params.peer?.id ?? "unknown"}`,
|
|
33
|
-
),
|
|
34
|
-
resolveAgentRoute: vi.fn().mockReturnValue({
|
|
35
|
-
agentId: "main",
|
|
36
|
-
accountId: undefined,
|
|
37
|
-
sessionKey: "agent:main:matrix:channel:!room:example.org",
|
|
38
|
-
mainSessionKey: "agent:main:main",
|
|
39
|
-
}),
|
|
40
|
-
},
|
|
41
|
-
session: {
|
|
42
|
-
resolveStorePath: vi.fn().mockReturnValue("/tmp/openclaw-test-session.json"),
|
|
43
|
-
readSessionUpdatedAt: vi.fn().mockReturnValue(123),
|
|
44
|
-
recordInboundSession,
|
|
45
|
-
},
|
|
46
|
-
reply: {
|
|
47
|
-
resolveEnvelopeFormatOptions: vi.fn().mockReturnValue({}),
|
|
48
|
-
formatInboundEnvelope,
|
|
49
|
-
formatAgentEnvelope: vi
|
|
50
|
-
.fn()
|
|
51
|
-
.mockImplementation((params: { body: string }) => params.body),
|
|
52
|
-
finalizeInboundContext,
|
|
53
|
-
resolveHumanDelayConfig: vi.fn().mockReturnValue(undefined),
|
|
54
|
-
createReplyDispatcherWithTyping: vi.fn().mockReturnValue({
|
|
55
|
-
dispatcher: {},
|
|
56
|
-
replyOptions: {},
|
|
57
|
-
markDispatchIdle: vi.fn(),
|
|
58
|
-
}),
|
|
59
|
-
withReplyDispatcher: vi
|
|
60
|
-
.fn()
|
|
61
|
-
.mockResolvedValue({ queuedFinal: false, counts: { final: 0, partial: 0, tool: 0 } }),
|
|
62
|
-
},
|
|
63
|
-
commands: {
|
|
64
|
-
shouldHandleTextCommands: vi.fn().mockReturnValue(true),
|
|
65
|
-
},
|
|
66
|
-
text: {
|
|
67
|
-
hasControlCommand: vi.fn().mockReturnValue(false),
|
|
68
|
-
resolveMarkdownTableMode: vi.fn().mockReturnValue("code"),
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
|
-
system: {
|
|
72
|
-
enqueueSystemEvent: vi.fn(),
|
|
73
|
-
},
|
|
74
|
-
} as unknown as PluginRuntime;
|
|
75
|
-
|
|
76
|
-
const runtime = {
|
|
77
|
-
error: vi.fn(),
|
|
78
|
-
} as unknown as RuntimeEnv;
|
|
79
|
-
const logger = {
|
|
80
|
-
info: vi.fn(),
|
|
81
|
-
warn: vi.fn(),
|
|
82
|
-
} as unknown as RuntimeLogger;
|
|
83
|
-
const logVerboseMessage = vi.fn();
|
|
84
|
-
|
|
85
|
-
const client = {
|
|
86
|
-
getUserId: vi.fn().mockResolvedValue("@bot:matrix.example.org"),
|
|
87
|
-
} as unknown as MatrixClient;
|
|
88
|
-
|
|
89
|
-
const handler = createMatrixRoomMessageHandler({
|
|
90
|
-
client,
|
|
91
|
-
core,
|
|
92
|
-
cfg: {},
|
|
93
|
-
runtime,
|
|
94
|
-
logger,
|
|
95
|
-
logVerboseMessage,
|
|
96
|
-
allowFrom: [],
|
|
97
|
-
roomsConfig: undefined,
|
|
98
|
-
mentionRegexes: [],
|
|
99
|
-
groupPolicy: "open",
|
|
100
|
-
replyToMode: "first",
|
|
101
|
-
threadReplies: "inbound",
|
|
102
|
-
dmEnabled: true,
|
|
103
|
-
dmPolicy: "open",
|
|
104
|
-
textLimit: 4000,
|
|
105
|
-
mediaMaxBytes: 5 * 1024 * 1024,
|
|
106
|
-
startupMs: Date.now(),
|
|
107
|
-
startupGraceMs: 60_000,
|
|
108
|
-
directTracker: {
|
|
109
|
-
isDirectMessage: vi.fn().mockResolvedValue(false),
|
|
110
|
-
},
|
|
111
|
-
getRoomInfo: vi.fn().mockResolvedValue({
|
|
112
|
-
name: "Dev Room",
|
|
113
|
-
canonicalAlias: "#dev:matrix.example.org",
|
|
114
|
-
altAliases: [],
|
|
115
|
-
}),
|
|
116
|
-
getMemberDisplayName: vi.fn().mockResolvedValue("Bu"),
|
|
117
|
-
accountId: undefined,
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
const event = {
|
|
121
|
-
type: EventType.RoomMessage,
|
|
122
|
-
event_id: "$event1",
|
|
123
|
-
sender: "@bu:matrix.example.org",
|
|
124
|
-
origin_server_ts: Date.now(),
|
|
125
|
-
content: {
|
|
126
|
-
msgtype: "m.text",
|
|
127
|
-
body: "show me my commits",
|
|
128
|
-
"m.mentions": { user_ids: ["@bot:matrix.example.org"] },
|
|
129
|
-
"m.relates_to": {
|
|
130
|
-
rel_type: "m.thread",
|
|
131
|
-
event_id: "$thread-root",
|
|
132
|
-
},
|
|
133
|
-
},
|
|
134
|
-
} as unknown as MatrixRawEvent;
|
|
135
|
-
|
|
136
|
-
await handler("!room:example.org", event);
|
|
137
|
-
|
|
138
|
-
expect(formatInboundEnvelope).toHaveBeenCalledWith(
|
|
139
|
-
expect.objectContaining({
|
|
140
|
-
chatType: "channel",
|
|
141
|
-
senderLabel: "Bu (bu)",
|
|
142
|
-
}),
|
|
143
|
-
);
|
|
144
|
-
expect(recordInboundSession).toHaveBeenCalledWith(
|
|
145
|
-
expect.objectContaining({
|
|
146
|
-
ctx: expect.objectContaining({
|
|
147
|
-
ChatType: "thread",
|
|
148
|
-
BodyForAgent: "Bu (bu): show me my commits",
|
|
149
|
-
}),
|
|
150
|
-
}),
|
|
151
|
-
);
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
it("uses room-scoped session keys for DM rooms matched via parentPeer binding", () => {
|
|
155
|
-
const buildAgentSessionKey = vi
|
|
156
|
-
.fn()
|
|
157
|
-
.mockReturnValue("agent:main:matrix:channel:!dmroom:example.org");
|
|
158
|
-
|
|
159
|
-
const resolved = resolveMatrixBaseRouteSession({
|
|
160
|
-
buildAgentSessionKey,
|
|
161
|
-
baseRoute: {
|
|
162
|
-
agentId: "main",
|
|
163
|
-
sessionKey: "agent:main:main",
|
|
164
|
-
mainSessionKey: "agent:main:main",
|
|
165
|
-
matchedBy: "binding.peer.parent",
|
|
166
|
-
},
|
|
167
|
-
isDirectMessage: true,
|
|
168
|
-
roomId: "!dmroom:example.org",
|
|
169
|
-
accountId: undefined,
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
expect(buildAgentSessionKey).toHaveBeenCalledWith({
|
|
173
|
-
agentId: "main",
|
|
174
|
-
channel: "matrix",
|
|
175
|
-
accountId: undefined,
|
|
176
|
-
peer: { kind: "channel", id: "!dmroom:example.org" },
|
|
177
|
-
});
|
|
178
|
-
expect(resolved).toEqual({
|
|
179
|
-
sessionKey: "agent:main:matrix:channel:!dmroom:example.org",
|
|
180
|
-
lastRoutePolicy: "session",
|
|
181
|
-
});
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
it("does not override DMs to groups for explicit allow:false room config", () => {
|
|
185
|
-
expect(
|
|
186
|
-
shouldOverrideMatrixDmToGroup({
|
|
187
|
-
isDirectMessage: true,
|
|
188
|
-
roomConfigInfo: {
|
|
189
|
-
config: { allow: false },
|
|
190
|
-
allowed: false,
|
|
191
|
-
matchSource: "direct",
|
|
192
|
-
},
|
|
193
|
-
}),
|
|
194
|
-
).toBe(false);
|
|
195
|
-
});
|
|
196
|
-
});
|