@archipelagolab/lobi 1.0.0

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 (315) hide show
  1. package/CHANGELOG.md +164 -0
  2. package/ENDOFFILE +0 -0
  3. package/EOF +0 -0
  4. package/LICENSE +21 -0
  5. package/SPEC-SUPPORT.md +116 -0
  6. package/YAMLEND +0 -0
  7. package/api.ts +18 -0
  8. package/archipelagolab-lobi-1.0.0.tgz +0 -0
  9. package/auth-presence.ts +56 -0
  10. package/channel-plugin-api.ts +3 -0
  11. package/cli-metadata.ts +11 -0
  12. package/contract-api.ts +17 -0
  13. package/docs/CHECKLIST.md +83 -0
  14. package/docs/FORK_SDK_GUIDE.md +279 -0
  15. package/helper-api.ts +3 -0
  16. package/index.test.ts +61 -0
  17. package/index.ts +65 -0
  18. package/openclaw.plugin.json +23 -0
  19. package/package.json +52 -0
  20. package/plugin-entry.handlers.runtime.ts +1 -0
  21. package/runtime-api.ts +54 -0
  22. package/runtime-heavy-api.ts +1 -0
  23. package/scripts/migrate-to-lobi.sh +72 -0
  24. package/secret-contract-api.ts +5 -0
  25. package/setup-entry.ts +13 -0
  26. package/src/account-selection.test.ts +124 -0
  27. package/src/account-selection.ts +226 -0
  28. package/src/actions.account-propagation.test.ts +251 -0
  29. package/src/actions.test.ts +251 -0
  30. package/src/actions.ts +336 -0
  31. package/src/approval-auth.test.ts +23 -0
  32. package/src/approval-auth.ts +25 -0
  33. package/src/approval-handler.runtime.test.ts +46 -0
  34. package/src/approval-handler.runtime.ts +400 -0
  35. package/src/approval-ids.ts +6 -0
  36. package/src/approval-native.test.ts +329 -0
  37. package/src/approval-native.ts +336 -0
  38. package/src/approval-reactions.test.ts +107 -0
  39. package/src/approval-reactions.ts +158 -0
  40. package/src/auth-precedence.ts +61 -0
  41. package/src/channel-account-paths.ts +92 -0
  42. package/src/channel.account-paths.test.ts +102 -0
  43. package/src/channel.directory.test.ts +601 -0
  44. package/src/channel.resolve.test.ts +38 -0
  45. package/src/channel.runtime.ts +16 -0
  46. package/src/channel.setup.test.ts +269 -0
  47. package/src/channel.ts +570 -0
  48. package/src/cli-metadata.ts +19 -0
  49. package/src/cli.test.ts +1015 -0
  50. package/src/cli.ts +1198 -0
  51. package/src/config-adapter.ts +41 -0
  52. package/src/config-schema.test.ts +90 -0
  53. package/src/config-schema.ts +114 -0
  54. package/src/directory-live.test.ts +200 -0
  55. package/src/directory-live.ts +238 -0
  56. package/src/doctor-contract.ts +287 -0
  57. package/src/doctor.test.ts +440 -0
  58. package/src/doctor.ts +262 -0
  59. package/src/env-vars.ts +92 -0
  60. package/src/exec-approval-resolver.test.ts +68 -0
  61. package/src/exec-approval-resolver.ts +23 -0
  62. package/src/exec-approvals.test.ts +483 -0
  63. package/src/exec-approvals.ts +290 -0
  64. package/src/group-mentions.ts +41 -0
  65. package/src/legacy-crypto-inspector-availability.test.ts +81 -0
  66. package/src/legacy-crypto-inspector-availability.ts +60 -0
  67. package/src/legacy-crypto.test.ts +234 -0
  68. package/src/legacy-crypto.ts +549 -0
  69. package/src/legacy-state.test.ts +86 -0
  70. package/src/legacy-state.ts +156 -0
  71. package/src/matrix/account-config.ts +150 -0
  72. package/src/matrix/accounts.readiness.test.ts +27 -0
  73. package/src/matrix/accounts.test.ts +757 -0
  74. package/src/matrix/accounts.ts +194 -0
  75. package/src/matrix/actions/client.test.ts +215 -0
  76. package/src/matrix/actions/client.ts +31 -0
  77. package/src/matrix/actions/devices.test.ts +114 -0
  78. package/src/matrix/actions/devices.ts +34 -0
  79. package/src/matrix/actions/limits.test.ts +15 -0
  80. package/src/matrix/actions/limits.ts +6 -0
  81. package/src/matrix/actions/messages.test.ts +289 -0
  82. package/src/matrix/actions/messages.ts +123 -0
  83. package/src/matrix/actions/pins.test.ts +74 -0
  84. package/src/matrix/actions/pins.ts +64 -0
  85. package/src/matrix/actions/polls.test.ts +71 -0
  86. package/src/matrix/actions/polls.ts +109 -0
  87. package/src/matrix/actions/profile.test.ts +109 -0
  88. package/src/matrix/actions/profile.ts +37 -0
  89. package/src/matrix/actions/reactions.test.ts +135 -0
  90. package/src/matrix/actions/reactions.ts +59 -0
  91. package/src/matrix/actions/room.test.ts +79 -0
  92. package/src/matrix/actions/room.ts +71 -0
  93. package/src/matrix/actions/summary.test.ts +87 -0
  94. package/src/matrix/actions/summary.ts +88 -0
  95. package/src/matrix/actions/types.ts +82 -0
  96. package/src/matrix/actions/verification.test.ts +105 -0
  97. package/src/matrix/actions/verification.ts +237 -0
  98. package/src/matrix/actions.ts +37 -0
  99. package/src/matrix/active-client.ts +26 -0
  100. package/src/matrix/async-lock.ts +18 -0
  101. package/src/matrix/backup-health.ts +115 -0
  102. package/src/matrix/client/config-runtime-api.ts +14 -0
  103. package/src/matrix/client/config-secret-input.runtime.ts +1 -0
  104. package/src/matrix/client/config.ts +982 -0
  105. package/src/matrix/client/create-client.test.ts +115 -0
  106. package/src/matrix/client/create-client.ts +101 -0
  107. package/src/matrix/client/env-auth.ts +6 -0
  108. package/src/matrix/client/file-sync-store.test.ts +265 -0
  109. package/src/matrix/client/file-sync-store.ts +289 -0
  110. package/src/matrix/client/logging.ts +123 -0
  111. package/src/matrix/client/migration-snapshot.runtime.ts +1 -0
  112. package/src/matrix/client/private-network-host.ts +56 -0
  113. package/src/matrix/client/runtime.ts +4 -0
  114. package/src/matrix/client/shared.test.ts +344 -0
  115. package/src/matrix/client/shared.ts +306 -0
  116. package/src/matrix/client/storage.test.ts +634 -0
  117. package/src/matrix/client/storage.ts +544 -0
  118. package/src/matrix/client/types.ts +50 -0
  119. package/src/matrix/client-bootstrap.test.ts +84 -0
  120. package/src/matrix/client-bootstrap.ts +164 -0
  121. package/src/matrix/client-resolver.test-helpers.ts +147 -0
  122. package/src/matrix/client.test.ts +1521 -0
  123. package/src/matrix/client.ts +23 -0
  124. package/src/matrix/config-paths.ts +31 -0
  125. package/src/matrix/config-update.test.ts +237 -0
  126. package/src/matrix/config-update.ts +291 -0
  127. package/src/matrix/credentials-read.ts +206 -0
  128. package/src/matrix/credentials-write.runtime.ts +26 -0
  129. package/src/matrix/credentials.test.ts +501 -0
  130. package/src/matrix/credentials.ts +95 -0
  131. package/src/matrix/deps.test.ts +74 -0
  132. package/src/matrix/deps.ts +225 -0
  133. package/src/matrix/device-health.test.ts +45 -0
  134. package/src/matrix/device-health.ts +31 -0
  135. package/src/matrix/direct-management.test.ts +350 -0
  136. package/src/matrix/direct-management.ts +347 -0
  137. package/src/matrix/direct-room.test.ts +61 -0
  138. package/src/matrix/direct-room.ts +128 -0
  139. package/src/matrix/draft-stream.test.ts +406 -0
  140. package/src/matrix/draft-stream.ts +216 -0
  141. package/src/matrix/encryption-guidance.ts +27 -0
  142. package/src/matrix/errors.ts +21 -0
  143. package/src/matrix/format.test.ts +340 -0
  144. package/src/matrix/format.ts +428 -0
  145. package/src/matrix/legacy-crypto-inspector.ts +95 -0
  146. package/src/matrix/media-errors.ts +20 -0
  147. package/src/matrix/media-text.ts +169 -0
  148. package/src/matrix/monitor/access-state.test.ts +45 -0
  149. package/src/matrix/monitor/access-state.ts +77 -0
  150. package/src/matrix/monitor/ack-config.test.ts +57 -0
  151. package/src/matrix/monitor/ack-config.ts +26 -0
  152. package/src/matrix/monitor/allowlist.test.ts +45 -0
  153. package/src/matrix/monitor/allowlist.ts +94 -0
  154. package/src/matrix/monitor/auto-join.test.ts +203 -0
  155. package/src/matrix/monitor/auto-join.ts +86 -0
  156. package/src/matrix/monitor/config.test.ts +197 -0
  157. package/src/matrix/monitor/config.ts +303 -0
  158. package/src/matrix/monitor/context-summary.ts +43 -0
  159. package/src/matrix/monitor/direct.test.ts +529 -0
  160. package/src/matrix/monitor/direct.ts +270 -0
  161. package/src/matrix/monitor/events.test.ts +1524 -0
  162. package/src/matrix/monitor/events.ts +213 -0
  163. package/src/matrix/monitor/handler.body-for-agent.test.ts +396 -0
  164. package/src/matrix/monitor/handler.group-history.test.ts +648 -0
  165. package/src/matrix/monitor/handler.media-failure.test.ts +267 -0
  166. package/src/matrix/monitor/handler.test-helpers.ts +308 -0
  167. package/src/matrix/monitor/handler.test.ts +2952 -0
  168. package/src/matrix/monitor/handler.thread-root-media.test.ts +82 -0
  169. package/src/matrix/monitor/handler.ts +1679 -0
  170. package/src/matrix/monitor/inbound-dedupe.test.ts +146 -0
  171. package/src/matrix/monitor/inbound-dedupe.ts +267 -0
  172. package/src/matrix/monitor/index.test.ts +920 -0
  173. package/src/matrix/monitor/index.ts +434 -0
  174. package/src/matrix/monitor/legacy-crypto-restore.test.ts +206 -0
  175. package/src/matrix/monitor/legacy-crypto-restore.ts +139 -0
  176. package/src/matrix/monitor/location.ts +100 -0
  177. package/src/matrix/monitor/media.test.ts +159 -0
  178. package/src/matrix/monitor/media.ts +119 -0
  179. package/src/matrix/monitor/mentions.test.ts +289 -0
  180. package/src/matrix/monitor/mentions.ts +177 -0
  181. package/src/matrix/monitor/reaction-events.test.ts +326 -0
  182. package/src/matrix/monitor/reaction-events.ts +187 -0
  183. package/src/matrix/monitor/recent-invite.test.ts +92 -0
  184. package/src/matrix/monitor/recent-invite.ts +30 -0
  185. package/src/matrix/monitor/replies.test.ts +265 -0
  186. package/src/matrix/monitor/replies.ts +136 -0
  187. package/src/matrix/monitor/reply-context.test.ts +276 -0
  188. package/src/matrix/monitor/reply-context.ts +92 -0
  189. package/src/matrix/monitor/room-history.test.ts +258 -0
  190. package/src/matrix/monitor/room-history.ts +301 -0
  191. package/src/matrix/monitor/room-info.test.ts +201 -0
  192. package/src/matrix/monitor/room-info.ts +126 -0
  193. package/src/matrix/monitor/rooms.test.ts +121 -0
  194. package/src/matrix/monitor/rooms.ts +52 -0
  195. package/src/matrix/monitor/route.test.ts +255 -0
  196. package/src/matrix/monitor/route.ts +178 -0
  197. package/src/matrix/monitor/runtime-api.ts +31 -0
  198. package/src/matrix/monitor/startup-verification.test.ts +294 -0
  199. package/src/matrix/monitor/startup-verification.ts +237 -0
  200. package/src/matrix/monitor/startup.test.ts +257 -0
  201. package/src/matrix/monitor/startup.ts +218 -0
  202. package/src/matrix/monitor/status.ts +111 -0
  203. package/src/matrix/monitor/sync-lifecycle.test.ts +224 -0
  204. package/src/matrix/monitor/sync-lifecycle.ts +91 -0
  205. package/src/matrix/monitor/task-runner.ts +38 -0
  206. package/src/matrix/monitor/thread-context.test.ts +149 -0
  207. package/src/matrix/monitor/thread-context.ts +108 -0
  208. package/src/matrix/monitor/threads.test.ts +68 -0
  209. package/src/matrix/monitor/threads.ts +85 -0
  210. package/src/matrix/monitor/types.ts +30 -0
  211. package/src/matrix/monitor/verification-events.ts +627 -0
  212. package/src/matrix/monitor/verification-utils.test.ts +47 -0
  213. package/src/matrix/monitor/verification-utils.ts +46 -0
  214. package/src/matrix/outbound-media-runtime.ts +1 -0
  215. package/src/matrix/poll-summary.ts +110 -0
  216. package/src/matrix/poll-types.test.ts +205 -0
  217. package/src/matrix/poll-types.ts +433 -0
  218. package/src/matrix/probe.runtime.ts +4 -0
  219. package/src/matrix/probe.test.ts +154 -0
  220. package/src/matrix/probe.ts +96 -0
  221. package/src/matrix/profile.test.ts +154 -0
  222. package/src/matrix/profile.ts +184 -0
  223. package/src/matrix/reaction-common.test.ts +96 -0
  224. package/src/matrix/reaction-common.ts +147 -0
  225. package/src/matrix/sdk/crypto-bootstrap.test.ts +505 -0
  226. package/src/matrix/sdk/crypto-bootstrap.ts +341 -0
  227. package/src/matrix/sdk/crypto-facade.test.ts +197 -0
  228. package/src/matrix/sdk/crypto-facade.ts +207 -0
  229. package/src/matrix/sdk/crypto-node.runtime.test.ts +27 -0
  230. package/src/matrix/sdk/crypto-node.runtime.ts +9 -0
  231. package/src/matrix/sdk/crypto-runtime.ts +11 -0
  232. package/src/matrix/sdk/decrypt-bridge.ts +356 -0
  233. package/src/matrix/sdk/event-helpers.test.ts +60 -0
  234. package/src/matrix/sdk/event-helpers.ts +71 -0
  235. package/src/matrix/sdk/http-client.test.ts +134 -0
  236. package/src/matrix/sdk/http-client.ts +87 -0
  237. package/src/matrix/sdk/idb-persistence-lock.ts +51 -0
  238. package/src/matrix/sdk/idb-persistence.lock-order.test.ts +108 -0
  239. package/src/matrix/sdk/idb-persistence.test-helpers.ts +88 -0
  240. package/src/matrix/sdk/idb-persistence.test.ts +149 -0
  241. package/src/matrix/sdk/idb-persistence.ts +283 -0
  242. package/src/matrix/sdk/logger.test.ts +25 -0
  243. package/src/matrix/sdk/logger.ts +108 -0
  244. package/src/matrix/sdk/read-response-with-limit.ts +19 -0
  245. package/src/matrix/sdk/recovery-key-store.test.ts +385 -0
  246. package/src/matrix/sdk/recovery-key-store.ts +430 -0
  247. package/src/matrix/sdk/transport.test.ts +161 -0
  248. package/src/matrix/sdk/transport.ts +344 -0
  249. package/src/matrix/sdk/types.ts +236 -0
  250. package/src/matrix/sdk/verification-manager.test.ts +509 -0
  251. package/src/matrix/sdk/verification-manager.ts +694 -0
  252. package/src/matrix/sdk/verification-status.ts +23 -0
  253. package/src/matrix/sdk.test.ts +2568 -0
  254. package/src/matrix/sdk.ts +1789 -0
  255. package/src/matrix/send/client.test.ts +174 -0
  256. package/src/matrix/send/client.ts +90 -0
  257. package/src/matrix/send/formatting.ts +189 -0
  258. package/src/matrix/send/media.ts +244 -0
  259. package/src/matrix/send/targets.test.ts +254 -0
  260. package/src/matrix/send/targets.ts +104 -0
  261. package/src/matrix/send/types.ts +134 -0
  262. package/src/matrix/send.test.ts +958 -0
  263. package/src/matrix/send.ts +609 -0
  264. package/src/matrix/session-store-metadata.ts +108 -0
  265. package/src/matrix/startup-abort.ts +44 -0
  266. package/src/matrix/sync-state.ts +27 -0
  267. package/src/matrix/target-ids.ts +102 -0
  268. package/src/matrix/thread-bindings-shared.ts +201 -0
  269. package/src/matrix/thread-bindings.test.ts +673 -0
  270. package/src/matrix/thread-bindings.ts +577 -0
  271. package/src/matrix-migration.runtime.ts +9 -0
  272. package/src/migration-config.test.ts +228 -0
  273. package/src/migration-config.ts +243 -0
  274. package/src/migration-snapshot-backup.ts +117 -0
  275. package/src/migration-snapshot.test.ts +184 -0
  276. package/src/migration-snapshot.ts +55 -0
  277. package/src/onboarding.resolve.test.ts +55 -0
  278. package/src/onboarding.test-harness.ts +158 -0
  279. package/src/onboarding.test.ts +665 -0
  280. package/src/onboarding.ts +773 -0
  281. package/src/outbound.test.ts +173 -0
  282. package/src/outbound.ts +78 -0
  283. package/src/plugin-entry.runtime.js +159 -0
  284. package/src/plugin-entry.runtime.test.ts +108 -0
  285. package/src/plugin-entry.runtime.ts +68 -0
  286. package/src/profile-update.ts +68 -0
  287. package/src/record-shared.ts +3 -0
  288. package/src/resolve-targets.test.ts +178 -0
  289. package/src/resolve-targets.ts +175 -0
  290. package/src/resolver.ts +21 -0
  291. package/src/runtime-api.ts +144 -0
  292. package/src/runtime.ts +7 -0
  293. package/src/secret-contract.ts +174 -0
  294. package/src/session-route.test.ts +315 -0
  295. package/src/session-route.ts +113 -0
  296. package/src/setup-bootstrap.ts +94 -0
  297. package/src/setup-config.ts +222 -0
  298. package/src/setup-contract.ts +89 -0
  299. package/src/setup-core.test.ts +326 -0
  300. package/src/setup-core.ts +50 -0
  301. package/src/setup-surface.ts +4 -0
  302. package/src/startup-maintenance.test.ts +227 -0
  303. package/src/startup-maintenance.ts +114 -0
  304. package/src/storage-paths.ts +92 -0
  305. package/src/test-helpers.ts +42 -0
  306. package/src/test-mocks.ts +55 -0
  307. package/src/test-runtime.ts +72 -0
  308. package/src/test-support/monitor-route-test-support.ts +8 -0
  309. package/src/tool-actions.runtime.ts +1 -0
  310. package/src/tool-actions.test.ts +422 -0
  311. package/src/tool-actions.ts +498 -0
  312. package/src/types.ts +230 -0
  313. package/test-api.ts +2 -0
  314. package/thread-bindings-runtime.ts +4 -0
  315. package/tsconfig.json +16 -0
@@ -0,0 +1,422 @@
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { handleMatrixAction } from "./tool-actions.js";
3
+ import type { CoreConfig } from "./types.js";
4
+
5
+ const mocks = vi.hoisted(() => ({
6
+ voteMatrixPoll: vi.fn(),
7
+ reactMatrixMessage: vi.fn(),
8
+ listMatrixReactions: vi.fn(),
9
+ removeMatrixReactions: vi.fn(),
10
+ sendMatrixMessage: vi.fn(),
11
+ listMatrixPins: vi.fn(),
12
+ getMatrixMemberInfo: vi.fn(),
13
+ getMatrixRoomInfo: vi.fn(),
14
+ applyMatrixProfileUpdate: vi.fn(),
15
+ }));
16
+
17
+ vi.mock("./matrix/actions.js", () => {
18
+ return {
19
+ getMatrixMemberInfo: mocks.getMatrixMemberInfo,
20
+ getMatrixRoomInfo: mocks.getMatrixRoomInfo,
21
+ listMatrixReactions: mocks.listMatrixReactions,
22
+ listMatrixPins: mocks.listMatrixPins,
23
+ removeMatrixReactions: mocks.removeMatrixReactions,
24
+ sendMatrixMessage: mocks.sendMatrixMessage,
25
+ voteMatrixPoll: mocks.voteMatrixPoll,
26
+ };
27
+ });
28
+
29
+ vi.mock("./matrix/send.js", () => {
30
+ return {
31
+ reactMatrixMessage: mocks.reactMatrixMessage,
32
+ };
33
+ });
34
+
35
+ vi.mock("./profile-update.js", () => ({
36
+ applyMatrixProfileUpdate: (...args: unknown[]) => mocks.applyMatrixProfileUpdate(...args),
37
+ }));
38
+
39
+ describe("handleMatrixAction pollVote", () => {
40
+ beforeEach(() => {
41
+ vi.clearAllMocks();
42
+ mocks.voteMatrixPoll.mockResolvedValue({
43
+ eventId: "evt-poll-vote",
44
+ roomId: "!room:example",
45
+ pollId: "$poll",
46
+ answerIds: ["a1", "a2"],
47
+ labels: ["Pizza", "Sushi"],
48
+ maxSelections: 2,
49
+ });
50
+ mocks.listMatrixReactions.mockResolvedValue([{ key: "👍", count: 1, users: ["@u:example"] }]);
51
+ mocks.listMatrixPins.mockResolvedValue({ pinned: ["$pin"], events: [] });
52
+ mocks.removeMatrixReactions.mockResolvedValue({ removed: 1 });
53
+ mocks.sendMatrixMessage.mockResolvedValue({
54
+ messageId: "$sent",
55
+ roomId: "!room:example",
56
+ });
57
+ mocks.getMatrixMemberInfo.mockResolvedValue({ userId: "@u:example" });
58
+ mocks.getMatrixRoomInfo.mockResolvedValue({ roomId: "!room:example" });
59
+ mocks.applyMatrixProfileUpdate.mockResolvedValue({
60
+ accountId: "ops",
61
+ displayName: "Ops Bot",
62
+ avatarUrl: "mxc://example/avatar",
63
+ profile: {
64
+ displayNameUpdated: true,
65
+ avatarUpdated: true,
66
+ resolvedAvatarUrl: "mxc://example/avatar",
67
+ uploadedAvatarSource: null,
68
+ convertedAvatarFromHttp: false,
69
+ },
70
+ configPath: "channels.lobi.accounts.ops",
71
+ });
72
+ });
73
+
74
+ it("parses snake_case vote params and forwards normalized selectors", async () => {
75
+ const cfg = {} as CoreConfig;
76
+ const result = await handleMatrixAction(
77
+ {
78
+ action: "pollVote",
79
+ account_id: "main",
80
+ room_id: "!room:example",
81
+ poll_id: "$poll",
82
+ poll_option_id: "a1",
83
+ poll_option_ids: ["a2", ""],
84
+ poll_option_index: "2",
85
+ poll_option_indexes: ["1", "bogus"],
86
+ },
87
+ cfg,
88
+ );
89
+
90
+ expect(mocks.voteMatrixPoll).toHaveBeenCalledWith("!room:example", "$poll", {
91
+ cfg,
92
+ accountId: "main",
93
+ optionIds: ["a2", "a1"],
94
+ optionIndexes: [1, 2],
95
+ });
96
+ expect(result.details).toMatchObject({
97
+ ok: true,
98
+ result: {
99
+ eventId: "evt-poll-vote",
100
+ answerIds: ["a1", "a2"],
101
+ },
102
+ });
103
+ });
104
+
105
+ it("rejects missing poll ids", async () => {
106
+ await expect(
107
+ handleMatrixAction(
108
+ {
109
+ action: "pollVote",
110
+ roomId: "!room:example",
111
+ pollOptionIndex: 1,
112
+ },
113
+ {} as CoreConfig,
114
+ ),
115
+ ).rejects.toThrow("pollId required");
116
+ });
117
+
118
+ it("accepts messageId as a pollId alias for poll votes", async () => {
119
+ const cfg = {} as CoreConfig;
120
+ await handleMatrixAction(
121
+ {
122
+ action: "pollVote",
123
+ roomId: "!room:example",
124
+ messageId: "$poll",
125
+ pollOptionIndex: 1,
126
+ },
127
+ cfg,
128
+ );
129
+
130
+ expect(mocks.voteMatrixPoll).toHaveBeenCalledWith("!room:example", "$poll", {
131
+ cfg,
132
+ optionIds: [],
133
+ optionIndexes: [1],
134
+ });
135
+ });
136
+
137
+ it("passes account-scoped opts to add reactions", async () => {
138
+ const cfg = { channels: { matrix: { actions: { reactions: true } } } } as CoreConfig;
139
+ await handleMatrixAction(
140
+ {
141
+ action: "react",
142
+ accountId: "ops",
143
+ roomId: "!room:example",
144
+ messageId: "$msg",
145
+ emoji: "👍",
146
+ },
147
+ cfg,
148
+ );
149
+
150
+ expect(mocks.reactMatrixMessage).toHaveBeenCalledWith("!room:example", "$msg", "👍", {
151
+ cfg,
152
+ accountId: "ops",
153
+ });
154
+ });
155
+
156
+ it("passes account-scoped opts to remove reactions", async () => {
157
+ const cfg = { channels: { matrix: { actions: { reactions: true } } } } as CoreConfig;
158
+ await handleMatrixAction(
159
+ {
160
+ action: "react",
161
+ account_id: "ops",
162
+ room_id: "!room:example",
163
+ message_id: "$msg",
164
+ emoji: "👍",
165
+ remove: true,
166
+ },
167
+ cfg,
168
+ );
169
+
170
+ expect(mocks.removeMatrixReactions).toHaveBeenCalledWith("!room:example", "$msg", {
171
+ cfg,
172
+ accountId: "ops",
173
+ emoji: "👍",
174
+ });
175
+ });
176
+
177
+ it("passes account-scoped opts and limit to reaction listing", async () => {
178
+ const cfg = { channels: { matrix: { actions: { reactions: true } } } } as CoreConfig;
179
+ const result = await handleMatrixAction(
180
+ {
181
+ action: "reactions",
182
+ account_id: "ops",
183
+ room_id: "!room:example",
184
+ message_id: "$msg",
185
+ limit: "5",
186
+ },
187
+ cfg,
188
+ );
189
+
190
+ expect(mocks.listMatrixReactions).toHaveBeenCalledWith("!room:example", "$msg", {
191
+ cfg,
192
+ accountId: "ops",
193
+ limit: 5,
194
+ });
195
+ expect(result.details).toMatchObject({
196
+ ok: true,
197
+ reactions: [{ key: "👍", count: 1 }],
198
+ });
199
+ });
200
+
201
+ it("passes account-scoped opts to message sends", async () => {
202
+ const cfg = { channels: { matrix: { actions: { messages: true } } } } as CoreConfig;
203
+ await handleMatrixAction(
204
+ {
205
+ action: "sendMessage",
206
+ accountId: "ops",
207
+ to: "room:!room:example",
208
+ content: "hello",
209
+ threadId: "$thread",
210
+ },
211
+ cfg,
212
+ { mediaLocalRoots: ["/tmp/openclaw-matrix-test"] },
213
+ );
214
+
215
+ expect(mocks.sendMatrixMessage).toHaveBeenCalledWith("room:!room:example", "hello", {
216
+ cfg,
217
+ accountId: "ops",
218
+ mediaUrl: undefined,
219
+ mediaLocalRoots: ["/tmp/openclaw-matrix-test"],
220
+ replyToId: undefined,
221
+ threadId: "$thread",
222
+ });
223
+ });
224
+
225
+ it("accepts media-only message sends", async () => {
226
+ const cfg = { channels: { matrix: { actions: { messages: true } } } } as CoreConfig;
227
+ await handleMatrixAction(
228
+ {
229
+ action: "sendMessage",
230
+ accountId: "ops",
231
+ to: "room:!room:example",
232
+ mediaUrl: "file:///tmp/photo.png",
233
+ },
234
+ cfg,
235
+ { mediaLocalRoots: ["/tmp/openclaw-matrix-test"] },
236
+ );
237
+
238
+ expect(mocks.sendMatrixMessage).toHaveBeenCalledWith("room:!room:example", undefined, {
239
+ cfg,
240
+ accountId: "ops",
241
+ mediaUrl: "file:///tmp/photo.png",
242
+ mediaLocalRoots: ["/tmp/openclaw-matrix-test"],
243
+ replyToId: undefined,
244
+ threadId: undefined,
245
+ });
246
+ });
247
+
248
+ it("accepts shared media aliases and voice-send flags", async () => {
249
+ const cfg = { channels: { matrix: { actions: { messages: true } } } } as CoreConfig;
250
+ await handleMatrixAction(
251
+ {
252
+ action: "sendMessage",
253
+ accountId: "ops",
254
+ to: "room:!room:example",
255
+ path: "/tmp/clip.mp3",
256
+ asVoice: true,
257
+ },
258
+ cfg,
259
+ { mediaLocalRoots: ["/tmp/openclaw-matrix-test"] },
260
+ );
261
+
262
+ expect(mocks.sendMatrixMessage).toHaveBeenCalledWith("room:!room:example", undefined, {
263
+ cfg,
264
+ accountId: "ops",
265
+ mediaUrl: "/tmp/clip.mp3",
266
+ mediaLocalRoots: ["/tmp/openclaw-matrix-test"],
267
+ replyToId: undefined,
268
+ threadId: undefined,
269
+ audioAsVoice: true,
270
+ });
271
+ });
272
+
273
+ it("passes mediaLocalRoots to profile updates", async () => {
274
+ const cfg = { channels: { matrix: { actions: { profile: true } } } } as CoreConfig;
275
+ await handleMatrixAction(
276
+ {
277
+ action: "setProfile",
278
+ accountId: "ops",
279
+ avatarPath: "/tmp/avatar.jpg",
280
+ },
281
+ cfg,
282
+ { mediaLocalRoots: ["/tmp/openclaw-matrix-test"] },
283
+ );
284
+
285
+ expect(mocks.applyMatrixProfileUpdate).toHaveBeenCalledWith(
286
+ expect.objectContaining({
287
+ cfg,
288
+ account: "ops",
289
+ avatarPath: "/tmp/avatar.jpg",
290
+ mediaLocalRoots: ["/tmp/openclaw-matrix-test"],
291
+ }),
292
+ );
293
+ });
294
+
295
+ it("passes account-scoped opts to pin listing", async () => {
296
+ const cfg = { channels: { matrix: { actions: { pins: true } } } } as CoreConfig;
297
+ await handleMatrixAction(
298
+ {
299
+ action: "listPins",
300
+ accountId: "ops",
301
+ roomId: "!room:example",
302
+ },
303
+ cfg,
304
+ );
305
+
306
+ expect(mocks.listMatrixPins).toHaveBeenCalledWith("!room:example", {
307
+ cfg,
308
+ accountId: "ops",
309
+ });
310
+ });
311
+
312
+ it("passes account-scoped opts to member and room info actions", async () => {
313
+ const memberCfg = {
314
+ channels: { matrix: { actions: { memberInfo: true } } },
315
+ } as CoreConfig;
316
+ await handleMatrixAction(
317
+ {
318
+ action: "memberInfo",
319
+ accountId: "ops",
320
+ userId: "@u:example",
321
+ roomId: "!room:example",
322
+ },
323
+ memberCfg,
324
+ );
325
+ const roomCfg = { channels: { matrix: { actions: { channelInfo: true } } } } as CoreConfig;
326
+ await handleMatrixAction(
327
+ {
328
+ action: "channelInfo",
329
+ accountId: "ops",
330
+ roomId: "!room:example",
331
+ },
332
+ roomCfg,
333
+ );
334
+
335
+ expect(mocks.getMatrixMemberInfo).toHaveBeenCalledWith("@u:example", {
336
+ cfg: memberCfg,
337
+ accountId: "ops",
338
+ roomId: "!room:example",
339
+ });
340
+ expect(mocks.getMatrixRoomInfo).toHaveBeenCalledWith("!room:example", {
341
+ cfg: roomCfg,
342
+ accountId: "ops",
343
+ });
344
+ });
345
+
346
+ it("persists self-profile updates through the shared profile helper", async () => {
347
+ const cfg = { channels: { matrix: { actions: { profile: true } } } } as CoreConfig;
348
+ const result = await handleMatrixAction(
349
+ {
350
+ action: "setProfile",
351
+ account_id: "ops",
352
+ display_name: "Ops Bot",
353
+ avatar_url: "mxc://example/avatar",
354
+ },
355
+ cfg,
356
+ );
357
+
358
+ expect(mocks.applyMatrixProfileUpdate).toHaveBeenCalledWith({
359
+ cfg,
360
+ account: "ops",
361
+ displayName: "Ops Bot",
362
+ avatarUrl: "mxc://example/avatar",
363
+ });
364
+ expect(result.details).toMatchObject({
365
+ ok: true,
366
+ accountId: "ops",
367
+ profile: {
368
+ displayNameUpdated: true,
369
+ avatarUpdated: true,
370
+ },
371
+ });
372
+ });
373
+
374
+ it("accepts local avatar paths for self-profile updates", async () => {
375
+ const cfg = { channels: { matrix: { actions: { profile: true } } } } as CoreConfig;
376
+ await handleMatrixAction(
377
+ {
378
+ action: "setProfile",
379
+ accountId: "ops",
380
+ path: "/tmp/avatar.jpg",
381
+ },
382
+ cfg,
383
+ );
384
+
385
+ expect(mocks.applyMatrixProfileUpdate).toHaveBeenCalledWith({
386
+ cfg,
387
+ account: "ops",
388
+ displayName: undefined,
389
+ avatarUrl: undefined,
390
+ avatarPath: "/tmp/avatar.jpg",
391
+ });
392
+ });
393
+
394
+ it("respects account-scoped action overrides when gating direct tool actions", async () => {
395
+ await expect(
396
+ handleMatrixAction(
397
+ {
398
+ action: "sendMessage",
399
+ accountId: "ops",
400
+ to: "room:!room:example",
401
+ content: "hello",
402
+ },
403
+ {
404
+ channels: {
405
+ matrix: {
406
+ actions: {
407
+ messages: true,
408
+ },
409
+ accounts: {
410
+ ops: {
411
+ actions: {
412
+ messages: false,
413
+ },
414
+ },
415
+ },
416
+ },
417
+ },
418
+ } as CoreConfig,
419
+ ),
420
+ ).rejects.toThrow("Matrix messages are disabled.");
421
+ });
422
+ });