@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
package/src/channel.ts ADDED
@@ -0,0 +1,570 @@
1
+ import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
2
+ import {
3
+ adaptScopedAccountAccessor,
4
+ createScopedDmSecurityResolver,
5
+ } from "openclaw/plugin-sdk/channel-config-helpers";
6
+ import { buildChannelConfigSchema } from "openclaw/plugin-sdk/channel-config-primitives";
7
+ import { createChatChannelPlugin, type ChannelPlugin } from "openclaw/plugin-sdk/channel-core";
8
+ import {
9
+ createAllowlistProviderOpenWarningCollector,
10
+ projectAccountConfigWarningCollector,
11
+ } from "openclaw/plugin-sdk/channel-policy";
12
+ import { createScopedAccountReplyToModeResolver } from "openclaw/plugin-sdk/conversation-runtime";
13
+ import {
14
+ createChannelDirectoryAdapter,
15
+ createResolvedDirectoryEntriesLister,
16
+ createRuntimeDirectoryLiveAdapter,
17
+ } from "openclaw/plugin-sdk/directory-runtime";
18
+ import { buildTrafficStatusSummary } from "openclaw/plugin-sdk/extension-shared";
19
+ import { createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
20
+ import { createRuntimeOutboundDelegates } from "openclaw/plugin-sdk/outbound-runtime";
21
+ import {
22
+ buildProbeChannelStatusSummary,
23
+ collectStatusIssuesFromLastError,
24
+ createComputedAccountStatusAdapter,
25
+ createDefaultChannelRuntimeState,
26
+ } from "openclaw/plugin-sdk/status-helpers";
27
+ import { chunkTextForOutbound } from "openclaw/plugin-sdk/text-chunking";
28
+ import {
29
+ normalizeLowercaseStringOrEmpty,
30
+ normalizeOptionalString,
31
+ } from "openclaw/plugin-sdk/text-runtime";
32
+ import { matrixMessageActions } from "./actions.js";
33
+ import { matrixApprovalCapability } from "./approval-native.js";
34
+ import { createMatrixPairingText, createMatrixProbeAccount } from "./channel-account-paths.js";
35
+ import { DEFAULT_ACCOUNT_ID, matrixConfigAdapter } from "./config-adapter.js";
36
+ import { MatrixConfigSchema } from "./config-schema.js";
37
+ import { matrixDoctor } from "./doctor.js";
38
+ import { shouldSuppressLocalMatrixExecApprovalPrompt } from "./exec-approvals.js";
39
+ import {
40
+ resolveMatrixGroupRequireMention,
41
+ resolveMatrixGroupToolPolicy,
42
+ } from "./group-mentions.js";
43
+ import {
44
+ resolveMatrixAccount,
45
+ resolveMatrixAccountConfig,
46
+ type ResolvedMatrixAccount,
47
+ } from "./matrix/accounts.js";
48
+ import { normalizeMatrixUserId } from "./matrix/monitor/allowlist.js";
49
+ import type { MatrixProbe } from "./matrix/probe.js";
50
+ import {
51
+ normalizeMatrixMessagingTarget,
52
+ resolveMatrixDirectUserId,
53
+ resolveMatrixTargetIdentity,
54
+ } from "./matrix/target-ids.js";
55
+ import {
56
+ setMatrixThreadBindingIdleTimeoutBySessionKey,
57
+ setMatrixThreadBindingMaxAgeBySessionKey,
58
+ } from "./matrix/thread-bindings-shared.js";
59
+ import { matrixResolverAdapter } from "./resolver.js";
60
+ import { collectRuntimeConfigAssignments, secretTargetRegistryEntries } from "./secret-contract.js";
61
+ import { resolveMatrixOutboundSessionRoute } from "./session-route.js";
62
+ import {
63
+ namedAccountPromotionKeys,
64
+ resolveSingleAccountPromotionTarget,
65
+ singleAccountKeysToMove,
66
+ } from "./setup-contract.js";
67
+ import { matrixSetupAdapter } from "./setup-core.js";
68
+ import { matrixSetupWizard } from "./setup-surface.js";
69
+ import { runMatrixStartupMaintenance } from "./startup-maintenance.js";
70
+ import type { CoreConfig } from "./types.js";
71
+ // Mutex for serializing account startup (workaround for concurrent dynamic import race condition)
72
+ let matrixStartupLock: Promise<void> = Promise.resolve();
73
+
74
+ const loadMatrixChannelRuntime = createLazyRuntimeNamedExport(
75
+ () => import("./channel.runtime.js"),
76
+ "matrixChannelRuntime",
77
+ );
78
+
79
+ const meta = {
80
+ id: "lobi",
81
+ label: "Lobi",
82
+ selectionLabel: "Lobi (plugin)",
83
+ docsPath: "/channels/lobi",
84
+ docsLabel: "lobi",
85
+ blurb: "Lobi - Lobisland official A2A messaging platform for AI agents.",
86
+ order: 70,
87
+ quickstartAllowFrom: true,
88
+ };
89
+
90
+ const listMatrixDirectoryPeersFromConfig =
91
+ createResolvedDirectoryEntriesLister<ResolvedMatrixAccount>({
92
+ kind: "user",
93
+ resolveAccount: adaptScopedAccountAccessor(resolveMatrixAccount),
94
+ resolveSources: (account) => [
95
+ account.config.dm?.allowFrom ?? [],
96
+ account.config.groupAllowFrom ?? [],
97
+ ...Object.values(account.config.groups ?? account.config.rooms ?? {}).map(
98
+ (room) => room.users ?? [],
99
+ ),
100
+ ],
101
+ normalizeId: (entry) => {
102
+ const raw = entry.replace(/^matrix:/i, "").trim();
103
+ if (!raw || raw === "*") {
104
+ return null;
105
+ }
106
+ const lowered = normalizeLowercaseStringOrEmpty(raw);
107
+ const cleaned = lowered.startsWith("user:") ? raw.slice("user:".length).trim() : raw;
108
+ return cleaned.startsWith("@") ? `user:${cleaned}` : cleaned;
109
+ },
110
+ });
111
+
112
+ const listMatrixDirectoryGroupsFromConfig =
113
+ createResolvedDirectoryEntriesLister<ResolvedMatrixAccount>({
114
+ kind: "group",
115
+ resolveAccount: adaptScopedAccountAccessor(resolveMatrixAccount),
116
+ resolveSources: (account) => [Object.keys(account.config.groups ?? account.config.rooms ?? {})],
117
+ normalizeId: (entry) => {
118
+ const raw = entry.replace(/^matrix:/i, "").trim();
119
+ if (!raw || raw === "*") {
120
+ return null;
121
+ }
122
+ const lowered = normalizeLowercaseStringOrEmpty(raw);
123
+ if (lowered.startsWith("room:") || lowered.startsWith("channel:")) {
124
+ return raw;
125
+ }
126
+ return raw.startsWith("!") ? `room:${raw}` : raw;
127
+ },
128
+ });
129
+
130
+ function projectMatrixConversationBinding(binding: {
131
+ boundAt: number;
132
+ metadata?: {
133
+ lastActivityAt?: number;
134
+ idleTimeoutMs?: number;
135
+ maxAgeMs?: number;
136
+ };
137
+ }) {
138
+ return {
139
+ boundAt: binding.boundAt,
140
+ lastActivityAt:
141
+ typeof binding.metadata?.lastActivityAt === "number"
142
+ ? binding.metadata.lastActivityAt
143
+ : binding.boundAt,
144
+ idleTimeoutMs:
145
+ typeof binding.metadata?.idleTimeoutMs === "number"
146
+ ? binding.metadata.idleTimeoutMs
147
+ : undefined,
148
+ maxAgeMs:
149
+ typeof binding.metadata?.maxAgeMs === "number" ? binding.metadata.maxAgeMs : undefined,
150
+ };
151
+ }
152
+
153
+ const resolveMatrixDmPolicy = createScopedDmSecurityResolver<ResolvedMatrixAccount>({
154
+ channelKey: "lobi",
155
+ resolvePolicy: (account) => account.config.dm?.policy,
156
+ resolveAllowFrom: (account) => account.config.dm?.allowFrom,
157
+ allowFromPathSuffix: "dm.",
158
+ normalizeEntry: (raw) => normalizeMatrixUserId(raw),
159
+ });
160
+
161
+ const collectMatrixSecurityWarnings =
162
+ createAllowlistProviderOpenWarningCollector<ResolvedMatrixAccount>({
163
+ providerConfigPresent: (cfg) => (cfg as CoreConfig).channels?.lobi !== undefined,
164
+ resolveGroupPolicy: (account) => account.config.groupPolicy,
165
+ buildOpenWarning: {
166
+ surface: "Matrix rooms",
167
+ openBehavior: "allows any room to trigger (mention-gated)",
168
+ remediation:
169
+ 'Set channels.lobi.groupPolicy="allowlist" + channels.lobi.groups (and optionally channels.lobi.groupAllowFrom) to restrict rooms',
170
+ },
171
+ });
172
+
173
+ function resolveMatrixAccountConfigPath(accountId: string, field: string): string {
174
+ return accountId === DEFAULT_ACCOUNT_ID
175
+ ? `channels.lobi.${field}`
176
+ : `channels.lobi.accounts.${accountId}.${field}`;
177
+ }
178
+
179
+ function collectMatrixSecurityWarningsForAccount(params: {
180
+ account: ResolvedMatrixAccount;
181
+ cfg: CoreConfig;
182
+ }): string[] {
183
+ const warnings = collectMatrixSecurityWarnings(params);
184
+ if (params.account.accountId !== DEFAULT_ACCOUNT_ID) {
185
+ const groupPolicyPath = resolveMatrixAccountConfigPath(params.account.accountId, "groupPolicy");
186
+ const groupsPath = resolveMatrixAccountConfigPath(params.account.accountId, "groups");
187
+ const groupAllowFromPath = resolveMatrixAccountConfigPath(
188
+ params.account.accountId,
189
+ "groupAllowFrom",
190
+ );
191
+ return warnings.map((warning) =>
192
+ warning
193
+ .replace("channels.lobi.groupPolicy", groupPolicyPath)
194
+ .replace("channels.lobi.groups", groupsPath)
195
+ .replace("channels.lobi.groupAllowFrom", groupAllowFromPath),
196
+ );
197
+ }
198
+ if (params.account.config.autoJoin !== "always") {
199
+ return warnings;
200
+ }
201
+ const autoJoinPath = resolveMatrixAccountConfigPath(params.account.accountId, "autoJoin");
202
+ const autoJoinAllowlistPath = resolveMatrixAccountConfigPath(
203
+ params.account.accountId,
204
+ "autoJoinAllowlist",
205
+ );
206
+ return [
207
+ ...warnings,
208
+ `- Matrix invites: autoJoin="always" joins any invited room before message policy applies. Set ${autoJoinPath}="allowlist" + ${autoJoinAllowlistPath} (or ${autoJoinPath}="off") to restrict joins.`,
209
+ ];
210
+ }
211
+
212
+ function normalizeMatrixAcpConversationId(conversationId: string) {
213
+ const target = resolveMatrixTargetIdentity(conversationId);
214
+ if (!target || target.kind !== "room") {
215
+ return null;
216
+ }
217
+ return { conversationId: target.id };
218
+ }
219
+
220
+ function matchMatrixAcpConversation(params: {
221
+ bindingConversationId: string;
222
+ conversationId: string;
223
+ parentConversationId?: string;
224
+ }) {
225
+ const binding = normalizeMatrixAcpConversationId(params.bindingConversationId);
226
+ if (!binding) {
227
+ return null;
228
+ }
229
+ if (binding.conversationId === params.conversationId) {
230
+ return { conversationId: params.conversationId, matchPriority: 2 };
231
+ }
232
+ if (
233
+ params.parentConversationId &&
234
+ params.parentConversationId !== params.conversationId &&
235
+ binding.conversationId === params.parentConversationId
236
+ ) {
237
+ return {
238
+ conversationId: params.parentConversationId,
239
+ matchPriority: 1,
240
+ };
241
+ }
242
+ return null;
243
+ }
244
+
245
+ function resolveMatrixCommandConversation(params: {
246
+ threadId?: string;
247
+ originatingTo?: string;
248
+ commandTo?: string;
249
+ fallbackTo?: string;
250
+ }) {
251
+ const parentConversationId = [params.originatingTo, params.commandTo, params.fallbackTo]
252
+ .map((candidate) => {
253
+ const trimmed = candidate?.trim();
254
+ if (!trimmed) {
255
+ return undefined;
256
+ }
257
+ const target = resolveMatrixTargetIdentity(trimmed);
258
+ return target?.kind === "room" ? target.id : undefined;
259
+ })
260
+ .find((candidate): candidate is string => Boolean(candidate));
261
+ if (params.threadId) {
262
+ return {
263
+ conversationId: params.threadId,
264
+ ...(parentConversationId ? { parentConversationId } : {}),
265
+ };
266
+ }
267
+ return parentConversationId ? { conversationId: parentConversationId } : null;
268
+ }
269
+
270
+ function resolveMatrixInboundConversation(params: {
271
+ to?: string;
272
+ conversationId?: string;
273
+ threadId?: string | number;
274
+ }) {
275
+ const rawTarget = params.to?.trim() || params.conversationId?.trim() || "";
276
+ const target = rawTarget ? resolveMatrixTargetIdentity(rawTarget) : null;
277
+ const parentConversationId = target?.kind === "room" ? target.id : undefined;
278
+ const threadId =
279
+ params.threadId != null ? normalizeOptionalString(String(params.threadId)) : undefined;
280
+ if (threadId) {
281
+ return {
282
+ conversationId: threadId,
283
+ ...(parentConversationId ? { parentConversationId } : {}),
284
+ };
285
+ }
286
+ return parentConversationId ? { conversationId: parentConversationId } : null;
287
+ }
288
+
289
+ function resolveMatrixDeliveryTarget(params: {
290
+ conversationId: string;
291
+ parentConversationId?: string;
292
+ }) {
293
+ const parentConversationId = params.parentConversationId?.trim();
294
+ if (parentConversationId && parentConversationId !== params.conversationId.trim()) {
295
+ const parentTarget = resolveMatrixTargetIdentity(parentConversationId);
296
+ if (parentTarget?.kind === "room") {
297
+ return {
298
+ to: `room:${parentTarget.id}`,
299
+ threadId: params.conversationId.trim(),
300
+ };
301
+ }
302
+ }
303
+ const conversationTarget = resolveMatrixTargetIdentity(params.conversationId);
304
+ if (conversationTarget?.kind === "room") {
305
+ return { to: `room:${conversationTarget.id}` };
306
+ }
307
+ return null;
308
+ }
309
+
310
+ export const matrixPlugin: ChannelPlugin<ResolvedMatrixAccount, MatrixProbe> =
311
+ createChatChannelPlugin<ResolvedMatrixAccount, MatrixProbe>({
312
+ base: {
313
+ id: "lobi",
314
+ meta,
315
+ setupWizard: matrixSetupWizard,
316
+ capabilities: {
317
+ chatTypes: ["direct", "group", "thread"],
318
+ polls: true,
319
+ reactions: true,
320
+ threads: true,
321
+ media: true,
322
+ },
323
+ reload: { configPrefixes: ["channels.lobi"] },
324
+ configSchema: buildChannelConfigSchema(MatrixConfigSchema),
325
+ config: {
326
+ ...matrixConfigAdapter,
327
+ isConfigured: (account) => account.configured,
328
+ describeAccount: (account) =>
329
+ describeAccountSnapshot({
330
+ account,
331
+ configured: account.configured,
332
+ extra: {
333
+ baseUrl: account.homeserver,
334
+ },
335
+ }),
336
+ },
337
+ approvalCapability: matrixApprovalCapability,
338
+ groups: {
339
+ resolveRequireMention: resolveMatrixGroupRequireMention,
340
+ resolveToolPolicy: resolveMatrixGroupToolPolicy,
341
+ },
342
+ conversationBindings: {
343
+ supportsCurrentConversationBinding: true,
344
+ defaultTopLevelPlacement: "child",
345
+ setIdleTimeoutBySessionKey: ({ targetSessionKey, accountId, idleTimeoutMs }) =>
346
+ setMatrixThreadBindingIdleTimeoutBySessionKey({
347
+ targetSessionKey,
348
+ accountId: accountId ?? "",
349
+ idleTimeoutMs,
350
+ }).map(projectMatrixConversationBinding),
351
+ setMaxAgeBySessionKey: ({ targetSessionKey, accountId, maxAgeMs }) =>
352
+ setMatrixThreadBindingMaxAgeBySessionKey({
353
+ targetSessionKey,
354
+ accountId: accountId ?? "",
355
+ maxAgeMs,
356
+ }).map(projectMatrixConversationBinding),
357
+ },
358
+ messaging: {
359
+ normalizeTarget: normalizeMatrixMessagingTarget,
360
+ resolveInboundConversation: ({ to, conversationId, threadId }) =>
361
+ resolveMatrixInboundConversation({ to, conversationId, threadId }),
362
+ resolveDeliveryTarget: ({ conversationId, parentConversationId }) =>
363
+ resolveMatrixDeliveryTarget({ conversationId, parentConversationId }),
364
+ resolveOutboundSessionRoute: (params) => resolveMatrixOutboundSessionRoute(params),
365
+ targetResolver: {
366
+ looksLikeId: (raw) => {
367
+ const trimmed = raw.trim();
368
+ if (!trimmed) {
369
+ return false;
370
+ }
371
+ if (/^(matrix:)?[!#@]/i.test(trimmed)) {
372
+ return true;
373
+ }
374
+ return trimmed.includes(":");
375
+ },
376
+ hint: "<room|alias|user>",
377
+ },
378
+ },
379
+ directory: createChannelDirectoryAdapter({
380
+ listPeers: async (params) => {
381
+ const entries = await listMatrixDirectoryPeersFromConfig(params);
382
+ return entries.map((entry) => {
383
+ const raw = entry.id.startsWith("user:") ? entry.id.slice("user:".length) : entry.id;
384
+ const incomplete = !raw.startsWith("@") || !raw.includes(":");
385
+ return incomplete ? { ...entry, name: "incomplete id; expected @user:server" } : entry;
386
+ });
387
+ },
388
+ listGroups: async (params) => await listMatrixDirectoryGroupsFromConfig(params),
389
+ ...createRuntimeDirectoryLiveAdapter({
390
+ getRuntime: loadMatrixChannelRuntime,
391
+ listPeersLive: (runtime) => runtime.listMatrixDirectoryPeersLive,
392
+ listGroupsLive: (runtime) => runtime.listMatrixDirectoryGroupsLive,
393
+ }),
394
+ }),
395
+ resolver: matrixResolverAdapter,
396
+ actions: matrixMessageActions,
397
+ secrets: {
398
+ secretTargetRegistryEntries,
399
+ collectRuntimeConfigAssignments,
400
+ },
401
+ setup: {
402
+ ...matrixSetupAdapter,
403
+ singleAccountKeysToMove,
404
+ namedAccountPromotionKeys,
405
+ resolveSingleAccountPromotionTarget,
406
+ },
407
+ bindings: {
408
+ compileConfiguredBinding: ({ conversationId }) =>
409
+ normalizeMatrixAcpConversationId(conversationId),
410
+ matchInboundConversation: ({ compiledBinding, conversationId, parentConversationId }) =>
411
+ matchMatrixAcpConversation({
412
+ bindingConversationId: compiledBinding.conversationId,
413
+ conversationId,
414
+ parentConversationId,
415
+ }),
416
+ resolveCommandConversation: ({ threadId, originatingTo, commandTo, fallbackTo }) =>
417
+ resolveMatrixCommandConversation({
418
+ threadId,
419
+ originatingTo,
420
+ commandTo,
421
+ fallbackTo,
422
+ }),
423
+ },
424
+ status: createComputedAccountStatusAdapter<ResolvedMatrixAccount, MatrixProbe>({
425
+ defaultRuntime: createDefaultChannelRuntimeState(DEFAULT_ACCOUNT_ID),
426
+ collectStatusIssues: (accounts) => collectStatusIssuesFromLastError("matrix", accounts),
427
+ buildChannelSummary: ({ snapshot }) =>
428
+ buildProbeChannelStatusSummary(snapshot, { baseUrl: snapshot.baseUrl ?? null }),
429
+ probeAccount: async ({ account, timeoutMs, cfg }) =>
430
+ await createMatrixProbeAccount({
431
+ resolveMatrixAuth: async ({ cfg, accountId }) =>
432
+ (await loadMatrixChannelRuntime()).resolveMatrixAuth({
433
+ cfg,
434
+ accountId,
435
+ }),
436
+ probeMatrix: async (params) =>
437
+ await (await loadMatrixChannelRuntime()).probeMatrix(params),
438
+ })({
439
+ account,
440
+ timeoutMs,
441
+ cfg,
442
+ }),
443
+ resolveAccountSnapshot: ({ account, runtime }) => ({
444
+ accountId: account.accountId,
445
+ name: account.name,
446
+ enabled: account.enabled,
447
+ configured: account.configured,
448
+ extra: {
449
+ baseUrl: account.homeserver,
450
+ lastProbeAt: runtime?.lastProbeAt ?? null,
451
+ ...buildTrafficStatusSummary(runtime),
452
+ },
453
+ }),
454
+ }),
455
+ gateway: {
456
+ startAccount: async (ctx) => {
457
+ const account = ctx.account;
458
+ ctx.setStatus({
459
+ accountId: account.accountId,
460
+ baseUrl: account.homeserver,
461
+ });
462
+ ctx.log?.info(
463
+ `[${account.accountId}] starting provider (${account.homeserver ?? "matrix"})`,
464
+ );
465
+
466
+ // Serialize startup: wait for any previous startup to complete import phase.
467
+ // This works around a race condition with concurrent dynamic imports.
468
+ //
469
+ // INVARIANT: The import() below cannot hang because:
470
+ // 1. It only loads local ESM modules with no circular awaits
471
+ // 2. Module initialization is synchronous (no top-level await in ./matrix/monitor/index.js)
472
+ // 3. The lock only serializes the import phase, not the provider startup
473
+ const previousLock = matrixStartupLock;
474
+ let releaseLock: () => void = () => {};
475
+ matrixStartupLock = new Promise<void>((resolve) => {
476
+ releaseLock = resolve;
477
+ });
478
+ await previousLock;
479
+
480
+ // Lazy import: the monitor pulls the reply pipeline; avoid ESM init cycles.
481
+ // Wrap in try/finally to ensure lock is released even if import fails.
482
+ let monitorMatrixProvider: typeof import("./matrix/monitor/index.js").monitorMatrixProvider;
483
+ try {
484
+ const module = await import("./matrix/monitor/index.js");
485
+ monitorMatrixProvider = module.monitorMatrixProvider;
486
+ } finally {
487
+ // Release lock after import completes or fails
488
+ releaseLock();
489
+ }
490
+
491
+ return monitorMatrixProvider({
492
+ runtime: ctx.runtime,
493
+ channelRuntime: ctx.channelRuntime,
494
+ abortSignal: ctx.abortSignal,
495
+ mediaMaxMb: account.config.mediaMaxMb,
496
+ initialSyncLimit: account.config.initialSyncLimit,
497
+ replyToMode: account.config.replyToMode,
498
+ accountId: account.accountId,
499
+ setStatus: ctx.setStatus,
500
+ });
501
+ },
502
+ },
503
+ doctor: matrixDoctor,
504
+ lifecycle: {
505
+ runStartupMaintenance: runMatrixStartupMaintenance,
506
+ },
507
+ },
508
+ security: {
509
+ resolveDmPolicy: resolveMatrixDmPolicy,
510
+ collectWarnings: projectAccountConfigWarningCollector(
511
+ (cfg) => cfg as CoreConfig,
512
+ collectMatrixSecurityWarningsForAccount,
513
+ ),
514
+ },
515
+ pairing: {
516
+ text: createMatrixPairingText(
517
+ async (to, message, options) =>
518
+ await (await loadMatrixChannelRuntime()).sendMessageMatrix(to, message, options),
519
+ ),
520
+ },
521
+ threading: {
522
+ resolveReplyToMode: createScopedAccountReplyToModeResolver<
523
+ ReturnType<typeof resolveMatrixAccountConfig>
524
+ >({
525
+ resolveAccount: adaptScopedAccountAccessor(resolveMatrixAccountConfig),
526
+ resolveReplyToMode: (account) => account.replyToMode,
527
+ }),
528
+ buildToolContext: ({ context, hasRepliedRef }) => {
529
+ const currentTarget = context.To;
530
+ return {
531
+ currentChannelId: normalizeOptionalString(currentTarget),
532
+ currentThreadTs:
533
+ context.MessageThreadId != null ? String(context.MessageThreadId) : undefined,
534
+ currentDirectUserId: resolveMatrixDirectUserId({
535
+ from: context.From,
536
+ to: context.To,
537
+ chatType: context.ChatType,
538
+ }),
539
+ hasRepliedRef,
540
+ };
541
+ },
542
+ },
543
+ outbound: {
544
+ deliveryMode: "direct",
545
+ chunker: chunkTextForOutbound,
546
+ chunkerMode: "markdown",
547
+ textChunkLimit: 4000,
548
+ shouldSuppressLocalPayloadPrompt: ({ cfg, accountId, payload }) =>
549
+ shouldSuppressLocalMatrixExecApprovalPrompt({
550
+ cfg,
551
+ accountId,
552
+ payload,
553
+ }),
554
+ ...createRuntimeOutboundDelegates({
555
+ getRuntime: loadMatrixChannelRuntime,
556
+ sendText: {
557
+ resolve: (runtime) => runtime.matrixOutbound.sendText,
558
+ unavailableMessage: "Matrix outbound text delivery is unavailable",
559
+ },
560
+ sendMedia: {
561
+ resolve: (runtime) => runtime.matrixOutbound.sendMedia,
562
+ unavailableMessage: "Matrix outbound media delivery is unavailable",
563
+ },
564
+ sendPoll: {
565
+ resolve: (runtime) => runtime.matrixOutbound.sendPoll,
566
+ unavailableMessage: "Matrix outbound poll delivery is unavailable",
567
+ },
568
+ }),
569
+ },
570
+ });
@@ -0,0 +1,19 @@
1
+ import type { OpenClawPluginApi } from "openclaw/plugin-sdk/channel-plugin-common";
2
+
3
+ export function registerMatrixCliMetadata(api: OpenClawPluginApi) {
4
+ api.registerCli(
5
+ async ({ program }) => {
6
+ const { registerMatrixCli } = await import("./cli.js");
7
+ registerMatrixCli({ program });
8
+ },
9
+ {
10
+ descriptors: [
11
+ {
12
+ name: "lobi",
13
+ description: "Manage Lobi accounts, verification, devices, and profile state",
14
+ hasSubcommands: true,
15
+ },
16
+ ],
17
+ },
18
+ );
19
+ }